mirror of
https://github.com/firefly-iii/firefly-iii.git
synced 2025-09-02 19:16:39 +00:00
Compare commits
63 Commits
develop-20
...
develop-20
Author | SHA1 | Date | |
---|---|---|---|
|
64073768fe | ||
|
fe6dd0f901 | ||
|
aac8d11ff6 | ||
|
afa99a35b5 | ||
|
e9cb0a51d7 | ||
|
9fbcccfd02 | ||
|
468c9c9d56 | ||
|
f76b27a73d | ||
|
579fe81616 | ||
|
ec9ba53690 | ||
|
85337c53d4 | ||
|
eb6d585bb2 | ||
|
378ffbc609 | ||
|
3b3c8e5bcd | ||
|
75cbdb6a57 | ||
|
cdaff0d983 | ||
|
dda3863889 | ||
|
57dc423b3f | ||
|
c0570bc3b2 | ||
|
65110d1666 | ||
|
5a10b29402 | ||
|
028544ca2e | ||
|
af46729372 | ||
|
4c7789a668 | ||
|
292908048c | ||
|
e300314e05 | ||
|
4f1f360346 | ||
|
bff856aeff | ||
|
7f5a1bda8d | ||
|
b506281bd6 | ||
|
dfe9b3e787 | ||
|
2428a2a7c5 | ||
|
0e8f608e00 | ||
|
70071767ab | ||
|
0ad6beb66c | ||
|
1197f65589 | ||
|
7bbf2dcc6f | ||
|
d4ab69ebe6 | ||
|
c8c552602e | ||
|
1921a8050b | ||
|
f488feda93 | ||
|
d90c033b83 | ||
|
9f256253f2 | ||
|
489b7c12e5 | ||
|
1049a8314d | ||
|
48301b6b9c | ||
|
5a92215921 | ||
|
ccfc75852a | ||
|
9804cffff3 | ||
|
901e113fef | ||
|
a4021ff056 | ||
|
902d91ad29 | ||
|
fa2cf22e73 | ||
|
970dad4c49 | ||
|
9d01c7bdb8 | ||
|
dc7d4fb258 | ||
|
a807ca5002 | ||
|
d59d326841 | ||
|
b915548e82 | ||
|
8200a81840 | ||
|
6a49918707 | ||
|
e55fc483bd | ||
|
4ff5f5883d |
@@ -30,6 +30,7 @@ use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
@@ -117,6 +118,13 @@ class ListController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.accounts.piggy-banks', [$account->id]).$this->buildParams());
|
||||
@@ -125,7 +133,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);
|
||||
|
@@ -32,6 +32,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
@@ -117,6 +118,14 @@ class ListController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.budget-limits', [$budget->id]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -82,6 +84,15 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$budgets = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$budgets = $enrichment->enrich($budgets);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($budgets, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.index').$this->buildParams());
|
||||
@@ -103,6 +114,15 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$enrichment->setStart($this->parameters->get('start'));
|
||||
$enrichment->setEnd($this->parameters->get('end'));
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Budget\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -69,6 +71,13 @@ class StoreController extends Controller
|
||||
$budget->refresh();
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Budget\UpdateRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetEnrichment;
|
||||
use FireflyIII\Transformers\BudgetTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -67,6 +69,13 @@ class UpdateController extends Controller
|
||||
$budget = $this->repository->update($budget, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budget = $enrichment->enrichSingle($budget);
|
||||
|
||||
/** @var BudgetTransformer $transformer */
|
||||
$transformer = app(BudgetTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -31,6 +31,7 @@ use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -84,6 +85,14 @@ class ShowController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budgets.limits.index', [$budget->id]).$this->buildParams());
|
||||
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -113,6 +122,13 @@ class ShowController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.budget-limits.index').$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -137,6 +153,13 @@ class ShowController extends Controller
|
||||
// continue!
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\BudgetLimit\StoreRequest;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -74,6 +75,13 @@ class StoreController extends Controller
|
||||
$budgetLimit = $this->blRepository->store($data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrichSingle($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -30,6 +30,7 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Transformers\BudgetLimitTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -80,6 +81,13 @@ class UpdateController extends Controller
|
||||
$budgetLimit = $this->blRepository->update($budgetLimit, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimit = $enrichment->enrich($budgetLimit);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
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 Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -78,6 +80,15 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$categories = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// 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'));
|
||||
$categories = $enrichment->enrich($categories);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($categories, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.categories.index').$this->buildParams());
|
||||
@@ -105,6 +116,15 @@ class ShowController 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);
|
||||
|
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
use FireflyIII\Transformers\ExchangeRateTransformer;
|
||||
@@ -39,7 +40,7 @@ class IndexController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'currency_exchange_rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
@@ -41,7 +42,7 @@ class ShowController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -24,6 +24,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\StoreRequest;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
@@ -37,7 +38,7 @@ class StoreController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Api\V1\Controllers\Models\CurrencyExchangeRate;
|
||||
|
||||
use FireflyIII\Api\V1\Requests\Models\CurrencyExchangeRate\UpdateRequest;
|
||||
use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\CurrencyExchangeRate;
|
||||
use FireflyIII\Repositories\ExchangeRate\ExchangeRateRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\ValidatesUserGroupTrait;
|
||||
@@ -37,7 +38,7 @@ class UpdateController extends Controller
|
||||
use ValidatesUserGroupTrait;
|
||||
|
||||
public const string RESOURCE_KEY = 'exchange-rates';
|
||||
|
||||
protected array $acceptedRoles = [UserRoleEnum::OWNER];
|
||||
private ExchangeRateRepositoryInterface $repository;
|
||||
|
||||
public function __construct()
|
||||
|
@@ -28,6 +28,7 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Repositories\ObjectGroup\ObjectGroupRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\Transformers\BillTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
@@ -124,6 +125,13 @@ class ListController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.object-groups.piggy-banks', [$objectGroup->id]).$this->buildParams());
|
||||
@@ -132,7 +140,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);
|
||||
|
@@ -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);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -77,6 +79,13 @@ class ShowController extends Controller
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBanks = $enrichment->enrich($piggyBanks);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.piggy-banks.index').$this->buildParams());
|
||||
@@ -85,7 +94,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);
|
||||
@@ -101,11 +110,19 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$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);
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\PiggyBank\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -68,6 +70,13 @@ class StoreController extends Controller
|
||||
$piggyBank = $this->repository->store($request->getAll());
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\PiggyBank\UpdateRequest;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -70,13 +72,20 @@ class UpdateController extends Controller
|
||||
$this->repository->setCurrentAmount($piggyBank, $data['current_amount']);
|
||||
}
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
$manager = $this->getManager();
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$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);
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use League\Fractal\Pagination\IlluminatePaginatorAdapter;
|
||||
@@ -76,17 +78,24 @@ class ShowController extends Controller
|
||||
// get list of budgets. Count it and split it.
|
||||
$collection = $this->repository->get();
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.recurrences.index').$this->buildParams());
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
|
||||
$resource = new FractalCollection($recurrences, $transformer, 'recurrences');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
@@ -102,6 +111,13 @@ class ShowController extends Controller
|
||||
{
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Recurrence\StoreRequest;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -69,6 +71,13 @@ class StoreController extends Controller
|
||||
$recurrence = $this->repository->store($data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -28,7 +28,9 @@ use FireflyIII\Api\V1\Controllers\Controller;
|
||||
use FireflyIII\Api\V1\Requests\Models\Recurrence\UpdateRequest;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
@@ -67,6 +69,13 @@ class UpdateController extends Controller
|
||||
$recurrence = $this->repository->update($recurrence, $data);
|
||||
$manager = $this->getManager();
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
@@ -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());
|
||||
|
@@ -43,6 +43,8 @@ use FireflyIII\Repositories\Rule\RuleRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Api\AccountFilter;
|
||||
use FireflyIII\Support\Http\Api\TransactionFilter;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\BudgetLimitEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\SubscriptionEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\TransactionGroupEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
@@ -227,6 +229,13 @@ class ListController extends Controller
|
||||
$paginator = new LengthAwarePaginator($budgetLimits, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.currencies.budget-limits', [$currency->code]).$this->buildParams());
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new BudgetLimitEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$budgetLimits = $enrichment->enrich($budgetLimits);
|
||||
|
||||
/** @var BudgetLimitTransformer $transformer */
|
||||
$transformer = app(BudgetLimitTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
@@ -268,17 +277,24 @@ class ListController extends Controller
|
||||
}
|
||||
);
|
||||
$count = $collection->count();
|
||||
$piggyBanks = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
$recurrences = $collection->slice(($this->parameters->get('page') - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
// make paginator:
|
||||
$paginator = new LengthAwarePaginator($piggyBanks, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator = new LengthAwarePaginator($recurrences, $count, $pageSize, $this->parameters->get('page'));
|
||||
$paginator->setPath(route('api.v1.currencies.recurrences', [$currency->code]).$this->buildParams());
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters($this->parameters);
|
||||
|
||||
$resource = new FractalCollection($piggyBanks, $transformer, 'recurrences');
|
||||
$resource = new FractalCollection($recurrences, $transformer, 'recurrences');
|
||||
$resource->setPaginator(new IlluminatePaginatorAdapter($paginator));
|
||||
|
||||
return response()->json($manager->createData($resource)->toArray())->header('Content-Type', self::CONTENT_TYPE);
|
||||
|
@@ -248,10 +248,10 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $sums[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'sub_title' => Amount::formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false)
|
||||
.' + '.Amount::formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
@@ -261,7 +261,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $expenses[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -273,7 +273,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, $incomes[$currencyId]['sum'] ?? '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -289,10 +289,10 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => app('amount')->formatAnything($currency, '0', false)
|
||||
.' + '.app('amount')->formatAnything($currency, '0', false),
|
||||
'sub_title' => Amount::formatAnything($currency, '0', false)
|
||||
.' + '.Amount::formatAnything($currency, '0', false),
|
||||
];
|
||||
$return[] = [
|
||||
'key' => sprintf('spent-in-%s', $currency->code),
|
||||
@@ -302,7 +302,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -314,7 +314,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatAnything($currency, '0', false),
|
||||
'value_parsed' => Amount::formatAnything($currency, '0', false),
|
||||
'local_icon' => 'balance-scale',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -405,7 +405,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'value_parsed' => Amount::formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'local_icon' => 'check',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -424,7 +424,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $info['code'],
|
||||
'currency_symbol' => $info['symbol'],
|
||||
'currency_decimal_places' => $info['decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'value_parsed' => Amount::formatFlat($info['symbol'], $info['decimal_places'], $amount, false),
|
||||
'local_icon' => 'calendar-o',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -443,7 +443,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'local_icon' => 'check',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -455,7 +455,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
'local_icon' => 'calendar-o',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -493,14 +493,9 @@ class BasicController extends Controller
|
||||
'currency_code' => $currencies[$currencyId]->code,
|
||||
'currency_symbol' => $currencies[$currencyId]->symbol,
|
||||
'currency_decimal_places' => $currencies[$currencyId]->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
'value_parsed' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$currencies[$currencyId]->symbol,
|
||||
$currencies[$currencyId]->decimal_places,
|
||||
$availableBudget,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($currencies[$currencyId]->symbol, $currencies[$currencyId]->decimal_places, $availableBudget, false),
|
||||
];
|
||||
}
|
||||
foreach ($spent as $row) {
|
||||
@@ -529,18 +524,14 @@ class BasicController extends Controller
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false),
|
||||
'value_parsed' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $leftToSpend, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$row['currency_symbol'],
|
||||
$row['currency_decimal_places'],
|
||||
$perDay,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $perDay, false),
|
||||
];
|
||||
}
|
||||
unset($leftToSpend);
|
||||
if (0 === count($return)) {
|
||||
$days = (int) $start->diffInDays($end, true) + 1;
|
||||
// a small trick to get every expense in this period, regardless of budget.
|
||||
$spent = $this->opsRepository->sumExpenses($start, $end, null, new Collection());
|
||||
foreach ($spent as $row) {
|
||||
@@ -563,14 +554,9 @@ class BasicController extends Controller
|
||||
'currency_code' => $row['currency_code'],
|
||||
'currency_symbol' => $row['currency_symbol'],
|
||||
'currency_decimal_places' => $row['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
|
||||
'value_parsed' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $spentInCurrency, false),
|
||||
'local_icon' => 'money',
|
||||
'sub_title' => app('amount')->formatFlat(
|
||||
$row['currency_symbol'],
|
||||
$row['currency_decimal_places'],
|
||||
$perDay,
|
||||
false
|
||||
),
|
||||
'sub_title' => Amount::formatFlat($row['currency_symbol'], $row['currency_decimal_places'], $perDay, false),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -587,9 +573,9 @@ class BasicController extends Controller
|
||||
// 'currency_code' => $currency->code,
|
||||
// 'currency_symbol' => $currency->symbol,
|
||||
// 'currency_decimal_places' => $currency->decimal_places,
|
||||
// 'value_parsed' => app('amount')->formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
// 'value_parsed' => Amount::formatFlat($currency->symbol, $currency->decimal_places, '0', false),
|
||||
// 'local_icon' => 'money',
|
||||
// 'sub_title' => app('amount')->formatFlat(
|
||||
// 'sub_title' => Amount::formatFlat(
|
||||
// $currency->symbol,
|
||||
// $currency->decimal_places,
|
||||
// '0',
|
||||
@@ -642,7 +628,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $data['currency_code'],
|
||||
'currency_symbol' => $data['currency_symbol'],
|
||||
'currency_decimal_places' => $data['currency_decimal_places'],
|
||||
'value_parsed' => app('amount')->formatFlat($data['currency_symbol'], $data['currency_decimal_places'], $data['balance'], false),
|
||||
'value_parsed' => Amount::formatFlat($data['currency_symbol'], $data['currency_decimal_places'], $data['balance'], false),
|
||||
'local_icon' => 'line-chart',
|
||||
'sub_title' => '',
|
||||
];
|
||||
@@ -656,7 +642,7 @@ class BasicController extends Controller
|
||||
'currency_code' => $this->primaryCurrency->code,
|
||||
'currency_symbol' => $this->primaryCurrency->symbol,
|
||||
'currency_decimal_places' => $this->primaryCurrency->decimal_places,
|
||||
'value_parsed' => app('amount')->formatFlat($this->primaryCurrency->symbol, $this->primaryCurrency->decimal_places, '0', false),
|
||||
'value_parsed' => Amount::formatFlat($this->primaryCurrency->symbol, $this->primaryCurrency->decimal_places, '0', false),
|
||||
'local_icon' => 'line-chart',
|
||||
'sub_title' => '',
|
||||
];
|
||||
|
@@ -136,6 +136,7 @@ class ShowController extends Controller
|
||||
->setAccounts(new Collection([$account]))
|
||||
->setLimit($pageSize)
|
||||
->setPage($page)
|
||||
->withAttachmentInformation()
|
||||
->withAPIInformation()
|
||||
->setRange($start, $end)
|
||||
;
|
||||
|
@@ -95,6 +95,7 @@ class EditController extends Controller
|
||||
$preFilled = [
|
||||
'active' => $hasOldInput ? (bool) $request->old('active') : $budget->active,
|
||||
'auto_budget_currency_id' => $hasOldInput ? (int) $request->old('auto_budget_currency_id') : $this->primaryCurrency->id,
|
||||
'notes' => $this->repository->getNoteText($budget),
|
||||
];
|
||||
if ($autoBudget instanceof AutoBudget) {
|
||||
$amount = $hasOldInput ? $request->old('auto_budget_amount') : $autoBudget->amount;
|
||||
|
@@ -210,7 +210,6 @@ class CategoryReportController extends Controller
|
||||
$spent = $this->opsRepository->listExpenses($start, $end, $accounts, new Collection([$category]));
|
||||
$earned = $this->opsRepository->listIncome($start, $end, $accounts, new Collection([$category]));
|
||||
$format = app('navigation')->preferredCarbonLocalizedFormat($start, $end);
|
||||
|
||||
// loop expenses.
|
||||
foreach ($spent as $currency) {
|
||||
// add things to chart Data for each currency:
|
||||
|
@@ -157,6 +157,11 @@ class DebugController extends Controller
|
||||
return view('debug', compact('table', 'now', 'logContent'));
|
||||
}
|
||||
|
||||
public function apiTest()
|
||||
{
|
||||
return view('test.api-test');
|
||||
}
|
||||
|
||||
private function generateTable(): string
|
||||
{
|
||||
// system information:
|
||||
|
@@ -32,8 +32,10 @@ use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\ObjectGroup\OrganisesObjectGroups;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\AccountEnrichment;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\AccountTransformer;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -114,6 +116,13 @@ class IndexController extends Controller
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
$piggyBanks = [];
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$collection = $enrichment->enrich($collection);
|
||||
|
||||
/** @var PiggyBank $piggy */
|
||||
foreach ($collection as $piggy) {
|
||||
$array = $transformer->transform($piggy);
|
||||
@@ -170,14 +179,6 @@ class IndexController extends Controller
|
||||
$return[$accountId]['target'] = '0';
|
||||
$return[$accountId]['to_save'] = '0';
|
||||
}
|
||||
|
||||
// calculate new interesting fields:
|
||||
// $return[$accountId]['left'] -= $array['current_amount'];
|
||||
// $return[$accountId]['saved'] += $array['current_amount'];
|
||||
// $return[$accountId]['target'] += $array['target_amount'];
|
||||
// $return[$accountId]['to_save'] += ($array['target_amount'] - $array['current_amount']);
|
||||
// $return['account_name'] = $account['name'];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +194,7 @@ class IndexController extends Controller
|
||||
// loop all accounts in this piggy bank subtract the current amount from "left to save" in the $accounts array.
|
||||
/** @var array $piggyAccount */
|
||||
foreach ($piggyBank['accounts'] as $piggyAccount) {
|
||||
$accountId = $piggyAccount['id'];
|
||||
$accountId = $piggyAccount['account_id'];
|
||||
if (array_key_exists($accountId, $accounts)) {
|
||||
$accounts[$accountId]['left'] = bcsub((string) $accounts[$accountId]['left'], (string) $piggyAccount['current_amount']);
|
||||
$accounts[$accountId]['saved'] = bcadd((string) $accounts[$accountId]['saved'], (string) $piggyAccount['current_amount']);
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\PiggyBankEnrichment;
|
||||
use FireflyIII\Transformers\PiggyBankTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
@@ -75,6 +77,13 @@ class ShowController extends Controller
|
||||
$parameters = new ParameterBag();
|
||||
$parameters->set('end', $end);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new PiggyBankEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$piggyBank = $enrichment->enrichSingle($piggyBank);
|
||||
|
||||
/** @var PiggyBankTransformer $transformer */
|
||||
$transformer = app(PiggyBankTransformer::class);
|
||||
$transformer->setParameters($parameters);
|
||||
|
@@ -44,7 +44,6 @@ use Illuminate\View\View;
|
||||
|
||||
use function Safe\json_decode;
|
||||
use function Safe\file_get_contents;
|
||||
use function Safe\strtotime;
|
||||
|
||||
/**
|
||||
* Class PreferencesController.
|
||||
@@ -277,10 +276,10 @@ class PreferencesController extends Controller
|
||||
|
||||
// custom fiscal year
|
||||
$customFiscalYear = 1 === (int) $request->get('customFiscalYear');
|
||||
$string = strtotime((string) $request->get('fiscalYearStart'));
|
||||
if (false !== $string) {
|
||||
$fiscalYearStart = Carbon::createFromTimestamp($string)->format('m-d');
|
||||
Preferences::set('customFiscalYear', $customFiscalYear);
|
||||
Preferences::set('customFiscalYear', $customFiscalYear);
|
||||
$fiscalYearString = (string) $request->get('fiscalYearStart');
|
||||
if ('' !== $fiscalYearString) {
|
||||
$fiscalYearStart = Carbon::parse($fiscalYearString, config('app.timezone'))->format('m-d');
|
||||
Preferences::set('fiscalYearStart', $fiscalYearStart);
|
||||
}
|
||||
|
||||
|
@@ -34,7 +34,10 @@ use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\ExpandedForm;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
@@ -92,13 +95,20 @@ class EditController extends Controller
|
||||
throw new FireflyException('This recurring transaction has no meta-data. You will have to delete it and recreate it. Sorry!');
|
||||
}
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
||||
$array = $transformer->transform($recurrence);
|
||||
$budgets = app('expandedform')->makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
|
||||
$bills = app('expandedform')->makeSelectListWithEmpty($this->billRepository->getActiveBills());
|
||||
$budgets = ExpandedForm::makeSelectListWithEmpty($this->budgetRepos->getActiveBudgets());
|
||||
$bills = ExpandedForm::makeSelectListWithEmpty($this->billRepository->getActiveBills());
|
||||
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
$repetition = $recurrence->recurrenceRepetitions()->first();
|
||||
|
@@ -29,7 +29,9 @@ use FireflyIII\Http\Controllers\Controller;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
@@ -85,6 +87,13 @@ class IndexController extends Controller
|
||||
$total = $collection->count();
|
||||
$recurrences = $collection->slice(($page - 1) * $pageSize, $pageSize);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrences = $enrichment->enrich($recurrences);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
@@ -32,8 +32,10 @@ use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Repositories\Attachment\AttachmentRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Http\Controllers\GetConfigurationData;
|
||||
use FireflyIII\Support\JsonApi\Enrichments\RecurringEnrichment;
|
||||
use FireflyIII\Transformers\AttachmentTransformer;
|
||||
use FireflyIII\Transformers\RecurrenceTransformer;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\View\Factory;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
@@ -80,6 +82,13 @@ class ShowController extends Controller
|
||||
{
|
||||
$repos = app(AttachmentRepositoryInterface::class);
|
||||
|
||||
// enrich
|
||||
/** @var User $admin */
|
||||
$admin = auth()->user();
|
||||
$enrichment = new RecurringEnrichment();
|
||||
$enrichment->setUser($admin);
|
||||
$recurrence = $enrichment->enrichSingle($recurrence);
|
||||
|
||||
/** @var RecurrenceTransformer $transformer */
|
||||
$transformer = app(RecurrenceTransformer::class);
|
||||
$transformer->setParameters(new ParameterBag());
|
||||
|
@@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Http\Controllers\Report;
|
||||
|
||||
use FireflyIII\Support\Facades\Navigation;
|
||||
use Throwable;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
@@ -290,11 +291,12 @@ class BudgetController extends Controller
|
||||
$cache->addProperty('budget-period-report');
|
||||
$cache->addProperty($accounts->pluck('id')->toArray());
|
||||
if ($cache->has()) {
|
||||
return $cache->get();
|
||||
// return $cache->get();
|
||||
}
|
||||
|
||||
$periods = app('navigation')->listOfPeriods($start, $end);
|
||||
$keyFormat = app('navigation')->preferredCarbonFormat($start, $end);
|
||||
$periods = Navigation::listOfPeriods($start, $end);
|
||||
$keyFormat = Navigation::preferredCarbonFormat($start, $end);
|
||||
|
||||
// list expenses for budgets in account(s)
|
||||
$expenses = $this->opsRepository->listExpenses($start, $end, $accounts);
|
||||
|
||||
@@ -303,6 +305,17 @@ class BudgetController extends Controller
|
||||
foreach ($currency['budgets'] as $budget) {
|
||||
$count = 0;
|
||||
foreach ($budget['transaction_journals'] as $journal) {
|
||||
// #10678
|
||||
// skip transactions between two asset / liability accounts.
|
||||
if (
|
||||
in_array($journal['source_account_type'], config('firefly.valid_currency_account_types'), true)
|
||||
&& in_array($journal['destination_account_type'], config('firefly.valid_currency_account_types'), true)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
|
||||
++$count;
|
||||
$key = sprintf('%d-%d', $budget['id'], $currency['currency_id']);
|
||||
$dateKey = $journal['date']->format($keyFormat);
|
||||
|
@@ -252,6 +252,7 @@ class TagController extends Controller
|
||||
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
|
||||
->withAttachmentInformation()
|
||||
;
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
@@ -283,6 +284,7 @@ class TagController extends Controller
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setRange($start, $end)->setLimit($pageSize)->setPage($page)->withAccountInformation()
|
||||
->setTag($tag)->withBudgetInformation()->withCategoryInformation()
|
||||
->withAttachmentInformation()
|
||||
;
|
||||
$groups = $collector->getPaginatedGroups();
|
||||
$groups->setPath($path);
|
||||
|
@@ -47,12 +47,13 @@ class BudgetFormUpdateRequest extends FormRequest
|
||||
public function getBudgetData(): array
|
||||
{
|
||||
return [
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'auto_budget_type' => $this->convertInteger('auto_budget_type'),
|
||||
'currency_id' => $this->convertInteger('auto_budget_currency_id'),
|
||||
'auto_budget_amount' => $this->convertString('auto_budget_amount'),
|
||||
'auto_budget_period' => $this->convertString('auto_budget_period'),
|
||||
'name' => $this->convertString('name'),
|
||||
'active' => $this->boolean('active'),
|
||||
'auto_budget_type' => $this->convertInteger('auto_budget_type'),
|
||||
'currency_id' => $this->convertInteger('auto_budget_currency_id'),
|
||||
'auto_budget_amount' => $this->convertString('auto_budget_amount'),
|
||||
'auto_budget_period' => $this->convertString('auto_budget_period'),
|
||||
'notes' => $this->stringWithNewlines('notes'),
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -202,8 +202,11 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
'amount' => $amount,
|
||||
'destination_account_id' => $journal['destination_account_id'],
|
||||
'destination_account_name' => $journal['destination_account_name'],
|
||||
'destination_account_type' => $journal['destination_account_type'],
|
||||
'currency_id' => $journalCurrencyId,
|
||||
'source_account_id' => $journal['source_account_id'],
|
||||
'source_account_name' => $journal['source_account_name'],
|
||||
'source_account_type' => $journal['source_account_type'],
|
||||
'category_name' => $journal['category_name'],
|
||||
'description' => $journal['description'],
|
||||
'transaction_group_id' => $journal['transaction_group_id'],
|
||||
@@ -290,7 +293,7 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range.
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($start, $end, $transactionCurrency): bool {
|
||||
return $expense['date']->between($start, $end) && $expense['currency_id'] === $transactionCurrency->id;
|
||||
});
|
||||
@@ -298,6 +301,20 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
|
||||
public function sumCollectedExpensesByBudget(array $expenses, Budget $budget, bool $convertToPrimary = false): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($budget): bool {
|
||||
return $expense['budget_id'] === $budget->id;
|
||||
});
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, 'negative', false);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null, ?TransactionCurrency $currency = null): array
|
||||
{
|
||||
|
@@ -76,5 +76,7 @@ interface OperationsRepositoryInterface
|
||||
|
||||
public function sumCollectedExpenses(array $expenses, Carbon $start, Carbon $end, TransactionCurrency $transactionCurrency, bool $convertToPrimary = false): array;
|
||||
|
||||
public function sumCollectedExpensesByBudget(array $expenses, Budget $budget, bool $convertToPrimary = false): array;
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $budgets = null, ?TransactionCurrency $currency = null): array;
|
||||
}
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Report\Summarizer\TransactionSummarizer;
|
||||
use FireflyIII\Support\Repositories\UserGroup\UserGroupInterface;
|
||||
@@ -444,4 +445,74 @@ class OperationsRepository implements OperationsRepositoryInterface, UserGroupIn
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)->setTypes([TransactionTypeEnum::WITHDRAWAL->value]);
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
$collector->withCategoryInformation();
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function collectIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)
|
||||
->setTypes([TransactionTypeEnum::DEPOSIT->value])
|
||||
;
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function collectTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array
|
||||
{
|
||||
/** @var GroupCollectorInterface $collector */
|
||||
$collector = app(GroupCollectorInterface::class);
|
||||
$collector->setUser($this->user)->setRange($start, $end)
|
||||
->setTypes([TransactionTypeEnum::TRANSFER->value])
|
||||
;
|
||||
|
||||
if ($accounts instanceof Collection && $accounts->count() > 0) {
|
||||
$collector->setAccounts($accounts);
|
||||
}
|
||||
if (!$categories instanceof Collection || 0 === $categories->count()) {
|
||||
$categories = $this->getCategories();
|
||||
}
|
||||
$collector->setCategories($categories);
|
||||
|
||||
return $collector->getExtractedJournals();
|
||||
}
|
||||
|
||||
public function sumCollectedTransactionsByCategory(array $expenses, Category $category, string $method, bool $convertToPrimary = false): array
|
||||
{
|
||||
Log::debug(sprintf('Start of %s.', __METHOD__));
|
||||
$summarizer = new TransactionSummarizer($this->user);
|
||||
$summarizer->setConvertToPrimary($convertToPrimary);
|
||||
|
||||
// filter $journals by range AND currency if it is present.
|
||||
$expenses = array_filter($expenses, static function (array $expense) use ($category): bool {
|
||||
return $expense['category_id'] === $category->id;
|
||||
});
|
||||
|
||||
return $summarizer->groupByCurrencyId($expenses, $method, false);
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,7 @@ namespace FireflyIII\Repositories\Category;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\UserRoleEnum;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
@@ -78,6 +79,14 @@ interface OperationsRepositoryInterface
|
||||
*/
|
||||
public function sumExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectExpenses(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectIncome(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function collectTransfers(Carbon $start, Carbon $end, ?Collection $accounts = null, ?Collection $categories = null): array;
|
||||
|
||||
public function sumCollectedTransactionsByCategory(array $expenses, Category $category, string $method, bool $convertToPrimary = false): array;
|
||||
|
||||
/**
|
||||
* Sum of income journals in period for a set of categories, grouped per currency. Amounts are always positive.
|
||||
*/
|
||||
|
@@ -33,6 +33,7 @@ use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\AccountType;
|
||||
use FireflyIII\Models\Location;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -41,6 +42,7 @@ use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Override;
|
||||
|
||||
@@ -51,36 +53,30 @@ use Override;
|
||||
*/
|
||||
class AccountEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private array $accountIds;
|
||||
private array $accountTypeIds;
|
||||
private array $accountTypes;
|
||||
private array $ids = [];
|
||||
private array $accountTypeIds = [];
|
||||
private array $accountTypes = [];
|
||||
private Collection $collection;
|
||||
private array $currencies;
|
||||
private array $locations;
|
||||
private array $meta;
|
||||
private array $currencies = [];
|
||||
private array $locations = [];
|
||||
private array $meta = [];
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private array $notes;
|
||||
private array $openingBalances;
|
||||
private array $notes = [];
|
||||
private array $openingBalances = [];
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private array $lastActivities;
|
||||
private ?Carbon $date = null;
|
||||
private bool $convertToPrimary = false;
|
||||
private array $lastActivities = [];
|
||||
private ?Carbon $date = null;
|
||||
private bool $convertToPrimary;
|
||||
private array $balances = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
|
||||
/**
|
||||
* TODO The account enricher must do conversion from and to the primary currency.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->accountIds = [];
|
||||
$this->openingBalances = [];
|
||||
$this->currencies = [];
|
||||
$this->accountTypeIds = [];
|
||||
$this->accountTypes = [];
|
||||
$this->meta = [];
|
||||
$this->notes = [];
|
||||
$this->lastActivities = [];
|
||||
$this->locations = [];
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
}
|
||||
@@ -105,27 +101,28 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
// prep local fields
|
||||
$this->collection = $collection;
|
||||
$this->collectAccountIds();
|
||||
$this->collectIds();
|
||||
$this->getAccountTypes();
|
||||
$this->collectMetaData();
|
||||
$this->collectNotes();
|
||||
$this->collectLastActivities();
|
||||
$this->collectLocations();
|
||||
$this->collectOpeningBalances();
|
||||
$this->collectObjectGroups();
|
||||
$this->collectBalances();
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
private function collectAccountIds(): void
|
||||
private function collectIds(): void
|
||||
{
|
||||
/** @var Account $account */
|
||||
foreach ($this->collection as $account) {
|
||||
$this->accountIds[] = (int) $account->id;
|
||||
$this->accountTypeIds[] = (int) $account->account_type_id;
|
||||
$this->ids[] = (int)$account->id;
|
||||
$this->accountTypeIds[] = (int)$account->account_type_id;
|
||||
}
|
||||
$this->accountIds = array_unique($this->accountIds);
|
||||
$this->ids = array_unique($this->ids);
|
||||
$this->accountTypeIds = array_unique($this->accountTypeIds);
|
||||
}
|
||||
|
||||
@@ -135,27 +132,29 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
/** @var AccountType $type */
|
||||
foreach ($types as $type) {
|
||||
$this->accountTypes[(int) $type->id] = $type->type;
|
||||
$this->accountTypes[(int)$type->id] = $type->type;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectMetaData(): void
|
||||
{
|
||||
$set = AccountMeta::whereIn('name', ['is_multi_currency', 'include_net_worth', 'currency_id', 'account_role', 'account_number', 'BIC', 'liability_direction', 'interest', 'interest_period', 'current_debt'])
|
||||
->whereIn('account_id', $this->accountIds)
|
||||
->whereIn('account_id', $this->ids)
|
||||
->get(['account_meta.id', 'account_meta.account_id', 'account_meta.name', 'account_meta.data'])->toArray()
|
||||
;
|
||||
|
||||
/** @var array $entry */
|
||||
foreach ($set as $entry) {
|
||||
$this->meta[(int) $entry['account_id']][$entry['name']] = (string) $entry['data'];
|
||||
$this->meta[(int)$entry['account_id']][$entry['name']] = (string)$entry['data'];
|
||||
if ('currency_id' === $entry['name']) {
|
||||
$this->currencies[(int) $entry['data']] = true;
|
||||
$this->currencies[(int)$entry['data']] = true;
|
||||
}
|
||||
}
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int) $currency->id] = $currency;
|
||||
if (count($this->currencies) > 0) {
|
||||
$currencies = TransactionCurrency::whereIn('id', array_keys($this->currencies))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
}
|
||||
$this->currencies[0] = $this->primaryCurrency;
|
||||
foreach ($this->currencies as $id => $currency) {
|
||||
@@ -167,28 +166,28 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->accountIds)
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Account::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int) $note['noteable_id']] = (string) $note['text'];
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function collectLocations(): void
|
||||
{
|
||||
$locations = Location::query()->whereIn('locatable_id', $this->accountIds)
|
||||
$locations = Location::query()->whereIn('locatable_id', $this->ids)
|
||||
->where('locatable_type', Account::class)->get(['locations.locatable_id', 'locations.latitude', 'locations.longitude', 'locations.zoom_level'])->toArray()
|
||||
;
|
||||
foreach ($locations as $location) {
|
||||
$this->locations[(int) $location['locatable_id']]
|
||||
$this->locations[(int)$location['locatable_id']]
|
||||
= [
|
||||
'latitude' => (float) $location['latitude'],
|
||||
'longitude' => (float) $location['longitude'],
|
||||
'zoom_level' => (int) $location['zoom_level'],
|
||||
'latitude' => (float)$location['latitude'],
|
||||
'longitude' => (float)$location['longitude'],
|
||||
'zoom_level' => (int)$location['zoom_level'],
|
||||
];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d locations(s)', count($this->locations)));
|
||||
@@ -208,12 +207,12 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
;
|
||||
$journals = $collector->getExtractedJournals();
|
||||
foreach ($journals as $journal) {
|
||||
$this->openingBalances[(int) $journal['source_account_id']]
|
||||
$this->openingBalances[(int)$journal['source_account_id']]
|
||||
= [
|
||||
'amount' => Steam::negative($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
];
|
||||
$this->openingBalances[(int) $journal['destination_account_id']]
|
||||
$this->openingBalances[(int)$journal['destination_account_id']]
|
||||
= [
|
||||
'amount' => Steam::positive($journal['amount']),
|
||||
'date' => $journal['date'],
|
||||
@@ -234,59 +233,72 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$notes = $this->notes;
|
||||
$openingBalances = $this->openingBalances;
|
||||
$locations = $this->locations;
|
||||
$lastActivities = $this->lastActivities;
|
||||
$this->collection = $this->collection->map(function (Account $item) use ($notes, $openingBalances, $locations, $lastActivities) {
|
||||
$item->full_account_type = $this->accountTypes[(int) $item->account_type_id] ?? null;
|
||||
$accountMeta = [
|
||||
'currency' => null,
|
||||
'location' => [
|
||||
$this->collection = $this->collection->map(function (Account $item) {
|
||||
$id = (int)$item->id;
|
||||
$item->full_account_type = $this->accountTypes[(int)$item->account_type_id] ?? null;
|
||||
$meta = [
|
||||
'currency' => null,
|
||||
'location' => [
|
||||
'latitude' => null,
|
||||
'longitude' => null,
|
||||
'zoom_level' => null,
|
||||
],
|
||||
'opening_balance_date' => null,
|
||||
'object_group_id' => null,
|
||||
'object_group_order' => null,
|
||||
'object_group_title' => null,
|
||||
'opening_balance_date' => null,
|
||||
'opening_balance_amount' => null,
|
||||
'account_number' => null,
|
||||
'notes' => $notes[$id] ?? null,
|
||||
'last_activity' => $this->lastActivities[$id] ?? null,
|
||||
];
|
||||
if (array_key_exists((int) $item->id, $this->meta)) {
|
||||
foreach ($this->meta[(int) $item->id] as $name => $value) {
|
||||
$accountMeta[$name] = $value;
|
||||
|
||||
// add object group if available
|
||||
if (array_key_exists($id, $this->mappedObjects)) {
|
||||
$key = $this->mappedObjects[$id];
|
||||
$meta['object_group_id'] = $this->objectGroups[$key]['id'];
|
||||
$meta['object_group_title'] = $this->objectGroups[$key]['title'];
|
||||
$meta['object_group_order'] = $this->objectGroups[$key]['order'];
|
||||
}
|
||||
|
||||
// if location, add location:
|
||||
if (array_key_exists($id, $this->locations)) {
|
||||
$meta['location'] = $this->locations[$id];
|
||||
}
|
||||
if (array_key_exists($id, $this->meta)) {
|
||||
foreach ($this->meta[$id] as $name => $value) {
|
||||
$meta[$name] = $value;
|
||||
}
|
||||
}
|
||||
// also add currency, if present.
|
||||
if (array_key_exists('currency_id', $accountMeta)) {
|
||||
$currencyId = (int) $accountMeta['currency_id'];
|
||||
$accountMeta['currency'] = $this->currencies[$currencyId];
|
||||
if (array_key_exists('currency_id', $meta)) {
|
||||
$currencyId = (int)$meta['currency_id'];
|
||||
$meta['currency'] = $this->currencies[$currencyId];
|
||||
}
|
||||
|
||||
// if notes, add notes.
|
||||
if (array_key_exists($item->id, $notes)) {
|
||||
$accountMeta['notes'] = $notes[$item->id];
|
||||
}
|
||||
// if opening balance, add opening balance
|
||||
if (array_key_exists($item->id, $openingBalances)) {
|
||||
$accountMeta['opening_balance_date'] = $openingBalances[$item->id]['date'];
|
||||
$accountMeta['opening_balance_amount'] = $openingBalances[$item->id]['amount'];
|
||||
if (array_key_exists($id, $this->openingBalances)) {
|
||||
$meta['opening_balance_date'] = $this->openingBalances[$id]['date'];
|
||||
$meta['opening_balance_amount'] = $this->openingBalances[$id]['amount'];
|
||||
}
|
||||
|
||||
// add balances
|
||||
// get currencies:
|
||||
$currency = $this->primaryCurrency; // assume primary currency
|
||||
if (null !== $accountMeta['currency']) {
|
||||
$currency = $accountMeta['currency'];
|
||||
if (null !== $meta['currency']) {
|
||||
$currency = $meta['currency'];
|
||||
}
|
||||
|
||||
// get the current balance:
|
||||
$date = $this->getDate();
|
||||
$finalBalance = Steam::finalAccountBalance($item, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
// $finalBalance = Steam::finalAccountBalance($item, $date, $this->primaryCurrency, $this->convertToPrimary);
|
||||
$finalBalance = $this->balances[$id];
|
||||
Log::debug(sprintf('Call finalAccountBalance(%s) with date/time "%s"', var_export($this->convertToPrimary, true), $date->toIso8601String()), $finalBalance);
|
||||
|
||||
// collect current balances:
|
||||
$currentBalance = Steam::bcround($finalBalance[$currency->code] ?? '0', $currency->decimal_places);
|
||||
$openingBalance = Steam::bcround($accountMeta['opening_balance_amount'] ?? '0', $currency->decimal_places);
|
||||
$openingBalance = Steam::bcround($meta['opening_balance_amount'] ?? '0', $currency->decimal_places);
|
||||
$virtualBalance = Steam::bcround($account->virtual_balance ?? '0', $currency->decimal_places);
|
||||
$debtAmount = $accountMeta['current_debt'] ?? null;
|
||||
$debtAmount = $meta['current_debt'] ?? null;
|
||||
|
||||
// set some pc_ default values to NULL:
|
||||
$pcCurrentBalance = null;
|
||||
@@ -311,11 +323,11 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
}
|
||||
|
||||
// set opening balance(s) to NULL if the date is null
|
||||
if (null === $accountMeta['opening_balance_date']) {
|
||||
if (null === $meta['opening_balance_date']) {
|
||||
$openingBalance = null;
|
||||
$pcOpeningBalance = null;
|
||||
}
|
||||
$accountMeta['balances'] = [
|
||||
$meta['balances'] = [
|
||||
'current_balance' => $currentBalance,
|
||||
'pc_current_balance' => $pcCurrentBalance,
|
||||
'opening_balance' => $openingBalance,
|
||||
@@ -326,16 +338,7 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
'pc_debt_amount' => $pcDebtAmount,
|
||||
];
|
||||
// end add balances
|
||||
|
||||
|
||||
// if location, add location:
|
||||
if (array_key_exists($item->id, $locations)) {
|
||||
$accountMeta['location'] = $locations[$item->id];
|
||||
}
|
||||
if (array_key_exists($item->id, $lastActivities)) {
|
||||
$accountMeta['last_activity'] = $lastActivities[$item->id];
|
||||
}
|
||||
$item->meta = $accountMeta;
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
@@ -343,10 +346,35 @@ class AccountEnrichment implements EnrichmentInterface
|
||||
|
||||
private function collectLastActivities(): void
|
||||
{
|
||||
$this->lastActivities = Steam::getLastActivities($this->accountIds);
|
||||
$this->lastActivities = Steam::getLastActivities($this->ids);
|
||||
}
|
||||
|
||||
private function collectBalances(): void {}
|
||||
private function collectBalances(): void
|
||||
{
|
||||
$this->balances = Steam::accountsBalancesOptimized($this->collection, $this->getDate(), $this->primaryCurrency, $this->convertToPrimary);
|
||||
}
|
||||
|
||||
private function collectObjectGroups(): void
|
||||
{
|
||||
$set = DB::table('object_groupables')
|
||||
->whereIn('object_groupable_id', $this->ids)
|
||||
->where('object_groupable_type', Account::class)
|
||||
->get(['object_groupable_id', 'object_group_id'])
|
||||
;
|
||||
|
||||
$ids = array_unique($set->pluck('object_group_id')->toArray());
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
|
||||
}
|
||||
|
||||
$groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray();
|
||||
foreach ($groups as $group) {
|
||||
$group['id'] = (int)$group['id'];
|
||||
$group['order'] = (int)$group['order'];
|
||||
$this->objectGroups[(int)$group['id']] = $group;
|
||||
}
|
||||
}
|
||||
|
||||
public function setDate(?Carbon $date): void
|
||||
{
|
||||
|
@@ -43,8 +43,10 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private bool $convertToPrimary = false;
|
||||
private bool $convertToPrimary;
|
||||
private array $ids = [];
|
||||
private array $currencyIds = [];
|
||||
private array $currencies = [];
|
||||
private Collection $collection;
|
||||
private array $spentInBudgets = [];
|
||||
private array $spentOutsideBudgets = [];
|
||||
@@ -72,6 +74,7 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectCurrencies();
|
||||
$this->collectSpentInfo();
|
||||
$this->appendCollectedData();
|
||||
|
||||
@@ -108,7 +111,8 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
{
|
||||
/** @var AvailableBudget $availableBudget */
|
||||
foreach ($this->collection as $availableBudget) {
|
||||
$this->ids[] = (int) $availableBudget->id;
|
||||
$this->ids[] = (int)$availableBudget->id;
|
||||
$this->currencyIds[(int)$availableBudget->id] = (int)$availableBudget->transaction_currency_id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
}
|
||||
@@ -121,15 +125,17 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
$spentInBudgets = $this->opsRepository->collectExpenses($start, $end, null, $allActive, null);
|
||||
$spentOutsideBudgets = $this->noBudgetRepository->collectExpenses($start, $end, null, null, null);
|
||||
foreach ($this->collection as $availableBudget) {
|
||||
$id = (int) $availableBudget->id;
|
||||
$filteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $availableBudget->transactionCurrency, false);
|
||||
$filteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $availableBudget->transactionCurrency, false);
|
||||
$id = (int)$availableBudget->id;
|
||||
$currencyId = $this->currencyIds[$id];
|
||||
$currency = $this->currencies[$currencyId];
|
||||
$filteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, false);
|
||||
$filteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, false);
|
||||
$this->spentInBudgets[$id] = array_values($filteredSpentInBudgets);
|
||||
$this->spentOutsideBudgets[$id] = array_values($filteredSpentOutsideBudgets);
|
||||
|
||||
if (true === $this->convertToPrimary) {
|
||||
$pcFilteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $availableBudget->transactionCurrency, true);
|
||||
$pcFilteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $availableBudget->transactionCurrency, true);
|
||||
$pcFilteredSpentInBudgets = $this->opsRepository->sumCollectedExpenses($spentInBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, true);
|
||||
$pcFilteredSpentOutsideBudgets = $this->opsRepository->sumCollectedExpenses($spentOutsideBudgets, $availableBudget->start_date, $availableBudget->end_date, $currency, true);
|
||||
$this->pcSpentInBudgets[$id] = array_values($pcFilteredSpentInBudgets);
|
||||
$this->pcSpentOutsideBudgets[$id] = array_values($pcFilteredSpentOutsideBudgets);
|
||||
}
|
||||
@@ -145,22 +151,29 @@ class AvailableBudgetEnrichment implements EnrichmentInterface
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$spentInsideBudgets = $this->spentInBudgets;
|
||||
$spentOutsideBudgets = $this->spentOutsideBudgets;
|
||||
$pcSpentInBudgets = $this->pcSpentInBudgets;
|
||||
$pcSpentOutsideBudgets = $this->pcSpentOutsideBudgets;
|
||||
$this->collection = $this->collection->map(function (AvailableBudget $item) use ($spentInsideBudgets, $spentOutsideBudgets, $pcSpentInBudgets, $pcSpentOutsideBudgets) {
|
||||
$id = (int) $item->id;
|
||||
$this->collection = $this->collection->map(function (AvailableBudget $item) {
|
||||
$id = (int)$item->id;
|
||||
$currencyId = $this->currencyIds[$id];
|
||||
$currency = $this->currencies[$currencyId];
|
||||
$meta = [
|
||||
'spent_in_budgets' => $spentInsideBudgets[$id] ?? [],
|
||||
'pc_spent_in_budgets' => $pcSpentInBudgets[$id] ?? [],
|
||||
|
||||
'spent_outside_budgets' => $spentOutsideBudgets[$id] ?? [],
|
||||
'pc_spent_outside_budgets' => $pcSpentOutsideBudgets[$id] ?? [],
|
||||
'currency' => $currency,
|
||||
'spent_in_budgets' => $this->spentInBudgets[$id] ?? [],
|
||||
'pc_spent_in_budgets' => $this->pcSpentInBudgets[$id] ?? [],
|
||||
'spent_outside_budgets' => $this->spentOutsideBudgets[$id] ?? [],
|
||||
'pc_spent_outside_budgets' => $this->pcSpentOutsideBudgets[$id] ?? [],
|
||||
];
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectCurrencies(): void
|
||||
{
|
||||
$ids = array_unique(array_values($this->currencyIds));
|
||||
$set = TransactionCurrency::whereIn('id', $ids)->get();
|
||||
foreach ($set as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
198
app/Support/JsonApi/Enrichments/BudgetEnrichment.php
Normal file
198
app/Support/JsonApi/Enrichments/BudgetEnrichment.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\AutoBudget;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
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 BudgetEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private Collection $collection;
|
||||
private bool $convertToPrimary;
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private array $ids = [];
|
||||
private array $notes = [];
|
||||
private array $autoBudgets = [];
|
||||
private array $currencies = [];
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
private array $spent = [];
|
||||
private array $pcSpent = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectNotes();
|
||||
$this->collectAutoBudgets();
|
||||
$this->collectExpenses();
|
||||
$this->collectObjectGroups();
|
||||
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $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 Budget $budget */
|
||||
foreach ($this->collection as $budget) {
|
||||
$this->ids[] = (int)$budget->id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Budget::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (Budget $item) {
|
||||
$id = (int)$item->id;
|
||||
$meta = [
|
||||
'object_group_id' => null,
|
||||
'object_group_order' => null,
|
||||
'object_group_title' => null,
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'currency' => $this->currencies[$id] ?? null,
|
||||
'auto_budget' => $this->autoBudgets[$id] ?? null,
|
||||
'spent' => $this->spent[$id] ?? null,
|
||||
'pc_spent' => $this->pcSpent[$id] ?? null,
|
||||
];
|
||||
|
||||
// add object group if available
|
||||
if (array_key_exists($id, $this->mappedObjects)) {
|
||||
$key = $this->mappedObjects[$id];
|
||||
$meta['object_group_id'] = $this->objectGroups[$key]['id'];
|
||||
$meta['object_group_title'] = $this->objectGroups[$key]['title'];
|
||||
$meta['object_group_order'] = $this->objectGroups[$key]['order'];
|
||||
}
|
||||
|
||||
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectAutoBudgets(): void
|
||||
{
|
||||
$set = AutoBudget::whereIn('budget_id', $this->ids)->with(['transactionCurrency'])->get();
|
||||
|
||||
/** @var AutoBudget $autoBudget */
|
||||
foreach ($set as $autoBudget) {
|
||||
$budgetId = (int)$autoBudget->budget_id;
|
||||
$this->currencies[$budgetId] = $autoBudget->transactionCurrency;
|
||||
$this->autoBudgets[$budgetId] = [
|
||||
'type' => (int)$autoBudget->auto_budget_type,
|
||||
'period' => $autoBudget->period,
|
||||
'amount' => $autoBudget->amount,
|
||||
'pc_amount' => $autoBudget->native_amount,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function collectExpenses(): void
|
||||
{
|
||||
if (null !== $this->start && null !== $this->end) {
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$opsRepository->setUser($this->user);
|
||||
$opsRepository->setUserGroup($this->userGroup);
|
||||
// $spent = $this->beautify();
|
||||
// $set = $this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget]))
|
||||
$expenses = $opsRepository->collectExpenses($this->start, $this->end, null, $this->collection, null);
|
||||
foreach ($this->collection as $item) {
|
||||
$id = (int)$item->id;
|
||||
$this->spent[$id] = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, false));
|
||||
$this->pcSpent[$id] = array_values($opsRepository->sumCollectedExpensesByBudget($expenses, $item, true));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setEnd(?Carbon $end): void
|
||||
{
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
public function setStart(?Carbon $start): void
|
||||
{
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
private function collectObjectGroups(): void
|
||||
{
|
||||
$set = DB::table('object_groupables')
|
||||
->whereIn('object_groupable_id', $this->ids)
|
||||
->where('object_groupable_type', Budget::class)
|
||||
->get(['object_groupable_id', 'object_group_id'])
|
||||
;
|
||||
|
||||
$ids = array_unique($set->pluck('object_group_id')->toArray());
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
|
||||
}
|
||||
|
||||
$groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray();
|
||||
foreach ($groups as $group) {
|
||||
$group['id'] = (int)$group['id'];
|
||||
$group['order'] = (int)$group['order'];
|
||||
$this->objectGroups[(int)$group['id']] = $group;
|
||||
}
|
||||
}
|
||||
}
|
158
app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php
Normal file
158
app/Support/JsonApi/Enrichments/BudgetLimitEnrichment.php
Normal file
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepository;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BudgetLimitEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private Collection $collection;
|
||||
private array $ids = [];
|
||||
private array $notes = [];
|
||||
private Carbon $start;
|
||||
private Carbon $end;
|
||||
private Collection $budgets;
|
||||
private array $expenses = [];
|
||||
private array $pcExpenses = [];
|
||||
private array $currencyIds = [];
|
||||
private array $currencies = [];
|
||||
private bool $convertToPrimary = true;
|
||||
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->collectCurrencies();
|
||||
$this->collectNotes();
|
||||
$this->collectBudgets();
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $model): array|Model
|
||||
{
|
||||
Log::debug(__METHOD__);
|
||||
$collection = new Collection()->push($model);
|
||||
$collection = $this->enrich($collection);
|
||||
|
||||
return $collection->first();
|
||||
}
|
||||
|
||||
public function setUser(User $user): void
|
||||
{
|
||||
$this->user = $user;
|
||||
$this->userGroup = $user->userGroup;
|
||||
}
|
||||
|
||||
public function setUserGroup(UserGroup $userGroup): void
|
||||
{
|
||||
$this->userGroup = $userGroup;
|
||||
}
|
||||
|
||||
private function collectIds(): void
|
||||
{
|
||||
$this->start = $this->collection->min('start_date');
|
||||
$this->end = $this->collection->max('end_date');
|
||||
|
||||
/** @var BudgetLimit $limit */
|
||||
foreach ($this->collection as $limit) {
|
||||
$id = (int)$limit->id;
|
||||
$this->ids[] = $id;
|
||||
if (0 !== (int)$limit->transaction_currency_id) {
|
||||
$this->currencyIds[$id] = (int)$limit->transaction_currency_id;
|
||||
}
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
$this->currencyIds = array_unique($this->currencyIds);
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', BudgetLimit::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (BudgetLimit $item) {
|
||||
$id = (int)$item->id;
|
||||
$currencyId = (int)$item->transaction_currency_id;
|
||||
if (0 === $currencyId) {
|
||||
$currencyId = $this->primaryCurrency->id;
|
||||
}
|
||||
$meta = [
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'spent' => $this->expenses[$id] ?? [],
|
||||
'pc_spent' => $this->pcExpenses[$id] ?? [],
|
||||
'currency' => $this->currencies[$currencyId],
|
||||
];
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectBudgets(): void
|
||||
{
|
||||
$budgetIds = $this->collection->pluck('budget_id')->unique()->toArray();
|
||||
$this->budgets = Budget::whereIn('id', $budgetIds)->get();
|
||||
|
||||
$repository = app(OperationsRepository::class);
|
||||
$repository->setUser($this->user);
|
||||
$expenses = $repository->collectExpenses($this->start, $this->end, null, $this->budgets, null);
|
||||
|
||||
/** @var BudgetLimit $budgetLimit */
|
||||
foreach ($this->collection as $budgetLimit) {
|
||||
$id = (int)$budgetLimit->id;
|
||||
$filteredExpenses = $repository->sumCollectedExpenses($expenses, $budgetLimit->start_date, $budgetLimit->end_date, $budgetLimit->transactionCurrency, false);
|
||||
$this->expenses[$id] = array_values($filteredExpenses);
|
||||
|
||||
if (true === $this->convertToPrimary && $budgetLimit->transactionCurrency->id !== $this->primaryCurrency->id) {
|
||||
$pcFilteredExpenses = $repository->sumCollectedExpenses($expenses, $budgetLimit->start_date, $budgetLimit->end_date, $budgetLimit->transactionCurrency, true);
|
||||
$this->pcExpenses[$id] = array_values($pcFilteredExpenses);
|
||||
}
|
||||
if (true === $this->convertToPrimary && $budgetLimit->transactionCurrency->id === $this->primaryCurrency->id) {
|
||||
$this->pcExpenses[$id] = $this->expenses[$id] ?? [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function collectCurrencies(): void
|
||||
{
|
||||
$this->currencies[$this->primaryCurrency->id] = $this->primaryCurrency;
|
||||
$currencies = TransactionCurrency::whereIn('id', $this->currencyIds)->whereNot('id', $this->primaryCurrency->id)->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
}
|
||||
}
|
136
app/Support/JsonApi/Enrichments/CategoryEnrichment.php
Normal file
136
app/Support/JsonApi/Enrichments/CategoryEnrichment.php
Normal file
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CategoryEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private Collection $collection;
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private array $ids = [];
|
||||
private array $notes = [];
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
private array $spent = [];
|
||||
private array $pcSpent = [];
|
||||
private array $earned = [];
|
||||
private array $pcEarned = [];
|
||||
private array $transfers = [];
|
||||
private array $pcTransfers = [];
|
||||
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectNotes();
|
||||
$this->collectTransactions();
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $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 Category $category */
|
||||
foreach ($this->collection as $category) {
|
||||
$this->ids[] = (int)$category->id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (Category $item) {
|
||||
$id = (int)$item->id;
|
||||
$meta = [
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'spent' => $this->spent[$id] ?? null,
|
||||
'pc_spent' => $this->pcSpent[$id] ?? null,
|
||||
'earned' => $this->earned[$id] ?? null,
|
||||
'pc_earned' => $this->pcEarned[$id] ?? null,
|
||||
'transfers' => $this->transfers[$id] ?? null,
|
||||
'pc_transfers' => $this->pcTransfers[$id] ?? null,
|
||||
];
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
public function setEnd(?Carbon $end): void
|
||||
{
|
||||
$this->end = $end;
|
||||
}
|
||||
|
||||
public function setStart(?Carbon $start): void
|
||||
{
|
||||
$this->start = $start;
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Category::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function collectTransactions(): void
|
||||
{
|
||||
if (null !== $this->start && null !== $this->end) {
|
||||
/** @var OperationsRepositoryInterface $opsRepository */
|
||||
$opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$opsRepository->setUser($this->user);
|
||||
$opsRepository->setUserGroup($this->userGroup);
|
||||
$expenses = $opsRepository->collectExpenses($this->start, $this->end, null, $this->collection);
|
||||
$income = $opsRepository->collectIncome($this->start, $this->end, null, $this->collection);
|
||||
$transfers = $opsRepository->collectTransfers($this->start, $this->end, null, $this->collection);
|
||||
foreach ($this->collection as $item) {
|
||||
$id = (int)$item->id;
|
||||
$this->spent[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($expenses, $item, 'negative', false));
|
||||
$this->pcSpent[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($expenses, $item, 'negative', true));
|
||||
$this->earned[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($income, $item, 'positive', false));
|
||||
$this->pcEarned[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($income, $item, 'positive', true));
|
||||
$this->transfers[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($transfers, $item, 'positive', false));
|
||||
$this->pcTransfers[$id] = array_values($opsRepository->sumCollectedTransactionsByCategory($transfers, $item, 'positive', true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
273
app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php
Normal file
273
app/Support/JsonApi/Enrichments/PiggyBankEnrichment.php
Normal file
@@ -0,0 +1,273 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PiggyBankEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private Collection $collection;
|
||||
private array $ids = [];
|
||||
private array $currencyIds = [];
|
||||
private array $currencies = [];
|
||||
private array $accountIds = [];
|
||||
// private array $accountCurrencies = [];
|
||||
private array $notes = [];
|
||||
private array $mappedObjects = [];
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private array $amounts = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectObjectGroups();
|
||||
$this->collectNotes();
|
||||
$this->collectCurrentAmounts();
|
||||
|
||||
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $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 PiggyBank $piggy */
|
||||
foreach ($this->collection as $piggy) {
|
||||
$id = (int)$piggy->id;
|
||||
$this->ids[] = $id;
|
||||
$this->currencyIds[$id] = (int)$piggy->transaction_currency_id;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
|
||||
// collect currencies.
|
||||
$currencies = TransactionCurrency::whereIn('id', $this->currencyIds)->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$this->currencies[(int)$currency->id] = $currency;
|
||||
}
|
||||
|
||||
// collect accounts
|
||||
$set = DB::table('account_piggy_bank')->whereIn('piggy_bank_id', $this->ids)->get(['piggy_bank_id', 'account_id', 'current_amount', 'native_current_amount']);
|
||||
foreach ($set as $item) {
|
||||
$id = (int)$item->piggy_bank_id;
|
||||
$accountId = (int)$item->account_id;
|
||||
$this->amounts[$id] ??= [];
|
||||
if (!array_key_exists($id, $this->accountIds)) {
|
||||
$this->accountIds[$id] = (int)$item->account_id;
|
||||
}
|
||||
if (!array_key_exists($accountId, $this->amounts[$id])) {
|
||||
$this->amounts[$id][$accountId] = [
|
||||
'current_amount' => '0',
|
||||
'pc_current_amount' => '0',
|
||||
];
|
||||
}
|
||||
$this->amounts[$id][$accountId]['current_amount'] = bcadd($this->amounts[$id][$accountId]['current_amount'], $item->current_amount);
|
||||
if (null !== $this->amounts[$id][$accountId]['pc_current_amount'] && null !== $item->native_current_amount) {
|
||||
$this->amounts[$id][$accountId]['pc_current_amount'] = bcadd($this->amounts[$id][$accountId]['pc_current_amount'], $item->native_current_amount);
|
||||
}
|
||||
}
|
||||
|
||||
// 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];
|
||||
}
|
||||
|
||||
// get account info.
|
||||
$set = Account::whereIn('id', array_values($this->accountIds))->get();
|
||||
|
||||
/** @var Account $item */
|
||||
foreach ($set as $item) {
|
||||
$id = (int)$item->id;
|
||||
$this->accounts[$id] = [
|
||||
'id' => $id,
|
||||
'name' => $item->name,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (PiggyBank $item) {
|
||||
$id = (int)$item->id;
|
||||
$currencyId = (int)$item->transaction_currency_id;
|
||||
$currency = $this->currencies[$currencyId] ?? $this->primaryCurrency;
|
||||
$targetAmount = null;
|
||||
if (0 !== bccomp($item->target_amount, '0')) {
|
||||
$targetAmount = $item->target_amount;
|
||||
}
|
||||
$meta = [
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'currency' => $this->currencies[$currencyId] ?? null,
|
||||
// 'auto_budget' => $this->autoBudgets[$id] ?? null,
|
||||
// 'spent' => $this->spent[$id] ?? null,
|
||||
// 'pc_spent' => $this->pcSpent[$id] ?? null,
|
||||
'object_group_id' => null,
|
||||
'object_group_order' => null,
|
||||
'object_group_title' => null,
|
||||
'current_amount' => '0',
|
||||
'pc_current_amount' => '0',
|
||||
'target_amount' => null === $targetAmount ? null : Steam::bcround($targetAmount, $currency->decimal_places),
|
||||
'pc_target_amount' => null === $item->native_target_amount ? null : Steam::bcround($item->native_target_amount, $this->primaryCurrency->decimal_places),
|
||||
'left_to_save' => null,
|
||||
'pc_left_to_save' => null,
|
||||
'save_per_month' => null,
|
||||
'pc_save_per_month' => null,
|
||||
'accounts' => [],
|
||||
];
|
||||
|
||||
// add object group if available
|
||||
if (array_key_exists($id, $this->mappedObjects)) {
|
||||
$key = $this->mappedObjects[$id];
|
||||
$meta['object_group_id'] = $this->objectGroups[$key]['id'];
|
||||
$meta['object_group_title'] = $this->objectGroups[$key]['title'];
|
||||
$meta['object_group_order'] = $this->objectGroups[$key]['order'];
|
||||
}
|
||||
// add current amount(s).
|
||||
foreach ($this->amounts[$id] as $accountId => $row) {
|
||||
$meta['accounts'][] = [
|
||||
'account_id' => (string)$accountId,
|
||||
'name' => $this->accounts[$accountId]['name'] ?? '',
|
||||
'current_amount' => Steam::bcround($row['current_amount'], $currency->decimal_places),
|
||||
'pc_current_amount' => Steam::bcround($row['pc_current_amount'], $this->primaryCurrency->decimal_places),
|
||||
];
|
||||
$meta['current_amount'] = bcadd($meta['current_amount'], $row['current_amount']);
|
||||
// only add pc_current_amount when the pc_current_amount is set
|
||||
$meta['pc_current_amount'] = null === $row['pc_current_amount'] ? null : bcadd($meta['pc_current_amount'], $row['pc_current_amount']);
|
||||
}
|
||||
$meta['current_amount'] = Steam::bcround($meta['current_amount'], $currency->decimal_places);
|
||||
// only round this number when pc_current_amount is set.
|
||||
$meta['pc_current_amount'] = null === $meta['pc_current_amount'] ? null : Steam::bcround($meta['pc_current_amount'], $this->primaryCurrency->decimal_places);
|
||||
|
||||
// calculate left to save, only when there is a target amount.
|
||||
if (null !== $targetAmount) {
|
||||
$meta['left_to_save'] = bcsub($meta['target_amount'], $meta['current_amount']);
|
||||
$meta['pc_left_to_save'] = null === $meta['pc_target_amount'] ? null : bcsub($meta['pc_target_amount'], $meta['pc_current_amount']);
|
||||
}
|
||||
|
||||
// get suggested per month.
|
||||
$meta['save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['target_amount'], $meta['current_amount']), $currency->decimal_places);
|
||||
$meta['pc_save_per_month'] = Steam::bcround($this->getSuggestedMonthlyAmount($item->start_date, $item->target_date, $meta['pc_target_amount'], $meta['pc_current_amount']), $currency->decimal_places);
|
||||
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', PiggyBank::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
|
||||
private function collectObjectGroups(): void
|
||||
{
|
||||
$set = DB::table('object_groupables')
|
||||
->whereIn('object_groupable_id', $this->ids)
|
||||
->where('object_groupable_type', PiggyBank::class)
|
||||
->get(['object_groupable_id', 'object_group_id'])
|
||||
;
|
||||
|
||||
$ids = array_unique($set->pluck('object_group_id')->toArray());
|
||||
|
||||
foreach ($set as $entry) {
|
||||
$this->mappedObjects[(int)$entry->object_groupable_id] = (int)$entry->object_group_id;
|
||||
}
|
||||
|
||||
$groups = ObjectGroup::whereIn('id', $ids)->get(['id', 'title', 'order'])->toArray();
|
||||
foreach ($groups as $group) {
|
||||
$group['id'] = (int)$group['id'];
|
||||
$group['order'] = (int)$group['order'];
|
||||
$this->objectGroups[(int)$group['id']] = $group;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectCurrentAmounts(): void {}
|
||||
|
||||
/**
|
||||
* Returns the suggested amount the user should save per month, or "".
|
||||
*/
|
||||
private function getSuggestedMonthlyAmount(?Carbon $startDate, ?Carbon $targetDate, ?string $targetAmount, string $currentAmount): string
|
||||
{
|
||||
if (null === $targetAmount || null === $targetDate || null === $startDate) {
|
||||
return '0';
|
||||
}
|
||||
$savePerMonth = '0';
|
||||
if (1 === bccomp($targetAmount, $currentAmount)) {
|
||||
$now = today(config('app.timezone'));
|
||||
$diffInMonths = (int)$startDate->diffInMonths($targetDate);
|
||||
$remainingAmount = bcsub($targetAmount, $currentAmount);
|
||||
|
||||
// more than 1 month to go and still need money to save:
|
||||
if ($diffInMonths > 0 && 1 === bccomp($remainingAmount, '0')) {
|
||||
$savePerMonth = bcdiv($remainingAmount, (string)$diffInMonths);
|
||||
}
|
||||
|
||||
// less than 1 month to go but still need money to save:
|
||||
if (0 === $diffInMonths && 1 === bccomp($remainingAmount, '0')) {
|
||||
$savePerMonth = $remainingAmount;
|
||||
}
|
||||
}
|
||||
|
||||
return $savePerMonth;
|
||||
}
|
||||
}
|
132
app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php
Normal file
132
app/Support/JsonApi/Enrichments/PiggyBankEventEnrichment.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
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(array|Model $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;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
586
app/Support/JsonApi/Enrichments/RecurringEnrichment.php
Normal file
586
app/Support/JsonApi/Enrichments/RecurringEnrichment.php
Normal file
@@ -0,0 +1,586 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Support\JsonApi\Enrichments;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Enums\RecurrenceRepetitionWeekend;
|
||||
use FireflyIII\Enums\TransactionTypeEnum;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Bill;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\Note;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Models\Preference;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Models\TransactionType;
|
||||
use FireflyIII\Models\UserGroup;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Preferences;
|
||||
use FireflyIII\Support\Http\Api\ExchangeRateConverter;
|
||||
use FireflyIII\User;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class RecurringEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private Collection $collection;
|
||||
private array $ids = [];
|
||||
private array $transactionTypeIds = [];
|
||||
private array $transactionTypes = [];
|
||||
private array $notes = [];
|
||||
private array $repetitions = [];
|
||||
private array $transactions = [];
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private string $language = 'en_US';
|
||||
private array $currencyIds = [];
|
||||
private array $foreignCurrencyIds = [];
|
||||
private array $sourceAccountIds = [];
|
||||
private array $destinationAccountIds = [];
|
||||
private array $accounts = [];
|
||||
private array $currencies = [];
|
||||
private array $recurrenceIds = [];
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private bool $convertToPrimary = false;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
}
|
||||
|
||||
public function enrich(Collection $collection): Collection
|
||||
{
|
||||
$this->collection = $collection;
|
||||
$this->collectIds();
|
||||
$this->collectRepetitions();
|
||||
$this->collectTransactions();
|
||||
$this->collectCurrencies();
|
||||
$this->collectNotes();
|
||||
$this->collectAccounts();
|
||||
$this->collectTransactionMetaData();
|
||||
|
||||
$this->appendCollectedData();
|
||||
|
||||
return $this->collection;
|
||||
}
|
||||
|
||||
public function enrichSingle(array|Model $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);
|
||||
$this->getLanguage();
|
||||
}
|
||||
|
||||
public function setUserGroup(UserGroup $userGroup): void
|
||||
{
|
||||
$this->userGroup = $userGroup;
|
||||
}
|
||||
|
||||
private function collectIds(): void
|
||||
{
|
||||
/** @var Recurrence $recurrence */
|
||||
foreach ($this->collection as $recurrence) {
|
||||
$id = (int)$recurrence->id;
|
||||
$typeId = (int)$recurrence->transaction_type_id;
|
||||
$this->ids[] = $id;
|
||||
$this->transactionTypeIds[$id] = $typeId;
|
||||
}
|
||||
$this->ids = array_unique($this->ids);
|
||||
|
||||
// collect transaction types.
|
||||
$transactionTypes = TransactionType::whereIn('id', array_unique($this->transactionTypeIds))->get();
|
||||
foreach ($transactionTypes as $transactionType) {
|
||||
$id = (int)$transactionType->id;
|
||||
$this->transactionTypes[$id] = TransactionTypeEnum::from($transactionType->type);
|
||||
}
|
||||
}
|
||||
|
||||
private function collectRepetitions(): void
|
||||
{
|
||||
Log::debug('Start of enrichment: collectRepetitions()');
|
||||
$repository = app(RecurringRepositoryInterface::class);
|
||||
$repository->setUserGroup($this->userGroup);
|
||||
$set = RecurrenceRepetition::whereIn('recurrence_id', $this->ids)->get();
|
||||
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
foreach ($set as $repetition) {
|
||||
$recurrence = $this->collection->filter(function (Recurrence $item) use ($repetition) {
|
||||
return (int)$item->id === (int)$repetition->recurrence_id;
|
||||
})->first();
|
||||
$fromDate = $recurrence->latest_date ?? $recurrence->first_date;
|
||||
$id = (int)$repetition->recurrence_id;
|
||||
$repId = (int)$repetition->id;
|
||||
$this->repetitions[$id] ??= [];
|
||||
|
||||
// get the (future) occurrences for this specific type of repetition:
|
||||
$amount = 'daily' === $repetition->repetition_type ? 9 : 5;
|
||||
$set = $repository->getXOccurrencesSince($repetition, $fromDate, now(config('app.timezone')), $amount);
|
||||
|
||||
/** @var Carbon $carbon */
|
||||
foreach ($set as $carbon) {
|
||||
$occurrences[] = $carbon->toAtomString();
|
||||
}
|
||||
|
||||
$this->repetitions[$id][$repId] = [
|
||||
'id' => (string)$repId,
|
||||
'created_at' => $repetition->created_at->toAtomString(),
|
||||
'updated_at' => $repetition->updated_at->toAtomString(),
|
||||
'type' => $repetition->repetition_type,
|
||||
'moment' => (string)$repetition->moment,
|
||||
'skip' => (int)$repetition->skip,
|
||||
'weekend' => RecurrenceRepetitionWeekend::from((int)$repetition->weekend),
|
||||
'description' => $this->getRepetitionDescription($repetition),
|
||||
'occurrences' => $occurrences,
|
||||
];
|
||||
}
|
||||
Log::debug('End of enrichment: collectRepetitions()');
|
||||
}
|
||||
|
||||
private function collectTransactions(): void
|
||||
{
|
||||
$set = RecurrenceTransaction::whereIn('recurrence_id', $this->ids)->get();
|
||||
|
||||
/** @var RecurrenceTransaction $transaction */
|
||||
foreach ($set as $transaction) {
|
||||
$id = (int)$transaction->recurrence_id;
|
||||
$transactionId = (int)$transaction->id;
|
||||
$this->recurrenceIds[$transactionId] = $id;
|
||||
$this->transactions[$id] ??= [];
|
||||
$amount = $transaction->amount;
|
||||
$foreignAmount = $transaction->foreign_amount;
|
||||
|
||||
$this->transactions[$id][$transactionId] = [
|
||||
'id' => (string)$transactionId,
|
||||
// 'recurrence_id' => $id,
|
||||
'transaction_currency_id' => (int)$transaction->transaction_currency_id,
|
||||
'foreign_currency_id' => null === $transaction->foreign_currency_id ? null : (int)$transaction->foreign_currency_id,
|
||||
'source_id' => (int)$transaction->source_id,
|
||||
'object_has_currency_setting' => true,
|
||||
'destination_id' => (int)$transaction->destination_id,
|
||||
'amount' => $amount,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
'pc_amount' => null,
|
||||
'pc_foreign_amount' => null,
|
||||
'description' => $transaction->description,
|
||||
'tags' => [],
|
||||
'category_id' => null,
|
||||
'category_name' => null,
|
||||
'budget_id' => null,
|
||||
'budget_name' => null,
|
||||
'piggy_bank_id' => null,
|
||||
'piggy_bank_name' => null,
|
||||
'subscription_id' => null,
|
||||
'subscription_name' => null,
|
||||
|
||||
];
|
||||
// collect all kinds of meta data to be collected later.
|
||||
$this->currencyIds[$transactionId] = (int)$transaction->transaction_currency_id;
|
||||
$this->sourceAccountIds[$transactionId] = (int)$transaction->source_id;
|
||||
$this->destinationAccountIds[$transactionId] = (int)$transaction->destination_id;
|
||||
if (null !== $transaction->foreign_currency_id) {
|
||||
$this->foreignCurrencyIds[$transactionId] = (int)$transaction->foreign_currency_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function appendCollectedData(): void
|
||||
{
|
||||
$this->collection = $this->collection->map(function (Recurrence $item) {
|
||||
$id = (int)$item->id;
|
||||
$meta = [
|
||||
'notes' => $this->notes[$id] ?? null,
|
||||
'repetitions' => array_values($this->repetitions[$id] ?? []),
|
||||
'transactions' => $this->processTransactions(array_values($this->transactions[$id] ?? [])),
|
||||
];
|
||||
|
||||
$item->meta = $meta;
|
||||
|
||||
return $item;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the repetition in a string that is user readable.
|
||||
* TODO duplicate with repository.
|
||||
*/
|
||||
public function getRepetitionDescription(RecurrenceRepetition $repetition): string
|
||||
{
|
||||
if ('daily' === $repetition->repetition_type) {
|
||||
return (string)trans('firefly.recurring_daily', [], $this->language);
|
||||
}
|
||||
if ('weekly' === $repetition->repetition_type) {
|
||||
$dayOfWeek = trans(sprintf('config.dow_%s', $repetition->repetition_moment), [], $this->language);
|
||||
if ($repetition->repetition_skip > 0) {
|
||||
return (string)trans('firefly.recurring_weekly_skip', ['weekday' => $dayOfWeek, 'skip' => $repetition->repetition_skip + 1], $this->language);
|
||||
}
|
||||
|
||||
return (string)trans('firefly.recurring_weekly', ['weekday' => $dayOfWeek], $this->language);
|
||||
}
|
||||
if ('monthly' === $repetition->repetition_type) {
|
||||
if ($repetition->repetition_skip > 0) {
|
||||
return (string)trans('firefly.recurring_monthly_skip', ['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip + 1], $this->language);
|
||||
}
|
||||
|
||||
return (string)trans('firefly.recurring_monthly', ['dayOfMonth' => $repetition->repetition_moment, 'skip' => $repetition->repetition_skip - 1], $this->language);
|
||||
}
|
||||
if ('ndom' === $repetition->repetition_type) {
|
||||
$parts = explode(',', $repetition->repetition_moment);
|
||||
// first part is number of week, second is weekday.
|
||||
$dayOfWeek = trans(sprintf('config.dow_%s', $parts[1]), [], $this->language);
|
||||
if ($repetition->repetition_skip > 0) {
|
||||
return (string)trans('firefly.recurring_ndom_skip', ['skip' => $repetition->repetition_skip, 'weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $this->language);
|
||||
}
|
||||
|
||||
return (string)trans('firefly.recurring_ndom', ['weekday' => $dayOfWeek, 'dayOfMonth' => $parts[0]], $this->language);
|
||||
}
|
||||
if ('yearly' === $repetition->repetition_type) {
|
||||
$today = today(config('app.timezone'))->endOfYear();
|
||||
$repDate = Carbon::createFromFormat('Y-m-d', $repetition->repetition_moment);
|
||||
if (!$repDate instanceof Carbon) {
|
||||
$repDate = clone $today;
|
||||
}
|
||||
// $diffInYears = (int)$today->diffInYears($repDate, true);
|
||||
// $repDate->addYears($diffInYears); // technically not necessary.
|
||||
$string = $repDate->isoFormat((string)trans('config.month_and_day_no_year_js'));
|
||||
|
||||
return (string)trans('firefly.recurring_yearly', ['date' => $string], $this->language);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function getLanguage(): void
|
||||
{
|
||||
/** @var Preference $preference */
|
||||
$preference = Preferences::getForUser($this->user, 'language', config('firefly.default_language', 'en_US'));
|
||||
$language = $preference->data;
|
||||
if (is_array($language)) {
|
||||
$language = 'en_US';
|
||||
}
|
||||
$language = (string)$language;
|
||||
$this->language = $language;
|
||||
}
|
||||
|
||||
private function collectCurrencies(): void
|
||||
{
|
||||
$all = array_merge(array_unique($this->currencyIds), array_unique($this->foreignCurrencyIds));
|
||||
$currencies = TransactionCurrency::whereIn('id', array_unique($all))->get();
|
||||
foreach ($currencies as $currency) {
|
||||
$id = (int)$currency->id;
|
||||
$this->currencies[$id] = $currency;
|
||||
}
|
||||
}
|
||||
|
||||
private function processTransactions(array $transactions): array
|
||||
{
|
||||
$return = [];
|
||||
$converter = new ExchangeRateConverter();
|
||||
foreach ($transactions as $transaction) {
|
||||
$currencyId = $transaction['transaction_currency_id'];
|
||||
$pcAmount = null;
|
||||
$pcForeignAmount = null;
|
||||
// set the same amount in the primary currency, if both are the same anyway.
|
||||
if (true === $this->convertToPrimary && $currencyId === (int)$this->primaryCurrency->id) {
|
||||
$pcAmount = $transaction['amount'];
|
||||
}
|
||||
// convert the amount to the primary currency, if it is not the same.
|
||||
if (true === $this->convertToPrimary && $currencyId !== (int)$this->primaryCurrency->id) {
|
||||
$pcAmount = $converter->convert($this->currencies[$currencyId], $this->primaryCurrency, today(), $transaction['amount']);
|
||||
}
|
||||
if (null !== $transaction['foreign_amount']) {
|
||||
$foreignCurrencyId = $transaction['foreign_currency_id'];
|
||||
if ($foreignCurrencyId !== $this->primaryCurrency->id) {
|
||||
$pcForeignAmount = $converter->convert($this->currencies[$foreignCurrencyId], $this->primaryCurrency, today(), $transaction['foreign_amount']);
|
||||
}
|
||||
}
|
||||
|
||||
$transaction['pc_amount'] = $pcAmount;
|
||||
$transaction['pc_foreign_amount'] = $pcForeignAmount;
|
||||
|
||||
$sourceId = $transaction['source_id'];
|
||||
$transaction['source_name'] = $this->accounts[$sourceId]->name;
|
||||
$transaction['source_iban'] = $this->accounts[$sourceId]->iban;
|
||||
$transaction['source_type'] = $this->accounts[$sourceId]->accountType->type;
|
||||
$transaction['source_id'] = (string)$transaction['source_id'];
|
||||
|
||||
$destId = $transaction['destination_id'];
|
||||
$transaction['destination_name'] = $this->accounts[$destId]->name;
|
||||
$transaction['destination_iban'] = $this->accounts[$destId]->iban;
|
||||
$transaction['destination_type'] = $this->accounts[$destId]->accountType->type;
|
||||
$transaction['destination_id'] = (string)$transaction['destination_id'];
|
||||
|
||||
$transaction['currency_id'] = (string)$currencyId;
|
||||
$transaction['currency_name'] = $this->currencies[$currencyId]->name;
|
||||
$transaction['currency_code'] = $this->currencies[$currencyId]->code;
|
||||
$transaction['currency_symbol'] = $this->currencies[$currencyId]->symbol;
|
||||
$transaction['currency_decimal_places'] = $this->currencies[$currencyId]->decimal_places;
|
||||
|
||||
$transaction['primary_currency_id'] = (string)$this->primaryCurrency->id;
|
||||
$transaction['primary_currency_name'] = $this->primaryCurrency->name;
|
||||
$transaction['primary_currency_code'] = $this->primaryCurrency->code;
|
||||
$transaction['primary_currency_symbol'] = $this->primaryCurrency->symbol;
|
||||
$transaction['primary_currency_decimal_places'] = $this->primaryCurrency->decimal_places;
|
||||
|
||||
// $transaction['foreign_currency_id'] = null;
|
||||
$transaction['foreign_currency_name'] = null;
|
||||
$transaction['foreign_currency_code'] = null;
|
||||
$transaction['foreign_currency_symbol'] = null;
|
||||
$transaction['foreign_currency_decimal_places'] = null;
|
||||
if (null !== $transaction['foreign_currency_id']) {
|
||||
$currencyId = $transaction['foreign_currency_id'];
|
||||
$transaction['foreign_currency_id'] = (string)$currencyId;
|
||||
$transaction['foreign_currency_name'] = $this->currencies[$currencyId]->name;
|
||||
$transaction['foreign_currency_code'] = $this->currencies[$currencyId]->code;
|
||||
$transaction['foreign_currency_symbol'] = $this->currencies[$currencyId]->symbol;
|
||||
$transaction['foreign_currency_decimal_places'] = $this->currencies[$currencyId]->decimal_places;
|
||||
}
|
||||
unset($transaction['transaction_currency_id']);
|
||||
$return[] = $transaction;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
private function collectAccounts(): void
|
||||
{
|
||||
$all = array_merge(array_unique($this->sourceAccountIds), array_unique($this->destinationAccountIds));
|
||||
$accounts = Account::with(['accountType'])->whereIn('id', array_unique($all))->get();
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$id = (int)$account->id;
|
||||
$this->accounts[$id] = $account;
|
||||
}
|
||||
}
|
||||
|
||||
private function collectTransactionMetaData(): void
|
||||
{
|
||||
$ids = array_keys($this->transactions);
|
||||
$meta = RecurrenceTransactionMeta::whereIn('rt_id', $ids)->get();
|
||||
// other meta-data to be collected:
|
||||
$billIds = [];
|
||||
$piggyBankIds = [];
|
||||
$categoryIds = [];
|
||||
$categoryNames = [];
|
||||
$budgetIds = [];
|
||||
foreach ($meta as $entry) {
|
||||
$id = (int)$entry->id;
|
||||
$transactionId = (int)$entry->rt_id;
|
||||
$recurrenceId = $this->recurrenceIds[$transactionId];
|
||||
$name = (string)$entry->name;
|
||||
|
||||
switch ($name) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Recurrence transformer cant handle field "%s"', $name));
|
||||
|
||||
case 'bill_id':
|
||||
if ((int)$entry->value > 0) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['subscription_id'] = $entry->value;
|
||||
if (!array_key_exists($id, $billIds)) {
|
||||
$billIds[$id] = [
|
||||
'recurrence_id' => $recurrenceId,
|
||||
'transaction_id' => $transactionId,
|
||||
'bill_id' => (int)$entry->value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'tags':
|
||||
$this->transactions[$recurrenceId][$transactionId]['tags'] = json_decode((string)$entry->value);
|
||||
|
||||
break;
|
||||
|
||||
case 'piggy_bank_id':
|
||||
if ((int)$entry->value > 0) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['piggy_bank_id'] = (string)$entry->value;
|
||||
if (!array_key_exists($id, $piggyBankIds)) {
|
||||
$piggyBankIds[$id] = [
|
||||
'recurrence_id' => $recurrenceId,
|
||||
'transaction_id' => $transactionId,
|
||||
'piggy_bank_id' => (int)$entry->value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'category_id':
|
||||
if ((int)$entry->value > 0) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['category_id'] = (string)$entry->value;
|
||||
if (!array_key_exists($id, $categoryIds)) {
|
||||
$categoryIds[$id] = [
|
||||
'recurrence_id' => $recurrenceId,
|
||||
'transaction_id' => $transactionId,
|
||||
'category_id' => (int)$entry->value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'category_name':
|
||||
if ('' !== (string)$entry->value) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['category_name'] = (string)$entry->value;
|
||||
if (!array_key_exists($id, $categoryIds)) {
|
||||
$categoryNames[$id] = [
|
||||
'recurrence_id' => $recurrenceId,
|
||||
'transaction_id' => $transactionId,
|
||||
'category_name' => $entry->value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'budget_id':
|
||||
if ((int)$entry->value > 0) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['budget_id'] = (string)$entry->value;
|
||||
if (!array_key_exists($id, $budgetIds)) {
|
||||
$budgetIds[$id] = [
|
||||
'recurrence_id' => $recurrenceId,
|
||||
'transaction_id' => $transactionId,
|
||||
'budget_id' => (int)$entry->value,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->collectBillInfo($billIds);
|
||||
$this->collectPiggyBankInfo($piggyBankIds);
|
||||
$this->collectCategoryIdInfo($categoryIds);
|
||||
$this->collectCategoryNameInfo($categoryNames);
|
||||
$this->collectBudgetInfo($budgetIds);
|
||||
}
|
||||
|
||||
private function collectBillInfo(array $billIds): void
|
||||
{
|
||||
if (0 === count($billIds)) {
|
||||
return;
|
||||
}
|
||||
$ids = Arr::pluck($billIds, 'bill_id');
|
||||
$bills = Bill::whereIn('id', $ids)->get();
|
||||
$mapped = [];
|
||||
foreach ($bills as $bill) {
|
||||
$mapped[(int)$bill->id] = $bill;
|
||||
}
|
||||
foreach ($billIds as $info) {
|
||||
$recurrenceId = $info['recurrence_id'];
|
||||
$transactionId = $info['transaction_id'];
|
||||
$this->transactions[$recurrenceId][$transactionId]['subscription_name'] = $mapped[$info['bill_id']]->name ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
private function collectPiggyBankInfo(array $piggyBankIds): void
|
||||
{
|
||||
if (0 === count($piggyBankIds)) {
|
||||
return;
|
||||
}
|
||||
$ids = Arr::pluck($piggyBankIds, 'piggy_bank_id');
|
||||
$piggyBanks = PiggyBank::whereIn('id', $ids)->get();
|
||||
$mapped = [];
|
||||
foreach ($piggyBanks as $piggyBank) {
|
||||
$mapped[(int)$piggyBank->id] = $piggyBank;
|
||||
}
|
||||
foreach ($piggyBankIds as $info) {
|
||||
$recurrenceId = $info['recurrence_id'];
|
||||
$transactionId = $info['transaction_id'];
|
||||
$this->transactions[$recurrenceId][$transactionId]['piggy_bank_name'] = $mapped[$info['piggy_bank_id']]->name ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
private function collectCategoryIdInfo(array $categoryIds): void
|
||||
{
|
||||
if (0 === count($categoryIds)) {
|
||||
return;
|
||||
}
|
||||
$ids = Arr::pluck($categoryIds, 'category_id');
|
||||
$categories = Category::whereIn('id', $ids)->get();
|
||||
$mapped = [];
|
||||
foreach ($categories as $category) {
|
||||
$mapped[(int)$category->id] = $category;
|
||||
}
|
||||
foreach ($categoryIds as $info) {
|
||||
$recurrenceId = $info['recurrence_id'];
|
||||
$transactionId = $info['transaction_id'];
|
||||
$this->transactions[$recurrenceId][$transactionId]['category_name'] = $mapped[$info['category_id']]->name ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO This method does look-up in a loop.
|
||||
*/
|
||||
private function collectCategoryNameInfo(array $categoryNames): void
|
||||
{
|
||||
if (0 === count($categoryNames)) {
|
||||
return;
|
||||
}
|
||||
$factory = app(CategoryFactory::class);
|
||||
$factory->setUser($this->user);
|
||||
foreach ($categoryNames as $info) {
|
||||
$recurrenceId = $info['recurrence_id'];
|
||||
$transactionId = $info['transaction_id'];
|
||||
$category = $factory->findOrCreate(null, $info['category_name']);
|
||||
if (null !== $category) {
|
||||
$this->transactions[$recurrenceId][$transactionId]['category_id'] = (string)$category->id;
|
||||
$this->transactions[$recurrenceId][$transactionId]['category_name'] = $category->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function collectBudgetInfo(array $budgetIds): void
|
||||
{
|
||||
if (0 === count($budgetIds)) {
|
||||
return;
|
||||
}
|
||||
$ids = Arr::pluck($budgetIds, 'budget_id');
|
||||
$categories = Budget::whereIn('id', $ids)->get();
|
||||
$mapped = [];
|
||||
foreach ($categories as $category) {
|
||||
$mapped[(int)$category->id] = $category;
|
||||
}
|
||||
foreach ($budgetIds as $info) {
|
||||
$recurrenceId = $info['recurrence_id'];
|
||||
$transactionId = $info['transaction_id'];
|
||||
$this->transactions[$recurrenceId][$transactionId]['budget_name'] = $mapped[$info['budget_id']]->name ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
private function collectNotes(): void
|
||||
{
|
||||
$notes = Note::query()->whereIn('noteable_id', $this->ids)
|
||||
->whereNotNull('notes.text')
|
||||
->where('notes.text', '!=', '')
|
||||
->where('noteable_type', Recurrence::class)->get(['notes.noteable_id', 'notes.text'])->toArray()
|
||||
;
|
||||
foreach ($notes as $note) {
|
||||
$this->notes[(int)$note['noteable_id']] = (string)$note['text'];
|
||||
}
|
||||
Log::debug(sprintf('Enrich with %d note(s)', count($this->notes)));
|
||||
}
|
||||
}
|
@@ -27,15 +27,15 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
||||
private User $user;
|
||||
private UserGroup $userGroup;
|
||||
private Collection $collection;
|
||||
private bool $convertToPrimary = false;
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
private array $subscriptionIds = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
private array $paidDates = [];
|
||||
private array $notes = [];
|
||||
private array $payDates = [];
|
||||
private bool $convertToPrimary;
|
||||
private ?Carbon $start = null;
|
||||
private ?Carbon $end = null;
|
||||
private array $subscriptionIds = [];
|
||||
private array $objectGroups = [];
|
||||
private array $mappedObjects = [];
|
||||
private array $paidDates = [];
|
||||
private array $notes = [];
|
||||
private array $payDates = [];
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
private BillDateCalculator $calculator;
|
||||
|
||||
@@ -56,6 +56,8 @@ class SubscriptionEnrichment implements EnrichmentInterface
|
||||
$this->collectPaidDates();
|
||||
$this->collectPayDates();
|
||||
|
||||
// TODO clean me up.
|
||||
|
||||
$notes = $this->notes;
|
||||
$objectGroups = $this->objectGroups;
|
||||
$paidDates = $this->paidDates;
|
||||
|
@@ -45,26 +45,20 @@ use Override;
|
||||
|
||||
class TransactionGroupEnrichment implements EnrichmentInterface
|
||||
{
|
||||
private array $attachmentCount;
|
||||
private array $attachmentCount = [];
|
||||
private Collection $collection;
|
||||
private readonly array $dateFields;
|
||||
private array $journalIds;
|
||||
private array $locations;
|
||||
private array $metaData; // @phpstan-ignore-line
|
||||
private array $notes; // @phpstan-ignore-line
|
||||
private array $tags;
|
||||
private array $journalIds = [];
|
||||
private array $locations = [];
|
||||
private array $metaData = [];
|
||||
private array $notes = [];
|
||||
private array $tags = [];
|
||||
private User $user;
|
||||
private readonly TransactionCurrency $primaryCurrency;
|
||||
private UserGroup $userGroup;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->notes = [];
|
||||
$this->journalIds = [];
|
||||
$this->tags = [];
|
||||
$this->metaData = [];
|
||||
$this->locations = [];
|
||||
$this->attachmentCount = [];
|
||||
$this->dateFields = ['interest_date', 'book_date', 'process_date', 'due_date', 'payment_date', 'invoice_date'];
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
@@ -565,11 +565,12 @@ class Navigation
|
||||
public function preferredCarbonLocalizedFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
$locale = app('steam')->getLocale();
|
||||
if ($start->diffInMonths($end, true) > 1) {
|
||||
$diff = $start->diffInMonths($end, true);
|
||||
if ($diff >= 1.001) {
|
||||
return (string) trans('config.month_js', [], $locale);
|
||||
}
|
||||
|
||||
if ($start->diffInMonths($end, true) > 12) {
|
||||
if ($diff >= 12.001) {
|
||||
return (string) trans('config.year_js', [], $locale);
|
||||
}
|
||||
|
||||
@@ -582,11 +583,12 @@ class Navigation
|
||||
*/
|
||||
public function preferredEndOfPeriod(Carbon $start, Carbon $end): string
|
||||
{
|
||||
if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
|
||||
$diff = $start->diffInMonths($end, true);
|
||||
if ($diff >= 1.001) {
|
||||
return 'endOfMonth';
|
||||
}
|
||||
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
if ($diff >= 12.001) {
|
||||
return 'endOfYear';
|
||||
}
|
||||
|
||||
@@ -599,11 +601,12 @@ class Navigation
|
||||
*/
|
||||
public function preferredRangeFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
|
||||
$diff = $start->diffInMonths($end, true);
|
||||
if ($diff >= 1.001) {
|
||||
return '1M';
|
||||
}
|
||||
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
if ($diff >= 12.001) {
|
||||
return '1Y';
|
||||
}
|
||||
|
||||
@@ -616,11 +619,12 @@ class Navigation
|
||||
*/
|
||||
public function preferredSqlFormat(Carbon $start, Carbon $end): string
|
||||
{
|
||||
if ((int) $start->diffInMonths($end, true) > 1 && (int) $start->diffInMonths($end, true) <= 12) {
|
||||
$diff = $start->diffInMonths($end, true);
|
||||
if ($diff >= 1.001) {
|
||||
return '%Y-%m';
|
||||
}
|
||||
|
||||
if ((int) $start->diffInMonths($end, true) > 12) {
|
||||
if ($diff >= 12.001) {
|
||||
return '%Y';
|
||||
}
|
||||
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Support\Repositories\Recurring;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class CalculateXOccurrencesSince
|
||||
@@ -37,7 +38,7 @@ trait CalculateXOccurrencesSince
|
||||
*/
|
||||
protected function getXDailyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$return = [];
|
||||
$mutator = clone $date;
|
||||
$total = 0;
|
||||
@@ -62,7 +63,7 @@ trait CalculateXOccurrencesSince
|
||||
*/
|
||||
protected function getXMonthlyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s(%s, %s, %d)', __METHOD__, $date->format('Y-m-d'), $afterDate->format('Y-m-d'), $count));
|
||||
Log::debug(sprintf('Now in %s(%s, %s, %d)', __METHOD__, $date->format('Y-m-d'), $afterDate->format('Y-m-d'), $count));
|
||||
$return = [];
|
||||
$mutator = clone $date;
|
||||
$total = 0;
|
||||
@@ -70,24 +71,25 @@ trait CalculateXOccurrencesSince
|
||||
$dayOfMonth = (int) $moment;
|
||||
$dayOfMonth = 0 === $dayOfMonth ? 1 : $dayOfMonth;
|
||||
if ($mutator->day > $dayOfMonth) {
|
||||
app('log')->debug(sprintf('%d is after %d, add a month. Mutator is now', $mutator->day, $dayOfMonth));
|
||||
Log::debug(sprintf('%d is after %d, add a month. Mutator is now...', $mutator->day, $dayOfMonth));
|
||||
// day has passed already, add a month.
|
||||
$mutator->addMonth();
|
||||
app('log')->debug(sprintf('%s', $mutator->format('Y-m-d')));
|
||||
Log::debug(sprintf('%s', $mutator->toAtomString()));
|
||||
}
|
||||
|
||||
while ($total < $count) {
|
||||
$domCorrected = min($dayOfMonth, $mutator->daysInMonth);
|
||||
$mutator->day = $domCorrected;
|
||||
app('log')->debug(sprintf('Mutator is now %s', $mutator->format('Y-m-d')));
|
||||
$mutator->setTime(0, 0, 0);
|
||||
if (0 === $attempts % $skipMod && $mutator->gte($afterDate)) {
|
||||
app('log')->debug('Is added to the list.');
|
||||
Log::debug(sprintf('Mutator is now %s and is added to the list.', $mutator->toAtomString()));
|
||||
$return[] = clone $mutator;
|
||||
++$total;
|
||||
}
|
||||
++$attempts;
|
||||
$mutator = $mutator->endOfMonth()->addDay();
|
||||
}
|
||||
Log::debug('Collected enough occurrences.');
|
||||
|
||||
return $return;
|
||||
}
|
||||
@@ -100,7 +102,7 @@ trait CalculateXOccurrencesSince
|
||||
*/
|
||||
protected function getXNDomOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$return = [];
|
||||
$total = 0;
|
||||
$attempts = 0;
|
||||
@@ -134,7 +136,7 @@ trait CalculateXOccurrencesSince
|
||||
*/
|
||||
protected function getXWeeklyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
Log::debug(sprintf('Now in %s', __METHOD__));
|
||||
$return = [];
|
||||
$total = 0;
|
||||
$attempts = 0;
|
||||
@@ -173,7 +175,7 @@ trait CalculateXOccurrencesSince
|
||||
*/
|
||||
protected function getXYearlyOccurrencesSince(Carbon $date, Carbon $afterDate, int $count, int $skipMod, string $moment): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s(%s, %d, %d, %s)', __METHOD__, $date->format('Y-m-d'), $date->format('Y-m-d'), $count, $skipMod));
|
||||
Log::debug(sprintf('Now in %s(%s, %d, %d, %s)', __METHOD__, $date->format('Y-m-d'), $date->format('Y-m-d'), $count, $skipMod));
|
||||
$return = [];
|
||||
$mutator = clone $date;
|
||||
$total = 0;
|
||||
@@ -181,19 +183,19 @@ trait CalculateXOccurrencesSince
|
||||
$date = new Carbon($moment);
|
||||
$date->year = $mutator->year;
|
||||
if ($mutator > $date) {
|
||||
app('log')->debug(
|
||||
Log::debug(
|
||||
sprintf('mutator (%s) > date (%s), so add a year to date (%s)', $mutator->format('Y-m-d'), $date->format('Y-m-d'), $date->format('Y-m-d'))
|
||||
);
|
||||
$date->addYear();
|
||||
app('log')->debug(sprintf('Date is now %s', $date->format('Y-m-d')));
|
||||
Log::debug(sprintf('Date is now %s', $date->format('Y-m-d')));
|
||||
}
|
||||
$obj = clone $date;
|
||||
while ($total < $count) {
|
||||
app('log')->debug(sprintf('total (%d) < count (%d) so go.', $total, $count));
|
||||
app('log')->debug(sprintf('attempts (%d) %% skipmod (%d) === %d', $attempts, $skipMod, $attempts % $skipMod));
|
||||
app('log')->debug(sprintf('Obj (%s) gte afterdate (%s)? %s', $obj->format('Y-m-d'), $afterDate->format('Y-m-d'), var_export($obj->gte($afterDate), true)));
|
||||
Log::debug(sprintf('total (%d) < count (%d) so go.', $total, $count));
|
||||
Log::debug(sprintf('attempts (%d) %% skipmod (%d) === %d', $attempts, $skipMod, $attempts % $skipMod));
|
||||
Log::debug(sprintf('Obj (%s) gte afterdate (%s)? %s', $obj->format('Y-m-d'), $afterDate->format('Y-m-d'), var_export($obj->gte($afterDate), true)));
|
||||
if (0 === $attempts % $skipMod && $obj->gte($afterDate)) {
|
||||
app('log')->debug('All conditions true, add obj.');
|
||||
Log::debug('All conditions true, add obj.');
|
||||
$return[] = clone $obj;
|
||||
++$total;
|
||||
}
|
||||
|
@@ -24,8 +24,10 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Support;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Exception;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\AccountMeta;
|
||||
use FireflyIII\Models\Transaction;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
@@ -34,11 +36,10 @@ use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Str;
|
||||
use Exception;
|
||||
use ValueError;
|
||||
|
||||
use function Safe\preg_replace;
|
||||
use function Safe\parse_url;
|
||||
use function Safe\preg_replace;
|
||||
|
||||
/**
|
||||
* Class Steam.
|
||||
@@ -277,7 +278,7 @@ class Steam
|
||||
$carbon = new Carbon($entry->date, $entry->date_tz);
|
||||
$carbonKey = $carbon->format('Y-m-d');
|
||||
// make sure sum is a string:
|
||||
$sumOfDay = (string) ($entry->sum_of_day ?? '0');
|
||||
$sumOfDay = (string)($entry->sum_of_day ?? '0');
|
||||
// #10426 make sure sum is not in scientific notation.
|
||||
$sumOfDay = $this->floatalize($sumOfDay);
|
||||
|
||||
@@ -292,20 +293,20 @@ class Steam
|
||||
|
||||
// add amount to current balance in currency code.
|
||||
$currentBalance[$entryCurrency->code] ??= '0';
|
||||
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string) $currentBalance[$entryCurrency->code]);
|
||||
$currentBalance[$entryCurrency->code] = bcadd($sumOfDay, (string)$currentBalance[$entryCurrency->code]);
|
||||
|
||||
// if not requested to convert to primary currency, add the amount to "balance", do nothing else.
|
||||
if (!$convertToPrimary) {
|
||||
$currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay);
|
||||
$currentBalance['balance'] = bcadd((string)$currentBalance['balance'], $sumOfDay);
|
||||
}
|
||||
// if convert to primary currency add the converted amount to "pc_balance".
|
||||
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
|
||||
if ($convertToPrimary) {
|
||||
$pcSumOfDay = $converter->convert($entryCurrency, $primaryCurrency, $carbon, $sumOfDay);
|
||||
$currentBalance['pc_balance'] = bcadd((string) ($currentBalance['pc_balance'] ?? '0'), $pcSumOfDay);
|
||||
$currentBalance['pc_balance'] = bcadd((string)($currentBalance['pc_balance'] ?? '0'), $pcSumOfDay);
|
||||
// if it's the same currency as the entry, also add to balance (see other code).
|
||||
if ($currency->id === $entryCurrency->id) {
|
||||
$currentBalance['balance'] = bcadd((string) $currentBalance['balance'], $sumOfDay);
|
||||
$currentBalance['balance'] = bcadd((string)$currentBalance['balance'], $sumOfDay);
|
||||
}
|
||||
}
|
||||
// add to final array.
|
||||
@@ -318,6 +319,72 @@ class Steam
|
||||
return $balances;
|
||||
}
|
||||
|
||||
public function accountsBalancesOptimized(Collection $accounts, Carbon $date, ?TransactionCurrency $primary = null, ?bool $convertToPrimary = null): array
|
||||
{
|
||||
$result = [];
|
||||
$convertToPrimary ??= Amount::convertToPrimary();
|
||||
$primary ??= Amount::getPrimaryCurrency();
|
||||
$currencies = $this->getCurrencies($accounts);
|
||||
|
||||
// balance(s) in all currencies for ALL accounts.
|
||||
$array = Transaction::whereIn('account_id', $accounts->pluck('id')->toArray())
|
||||
->leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id')
|
||||
->leftJoin('transaction_currencies', 'transaction_currencies.id', '=', 'transactions.transaction_currency_id')
|
||||
->where('transaction_journals.date', '<=', $date->format('Y-m-d H:i:s'))
|
||||
->get(['transactions.account_id', 'transaction_currencies.code', 'transactions.amount'])->toArray()
|
||||
;
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
// filter array back to this account:
|
||||
$filtered = array_filter($array, function ($item) use ($account) {
|
||||
return (int)$item['account_id'] === $account->id;
|
||||
});
|
||||
$currency = $currencies[$account->id];
|
||||
// this array is PER account, so we wait a bit before we change code here.
|
||||
$return = [
|
||||
'pc_balance' => '0',
|
||||
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||
];
|
||||
|
||||
// balance(s) in all currencies.
|
||||
$others = $this->groupAndSumTransactions($filtered, 'code', 'amount');
|
||||
// Log::debug('All balances are (joined)', $others);
|
||||
// if there is no request to convert, take this as "balance" and "pc_balance".
|
||||
$return['balance'] = $others[$currency->code] ?? '0';
|
||||
if (!$convertToPrimary) {
|
||||
unset($return['pc_balance']);
|
||||
// Log::debug(sprintf('Set balance to %s, unset pc_balance', $return['balance']));
|
||||
}
|
||||
// if there is a request to convert, convert to "pc_balance" and use "balance" for whichever amount is in the primary currency.
|
||||
if ($convertToPrimary) {
|
||||
$return['pc_balance'] = $this->convertAllBalances($others, $primary, $date); // todo sum all and convert.
|
||||
// Log::debug(sprintf('Set pc_balance to %s', $return['pc_balance']));
|
||||
}
|
||||
|
||||
// either way, the balance is always combined with the virtual balance:
|
||||
$virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance);
|
||||
|
||||
if ($convertToPrimary) {
|
||||
// the primary currency balance is combined with a converted virtual_balance:
|
||||
$converter = new ExchangeRateConverter();
|
||||
$pcVirtualBalance = $converter->convert($currency, $primary, $date, $virtualBalance);
|
||||
$return['pc_balance'] = bcadd($pcVirtualBalance, $return['pc_balance']);
|
||||
// Log::debug(sprintf('Primary virtual balance makes the primary total %s', $return['pc_balance']));
|
||||
}
|
||||
if (!$convertToPrimary) {
|
||||
// if not, also increase the balance + primary balance for consistency.
|
||||
$return['balance'] = bcadd($return['balance'], $virtualBalance);
|
||||
// Log::debug(sprintf('Virtual balance makes the (primary currency) total %s', $return['balance']));
|
||||
}
|
||||
$final = array_merge($return, $others);
|
||||
$result[$account->id] = $final;
|
||||
// Log::debug('Final balance is', $final);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns smaller than or equal to, so be careful with END OF DAY.
|
||||
*
|
||||
@@ -340,7 +407,7 @@ class Steam
|
||||
if ($cache->has()) {
|
||||
Log::debug(sprintf('CACHED finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
|
||||
|
||||
return $cache->get();
|
||||
// return $cache->get();
|
||||
}
|
||||
// Log::debug(sprintf('finalAccountBalance(#%d, %s)', $account->id, $date->format('Y-m-d H:i:s')));
|
||||
if (null === $convertToPrimary) {
|
||||
@@ -361,8 +428,8 @@ class Steam
|
||||
$hasCurrency = null !== $accountCurrency;
|
||||
$currency = $hasCurrency ? $accountCurrency : $primary;
|
||||
$return = [
|
||||
'pc_balance' => '0',
|
||||
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||
'pc_balance' => '0',
|
||||
'balance' => '0', // this key is overwritten right away, but I must remember it is always created.
|
||||
];
|
||||
// balance(s) in all currencies.
|
||||
$array = $account->transactions()
|
||||
@@ -386,7 +453,7 @@ class Steam
|
||||
}
|
||||
|
||||
// either way, the balance is always combined with the virtual balance:
|
||||
$virtualBalance = (string) ('' === (string) $account->virtual_balance ? '0' : $account->virtual_balance);
|
||||
$virtualBalance = (string)('' === (string)$account->virtual_balance ? '0' : $account->virtual_balance);
|
||||
|
||||
if ($convertToPrimary) {
|
||||
// the primary currency balance is combined with a converted virtual_balance:
|
||||
@@ -421,7 +488,7 @@ class Steam
|
||||
return null;
|
||||
}
|
||||
|
||||
return TransactionCurrency::find((int) $result->data);
|
||||
return TransactionCurrency::find((int)$result->data);
|
||||
}
|
||||
|
||||
private function groupAndSumTransactions(array $array, string $group, string $field): array
|
||||
@@ -430,7 +497,7 @@ class Steam
|
||||
|
||||
foreach ($array as $item) {
|
||||
$groupKey = $item[$group] ?? 'unknown';
|
||||
$return[$groupKey] = bcadd($return[$groupKey] ?? '0', (string) $item[$field]);
|
||||
$return[$groupKey] = bcadd($return[$groupKey] ?? '0', (string)$item[$field]);
|
||||
}
|
||||
|
||||
return $return;
|
||||
@@ -478,11 +545,11 @@ class Steam
|
||||
$hostName = $ipAddress;
|
||||
}
|
||||
|
||||
if ('' !== (string) $hostName && $hostName !== $ipAddress) {
|
||||
if ('' !== (string)$hostName && $hostName !== $ipAddress) {
|
||||
$host = $hostName;
|
||||
}
|
||||
|
||||
return (string) $host;
|
||||
return (string)$host;
|
||||
}
|
||||
|
||||
public function getLastActivities(array $accounts): array
|
||||
@@ -497,9 +564,9 @@ class Steam
|
||||
|
||||
/** @var Transaction $entry */
|
||||
foreach ($set as $entry) {
|
||||
$date = new Carbon($entry->max_date, config('app.timezone'));
|
||||
$date = new Carbon($entry->max_date, config('app.timezone'));
|
||||
$date->setTimezone(config('app.timezone'));
|
||||
$list[(int) $entry->account_id] = $date;
|
||||
$list[(int)$entry->account_id] = $date;
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -517,7 +584,7 @@ class Steam
|
||||
if ('equal' === $locale) {
|
||||
$locale = $this->getLanguage();
|
||||
}
|
||||
$locale = (string) $locale;
|
||||
$locale = (string)$locale;
|
||||
|
||||
// Check for Windows to replace the locale correctly.
|
||||
if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
|
||||
@@ -617,20 +684,20 @@ class Steam
|
||||
}
|
||||
Log::debug(sprintf('Floatalizing %s', $value));
|
||||
|
||||
$number = substr($value, 0, (int) strpos($value, 'E'));
|
||||
$number = substr($value, 0, (int)strpos($value, 'E'));
|
||||
if (str_contains($number, '.')) {
|
||||
$post = strlen(substr($number, (int) strpos($number, '.') + 1));
|
||||
$mantis = substr($value, (int) strpos($value, 'E') + 1);
|
||||
$post = strlen(substr($number, (int)strpos($number, '.') + 1));
|
||||
$mantis = substr($value, (int)strpos($value, 'E') + 1);
|
||||
if ($mantis < 0) {
|
||||
$post += abs((int) $mantis);
|
||||
$post += abs((int)$mantis);
|
||||
}
|
||||
|
||||
// TODO careless float could break financial math.
|
||||
return number_format((float) $value, $post, '.', '');
|
||||
return number_format((float)$value, $post, '.', '');
|
||||
}
|
||||
|
||||
// TODO careless float could break financial math.
|
||||
return number_format((float) $value, 0, '.', '');
|
||||
return number_format((float)$value, 0, '.', '');
|
||||
}
|
||||
|
||||
public function opposite(?string $amount = null): ?string
|
||||
@@ -650,24 +717,24 @@ class Steam
|
||||
// has a K in it, remove the K and multiply by 1024.
|
||||
$bytes = bcmul(rtrim($string, 'k'), '1024');
|
||||
|
||||
return (int) $bytes;
|
||||
return (int)$bytes;
|
||||
}
|
||||
|
||||
if (false !== stripos($string, 'm')) {
|
||||
// has a M in it, remove the M and multiply by 1048576.
|
||||
$bytes = bcmul(rtrim($string, 'm'), '1048576');
|
||||
|
||||
return (int) $bytes;
|
||||
return (int)$bytes;
|
||||
}
|
||||
|
||||
if (false !== stripos($string, 'g')) {
|
||||
// has a G in it, remove the G and multiply by (1024)^3.
|
||||
$bytes = bcmul(rtrim($string, 'g'), '1073741824');
|
||||
|
||||
return (int) $bytes;
|
||||
return (int)$bytes;
|
||||
}
|
||||
|
||||
return (int) $string;
|
||||
return (int)$string;
|
||||
}
|
||||
|
||||
public function positive(string $amount): string
|
||||
@@ -689,4 +756,48 @@ class Steam
|
||||
|
||||
return $amount;
|
||||
}
|
||||
|
||||
private function getCurrencies(Collection $accounts): array
|
||||
{
|
||||
$currencies = [];
|
||||
$accountCurrencies = [];
|
||||
$accountPreferences = [];
|
||||
$primary = Amount::getPrimaryCurrency();
|
||||
$currencies[$primary->id] = $primary;
|
||||
|
||||
$ids = $accounts->pluck('id')->toArray();
|
||||
$result = AccountMeta::whereIn('account_id', $ids)->where('name', 'currency_id')->get();
|
||||
|
||||
/** @var AccountMeta $item */
|
||||
foreach ($result as $item) {
|
||||
$integer = (int)$item->data;
|
||||
if (0 !== $integer) {
|
||||
$accountPreferences[(int)$item->account_id] = $integer;
|
||||
}
|
||||
}
|
||||
// collect those currencies, skip primary because we already have it.
|
||||
$set = TransactionCurrency::whereIn('id', $accountPreferences)->where('id', '!=', $primary->id)->get();
|
||||
foreach ($set as $item) {
|
||||
$currencies[$item->id] = $item;
|
||||
}
|
||||
|
||||
/** @var Account $account */
|
||||
foreach ($accounts as $account) {
|
||||
$accountId = $account->id;
|
||||
$currencyPresent = isset($account->meta) && array_key_exists('currency', $account->meta) && null !== $account->meta['currency'];
|
||||
if ($currencyPresent) {
|
||||
$currencyId = $account->meta['currency']->id;
|
||||
$currencies[$currencyId] ??= $account->meta['currency'];
|
||||
$accountCurrencies[$accountId] = $account->meta['currency'];
|
||||
}
|
||||
if (!$currencyPresent && !array_key_exists($accountId, $accountPreferences)) {
|
||||
$accountCurrencies[$accountId] = $primary;
|
||||
}
|
||||
if (!$currencyPresent && array_key_exists($accountId, $accountPreferences)) {
|
||||
$accountCurrencies[$accountId] = $currencies[$accountPreferences[$account->id]];
|
||||
}
|
||||
}
|
||||
|
||||
return $accountCurrencies;
|
||||
}
|
||||
}
|
||||
|
@@ -108,15 +108,22 @@ class AccountTransformer extends AbstractTransformer
|
||||
'type' => strtolower($accountType),
|
||||
'account_role' => $accountRole,
|
||||
|
||||
'object_group_id' => $account->meta['object_group_id'],
|
||||
'object_group_order' => $account->meta['object_group_order'],
|
||||
'object_group_title' => $account->meta['object_group_title'],
|
||||
|
||||
// currency information, structured for 6.3.0.
|
||||
'object_has_currency_setting' => $hasCurrencySettings,
|
||||
|
||||
// currency is object specific or primary, already determined above.
|
||||
'currency_id' => (string) $currency['id'],
|
||||
'currency_name' => $currency['name'],
|
||||
'currency_code' => $currency['code'],
|
||||
'currency_symbol' => $currency['symbol'],
|
||||
'currency_decimal_places' => $currency['decimal_places'],
|
||||
|
||||
'primary_currency_id' => (string) $this->primary->id,
|
||||
'primary_currency_name' => $this->primary->name,
|
||||
'primary_currency_code' => $this->primary->code,
|
||||
'primary_currency_symbol' => $this->primary->symbol,
|
||||
'primary_currency_decimal_places' => $this->primary->decimal_places,
|
||||
@@ -138,7 +145,7 @@ class AccountTransformer extends AbstractTransformer
|
||||
'notes' => $account->meta['notes'] ?? null,
|
||||
'monthly_payment_date' => $monthlyPaymentDate,
|
||||
'credit_card_type' => $creditCardType,
|
||||
'account_number' => $account->meta['account_number'] ?? null,
|
||||
'account_number' => $account->meta['account_number'],
|
||||
'iban' => '' === $account->iban ? null : $account->iban,
|
||||
'bic' => $account->meta['BIC'] ?? null,
|
||||
'opening_balance_date' => $openingBalanceDate,
|
||||
@@ -150,7 +157,7 @@ class AccountTransformer extends AbstractTransformer
|
||||
'longitude' => $longitude,
|
||||
'latitude' => $latitude,
|
||||
'zoom_level' => $zoomLevel,
|
||||
'last_activity' => array_key_exists('last_activity', $account->meta) ? $account->meta['last_activity']->toAtomString() : null,
|
||||
'last_activity' => $account->meta['last_activity']?->toAtomString(),
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
|
@@ -55,7 +55,6 @@ class AttachmentTransformer extends AbstractTransformer
|
||||
'updated_at' => $attachment->updated_at->toAtomString(),
|
||||
'attachable_id' => (string) $attachment->attachable_id,
|
||||
'attachable_type' => str_replace('FireflyIII\Models\\', '', $attachment->attachable_type),
|
||||
'md5' => $attachment->md5,
|
||||
'hash' => $attachment->md5,
|
||||
'filename' => $attachment->filename,
|
||||
'download_url' => route('api.v1.attachments.download', [$attachment->id]),
|
||||
|
@@ -27,6 +27,7 @@ namespace FireflyIII\Transformers;
|
||||
use FireflyIII\Models\AvailableBudget;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
|
||||
/**
|
||||
* Class AvailableBudgetTransformer
|
||||
@@ -50,12 +51,12 @@ class AvailableBudgetTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(AvailableBudget $availableBudget): array
|
||||
{
|
||||
$currency = $availableBudget->transactionCurrency;
|
||||
$amount = app('steam')->bcround($availableBudget->amount, $currency->decimal_places);
|
||||
$currency = $availableBudget->meta['currency'];
|
||||
$amount = Steam::bcround($availableBudget->amount, $currency->decimal_places);
|
||||
$pcAmount = null;
|
||||
|
||||
if ($this->convertToPrimary) {
|
||||
$pcAmount = app('steam')->bcround($availableBudget->native_amount, $this->primary->decimal_places);
|
||||
$pcAmount = Steam::bcround($availableBudget->native_amount, $this->primary->decimal_places);
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -66,16 +67,17 @@ class AvailableBudgetTransformer extends AbstractTransformer
|
||||
// currencies according to 6.3.0
|
||||
'object_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,
|
||||
|
||||
'primary_currency_id' => (string) $this->primary->id,
|
||||
'primary_currency_name' => $this->primary->name,
|
||||
'primary_currency_code' => $this->primary->code,
|
||||
'primary_currency_symbol' => $this->primary->symbol,
|
||||
'primary_currency_decimal_places' => $this->primary->decimal_places,
|
||||
|
||||
|
||||
'amount' => $amount,
|
||||
'pc_amount' => $pcAmount,
|
||||
'start' => $availableBudget->start_date->toAtomString(),
|
||||
|
@@ -60,11 +60,13 @@ class BillTransformer extends AbstractTransformer
|
||||
// currencies according to 6.3.0
|
||||
'object_has_currency_setting' => true,
|
||||
'currency_id' => (string) $bill->transaction_currency_id,
|
||||
'currency_name' => $currency->name,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
|
||||
'primary_currency_id' => (string) $this->primary->id,
|
||||
'primary_currency_name' => $this->primary->name,
|
||||
'primary_currency_code' => $this->primary->code,
|
||||
'primary_currency_symbol' => $this->primary->symbol,
|
||||
'primary_currency_decimal_places' => $this->primary->decimal_places,
|
||||
@@ -91,7 +93,6 @@ class BillTransformer extends AbstractTransformer
|
||||
'object_group_order' => $bill->meta['object_group_order'],
|
||||
'object_group_title' => $bill->meta['object_group_title'],
|
||||
|
||||
|
||||
'paid_dates' => $bill->meta['paid_dates'],
|
||||
'pay_dates' => $bill->meta['pay_dates'],
|
||||
'next_expected_match' => $bill->meta['nem']?->toAtomString(),
|
||||
|
@@ -26,10 +26,8 @@ namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Models\BudgetLimit;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Budget\BudgetLimitRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepository;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use League\Fractal\Resource\Item;
|
||||
|
||||
/**
|
||||
@@ -42,11 +40,11 @@ class BudgetLimitTransformer extends AbstractTransformer
|
||||
'budget',
|
||||
];
|
||||
protected bool $convertToPrimary;
|
||||
protected TransactionCurrency $primary;
|
||||
protected TransactionCurrency $primaryCurrency;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->primary = Amount::getPrimaryCurrency();
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
}
|
||||
|
||||
@@ -65,39 +63,16 @@ class BudgetLimitTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(BudgetLimit $budgetLimit): array
|
||||
{
|
||||
$repository = app(OperationsRepository::class);
|
||||
$limitRepos = app(BudgetLimitRepositoryInterface::class);
|
||||
$repository->setUser($budgetLimit->budget->user);
|
||||
$limitRepos->setUser($budgetLimit->budget->user);
|
||||
$expenses = $repository->sumExpenses(
|
||||
$budgetLimit->start_date,
|
||||
$budgetLimit->end_date,
|
||||
null,
|
||||
new Collection([$budgetLimit->budget]),
|
||||
$budgetLimit->transactionCurrency
|
||||
);
|
||||
$currency = $budgetLimit->transactionCurrency;
|
||||
$amount = $budgetLimit->amount;
|
||||
$notes = $limitRepos->getNoteText($budgetLimit);
|
||||
$currencyDecimalPlaces = 2;
|
||||
$currencyId = null;
|
||||
$currencyName = null;
|
||||
$currencyCode = null;
|
||||
$currencySymbol = null;
|
||||
if (null !== $currency) {
|
||||
$amount = $budgetLimit->amount;
|
||||
$currencyId = $currency->id;
|
||||
$currencyName = $currency->name;
|
||||
$currencyCode = $currency->code;
|
||||
$currencySymbol = $currency->symbol;
|
||||
$currencyDecimalPlaces = $currency->decimal_places;
|
||||
}
|
||||
$amount = app('steam')->bcround($amount, $currencyDecimalPlaces);
|
||||
$primary = $this->primary;
|
||||
if (!$this->convertToPrimary) {
|
||||
$primary = null;
|
||||
}
|
||||
|
||||
$currency = $budgetLimit->meta['currency'];
|
||||
$amount = Steam::bcround($budgetLimit->amount, $currency->decimal_places);
|
||||
$pcAmount = null;
|
||||
if ($this->convertToPrimary && $currency->id === $this->primaryCurrency->id) {
|
||||
$pcAmount = $amount;
|
||||
}
|
||||
if ($this->convertToPrimary && $currency->id !== $this->primaryCurrency->id) {
|
||||
$pcAmount = Steam::bcround($budgetLimit->native_amount, $this->primaryCurrency->decimal_places);
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (string)$budgetLimit->id,
|
||||
@@ -106,20 +81,28 @@ class BudgetLimitTransformer extends AbstractTransformer
|
||||
'start' => $budgetLimit->start_date->toAtomString(),
|
||||
'end' => $budgetLimit->end_date->endOfDay()->toAtomString(),
|
||||
'budget_id' => (string)$budgetLimit->budget_id,
|
||||
'currency_id' => (string)$currencyId,
|
||||
'currency_code' => $currencyCode,
|
||||
'currency_name' => $currencyName,
|
||||
'currency_decimal_places' => $currencyDecimalPlaces,
|
||||
'currency_symbol' => $currencySymbol,
|
||||
'primary_currency_id' => $primary instanceof TransactionCurrency ? (string)$primary->id : null,
|
||||
'primary_currency_code' => $primary?->code,
|
||||
'primary_currency_symbol' => $primary?->symbol,
|
||||
'primary_currency_decimal_places' => $primary?->decimal_places,
|
||||
|
||||
// currency settings according to 6.3.0
|
||||
'object_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,
|
||||
|
||||
'primary_currency_id' => (int)$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,
|
||||
|
||||
'amount' => $amount,
|
||||
'pc_amount' => $this->convertToPrimary ? app('steam')->bcround($budgetLimit->native_amount, $primary->decimal_places) : null,
|
||||
'pc_amount' => $pcAmount,
|
||||
'period' => $budgetLimit->period,
|
||||
'spent' => $expenses[$currencyId]['sum'] ?? '0', // will be in primary currency if convertToPrimary.
|
||||
'notes' => '' === $notes ? null : $notes,
|
||||
'spent' => $budgetLimit->meta['spent'],
|
||||
'pc_spent' => $budgetLimit->meta['pc_spent'],
|
||||
'notes' => $budgetLimit->meta['notes'],
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
|
@@ -27,10 +27,8 @@ namespace FireflyIII\Transformers;
|
||||
use FireflyIII\Enums\AutoBudgetType;
|
||||
use FireflyIII\Models\Budget;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
|
||||
/**
|
||||
@@ -38,21 +36,23 @@ use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
*/
|
||||
class BudgetTransformer extends AbstractTransformer
|
||||
{
|
||||
private readonly bool $convertToPrimary;
|
||||
private readonly TransactionCurrency $primary;
|
||||
private readonly OperationsRepositoryInterface $opsRepository;
|
||||
private readonly BudgetRepositoryInterface $repository;
|
||||
private readonly bool $convertToPrimary;
|
||||
private readonly TransactionCurrency $primaryCurrency;
|
||||
private array $types;
|
||||
|
||||
/**
|
||||
* BudgetTransformer constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->repository = app(BudgetRepositoryInterface::class);
|
||||
$this->parameters = new ParameterBag();
|
||||
$this->primary = Amount::getPrimaryCurrency();
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
$this->convertToPrimary = Amount::convertToPrimary();
|
||||
$this->types = [
|
||||
AutoBudgetType::AUTO_BUDGET_RESET->value => 'reset',
|
||||
AutoBudgetType::AUTO_BUDGET_ROLLOVER->value => 'rollover',
|
||||
AutoBudgetType::AUTO_BUDGET_ADJUSTED->value => 'adjusted',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,69 +60,54 @@ class BudgetTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(Budget $budget): array
|
||||
{
|
||||
$this->opsRepository->setUser($budget->user);
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
$autoBudget = $this->repository->getAutoBudget($budget);
|
||||
$spent = [];
|
||||
if (null !== $start && null !== $end) {
|
||||
$spent = $this->beautify($this->opsRepository->sumExpenses($start, $end, null, new Collection([$budget])));
|
||||
}
|
||||
|
||||
// info for auto budget.
|
||||
$abType = null;
|
||||
$abAmount = null;
|
||||
$abPrimary = null;
|
||||
$abPeriod = null;
|
||||
$notes = $this->repository->getNoteText($budget);
|
||||
$abType = null;
|
||||
$abAmount = null;
|
||||
$abPrimary = null;
|
||||
$abPeriod = null;
|
||||
|
||||
$types = [
|
||||
AutoBudgetType::AUTO_BUDGET_RESET->value => 'reset',
|
||||
AutoBudgetType::AUTO_BUDGET_ROLLOVER->value => 'rollover',
|
||||
AutoBudgetType::AUTO_BUDGET_ADJUSTED->value => 'adjusted',
|
||||
];
|
||||
$currency = $autoBudget?->transactionCurrency;
|
||||
$primary = $this->primary;
|
||||
if (!$this->convertToPrimary) {
|
||||
$primary = null;
|
||||
}
|
||||
if (null === $autoBudget) {
|
||||
$currency = $primary;
|
||||
}
|
||||
if (null !== $autoBudget) {
|
||||
$abType = $types[$autoBudget->auto_budget_type];
|
||||
$abAmount = app('steam')->bcround($autoBudget->amount, $currency->decimal_places);
|
||||
$abPrimary = $this->convertToPrimary ? app('steam')->bcround($autoBudget->native_amount, $primary->decimal_places) : null;
|
||||
$abPeriod = $autoBudget->period;
|
||||
$currency = $budget->meta['currency'] ?? null;
|
||||
|
||||
if (null !== $budget->meta['auto_budget']) {
|
||||
$abType = $this->types[$budget->meta['auto_budget']['type']];
|
||||
$abAmount = Steam::bcround($budget->meta['auto_budget']['amount'], $currency->decimal_places);
|
||||
$abPrimary = $this->convertToPrimary ? Steam::bcround($budget->meta['auto_budget']['pc_amount'], $this->primaryCurrency->decimal_places) : null;
|
||||
$abPeriod = $budget->meta['auto_budget']['period'];
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => (string) $budget->id,
|
||||
'id' => (string)$budget->id,
|
||||
'created_at' => $budget->created_at->toAtomString(),
|
||||
'updated_at' => $budget->updated_at->toAtomString(),
|
||||
'active' => $budget->active,
|
||||
'name' => $budget->name,
|
||||
'order' => $budget->order,
|
||||
'notes' => $notes,
|
||||
'notes' => $budget->meta['notes'],
|
||||
'auto_budget_type' => $abType,
|
||||
'auto_budget_period' => $abPeriod,
|
||||
'object_group_id' => $budget->meta['object_group_id'],
|
||||
'object_group_order' => $budget->meta['object_group_order'],
|
||||
'object_group_title' => $budget->meta['object_group_title'],
|
||||
|
||||
'currency_id' => null === $autoBudget ? null : (string) $autoBudget->transactionCurrency->id,
|
||||
'currency_code' => $autoBudget?->transactionCurrency->code,
|
||||
'currency_name' => $autoBudget?->transactionCurrency->name,
|
||||
'currency_decimal_places' => $autoBudget?->transactionCurrency->decimal_places,
|
||||
'currency_symbol' => $autoBudget?->transactionCurrency->symbol,
|
||||
// new currency settings.
|
||||
'object_has_currency_setting' => null !== $budget->meta['currency'],
|
||||
'currency_id' => null === $currency ? null : (string)$currency->id,
|
||||
'currency_code' => $currency?->code,
|
||||
'currency_name' => $currency?->name,
|
||||
'currency_symbol' => $currency?->symbol,
|
||||
'currency_decimal_places' => $currency?->decimal_places,
|
||||
|
||||
'primary_currency_id' => $primary instanceof TransactionCurrency ? (string) $primary->id : null,
|
||||
'primary_currency_code' => $primary?->code,
|
||||
'primary_currency_symbol' => $primary?->symbol,
|
||||
'primary_currency_decimal_places' => $primary?->decimal_places,
|
||||
|
||||
// amount and primary currency amount if present.
|
||||
'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,
|
||||
|
||||
'auto_budget_amount' => $abAmount,
|
||||
'pc_auto_budget_amount' => $abPrimary,
|
||||
'spent' => $spent, // always in primary currency.
|
||||
'spent' => null === $budget->meta['spent'] ? null : $this->beautify($budget->meta['spent']),
|
||||
'pc_spent' => null === $budget->meta['pc_spent'] ? null : $this->beautify($budget->meta['pc_spent']),
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
@@ -136,7 +121,7 @@ class BudgetTransformer extends AbstractTransformer
|
||||
{
|
||||
$return = [];
|
||||
foreach ($array as $data) {
|
||||
$data['sum'] = app('steam')->bcround($data['sum'], (int) $data['currency_decimal_places']);
|
||||
$data['sum'] = Steam::bcround($data['sum'], (int)$data['currency_decimal_places']);
|
||||
$return[] = $data;
|
||||
}
|
||||
|
||||
|
@@ -26,30 +26,22 @@ namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Models\Category;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
|
||||
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
use Illuminate\Support\Collection;
|
||||
use FireflyIII\Support\Facades\Steam;
|
||||
|
||||
/**
|
||||
* Class CategoryTransformer
|
||||
*/
|
||||
class CategoryTransformer extends AbstractTransformer
|
||||
{
|
||||
private readonly bool $convertToNative;
|
||||
private readonly TransactionCurrency $primary;
|
||||
private readonly OperationsRepositoryInterface $opsRepository;
|
||||
private readonly CategoryRepositoryInterface $repository;
|
||||
private readonly TransactionCurrency $primaryCurrency;
|
||||
|
||||
/**
|
||||
* CategoryTransformer constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->opsRepository = app(OperationsRepositoryInterface::class);
|
||||
$this->repository = app(CategoryRepositoryInterface::class);
|
||||
$this->primary = Amount::getPrimaryCurrency();
|
||||
$this->convertToNative = Amount::convertToPrimary();
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,35 +49,27 @@ class CategoryTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(Category $category): array
|
||||
{
|
||||
$this->opsRepository->setUser($category->user);
|
||||
$this->repository->setUser($category->user);
|
||||
|
||||
$spent = [];
|
||||
$earned = [];
|
||||
$start = $this->parameters->get('start');
|
||||
$end = $this->parameters->get('end');
|
||||
if (null !== $start && null !== $end) {
|
||||
$earned = $this->beautify($this->opsRepository->sumIncome($start, $end, null, new Collection([$category])));
|
||||
$spent = $this->beautify($this->opsRepository->sumExpenses($start, $end, null, new Collection([$category])));
|
||||
}
|
||||
$primary = $this->primary;
|
||||
if (!$this->convertToNative) {
|
||||
$primary = null;
|
||||
}
|
||||
$notes = $this->repository->getNoteText($category);
|
||||
|
||||
return [
|
||||
'id' => $category->id,
|
||||
'created_at' => $category->created_at->toAtomString(),
|
||||
'updated_at' => $category->updated_at->toAtomString(),
|
||||
'name' => $category->name,
|
||||
'notes' => $notes,
|
||||
'primary_currency_id' => $primary instanceof TransactionCurrency ? (string)$primary->id : null,
|
||||
'primary_currency_code' => $primary?->code,
|
||||
'primary_currency_symbol' => $primary?->symbol,
|
||||
'primary_currency_decimal_places' => $primary?->decimal_places,
|
||||
'spent' => $spent,
|
||||
'earned' => $earned,
|
||||
'notes' => $category->meta['notes'],
|
||||
|
||||
// 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,
|
||||
'spent' => $this->beautify($category->meta['spent']),
|
||||
'pc_spent' => $this->beautify($category->meta['pc_spent']),
|
||||
'earned' => $this->beautify($category->meta['earned']),
|
||||
'pc_earned' => $this->beautify($category->meta['pc_earned']),
|
||||
'transferred' => $this->beautify($category->meta['transfers']),
|
||||
'pc_transferred' => $this->beautify($category->meta['pc_transfers']),
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
@@ -99,7 +83,7 @@ class CategoryTransformer extends AbstractTransformer
|
||||
{
|
||||
$return = [];
|
||||
foreach ($array as $data) {
|
||||
$data['sum'] = app('steam')->bcround($data['sum'], (int)$data['currency_decimal_places']);
|
||||
$data['sum'] = Steam::bcround($data['sum'], (int)$data['currency_decimal_places']);
|
||||
$return[] = $data;
|
||||
}
|
||||
|
||||
|
@@ -26,24 +26,25 @@ 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;
|
||||
|
||||
/**
|
||||
* Class PiggyBankEventTransformer
|
||||
*/
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,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) ?? app('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,
|
||||
'created_at' => $event->created_at?->toAtomString(),
|
||||
'updated_at' => $event->updated_at?->toAtomString(),
|
||||
'amount' => app('steam')->bcround($event->amount, $currency->decimal_places),
|
||||
'currency_id' => (string) $currency->id,
|
||||
'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' => [
|
||||
'id' => (string)$event->id,
|
||||
'created_at' => $event->created_at?->toAtomString(),
|
||||
'updated_at' => $event->updated_at?->toAtomString(),
|
||||
'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,
|
||||
|
||||
'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),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
@@ -25,26 +25,23 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Models\ObjectGroup;
|
||||
use FireflyIII\Models\PiggyBank;
|
||||
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Models\TransactionCurrency;
|
||||
use FireflyIII\Support\Facades\Amount;
|
||||
|
||||
/**
|
||||
* Class PiggyBankTransformer
|
||||
*/
|
||||
class PiggyBankTransformer extends AbstractTransformer
|
||||
{
|
||||
private readonly AccountRepositoryInterface $accountRepos;
|
||||
private readonly PiggyBankRepositoryInterface $piggyRepos;
|
||||
private TransactionCurrency $primaryCurrency;
|
||||
|
||||
/**
|
||||
* PiggyBankTransformer constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->accountRepos = app(AccountRepositoryInterface::class);
|
||||
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
|
||||
$this->primaryCurrency = Amount::getPrimaryCurrency();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,74 +51,58 @@ class PiggyBankTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(PiggyBank $piggyBank): array
|
||||
{
|
||||
$user = $piggyBank->accounts()->first()->user;
|
||||
|
||||
// set up repositories
|
||||
$this->accountRepos->setUser($user);
|
||||
$this->piggyRepos->setUser($user);
|
||||
|
||||
// note
|
||||
$notes = $this->piggyRepos->getNoteText($piggyBank);
|
||||
$notes = '' === $notes ? null : $notes;
|
||||
|
||||
$objectGroupId = null;
|
||||
$objectGroupOrder = null;
|
||||
$objectGroupTitle = null;
|
||||
|
||||
/** @var null|ObjectGroup $objectGroup */
|
||||
$objectGroup = $piggyBank->objectGroups->first();
|
||||
if (null !== $objectGroup) {
|
||||
$objectGroupId = $objectGroup->id;
|
||||
$objectGroupOrder = $objectGroup->order;
|
||||
$objectGroupTitle = $objectGroup->title;
|
||||
}
|
||||
|
||||
// get currently saved amount:
|
||||
$currency = $piggyBank->transactionCurrency;
|
||||
$currentAmount = $this->piggyRepos->getCurrentAmount($piggyBank);
|
||||
|
||||
// Amounts, depending on 0.0 state of target amount
|
||||
$percentage = null;
|
||||
$targetAmount = $piggyBank->target_amount;
|
||||
$leftToSave = null;
|
||||
$savePerMonth = null;
|
||||
if (0 !== bccomp($targetAmount, '0')) { // target amount is not 0.00
|
||||
$leftToSave = bcsub($piggyBank->target_amount, $currentAmount);
|
||||
$percentage = (int) bcmul(bcdiv($currentAmount, $targetAmount), '100');
|
||||
$targetAmount = app('steam')->bcround($targetAmount, $currency->decimal_places);
|
||||
$leftToSave = app('steam')->bcround($leftToSave, $currency->decimal_places);
|
||||
$savePerMonth = app('steam')->bcround($this->piggyRepos->getSuggestedMonthlyAmount($piggyBank), $currency->decimal_places);
|
||||
$percentage = null;
|
||||
if (null !== $piggyBank->meta['target_amount'] && 0 !== bccomp($piggyBank->meta['current_amount'], '0')) { // target amount is not 0.00
|
||||
$percentage = (int)bcmul(bcdiv($piggyBank->meta['current_amount'], $piggyBank->meta['target_amount']), '100');
|
||||
}
|
||||
$startDate = $piggyBank->start_date?->format('Y-m-d');
|
||||
$targetDate = $piggyBank->target_date?->format('Y-m-d');
|
||||
$startDate = $piggyBank->start_date?->toAtomString();
|
||||
$targetDate = $piggyBank->target_date?->toAtomString();
|
||||
|
||||
return [
|
||||
'id' => (string) $piggyBank->id,
|
||||
'created_at' => $piggyBank->created_at->toAtomString(),
|
||||
'updated_at' => $piggyBank->updated_at->toAtomString(),
|
||||
'name' => $piggyBank->name,
|
||||
'accounts' => $this->renderAccounts($piggyBank),
|
||||
'currency_id' => (string) $currency->id,
|
||||
'currency_code' => $currency->code,
|
||||
'currency_symbol' => $currency->symbol,
|
||||
'currency_decimal_places' => $currency->decimal_places,
|
||||
'target_amount' => $targetAmount,
|
||||
'percentage' => $percentage,
|
||||
'current_amount' => $currentAmount,
|
||||
'left_to_save' => $leftToSave,
|
||||
'save_per_month' => $savePerMonth,
|
||||
'start_date' => $startDate,
|
||||
'target_date' => $targetDate,
|
||||
'order' => $piggyBank->order,
|
||||
'active' => true,
|
||||
'notes' => $notes,
|
||||
'object_group_id' => null !== $objectGroupId ? (string) $objectGroupId : null,
|
||||
'object_group_order' => $objectGroupOrder,
|
||||
'object_group_title' => $objectGroupTitle,
|
||||
'links' => [
|
||||
'id' => (string)$piggyBank->id,
|
||||
'created_at' => $piggyBank->created_at->toAtomString(),
|
||||
'updated_at' => $piggyBank->updated_at->toAtomString(),
|
||||
'name' => $piggyBank->name,
|
||||
'percentage' => $percentage,
|
||||
'start_date' => $startDate,
|
||||
'target_date' => $targetDate,
|
||||
'order' => $piggyBank->order,
|
||||
'active' => true,
|
||||
'notes' => $piggyBank->meta['notes'],
|
||||
'object_group_id' => $piggyBank->meta['object_group_id'],
|
||||
'object_group_order' => $piggyBank->meta['object_group_order'],
|
||||
'object_group_title' => $piggyBank->meta['object_group_title'],
|
||||
'accounts' => $piggyBank->meta['accounts'],
|
||||
|
||||
// currency settings, 6.3.0.
|
||||
'object_has_currency_setting' => true,
|
||||
'currency_id' => (string)$piggyBank->meta['currency']->id,
|
||||
'currency_name' => $piggyBank->meta['currency']->name,
|
||||
'currency_code' => $piggyBank->meta['currency']->code,
|
||||
'currency_symbol' => $piggyBank->meta['currency']->symbol,
|
||||
'currency_decimal_places' => $piggyBank->meta['currency']->decimal_places,
|
||||
|
||||
'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,
|
||||
|
||||
|
||||
'target_amount' => $piggyBank->meta['target_amount'],
|
||||
'pc_target_amount' => $piggyBank->meta['pc_target_amount'],
|
||||
'current_amount' => $piggyBank->meta['current_amount'],
|
||||
'pc_current_amount' => $piggyBank->meta['pc_current_amount'],
|
||||
'left_to_save' => $piggyBank->meta['left_to_save'],
|
||||
'pc_left_to_save' => $piggyBank->meta['pc_left_to_save'],
|
||||
'save_per_month' => $piggyBank->meta['save_per_month'],
|
||||
'pc_save_per_month' => $piggyBank->meta['pc_save_per_month'],
|
||||
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
'uri' => '/piggy_banks/'.$piggyBank->id,
|
||||
'uri' => sprintf('/piggy-banks/%d', $piggyBank->id),
|
||||
],
|
||||
],
|
||||
];
|
||||
@@ -132,10 +113,10 @@ class PiggyBankTransformer extends AbstractTransformer
|
||||
$return = [];
|
||||
foreach ($piggyBank->accounts()->get() as $account) {
|
||||
$return[] = [
|
||||
'id' => (string) $account->id,
|
||||
'name' => $account->name,
|
||||
'current_amount' => (string) $account->pivot->current_amount,
|
||||
'pc_current_amount' => (string) $account->pivot->native_current_amount,
|
||||
'id' => (string)$account->id,
|
||||
'name' => $account->name,
|
||||
'current_amount' => (string)$account->pivot->current_amount,
|
||||
'pc_current_amount' => (string)$account->pivot->native_current_amount,
|
||||
// TODO add balance, add left to save.
|
||||
];
|
||||
}
|
||||
|
@@ -24,43 +24,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use FireflyIII\Exceptions\FireflyException;
|
||||
use FireflyIII\Factory\CategoryFactory;
|
||||
use FireflyIII\Models\Account;
|
||||
use FireflyIII\Models\Recurrence;
|
||||
use FireflyIII\Models\RecurrenceRepetition;
|
||||
use FireflyIII\Models\RecurrenceTransaction;
|
||||
use FireflyIII\Models\RecurrenceTransactionMeta;
|
||||
use FireflyIII\Repositories\Bill\BillRepositoryInterface;
|
||||
use FireflyIII\Repositories\Budget\BudgetRepositoryInterface;
|
||||
use FireflyIII\Repositories\PiggyBank\PiggyBankRepositoryInterface;
|
||||
use FireflyIII\Repositories\Recurring\RecurringRepositoryInterface;
|
||||
|
||||
use function Safe\json_decode;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Class RecurringTransactionTransformer
|
||||
*/
|
||||
class RecurrenceTransformer extends AbstractTransformer
|
||||
{
|
||||
private readonly BillRepositoryInterface $billRepos;
|
||||
private readonly BudgetRepositoryInterface $budgetRepos;
|
||||
private readonly CategoryFactory $factory;
|
||||
private readonly PiggyBankRepositoryInterface $piggyRepos;
|
||||
private readonly RecurringRepositoryInterface $repository;
|
||||
|
||||
/**
|
||||
* RecurrenceTransformer constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->repository = app(RecurringRepositoryInterface::class);
|
||||
$this->piggyRepos = app(PiggyBankRepositoryInterface::class);
|
||||
$this->factory = app(CategoryFactory::class);
|
||||
$this->budgetRepos = app(BudgetRepositoryInterface::class);
|
||||
$this->billRepos = app(BillRepositoryInterface::class);
|
||||
}
|
||||
public function __construct() {}
|
||||
|
||||
/**
|
||||
* Transform the recurring transaction.
|
||||
@@ -69,35 +45,29 @@ class RecurrenceTransformer extends AbstractTransformer
|
||||
*/
|
||||
public function transform(Recurrence $recurrence): array
|
||||
{
|
||||
app('log')->debug('Now in Recurrence::transform()');
|
||||
$this->repository->setUser($recurrence->user);
|
||||
$this->piggyRepos->setUser($recurrence->user);
|
||||
$this->factory->setUser($recurrence->user);
|
||||
$this->budgetRepos->setUser($recurrence->user);
|
||||
app('log')->debug('Set user.');
|
||||
Log::debug('Now in Recurrence::transform()');
|
||||
|
||||
$shortType = (string) config(sprintf('firefly.transactionTypesToShort.%s', $recurrence->transactionType->type));
|
||||
$notes = $this->repository->getNoteText($recurrence);
|
||||
$reps = 0 === (int) $recurrence->repetitions ? null : (int) $recurrence->repetitions;
|
||||
app('log')->debug('Get basic data.');
|
||||
$shortType = (string)config(sprintf('firefly.transactionTypesToShort.%s', $recurrence->transactionType->type));
|
||||
$reps = 0 === (int)$recurrence->repetitions ? null : (int)$recurrence->repetitions;
|
||||
Log::debug('Get basic data.');
|
||||
|
||||
// basic data.
|
||||
return [
|
||||
'id' => (string) $recurrence->id,
|
||||
'id' => (string)$recurrence->id,
|
||||
'created_at' => $recurrence->created_at->toAtomString(),
|
||||
'updated_at' => $recurrence->updated_at->toAtomString(),
|
||||
'type' => $shortType,
|
||||
'title' => $recurrence->title,
|
||||
'description' => $recurrence->description,
|
||||
'first_date' => $recurrence->first_date->format('Y-m-d'),
|
||||
'latest_date' => $recurrence->latest_date?->format('Y-m-d'),
|
||||
'repeat_until' => $recurrence->repeat_until?->format('Y-m-d'),
|
||||
'first_date' => $recurrence->first_date->toAtomString(),
|
||||
'latest_date' => $recurrence->latest_date?->toAtomString(),
|
||||
'repeat_until' => $recurrence->repeat_until?->toAtomString(),
|
||||
'apply_rules' => $recurrence->apply_rules,
|
||||
'active' => $recurrence->active,
|
||||
'nr_of_repetitions' => $reps,
|
||||
'notes' => '' === $notes ? null : $notes,
|
||||
'repetitions' => $this->getRepetitions($recurrence),
|
||||
'transactions' => $this->getTransactions($recurrence),
|
||||
'notes' => $recurrence->meta['notes'],
|
||||
'repetitions' => $recurrence->meta['repetitions'],
|
||||
'transactions' => $recurrence->meta['transactions'],
|
||||
'links' => [
|
||||
[
|
||||
'rel' => 'self',
|
||||
@@ -106,208 +76,4 @@ class RecurrenceTransformer extends AbstractTransformer
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getRepetitions(Recurrence $recurrence): array
|
||||
{
|
||||
app('log')->debug('Now in getRepetitions().');
|
||||
$fromDate = $recurrence->latest_date ?? $recurrence->first_date;
|
||||
$return = [];
|
||||
|
||||
/** @var RecurrenceRepetition $repetition */
|
||||
foreach ($recurrence->recurrenceRepetitions as $repetition) {
|
||||
$repetitionArray = [
|
||||
'id' => (string) $repetition->id,
|
||||
'created_at' => $repetition->created_at->toAtomString(),
|
||||
'updated_at' => $repetition->updated_at->toAtomString(),
|
||||
'type' => $repetition->repetition_type,
|
||||
'moment' => $repetition->repetition_moment,
|
||||
'skip' => $repetition->repetition_skip,
|
||||
'weekend' => $repetition->weekend,
|
||||
'description' => $this->repository->repetitionDescription($repetition),
|
||||
'occurrences' => [],
|
||||
];
|
||||
|
||||
// get the (future) occurrences for this specific type of repetition:
|
||||
$amount = 'daily' === $repetition->repetition_type ? 9 : 5;
|
||||
$occurrences = $this->repository->getXOccurrencesSince($repetition, $fromDate, now(), $amount);
|
||||
|
||||
/** @var Carbon $carbon */
|
||||
foreach ($occurrences as $carbon) {
|
||||
$repetitionArray['occurrences'][] = $carbon->toAtomString();
|
||||
}
|
||||
|
||||
$return[] = $repetitionArray;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getTransactions(Recurrence $recurrence): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
$return = [];
|
||||
|
||||
// get all transactions:
|
||||
/** @var RecurrenceTransaction $transaction */
|
||||
foreach ($recurrence->recurrenceTransactions()->get() as $transaction) {
|
||||
/** @var null|Account $sourceAccount */
|
||||
$sourceAccount = $transaction->sourceAccount;
|
||||
|
||||
/** @var null|Account $destinationAccount */
|
||||
$destinationAccount = $transaction->destinationAccount;
|
||||
$foreignCurrencyCode = null;
|
||||
$foreignCurrencySymbol = null;
|
||||
$foreignCurrencyDp = null;
|
||||
$foreignCurrencyId = null;
|
||||
if (null !== $transaction->foreign_currency_id) {
|
||||
$foreignCurrencyId = (int) $transaction->foreign_currency_id;
|
||||
$foreignCurrencyCode = $transaction->foreignCurrency->code;
|
||||
$foreignCurrencySymbol = $transaction->foreignCurrency->symbol;
|
||||
$foreignCurrencyDp = $transaction->foreignCurrency->decimal_places;
|
||||
}
|
||||
|
||||
// source info:
|
||||
$sourceName = '';
|
||||
$sourceId = null;
|
||||
$sourceType = null;
|
||||
$sourceIban = null;
|
||||
if (null !== $sourceAccount) {
|
||||
$sourceName = $sourceAccount->name;
|
||||
$sourceId = $sourceAccount->id;
|
||||
$sourceType = $sourceAccount->accountType->type;
|
||||
$sourceIban = $sourceAccount->iban;
|
||||
}
|
||||
$destinationName = '';
|
||||
$destinationId = null;
|
||||
$destinationType = null;
|
||||
$destinationIban = null;
|
||||
if (null !== $destinationAccount) {
|
||||
$destinationName = $destinationAccount->name;
|
||||
$destinationId = $destinationAccount->id;
|
||||
$destinationType = $destinationAccount->accountType->type;
|
||||
$destinationIban = $destinationAccount->iban;
|
||||
}
|
||||
$amount = app('steam')->bcround($transaction->amount, $transaction->transactionCurrency->decimal_places);
|
||||
$foreignAmount = null;
|
||||
if (null !== $transaction->foreign_currency_id && null !== $transaction->foreign_amount) {
|
||||
$foreignAmount = app('steam')->bcround($transaction->foreign_amount, $foreignCurrencyDp);
|
||||
}
|
||||
$transactionArray = [
|
||||
'id' => (string) $transaction->id,
|
||||
'currency_id' => (string) $transaction->transaction_currency_id,
|
||||
'currency_code' => $transaction->transactionCurrency->code,
|
||||
'currency_symbol' => $transaction->transactionCurrency->symbol,
|
||||
'currency_decimal_places' => $transaction->transactionCurrency->decimal_places,
|
||||
'foreign_currency_id' => null === $foreignCurrencyId ? null : (string) $foreignCurrencyId,
|
||||
'foreign_currency_code' => $foreignCurrencyCode,
|
||||
'foreign_currency_symbol' => $foreignCurrencySymbol,
|
||||
'foreign_currency_decimal_places' => $foreignCurrencyDp,
|
||||
'source_id' => (string) $sourceId,
|
||||
'source_name' => $sourceName,
|
||||
'source_iban' => $sourceIban,
|
||||
'source_type' => $sourceType,
|
||||
'destination_id' => (string) $destinationId,
|
||||
'destination_name' => $destinationName,
|
||||
'destination_iban' => $destinationIban,
|
||||
'destination_type' => $destinationType,
|
||||
'amount' => $amount,
|
||||
'foreign_amount' => $foreignAmount,
|
||||
'description' => $transaction->description,
|
||||
];
|
||||
$transactionArray = $this->getTransactionMeta($transaction, $transactionArray);
|
||||
if (null !== $transaction->foreign_currency_id) {
|
||||
$transactionArray['foreign_currency_code'] = $transaction->foreignCurrency->code;
|
||||
$transactionArray['foreign_currency_symbol'] = $transaction->foreignCurrency->symbol;
|
||||
$transactionArray['foreign_currency_decimal_places'] = $transaction->foreignCurrency->decimal_places;
|
||||
}
|
||||
|
||||
// store transaction in recurrence array.
|
||||
$return[] = $transactionArray;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FireflyException
|
||||
*/
|
||||
private function getTransactionMeta(RecurrenceTransaction $transaction, array $array): array
|
||||
{
|
||||
app('log')->debug(sprintf('Now in %s', __METHOD__));
|
||||
$array['tags'] = [];
|
||||
$array['category_id'] = null;
|
||||
$array['category_name'] = null;
|
||||
$array['budget_id'] = null;
|
||||
$array['budget_name'] = null;
|
||||
$array['piggy_bank_id'] = null;
|
||||
$array['piggy_bank_name'] = null;
|
||||
$array['bill_id'] = null;
|
||||
$array['bill_name'] = null;
|
||||
|
||||
/** @var RecurrenceTransactionMeta $transactionMeta */
|
||||
foreach ($transaction->recurrenceTransactionMeta as $transactionMeta) {
|
||||
switch ($transactionMeta->name) {
|
||||
default:
|
||||
throw new FireflyException(sprintf('Recurrence transformer cant handle field "%s"', $transactionMeta->name));
|
||||
|
||||
case 'bill_id':
|
||||
$bill = $this->billRepos->find((int) $transactionMeta->value);
|
||||
if (null !== $bill) {
|
||||
$array['bill_id'] = (string) $bill->id;
|
||||
$array['bill_name'] = $bill->name;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'tags':
|
||||
$array['tags'] = json_decode((string) $transactionMeta->value);
|
||||
|
||||
break;
|
||||
|
||||
case 'piggy_bank_id':
|
||||
$piggy = $this->piggyRepos->find((int) $transactionMeta->value);
|
||||
if (null !== $piggy) {
|
||||
$array['piggy_bank_id'] = (string) $piggy->id;
|
||||
$array['piggy_bank_name'] = $piggy->name;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'category_id':
|
||||
$category = $this->factory->findOrCreate((int) $transactionMeta->value, null);
|
||||
if (null !== $category) {
|
||||
$array['category_id'] = (string) $category->id;
|
||||
$array['category_name'] = $category->name;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'category_name':
|
||||
$category = $this->factory->findOrCreate(null, $transactionMeta->value);
|
||||
if (null !== $category) {
|
||||
$array['category_id'] = (string) $category->id;
|
||||
$array['category_name'] = $category->name;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'budget_id':
|
||||
$budget = $this->budgetRepos->find((int) $transactionMeta->value);
|
||||
if (null !== $budget) {
|
||||
$array['budget_id'] = (string) $budget->id;
|
||||
$array['budget_name'] = $budget->name;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
@@ -288,8 +288,8 @@ class TransactionGroupTransformer extends AbstractTransformer
|
||||
],
|
||||
];
|
||||
} catch (FireflyException $e) {
|
||||
app('log')->error($e->getMessage());
|
||||
app('log')->error($e->getTraceAsString());
|
||||
Log::error($e->getMessage());
|
||||
Log::error($e->getTraceAsString());
|
||||
|
||||
throw new FireflyException(sprintf('Transaction group #%d is broken. Please check out your log files.', $group->id), 0, $e);
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ declare(strict_types=1);
|
||||
namespace FireflyIII\Transformers;
|
||||
|
||||
use FireflyIII\Models\WebhookMessage;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use JsonException;
|
||||
|
||||
use function Safe\json_encode;
|
||||
@@ -44,7 +45,7 @@ class WebhookMessageTransformer extends AbstractTransformer
|
||||
try {
|
||||
$json = json_encode($message->message, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $e) {
|
||||
app('log')->error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage()));
|
||||
Log::error(sprintf('Could not encode webhook message #%d: %s', $message->id, $e->getMessage()));
|
||||
}
|
||||
|
||||
return [
|
||||
|
53
composer.lock
generated
53
composer.lock
generated
@@ -1879,16 +1879,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v12.21.0",
|
||||
"version": "v12.22.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/framework.git",
|
||||
"reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b"
|
||||
"reference": "6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/ac8c4e73bf1b5387b709f7736d41427e6af1c93b",
|
||||
"reference": "ac8c4e73bf1b5387b709f7736d41427e6af1c93b",
|
||||
"url": "https://api.github.com/repos/laravel/framework/zipball/6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3",
|
||||
"reference": "6ab00c913ef6ec6fad0bd506f7452c0bb9e792c3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2090,7 +2090,7 @@
|
||||
"issues": "https://github.com/laravel/framework/issues",
|
||||
"source": "https://github.com/laravel/framework"
|
||||
},
|
||||
"time": "2025-07-22T15:41:55+00:00"
|
||||
"time": "2025-08-07T13:49:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/passport",
|
||||
@@ -3878,29 +3878,29 @@
|
||||
},
|
||||
{
|
||||
"name": "nette/utils",
|
||||
"version": "v4.0.7",
|
||||
"version": "v4.0.8",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nette/utils.git",
|
||||
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2"
|
||||
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2",
|
||||
"reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2",
|
||||
"url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede",
|
||||
"reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "8.0 - 8.4"
|
||||
"php": "8.0 - 8.5"
|
||||
},
|
||||
"conflict": {
|
||||
"nette/finder": "<3",
|
||||
"nette/schema": "<1.2.2"
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "dev-master",
|
||||
"jetbrains/phpstorm-attributes": "^1.2",
|
||||
"nette/tester": "^2.5",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpstan/phpstan-nette": "^2.0@stable",
|
||||
"tracy/tracy": "^2.9"
|
||||
},
|
||||
"suggest": {
|
||||
@@ -3918,6 +3918,9 @@
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Nette\\": "src"
|
||||
},
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
@@ -3958,9 +3961,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nette/utils/issues",
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.7"
|
||||
"source": "https://github.com/nette/utils/tree/v4.0.8"
|
||||
},
|
||||
"time": "2025-06-03T04:55:08+00:00"
|
||||
"time": "2025-08-06T21:43:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "nunomaduro/collision",
|
||||
@@ -5101,16 +5104,16 @@
|
||||
},
|
||||
{
|
||||
"name": "predis/predis",
|
||||
"version": "v3.1.0",
|
||||
"version": "v3.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/predis/predis.git",
|
||||
"reference": "202e0c5322b906ec4c761c0cefebad6d0959a699"
|
||||
"reference": "9e9deec4dfd3ebf65d32eb368f498c646ba2ecd8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/202e0c5322b906ec4c761c0cefebad6d0959a699",
|
||||
"reference": "202e0c5322b906ec4c761c0cefebad6d0959a699",
|
||||
"url": "https://api.github.com/repos/predis/predis/zipball/9e9deec4dfd3ebf65d32eb368f498c646ba2ecd8",
|
||||
"reference": "9e9deec4dfd3ebf65d32eb368f498c646ba2ecd8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5152,7 +5155,7 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/predis/predis/issues",
|
||||
"source": "https://github.com/predis/predis/tree/v3.1.0"
|
||||
"source": "https://github.com/predis/predis/tree/v3.2.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -5160,7 +5163,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-22T15:37:44+00:00"
|
||||
"time": "2025-08-06T06:41:24+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/cache",
|
||||
@@ -11128,16 +11131,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.1.21",
|
||||
"version": "2.1.22",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "1ccf445757458c06a04eb3f803603cb118fe5fa6"
|
||||
"reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/1ccf445757458c06a04eb3f803603cb118fe5fa6",
|
||||
"reference": "1ccf445757458c06a04eb3f803603cb118fe5fa6",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/41600c8379eb5aee63e9413fe9e97273e25d57e4",
|
||||
"reference": "41600c8379eb5aee63e9413fe9e97273e25d57e4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -11182,7 +11185,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-28T19:35:08+00:00"
|
||||
"time": "2025-08-04T19:17:37+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan-deprecation-rules",
|
||||
|
@@ -78,8 +78,8 @@ return [
|
||||
'running_balance_column' => env('USE_RUNNING_BALANCE', false),
|
||||
// see cer.php for exchange rates feature flag.
|
||||
],
|
||||
'version' => 'develop/2025-08-03',
|
||||
'build_time' => 1754232243,
|
||||
'version' => 'develop/2025-08-07',
|
||||
'build_time' => 1754590535,
|
||||
'api_version' => '2.1.0', // field is no longer used.
|
||||
'db_version' => 26,
|
||||
|
||||
@@ -121,6 +121,7 @@ return [
|
||||
'languages' => [
|
||||
// currently enabled languages
|
||||
// 'af_ZA' => ['name_locale' => 'Afrikaans', 'name_english' => 'Afrikaans'],
|
||||
'ar_SA' => ['name_locale' => 'العربية', 'name_english' => 'Arabic'],
|
||||
'bg_BG' => ['name_locale' => 'Български', 'name_english' => 'Bulgarian'],
|
||||
'cs_CZ' => ['name_locale' => 'Czech', 'name_english' => 'Czech'],
|
||||
'da_DK' => ['name_locale' => 'Danish', 'name_english' => 'Danish'],
|
||||
|
@@ -23,243 +23,244 @@
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'operators' => [
|
||||
'user_action' => ['alias' => false, 'needs_context' => true],
|
||||
'account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'reconciled' => ['alias' => false, 'needs_context' => false],
|
||||
'source_account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'transaction_type' => ['alias' => false, 'needs_context' => true],
|
||||
'type' => ['alias' => true, 'alias_for' => 'transaction_type', 'needs_context' => true],
|
||||
'tag_is' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_is_not' => ['alias' => false, 'needs_context' => true],
|
||||
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true],
|
||||
'tag_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'description_is' => ['alias' => false, 'needs_context' => true],
|
||||
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true],
|
||||
'description_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'description_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'description_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_is' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_are' => ['alias' => true, 'alias_for' => 'notes_is', 'needs_context' => true],
|
||||
'notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_contain' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||
'notes' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||
'notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_end' => ['alias' => true, 'alias_for' => 'notes_ends', 'needs_context' => true],
|
||||
'notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_start' => ['alias' => true, 'alias_for' => 'notes_starts', 'needs_context' => true],
|
||||
'source_account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_is' => ['alias' => true, 'alias_for' => 'source_account_is', 'needs_context' => true],
|
||||
'source_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'source' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'from' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'from_account_contains' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'source_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_ends' => ['alias' => true, 'alias_for' => 'source_account_ends', 'needs_context' => true],
|
||||
'source_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_starts' => ['alias' => true, 'alias_for' => 'source_account_starts', 'needs_context' => true],
|
||||
'source_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_is' => ['alias' => true, 'alias_for' => 'source_account_nr_is', 'needs_context' => true],
|
||||
'source_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_contains' => ['alias' => true, 'alias_for' => 'source_account_nr_contains', 'needs_context' => true],
|
||||
'source_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_ends' => ['alias' => true, 'alias_for' => 'source_account_nr_ends', 'needs_context' => true],
|
||||
'source_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_starts' => ['alias' => true, 'alias_for' => 'source_account_nr_starts', 'needs_context' => true],
|
||||
'destination_account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_is' => ['alias' => true, 'alias_for' => 'destination_account_is', 'needs_context' => true],
|
||||
'destination_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'destination' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'to' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'to_account_contains' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'destination_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_ends' => ['alias' => true, 'alias_for' => 'destination_account_ends', 'needs_context' => true],
|
||||
'destination_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_starts' => ['alias' => true, 'alias_for' => 'destination_account_starts', 'needs_context' => true],
|
||||
'destination_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_is' => ['alias' => true, 'alias_for' => 'destination_account_nr_is', 'needs_context' => true],
|
||||
'destination_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_contains' => ['alias' => true, 'alias_for' => 'destination_account_nr_contains', 'needs_context' => true],
|
||||
'destination_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_ends' => ['alias' => true, 'alias_for' => 'destination_account_nr_ends', 'needs_context' => true],
|
||||
'destination_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_starts' => ['alias' => true, 'alias_for' => 'destination_account_nr_starts', 'needs_context' => true],
|
||||
'account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'category_is' => ['alias' => false, 'needs_context' => true],
|
||||
'category_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'category' => ['alias' => true, 'alias_for' => 'category_contains', 'needs_context' => true],
|
||||
'category_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'category_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_is' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'budget' => ['alias' => true, 'alias_for' => 'budget_contains', 'needs_context' => true],
|
||||
'budget_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_is' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'bill' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'bill_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'subscription_is' => ['alias' => true, 'alias_for' => 'bill_is', 'needs_context' => true],
|
||||
'subscription_contains' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'subscription' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'subscription_ends' => ['alias' => true, 'alias_for' => 'bill_ends', 'needs_context' => true],
|
||||
'subscription_starts' => ['alias' => true, 'alias_for' => 'bill_starts', 'needs_context' => true],
|
||||
'external_id_is' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id' => ['alias' => true, 'alias_for' => 'external_id_contains', 'needs_context' => true],
|
||||
'external_id_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_is' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference' => ['alias' => true, 'alias_for' => 'internal_reference_contains', 'needs_context' => true],
|
||||
'internal_reference_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_is' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url' => ['alias' => true, 'alias_for' => 'external_url_contains', 'needs_context' => true],
|
||||
'external_url_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'has_attachments' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_category' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_budget' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_bill' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_any_bill'],
|
||||
'has_any_tag' => ['alias' => false, 'needs_context' => false],
|
||||
'any_notes' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||
'has_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||
'any_external_url' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_external_url' => ['alias' => true, 'alias_for' => 'any_external_url', 'needs_context' => false],
|
||||
'has_no_attachments' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_category' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_budget' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_bill' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_no_bill'],
|
||||
'has_no_tag' => ['alias' => false, 'needs_context' => false],
|
||||
'no_notes' => ['alias' => false, 'needs_context' => false],
|
||||
'no_external_url' => ['alias' => false, 'needs_context' => false],
|
||||
'source_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'destination_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'account_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'currency_is' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_currency_is' => ['alias' => false, 'needs_context' => true],
|
||||
'id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'journal_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'recurrence_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'date' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'date_is' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'on' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'before' => ['alias' => true, 'alias_for' => 'date_before', 'needs_context' => true],
|
||||
'date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'after' => ['alias' => true, 'alias_for' => 'date_after', 'needs_context' => true],
|
||||
'interest_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'interest_date' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||
'interest_date_is' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||
'interest_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'interest_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||
'book_date_is' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||
'book_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||
'process_date_is' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||
'process_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||
'due_date_is' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||
'due_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||
'payment_date_is' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||
'payment_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||
'invoice_date_is' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||
'invoice_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at_on' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_at_is' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_at_before' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at_after' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at_on' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_at_is' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_at_before' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at_after' => ['alias' => false, 'needs_context' => true],
|
||||
'created_on_on' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_on' => ['alias' => true, 'alias_for' => 'created_at', 'needs_context' => true],
|
||||
'created_on_before' => ['alias' => true, 'alias_for' => 'created_at_before', 'needs_context' => true],
|
||||
'created_on_after' => ['alias' => true, 'alias_for' => 'created_at_after', 'needs_context' => true],
|
||||
'updated_on_on' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_on' => ['alias' => true, 'alias_for' => 'updated_at', 'needs_context' => true],
|
||||
'updated_on_before' => ['alias' => true, 'alias_for' => 'updated_at_before', 'needs_context' => true],
|
||||
'updated_on_after' => ['alias' => true, 'alias_for' => 'updated_at_after', 'needs_context' => true],
|
||||
'amount_is' => ['alias' => false, 'needs_context' => true],
|
||||
'amount' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||
'amount_exactly' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||
'amount_less' => ['alias' => false, 'needs_context' => true],
|
||||
'amount_max' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||
'less' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||
'amount_more' => ['alias' => false, 'needs_context' => true],
|
||||
'amount_min' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||
'more' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||
'foreign_amount_is' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount' => ['alias' => true, 'alias_for' => 'foreign_amount_is', 'needs_context' => true],
|
||||
'foreign_amount_less' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount_max' => ['alias' => true, 'alias_for' => 'foreign_amount_less', 'needs_context' => true],
|
||||
'foreign_amount_more' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount_min' => ['alias' => true, 'alias_for' => 'foreign_amount_more', 'needs_context' => true],
|
||||
'attachment_name_is' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_is' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_name' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_name_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_name_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_name_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes' => ['alias' => true, 'alias_for' => 'attachment_notes_are', 'needs_context' => true],
|
||||
'attachment_notes_are' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_contain' => ['alias' => true, 'alias_for' => 'attachment_notes_contains', 'needs_context' => true],
|
||||
'attachment_notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_start' => ['alias' => true, 'alias_for' => 'attachment_notes_starts', 'needs_context' => true],
|
||||
'attachment_notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true],
|
||||
'exists' => ['alias' => false, 'needs_context' => false],
|
||||
'sepa_ct_is' => ['alias' => false, 'needs_context' => true],
|
||||
'no_external_id' => ['alias' => false, 'needs_context' => false],
|
||||
'any_external_id' => ['alias' => false, 'needs_context' => false],
|
||||
'operators' => [
|
||||
'user_action' => ['alias' => false, 'needs_context' => true],
|
||||
'account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'reconciled' => ['alias' => false, 'needs_context' => false],
|
||||
'source_account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_account_id' => ['alias' => false, 'needs_context' => true],
|
||||
'transaction_type' => ['alias' => false, 'needs_context' => true],
|
||||
'type' => ['alias' => true, 'alias_for' => 'transaction_type', 'needs_context' => true],
|
||||
'tag_is' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_is_not' => ['alias' => false, 'needs_context' => true],
|
||||
'tag' => ['alias' => true, 'alias_for' => 'tag_is', 'needs_context' => true],
|
||||
'tag_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'tag_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'description_is' => ['alias' => false, 'needs_context' => true],
|
||||
'description' => ['alias' => true, 'alias_for' => 'description_is', 'needs_context' => true],
|
||||
'description_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'description_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'description_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_is' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_are' => ['alias' => true, 'alias_for' => 'notes_is', 'needs_context' => true],
|
||||
'notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_contain' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||
'notes' => ['alias' => true, 'alias_for' => 'notes_contains', 'needs_context' => true],
|
||||
'notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_end' => ['alias' => true, 'alias_for' => 'notes_ends', 'needs_context' => true],
|
||||
'notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'notes_start' => ['alias' => true, 'alias_for' => 'notes_starts', 'needs_context' => true],
|
||||
'source_account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_is' => ['alias' => true, 'alias_for' => 'source_account_is', 'needs_context' => true],
|
||||
'source_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'source' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'from' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'from_account_contains' => ['alias' => true, 'alias_for' => 'source_account_contains', 'needs_context' => true],
|
||||
'source_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_ends' => ['alias' => true, 'alias_for' => 'source_account_ends', 'needs_context' => true],
|
||||
'source_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_starts' => ['alias' => true, 'alias_for' => 'source_account_starts', 'needs_context' => true],
|
||||
'source_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_is' => ['alias' => true, 'alias_for' => 'source_account_nr_is', 'needs_context' => true],
|
||||
'source_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_contains' => ['alias' => true, 'alias_for' => 'source_account_nr_contains', 'needs_context' => true],
|
||||
'source_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_ends' => ['alias' => true, 'alias_for' => 'source_account_nr_ends', 'needs_context' => true],
|
||||
'source_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'from_account_nr_starts' => ['alias' => true, 'alias_for' => 'source_account_nr_starts', 'needs_context' => true],
|
||||
'destination_account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_is' => ['alias' => true, 'alias_for' => 'destination_account_is', 'needs_context' => true],
|
||||
'destination_account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'destination' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'to' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'to_account_contains' => ['alias' => true, 'alias_for' => 'destination_account_contains', 'needs_context' => true],
|
||||
'destination_account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_ends' => ['alias' => true, 'alias_for' => 'destination_account_ends', 'needs_context' => true],
|
||||
'destination_account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_starts' => ['alias' => true, 'alias_for' => 'destination_account_starts', 'needs_context' => true],
|
||||
'destination_account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_is' => ['alias' => true, 'alias_for' => 'destination_account_nr_is', 'needs_context' => true],
|
||||
'destination_account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_contains' => ['alias' => true, 'alias_for' => 'destination_account_nr_contains', 'needs_context' => true],
|
||||
'destination_account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_ends' => ['alias' => true, 'alias_for' => 'destination_account_nr_ends', 'needs_context' => true],
|
||||
'destination_account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'to_account_nr_starts' => ['alias' => true, 'alias_for' => 'destination_account_nr_starts', 'needs_context' => true],
|
||||
'account_is' => ['alias' => false, 'needs_context' => true],
|
||||
'account_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'account_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'account_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_is' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'account_nr_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'category_is' => ['alias' => false, 'needs_context' => true],
|
||||
'category_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'category' => ['alias' => true, 'alias_for' => 'category_contains', 'needs_context' => true],
|
||||
'category_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'category_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_is' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'budget' => ['alias' => true, 'alias_for' => 'budget_contains', 'needs_context' => true],
|
||||
'budget_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'budget_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_is' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'bill' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'bill_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'bill_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'subscription_is' => ['alias' => true, 'alias_for' => 'bill_is', 'needs_context' => true],
|
||||
'subscription_contains' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'subscription' => ['alias' => true, 'alias_for' => 'bill_contains', 'needs_context' => true],
|
||||
'subscription_ends' => ['alias' => true, 'alias_for' => 'bill_ends', 'needs_context' => true],
|
||||
'subscription_starts' => ['alias' => true, 'alias_for' => 'bill_starts', 'needs_context' => true],
|
||||
'external_id_is' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id' => ['alias' => true, 'alias_for' => 'external_id_contains', 'needs_context' => true],
|
||||
'external_id_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'external_id_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_is' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference' => ['alias' => true, 'alias_for' => 'internal_reference_contains', 'needs_context' => true],
|
||||
'internal_reference_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'internal_reference_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_is' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url' => ['alias' => true, 'alias_for' => 'external_url_contains', 'needs_context' => true],
|
||||
'external_url_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'external_url_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'has_attachments' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_category' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_budget' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_bill' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_any_bill'],
|
||||
'has_any_tag' => ['alias' => false, 'needs_context' => false],
|
||||
'any_notes' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||
'has_notes' => ['alias' => true, 'alias_for' => 'any_notes', 'needs_context' => false],
|
||||
'any_external_url' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_external_url' => ['alias' => true, 'alias_for' => 'any_external_url', 'needs_context' => false],
|
||||
'has_no_attachments' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_category' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_budget' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_bill' => ['alias' => false, 'needs_context' => false],
|
||||
'has_no_subscription' => ['alias' => true, 'needs_context' => false, 'alias_for' => 'has_no_bill'],
|
||||
'has_no_tag' => ['alias' => false, 'needs_context' => false],
|
||||
'no_notes' => ['alias' => false, 'needs_context' => false],
|
||||
'no_external_url' => ['alias' => false, 'needs_context' => false],
|
||||
'source_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'destination_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'account_is_cash' => ['alias' => false, 'needs_context' => false],
|
||||
'currency_is' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_currency_is' => ['alias' => false, 'needs_context' => true],
|
||||
'id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'journal_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'recurrence_id' => ['alias' => false, 'trigger_class' => '', 'needs_context' => true],
|
||||
'date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'date' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'date_is' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'on' => ['alias' => true, 'alias_for' => 'date_on', 'needs_context' => true],
|
||||
'date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'before' => ['alias' => true, 'alias_for' => 'date_before', 'needs_context' => true],
|
||||
'date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'after' => ['alias' => true, 'alias_for' => 'date_after', 'needs_context' => true],
|
||||
'interest_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'interest_date' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||
'interest_date_is' => ['alias' => true, 'alias_for' => 'interest_date_on', 'needs_context' => true],
|
||||
'interest_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'interest_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||
'book_date_is' => ['alias' => true, 'alias_for' => 'book_date_on', 'needs_context' => true],
|
||||
'book_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'book_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||
'process_date_is' => ['alias' => true, 'alias_for' => 'process_date_on', 'needs_context' => true],
|
||||
'process_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'process_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||
'due_date_is' => ['alias' => true, 'alias_for' => 'due_date_on', 'needs_context' => true],
|
||||
'due_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'due_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||
'payment_date_is' => ['alias' => true, 'alias_for' => 'payment_date_on', 'needs_context' => true],
|
||||
'payment_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'payment_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date_on' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||
'invoice_date_is' => ['alias' => true, 'alias_for' => 'invoice_date_on', 'needs_context' => true],
|
||||
'invoice_date_before' => ['alias' => false, 'needs_context' => true],
|
||||
'invoice_date_after' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at_on' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_at_is' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_at_before' => ['alias' => false, 'needs_context' => true],
|
||||
'created_at_after' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at_on' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_at_is' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_at_before' => ['alias' => false, 'needs_context' => true],
|
||||
'updated_at_after' => ['alias' => false, 'needs_context' => true],
|
||||
'created_on_on' => ['alias' => true, 'alias_for' => 'created_at_on', 'needs_context' => true],
|
||||
'created_on' => ['alias' => true, 'alias_for' => 'created_at', 'needs_context' => true],
|
||||
'created_on_before' => ['alias' => true, 'alias_for' => 'created_at_before', 'needs_context' => true],
|
||||
'created_on_after' => ['alias' => true, 'alias_for' => 'created_at_after', 'needs_context' => true],
|
||||
'updated_on_on' => ['alias' => true, 'alias_for' => 'updated_at_on', 'needs_context' => true],
|
||||
'updated_on' => ['alias' => true, 'alias_for' => 'updated_at', 'needs_context' => true],
|
||||
'updated_on_before' => ['alias' => true, 'alias_for' => 'updated_at_before', 'needs_context' => true],
|
||||
'updated_on_after' => ['alias' => true, 'alias_for' => 'updated_at_after', 'needs_context' => true],
|
||||
'amount_is' => ['alias' => false, 'needs_context' => true],
|
||||
'amount' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||
'amount_exactly' => ['alias' => true, 'alias_for' => 'amount_is', 'needs_context' => true],
|
||||
'amount_less' => ['alias' => false, 'needs_context' => true],
|
||||
'amount_max' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||
'less' => ['alias' => true, 'alias_for' => 'amount_less', 'needs_context' => true],
|
||||
'amount_more' => ['alias' => false, 'needs_context' => true],
|
||||
'amount_min' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||
'more' => ['alias' => true, 'alias_for' => 'amount_more', 'needs_context' => true],
|
||||
'foreign_amount_is' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount' => ['alias' => true, 'alias_for' => 'foreign_amount_is', 'needs_context' => true],
|
||||
'foreign_amount_less' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount_max' => ['alias' => true, 'alias_for' => 'foreign_amount_less', 'needs_context' => true],
|
||||
'foreign_amount_more' => ['alias' => false, 'needs_context' => true],
|
||||
'foreign_amount_min' => ['alias' => true, 'alias_for' => 'foreign_amount_more', 'needs_context' => true],
|
||||
'attachment_name_is' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_is' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_name' => ['alias' => true, 'alias_for' => 'attachment_name_is', 'needs_context' => true],
|
||||
'attachment_name_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_name_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_name_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes' => ['alias' => true, 'alias_for' => 'attachment_notes_are', 'needs_context' => true],
|
||||
'attachment_notes_are' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_contains' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_contain' => ['alias' => true, 'alias_for' => 'attachment_notes_contains', 'needs_context' => true],
|
||||
'attachment_notes_starts' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_start' => ['alias' => true, 'alias_for' => 'attachment_notes_starts', 'needs_context' => true],
|
||||
'attachment_notes_ends' => ['alias' => false, 'needs_context' => true],
|
||||
'attachment_notes_end' => ['alias' => true, 'alias_for' => 'attachment_notes_ends', 'needs_context' => true],
|
||||
'exists' => ['alias' => false, 'needs_context' => false],
|
||||
'sepa_ct_is' => ['alias' => false, 'needs_context' => true],
|
||||
'no_external_id' => ['alias' => false, 'needs_context' => false],
|
||||
'any_external_id' => ['alias' => false, 'needs_context' => false],
|
||||
'has_any_external_id' => ['alias' => true, 'alias_for' => 'any_external_id', 'needs_context' => false],
|
||||
|
||||
// based on source or destination balance. Very heavy search.
|
||||
'source_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||
'source_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_gte' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_gt' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_lte' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_lt' => ['alias' => false, 'needs_context' => true],
|
||||
'destination_balance_is' => ['alias' => false, 'needs_context' => true],
|
||||
],
|
||||
// Which query parser to use - 'new' or 'legacy'
|
||||
'query_parser' => env('QUERY_PARSER_IMPLEMENTATION', 'legacy'),
|
||||
'query_parser' => env('QUERY_PARSER_IMPLEMENTATION', 'legacy'),
|
||||
];
|
||||
|
@@ -333,6 +333,7 @@ return [
|
||||
'languages' => [
|
||||
// currently enabled languages
|
||||
'af_ZA',
|
||||
'ar_SA',
|
||||
'bg_BG',
|
||||
'cs_CZ',
|
||||
'da_DK',
|
||||
|
@@ -67,6 +67,7 @@ class TransactionCurrencySeeder extends Seeder
|
||||
// asian currencies
|
||||
$currencies[] = ['code' => 'JPY', 'name' => 'Japanese yen', 'symbol' => '¥', 'decimal_places' => 0];
|
||||
$currencies[] = ['code' => 'CNY', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
|
||||
$currencies[] = ['code' => 'KRW', 'name' => 'South Korean won','symbol' => '₩', 'decimal_places' => 2,];
|
||||
// $currencies[] = ['code' => 'RMB', 'name' => 'Chinese yuan', 'symbol' => '¥', 'decimal_places' => 2];
|
||||
$currencies[] = ['code' => 'RUB', 'name' => 'Russian ruble', 'symbol' => '₽', 'decimal_places' => 2];
|
||||
$currencies[] = ['code' => 'INR', 'name' => 'Indian rupee', 'symbol' => '₹', 'decimal_places' => 2];
|
||||
|
58
package-lock.json
generated
58
package-lock.json
generated
@@ -3148,13 +3148,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "24.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.1.0.tgz",
|
||||
"integrity": "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==",
|
||||
"version": "24.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz",
|
||||
"integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~7.8.0"
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-forge": {
|
||||
@@ -4930,9 +4930,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/core-js-compat": {
|
||||
"version": "3.44.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.44.0.tgz",
|
||||
"integrity": "sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==",
|
||||
"version": "3.45.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz",
|
||||
"integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -5700,9 +5700,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.194",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz",
|
||||
"integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==",
|
||||
"version": "1.5.198",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.198.tgz",
|
||||
"integrity": "sha512-G5COfnp3w+ydVu80yprgWSfmfQaYRh9DOxfhAxstLyetKaLyl55QrNjx8C38Pc/C+RaDmb1M0Lk8wPEMQ+bGgQ==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -5757,9 +5757,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.18.2",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz",
|
||||
"integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==",
|
||||
"version": "5.18.3",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
|
||||
"integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -7838,9 +7838,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/launch-editor": {
|
||||
"version": "2.11.0",
|
||||
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.0.tgz",
|
||||
"integrity": "sha512-R/PIF14L6e2eHkhvQPu7jDRCr0msfCYCxbYiLgkkAGi0dVPWuM+RrsPu0a5dpuNe0KWGL3jpAkOlv53xGfPheQ==",
|
||||
"version": "2.11.1",
|
||||
"resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz",
|
||||
"integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -10214,9 +10214,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/sass": {
|
||||
"version": "1.89.2",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.89.2.tgz",
|
||||
"integrity": "sha512-xCmtksBKd/jdJ9Bt9p7nPKiuqrlBMBuuGkQlkhZjjQk3Ty48lv93k5Dq6OPkKt4XwxDJ7tvlfrTa1MPA9bf+QA==",
|
||||
"version": "1.90.0",
|
||||
"resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz",
|
||||
"integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -11327,9 +11327,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "7.8.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
|
||||
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
|
||||
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
@@ -11524,9 +11524,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.0.6.tgz",
|
||||
"integrity": "sha512-MHFiOENNBd+Bd9uvc8GEsIzdkn1JxMmEeYX35tI3fv0sJBUTfW5tQsoaOwuY4KhBI09A3dUJ/DXf2yxPVPUceg==",
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-7.1.0.tgz",
|
||||
"integrity": "sha512-3jdAy3NhBJYsa/lCFcnRfbK4kNkO/bhijFCnv5ByUQk/eekYagoV2yQSISUrhpV+5JiY5hmwOh7jNnQ68dFMuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -11534,7 +11534,7 @@
|
||||
"fdir": "^6.4.6",
|
||||
"picomatch": "^4.0.3",
|
||||
"postcss": "^8.5.6",
|
||||
"rollup": "^4.40.0",
|
||||
"rollup": "^4.43.0",
|
||||
"tinyglobby": "^0.2.14"
|
||||
},
|
||||
"bin": {
|
||||
@@ -12459,9 +12459,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz",
|
||||
"integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==",
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
|
@@ -364,6 +364,8 @@ function updateTriggerInput(selectList) {
|
||||
createAutoComplete(inputResult, 'api/v1/autocomplete/transactions');
|
||||
break;
|
||||
case 'has_no_category':
|
||||
case 'no_external_id':
|
||||
case 'any_external_id':
|
||||
case 'has_any_category':
|
||||
case 'has_no_budget':
|
||||
case 'has_any_budget':
|
||||
|
71
public/v1/js/lib/moment/af_ZA.js
Normal file
71
public/v1/js/lib/moment/af_ZA.js
Normal file
@@ -0,0 +1,71 @@
|
||||
//! moment.js locale configuration
|
||||
//! locale : Afrikaans [af]
|
||||
//! author : Werner Mollentze : https://github.com/wernerm
|
||||
|
||||
import moment from '../moment';
|
||||
|
||||
export default moment.defineLocale('af', {
|
||||
months: 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort: 'Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'),
|
||||
weekdays: 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split(
|
||||
'_'
|
||||
),
|
||||
weekdaysShort: 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'),
|
||||
weekdaysMin: 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'),
|
||||
meridiemParse: /vm|nm/i,
|
||||
isPM: function (input) {
|
||||
return /^nm$/i.test(input);
|
||||
},
|
||||
meridiem: function (hours, minutes, isLower) {
|
||||
if (hours < 12) {
|
||||
return isLower ? 'vm' : 'VM';
|
||||
} else {
|
||||
return isLower ? 'nm' : 'NM';
|
||||
}
|
||||
},
|
||||
longDateFormat: {
|
||||
LT: 'HH:mm',
|
||||
LTS: 'HH:mm:ss',
|
||||
L: 'DD/MM/YYYY',
|
||||
LL: 'D MMMM YYYY',
|
||||
LLL: 'D MMMM YYYY HH:mm',
|
||||
LLLL: 'dddd, D MMMM YYYY HH:mm',
|
||||
},
|
||||
calendar: {
|
||||
sameDay: '[Vandag om] LT',
|
||||
nextDay: '[Môre om] LT',
|
||||
nextWeek: 'dddd [om] LT',
|
||||
lastDay: '[Gister om] LT',
|
||||
lastWeek: '[Laas] dddd [om] LT',
|
||||
sameElse: 'L',
|
||||
},
|
||||
relativeTime: {
|
||||
future: 'oor %s',
|
||||
past: '%s gelede',
|
||||
s: "'n paar sekondes",
|
||||
ss: '%d sekondes',
|
||||
m: "'n minuut",
|
||||
mm: '%d minute',
|
||||
h: "'n uur",
|
||||
hh: '%d ure',
|
||||
d: "'n dag",
|
||||
dd: '%d dae',
|
||||
M: "'n maand",
|
||||
MM: '%d maande',
|
||||
y: "'n jaar",
|
||||
yy: '%d jaar',
|
||||
},
|
||||
dayOfMonthOrdinalParse: /\d{1,2}(ste|de)/,
|
||||
ordinal: function (number) {
|
||||
return (
|
||||
number +
|
||||
(number === 1 || number === 8 || number >= 20 ? 'ste' : 'de')
|
||||
); // Thanks to Joris Röling : https://github.com/jjupiter
|
||||
},
|
||||
week: {
|
||||
dow: 1, // Maandag is die eerste dag van die week.
|
||||
doy: 4, // Die week wat die 4de Januarie bevat is die eerste week van die jaar.
|
||||
},
|
||||
});
|
105
public/v1/js/lib/moment/ar_SA.js
Normal file
105
public/v1/js/lib/moment/ar_SA.js
Normal file
@@ -0,0 +1,105 @@
|
||||
//! moment.js locale configuration
|
||||
//! locale : Arabic (Saudi Arabia) [ar-sa]
|
||||
//! author : Suhail Alkowaileet : https://github.com/xsoh
|
||||
|
||||
import moment from '../moment';
|
||||
|
||||
var symbolMap = {
|
||||
1: '١',
|
||||
2: '٢',
|
||||
3: '٣',
|
||||
4: '٤',
|
||||
5: '٥',
|
||||
6: '٦',
|
||||
7: '٧',
|
||||
8: '٨',
|
||||
9: '٩',
|
||||
0: '٠',
|
||||
},
|
||||
numberMap = {
|
||||
'١': '1',
|
||||
'٢': '2',
|
||||
'٣': '3',
|
||||
'٤': '4',
|
||||
'٥': '5',
|
||||
'٦': '6',
|
||||
'٧': '7',
|
||||
'٨': '8',
|
||||
'٩': '9',
|
||||
'٠': '0',
|
||||
};
|
||||
|
||||
export default moment.defineLocale('ar-sa', {
|
||||
months: 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split(
|
||||
'_'
|
||||
),
|
||||
monthsShort:
|
||||
'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split(
|
||||
'_'
|
||||
),
|
||||
weekdays: 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'),
|
||||
weekdaysShort: 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'),
|
||||
weekdaysMin: 'ح_ن_ث_ر_خ_ج_س'.split('_'),
|
||||
weekdaysParseExact: true,
|
||||
longDateFormat: {
|
||||
LT: 'HH:mm',
|
||||
LTS: 'HH:mm:ss',
|
||||
L: 'DD/MM/YYYY',
|
||||
LL: 'D MMMM YYYY',
|
||||
LLL: 'D MMMM YYYY HH:mm',
|
||||
LLLL: 'dddd D MMMM YYYY HH:mm',
|
||||
},
|
||||
meridiemParse: /ص|م/,
|
||||
isPM: function (input) {
|
||||
return 'م' === input;
|
||||
},
|
||||
meridiem: function (hour, minute, isLower) {
|
||||
if (hour < 12) {
|
||||
return 'ص';
|
||||
} else {
|
||||
return 'م';
|
||||
}
|
||||
},
|
||||
calendar: {
|
||||
sameDay: '[اليوم على الساعة] LT',
|
||||
nextDay: '[غدا على الساعة] LT',
|
||||
nextWeek: 'dddd [على الساعة] LT',
|
||||
lastDay: '[أمس على الساعة] LT',
|
||||
lastWeek: 'dddd [على الساعة] LT',
|
||||
sameElse: 'L',
|
||||
},
|
||||
relativeTime: {
|
||||
future: 'في %s',
|
||||
past: 'منذ %s',
|
||||
s: 'ثوان',
|
||||
ss: '%d ثانية',
|
||||
m: 'دقيقة',
|
||||
mm: '%d دقائق',
|
||||
h: 'ساعة',
|
||||
hh: '%d ساعات',
|
||||
d: 'يوم',
|
||||
dd: '%d أيام',
|
||||
M: 'شهر',
|
||||
MM: '%d أشهر',
|
||||
y: 'سنة',
|
||||
yy: '%d سنوات',
|
||||
},
|
||||
preparse: function (string) {
|
||||
return string
|
||||
.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
|
||||
return numberMap[match];
|
||||
})
|
||||
.replace(/،/g, ',');
|
||||
},
|
||||
postformat: function (string) {
|
||||
return string
|
||||
.replace(/\d/g, function (match) {
|
||||
return symbolMap[match];
|
||||
})
|
||||
.replace(/,/g, '،');
|
||||
},
|
||||
week: {
|
||||
dow: 0, // Sunday is the first day of the week.
|
||||
doy: 6, // The week that contains Jan 6th is the first week of the year.
|
||||
},
|
||||
});
|
@@ -110,6 +110,8 @@
|
||||
"/public/v1/js/lib/jquery.autocomplete.min.js": "/public/v1/js/lib/jquery.autocomplete.min.js",
|
||||
"/public/v1/js/lib/jquery.color-2.1.2.min.js": "/public/v1/js/lib/jquery.color-2.1.2.min.js",
|
||||
"/public/v1/js/lib/modernizr-custom.js": "/public/v1/js/lib/modernizr-custom.js",
|
||||
"/public/v1/js/lib/moment/af_ZA.js": "/public/v1/js/lib/moment/af_ZA.js",
|
||||
"/public/v1/js/lib/moment/ar_SA.js": "/public/v1/js/lib/moment/ar_SA.js",
|
||||
"/public/v1/js/lib/moment/bg_BG.js": "/public/v1/js/lib/moment/bg_BG.js",
|
||||
"/public/v1/js/lib/moment/ca_ES.js": "/public/v1/js/lib/moment/ca_ES.js",
|
||||
"/public/v1/js/lib/moment/cs_CZ.js": "/public/v1/js/lib/moment/cs_CZ.js",
|
||||
|
@@ -24,6 +24,7 @@ module.exports = new vuei18n({
|
||||
fallbackLocale: 'en',
|
||||
messages: {
|
||||
'af': require('./locales/af.json'),
|
||||
'ar': require('./locales/ar.json'),
|
||||
'bg': require('./locales/bg.json'),
|
||||
'ca-es': require('./locales/ca.json'),
|
||||
'cs': require('./locales/cs.json'),
|
||||
|
188
resources/assets/v1/src/locales/ar.json
Normal file
188
resources/assets/v1/src/locales/ar.json
Normal file
@@ -0,0 +1,188 @@
|
||||
{
|
||||
"firefly": {
|
||||
"administrations_page_title": "\u0627\u0644\u0625\u062f\u0627\u0631\u0627\u062a \u0627\u0644\u0645\u0627\u0644\u064a\u0629",
|
||||
"administrations_index_menu": "\u0627\u0644\u0625\u062f\u0627\u0631\u0627\u062a \u0627\u0644\u0645\u0627\u0644\u064a\u0629",
|
||||
"expires_at": "\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0627\u0646\u062a\u0647\u0627\u0621",
|
||||
"temp_administrations_introduction": "\u0633\u064a\u062d\u0635\u0644 Firefly III \u0642\u0631\u064a\u0628\u0627\u064b \u0639\u0644\u0649 \u0625\u0645\u0643\u0627\u0646\u064a\u0629 \u0625\u062f\u0627\u0631\u0629 \u0639\u062f\u0629 \u0625\u062f\u0627\u0631\u0627\u062a \u0645\u0627\u0644\u064a\u0629. \u062d\u0627\u0644\u064a\u0627\u064b \u0644\u062f\u064a\u0643 \u0648\u0627\u062d\u062f\u0629 \u0641\u0642\u0637. \u064a\u0645\u0643\u0646\u0643 \u062a\u0639\u064a\u064a\u0646 \u0639\u0646\u0648\u0627\u0646 \u0647\u0630\u0647 \u0627\u0644\u0625\u062f\u0627\u0631\u0629 \u0648\u0639\u0645\u0644\u062a\u0647\u0627 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629. \u0647\u0630\u0627 \u064a\u0633\u062a\u0628\u062f\u0644 \u0627\u0644\u0625\u0639\u062f\u0627\u062f \u0627\u0644\u0633\u0627\u0628\u0642 \u062d\u064a\u062b \u0643\u0646\u062a \u062a\u0639\u064a\u0646 \"\u0627\u0644\u0639\u0645\u0644\u0629 \u0627\u0644\u0627\u0641\u062a\u0631\u0627\u0636\u064a\u0629\". \u0647\u0630\u0627 \u0627\u0644\u0625\u0639\u062f\u0627\u062f \u0623\u0635\u0628\u062d \u0627\u0644\u0622\u0646 \u0645\u0631\u062a\u0628\u0637\u0627\u064b \u0628\u0627\u0644\u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0627\u0644\u064a\u0629 \u0648\u064a\u0645\u0643\u0646 \u0623\u0646 \u064a\u062e\u062a\u0644\u0641 \u0644\u0643\u0644 \u0625\u062f\u0627\u0631\u0629.",
|
||||
"administration_currency_form_help": "\u0642\u062f \u064a\u0633\u062a\u063a\u0631\u0642 \u062a\u062d\u0645\u064a\u0644 \u0627\u0644\u0635\u0641\u062d\u0629 \u0648\u0642\u062a\u0627\u064b \u0637\u0648\u064a\u0644\u0627\u064b \u0625\u0630\u0627 \u0642\u0645\u062a \u0628\u062a\u063a\u064a\u064a\u0631 \u0627\u0644\u0639\u0645\u0644\u0629 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629 \u0644\u0623\u0646 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0627\u062a \u0642\u062f \u062a\u062d\u062a\u0627\u062c \u0625\u0644\u0649 \u0627\u0644\u062a\u062d\u0648\u064a\u0644 \u0625\u0644\u0649 \u0639\u0645\u0644\u062a\u0643 (\u0627\u0644\u062c\u062f\u064a\u062f\u0629) \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629.",
|
||||
"administrations_page_edit_sub_title_js": "\u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u0625\u062f\u0627\u0631\u0629 \u0627\u0644\u0645\u0627\u0644\u064a\u0629 \"{title}\"",
|
||||
"table": "\u062c\u062f\u0648\u0644",
|
||||
"welcome_back": "\u0623\u0647\u0644\u0627\u064b \u0648\u0633\u0647\u0644\u0627\u064b!",
|
||||
"flash_error": "\u062e\u0637\u0623!",
|
||||
"flash_warning": "\u062a\u062d\u0630\u064a\u0631!",
|
||||
"flash_success": "\u0646\u062c\u062d!",
|
||||
"close": "\u0625\u063a\u0644\u0627\u0642",
|
||||
"select_dest_account": "\u064a\u0631\u062c\u0649 \u0627\u062e\u062a\u064a\u0627\u0631 \u0623\u0648 \u0643\u062a\u0627\u0628\u0629 \u0627\u0633\u0645 \u062d\u0633\u0627\u0628 \u0648\u062c\u0647\u0629 \u0635\u0627\u0644\u062d",
|
||||
"select_source_account": "\u064a\u0631\u062c\u0649 \u0627\u062e\u062a\u064a\u0627\u0631 \u0623\u0648 \u0643\u062a\u0627\u0628\u0629 \u0627\u0633\u0645 \u062d\u0633\u0627\u0628 \u0645\u0635\u062f\u0631 \u0635\u0627\u0644\u062d",
|
||||
"split_transaction_title": "\u0648\u0635\u0641 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u0627\u0644\u0645\u0646\u0642\u0633\u0645\u0629",
|
||||
"errors_submission": "\u0643\u0627\u0646 \u0647\u0646\u0627\u0643 \u062e\u0637\u0623 \u0645\u0627 \u0641\u064a \u062a\u0642\u062f\u064a\u0645\u0643. \u064a\u0631\u062c\u0649 \u0627\u0644\u062a\u062d\u0642\u0642 \u0645\u0646 \u0627\u0644\u0623\u062e\u0637\u0627\u0621 \u0623\u062f\u0646\u0627\u0647.",
|
||||
"is_reconciled": "\u062a\u0645\u062a \u0627\u0644\u062a\u0633\u0648\u064a\u0629",
|
||||
"split": "\u062a\u0642\u0633\u064a\u0645",
|
||||
"single_split": "\u062a\u0642\u0633\u064a\u0645",
|
||||
"not_enough_currencies": "\u0639\u062f\u062f \u0627\u0644\u0639\u0645\u0644\u0627\u062a \u063a\u064a\u0631 \u0643\u0627\u0641\u064d",
|
||||
"not_enough_currencies_enabled": "\u0625\u0630\u0627 \u0643\u0627\u0646 \u0644\u062f\u064a\u0643 \u0639\u0645\u0644\u0629 \u0648\u0627\u062d\u062f\u0629 \u0641\u0642\u0637 \u0645\u0641\u0639\u0644\u0629\u060c \u0641\u0644\u0627 \u062f\u0627\u0639\u064a \u0644\u0625\u0636\u0627\u0641\u0629 \u0623\u0633\u0639\u0627\u0631 \u0635\u0631\u0641.",
|
||||
"transaction_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 #{ID} (\"{title}\")<\/a> \u062a\u0645 \u062d\u0641\u0638\u0647\u0627.",
|
||||
"webhook_stored_link": "<a href=\"webhooks\/show\/{ID}\">\u0648\u064a\u0628 \u0647\u0648\u0643 #{ID} (\"{title}\")<\/a> \u062a\u0645 \u062d\u0641\u0638\u0647.",
|
||||
"webhook_updated_link": "<a href=\"webhooks\/show\/{ID}\">\u0648\u064a\u0628 \u0647\u0648\u0643 #{ID}<\/a> (\"{title}\") \u062a\u0645 \u062a\u062d\u062f\u064a\u062b\u0647.",
|
||||
"transaction_updated_link": "<a href=\"transactions\/show\/{ID}\">\u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 #{ID}<\/a> (\"{title}\") \u062a\u0645 \u062a\u062d\u062f\u064a\u062b\u0647\u0627.",
|
||||
"transaction_new_stored_link": "<a href=\"transactions\/show\/{ID}\">\u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 #{ID}<\/a> \u062a\u0645 \u062d\u0641\u0638\u0647\u0627.",
|
||||
"transaction_journal_information": "\u0645\u0639\u0644\u0648\u0645\u0627\u062a \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"submission_options": "\u062e\u064a\u0627\u0631\u0627\u062a \u0627\u0644\u0625\u0631\u0633\u0627\u0644",
|
||||
"apply_rules_checkbox": "\u062a\u0637\u0628\u064a\u0642 \u0627\u0644\u0642\u0648\u0627\u0639\u062f",
|
||||
"fire_webhooks_checkbox": "\u062a\u0634\u063a\u064a\u0644 Webhooks",
|
||||
"no_budget_pointer": "\u064a\u0628\u062f\u0648 \u0623\u0646\u0647 \u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0645\u064a\u0632\u0627\u0646\u064a\u0627\u062a \u0628\u0639\u062f. \u064a\u062c\u0628 \u0623\u0646 \u062a\u0646\u0634\u0626 \u0628\u0639\u0636\u0647\u0627 \u0641\u064a <a href=\"budgets\">\u0635\u0641\u062d\u0629 \u0627\u0644\u0645\u064a\u0632\u0627\u0646\u064a\u0627\u062a<\/a>. \u0627\u0644\u0645\u064a\u0632\u0627\u0646\u064a\u0627\u062a \u064a\u0645\u0643\u0646 \u0623\u0646 \u062a\u0633\u0627\u0639\u062f\u0643 \u0641\u064a \u062a\u062a\u0628\u0639 \u0627\u0644\u0646\u0641\u0642\u0627\u062a.",
|
||||
"no_bill_pointer": "\u064a\u0628\u062f\u0648 \u0623\u0646\u0647 \u0644\u064a\u0633 \u0644\u062f\u064a\u0643 \u0627\u0634\u062a\u0631\u0627\u0643\u0627\u062a \u0628\u0639\u062f. \u064a\u062c\u0628 \u0623\u0646 \u062a\u0646\u0634\u0626 \u0628\u0639\u0636\u0647\u0627 \u0641\u064a <a href=\"subscriptions\">\u0635\u0641\u062d\u0629 \u0627\u0644\u0627\u0634\u062a\u0631\u0627\u0643\u0627\u062a<\/a>. \u0627\u0644\u0627\u0634\u062a\u0631\u0627\u0643\u0627\u062a \u064a\u0645\u0643\u0646 \u0623\u0646 \u062a\u0633\u0627\u0639\u062f\u0643 \u0641\u064a \u062a\u062a\u0628\u0639 \u0627\u0644\u0646\u0641\u0642\u0627\u062a.",
|
||||
"source_account": "\u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0635\u062f\u0631",
|
||||
"hidden_fields_preferences": "\u064a\u0645\u0643\u0646\u0643 \u062a\u0645\u0643\u064a\u0646 \u0627\u0644\u0645\u0632\u064a\u062f \u0645\u0646 \u062e\u064a\u0627\u0631\u0627\u062a \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0627\u062a \u0641\u064a <a href=\"preferences\">\u0627\u0644\u062a\u0641\u0636\u064a\u0644\u0627\u062a<\/a> \u0627\u0644\u062e\u0627\u0635\u0629 \u0628\u0643.",
|
||||
"destination_account": "\u062d\u0633\u0627\u0628 \u0627\u0644\u0648\u062c\u0647\u0629",
|
||||
"add_another_split": "\u0625\u0636\u0627\u0641\u0629 \u062a\u0642\u0633\u064a\u0645 \u0622\u062e\u0631",
|
||||
"submission": "\u0625\u0631\u0633\u0627\u0644",
|
||||
"stored_journal": "\u062a\u0645 \u0625\u0646\u0634\u0627\u0621 \u0645\u0639\u0627\u0645\u0644\u0629 \u062c\u062f\u064a\u062f\u0629 \":description\"",
|
||||
"create_another": "\u0628\u0639\u062f \u0627\u0644\u062a\u062e\u0632\u064a\u0646\u060c \u0639\u062f \u0625\u0644\u0649 \u0647\u0646\u0627 \u0644\u0625\u0646\u0634\u0627\u0621 \u0648\u0627\u062d\u062f\u0629 \u0623\u062e\u0631\u0649.",
|
||||
"reset_after": "\u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0627\u0644\u0646\u0645\u0648\u0630\u062c \u0628\u0639\u062f \u0627\u0644\u0625\u0631\u0633\u0627\u0644",
|
||||
"submit": "\u0625\u0631\u0633\u0627\u0644",
|
||||
"amount": "\u0627\u0644\u0645\u0628\u0644\u063a",
|
||||
"date": "\u0627\u0644\u062a\u0627\u0631\u064a\u062e",
|
||||
"is_reconciled_fields_dropped": "\u0644\u0623\u0646 \u0647\u0630\u0647 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u062a\u0645\u062a \u062a\u0633\u0648\u064a\u062a\u0647\u0627\u060c \u0644\u0646 \u062a\u062a\u0645\u0643\u0646 \u0645\u0646 \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u062d\u0633\u0627\u0628\u0627\u062a \u0623\u0648 \u0627\u0644\u0645\u0628\u0627\u0644\u063a \u0625\u0644\u0627 \u0625\u0630\u0627 \u0623\u0632\u0644\u062a \u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u062a\u0633\u0648\u064a\u0629.",
|
||||
"tags": "\u0627\u0644\u0648\u0633\u0648\u0645",
|
||||
"no_budget": "(\u0644\u0627 \u062a\u0648\u062c\u062f \u0645\u064a\u0632\u0627\u0646\u064a\u0629)",
|
||||
"no_bill": "(\u0644\u0627 \u062a\u0648\u062c\u062f \u0627\u0634\u062a\u0631\u0627\u0643)",
|
||||
"category": "\u0641\u0626\u0629",
|
||||
"attachments": "\u0627\u0644\u0645\u0631\u0641\u0642\u0627\u062a",
|
||||
"notes": "\u0645\u0644\u0627\u062d\u0638\u0627\u062a",
|
||||
"external_url": "\u0631\u0627\u0628\u0637 \u062e\u0627\u0631\u062c\u064a",
|
||||
"update_transaction": "\u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"after_update_create_another": "\u0628\u0639\u062f \u0627\u0644\u062a\u062d\u062f\u064a\u062b\u060c \u0639\u062f \u0625\u0644\u0649 \u0647\u0646\u0627 \u0644\u0645\u062a\u0627\u0628\u0639\u0629 \u0627\u0644\u062a\u062d\u0631\u064a\u0631.",
|
||||
"store_as_new": "\u062a\u062e\u0632\u064a\u0646 \u0643\u0645\u0639\u0627\u0645\u0644\u0629 \u062c\u062f\u064a\u062f\u0629 \u0628\u062f\u0644\u0627\u064b \u0645\u0646 \u0627\u0644\u062a\u062d\u062f\u064a\u062b.",
|
||||
"split_title_help": "\u0625\u0630\u0627 \u0642\u0645\u062a \u0628\u0625\u0646\u0634\u0627\u0621 \u0645\u0639\u0627\u0645\u0644\u0629 \u0645\u0646\u0642\u0633\u0645\u0629\u060c \u064a\u062c\u0628 \u0623\u0646 \u064a\u0643\u0648\u0646 \u0647\u0646\u0627\u0643 \u0648\u0635\u0641 \u0639\u0627\u0644\u0645\u064a \u0644\u062c\u0645\u064a\u0639 \u0627\u0646\u0642\u0633\u0627\u0645\u0627\u062a \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629.",
|
||||
"none_in_select_list": "(\u0644\u0627 \u064a\u0648\u062c\u062f)",
|
||||
"no_piggy_bank": "(\u0644\u0627 \u062a\u0648\u062c\u062f \u062d\u0635\u0627\u0644\u0629)",
|
||||
"description": "\u0627\u0644\u0648\u0635\u0641",
|
||||
"split_transaction_title_help": "\u0625\u0630\u0627 \u0642\u0645\u062a \u0628\u0625\u0646\u0634\u0627\u0621 \u0645\u0639\u0627\u0645\u0644\u0629 \u0645\u0646\u0642\u0633\u0645\u0629\u060c \u064a\u062c\u0628 \u0623\u0646 \u064a\u0643\u0648\u0646 \u0647\u0646\u0627\u0643 \u0648\u0635\u0641 \u0639\u0627\u0644\u0645\u064a \u0644\u062c\u0645\u064a\u0639 \u0627\u0646\u0642\u0633\u0627\u0645\u0627\u062a \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629.",
|
||||
"destination_account_reconciliation": "\u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u062a\u0639\u062f\u064a\u0644 \u062d\u0633\u0627\u0628 \u0627\u0644\u0648\u062c\u0647\u0629 \u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u0627\u0644\u062a\u0633\u0648\u064a\u0629.",
|
||||
"source_account_reconciliation": "\u0644\u0627 \u064a\u0645\u0643\u0646\u0643 \u062a\u0639\u062f\u064a\u0644 \u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0635\u062f\u0631 \u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u0627\u0644\u062a\u0633\u0648\u064a\u0629.",
|
||||
"budget": "\u0645\u064a\u0632\u0627\u0646\u064a\u0629",
|
||||
"bill": "\u0627\u0634\u062a\u0631\u0627\u0643",
|
||||
"you_create_withdrawal": "\u0623\u0646\u062a \u062a\u0642\u0648\u0645 \u0628\u0625\u0646\u0634\u0627\u0621 \u0633\u062d\u0628.",
|
||||
"you_create_transfer": "\u0623\u0646\u062a \u062a\u0642\u0648\u0645 \u0628\u0625\u0646\u0634\u0627\u0621 \u062a\u062d\u0648\u064a\u0644.",
|
||||
"you_create_deposit": "\u0623\u0646\u062a \u062a\u0642\u0648\u0645 \u0628\u0625\u0646\u0634\u0627\u0621 \u0625\u064a\u062f\u0627\u0639.",
|
||||
"edit": "\u062a\u0639\u062f\u064a\u0644",
|
||||
"delete": "\u062d\u0630\u0641",
|
||||
"name": "\u0627\u0644\u0627\u0633\u0645",
|
||||
"profile_whoops": "\u0639\u0630\u0631\u0627\u064b!",
|
||||
"profile_something_wrong": "\u062d\u062f\u062b \u062e\u0637\u0623 \u0645\u0627!",
|
||||
"profile_try_again": "\u062d\u062f\u062b \u062e\u0637\u0623 \u0645\u0627. \u064a\u0631\u062c\u0649 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629 \u0645\u0631\u0629 \u0623\u062e\u0631\u0649.",
|
||||
"profile_oauth_clients": "\u0639\u0645\u0644\u0627\u0621 OAuth",
|
||||
"profile_oauth_no_clients": "\u0644\u0645 \u062a\u0642\u0645 \u0628\u0625\u0646\u0634\u0627\u0621 \u0623\u064a \u0639\u0645\u0644\u0627\u0621 OAuth.",
|
||||
"profile_oauth_clients_header": "\u0627\u0644\u0639\u0645\u0644\u0627\u0621",
|
||||
"profile_oauth_client_id": "\u0645\u0639\u0631\u0651\u0641 \u0627\u0644\u0639\u0645\u064a\u0644",
|
||||
"profile_oauth_client_name": "\u0627\u0644\u0627\u0633\u0645",
|
||||
"profile_oauth_client_secret": "\u0627\u0644\u0633\u0631",
|
||||
"profile_oauth_create_new_client": "\u0625\u0646\u0634\u0627\u0621 \u0639\u0645\u064a\u0644 \u062c\u062f\u064a\u062f",
|
||||
"profile_oauth_create_client": "\u0625\u0646\u0634\u0627\u0621 \u0639\u0645\u064a\u0644",
|
||||
"profile_oauth_edit_client": "\u062a\u0639\u062f\u064a\u0644 \u0627\u0644\u0639\u0645\u064a\u0644",
|
||||
"profile_oauth_name_help": "\u0634\u064a\u0621 \u0633\u064a\u062a\u0639\u0631\u0641 \u0639\u0644\u064a\u0647 \u0627\u0644\u0645\u0633\u062a\u062e\u062f\u0645\u0648\u0646 \u0648\u064a\u062b\u0642\u0648\u0646 \u0628\u0647.",
|
||||
"profile_oauth_redirect_url": "\u0631\u0627\u0628\u0637 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0648\u062c\u064a\u0647",
|
||||
"profile_oauth_clients_external_auth": "\u0625\u0630\u0627 \u0643\u0646\u062a \u062a\u0633\u062a\u062e\u062f\u0645 \u0645\u0648\u0641\u0631 \u0645\u0635\u0627\u062f\u0642\u0629 \u062e\u0627\u0631\u062c\u064a \u0645\u062b\u0644 Authelia\u060c \u0641\u0644\u0646 \u062a\u0639\u0645\u0644 \u0639\u0645\u0644\u0627\u0621 OAuth. \u064a\u0645\u0643\u0646\u0643 \u0641\u0642\u0637 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0631\u0645\u0648\u0632 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0634\u062e\u0635\u064a\u0629.",
|
||||
"profile_oauth_redirect_url_help": "\u0631\u0627\u0628\u0637 \u0625\u0639\u0627\u062f\u0629 \u0627\u0644\u062a\u0648\u062c\u064a\u0647 \u0644\u062a\u0637\u0628\u064a\u0642\u0643.",
|
||||
"profile_authorized_apps": "\u0627\u0644\u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0627\u0644\u0645\u0635\u0631\u062d \u0628\u0647\u0627",
|
||||
"profile_authorized_clients": "\u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0627\u0644\u0645\u0635\u0631\u062d \u0644\u0647\u0645",
|
||||
"profile_scopes": "\u0627\u0644\u0646\u0637\u0627\u0642\u0627\u062a",
|
||||
"profile_revoke": "\u0625\u0644\u063a\u0627\u0621",
|
||||
"profile_personal_access_tokens": "\u0631\u0645\u0648\u0632 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0634\u062e\u0635\u064a\u0629",
|
||||
"profile_personal_access_token": "\u0631\u0645\u0632 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0634\u062e\u0635\u064a",
|
||||
"profile_personal_access_token_explanation": "\u0647\u0630\u0627 \u0647\u0648 \u0631\u0645\u0632 \u0627\u0644\u0648\u0635\u0648\u0644 \u0627\u0644\u0634\u062e\u0635\u064a \u0627\u0644\u062c\u062f\u064a\u062f \u0627\u0644\u062e\u0627\u0635 \u0628\u0643. \u0647\u0630\u0647 \u0647\u064a \u0627\u0644\u0645\u0631\u0629 \u0627\u0644\u0648\u062d\u064a\u062f\u0629 \u0627\u0644\u062a\u064a \u0633\u064a\u0638\u0647\u0631 \u0641\u064a\u0647\u0627 \u0641\u0644\u0627 \u062a\u0641\u0642\u062f\u0647! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0622\u0646 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0647\u0630\u0627 \u0627\u0644\u0631\u0645\u0632 \u0644\u0625\u062c\u0631\u0627\u0621 \u0637\u0644\u0628\u0627\u062a API.",
|
||||
"profile_no_personal_access_token": "\u0644\u0645 \u062a\u0642\u0645 \u0628\u0625\u0646\u0634\u0627\u0621 \u0623\u064a \u0631\u0645\u0648\u0632 \u0648\u0635\u0648\u0644 \u0634\u062e\u0635\u064a\u0629.",
|
||||
"profile_create_new_token": "\u0625\u0646\u0634\u0627\u0621 \u0631\u0645\u0632 \u062c\u062f\u064a\u062f",
|
||||
"profile_create_token": "\u0625\u0646\u0634\u0627\u0621 \u0631\u0645\u0632",
|
||||
"profile_create": "\u0625\u0646\u0634\u0627\u0621",
|
||||
"profile_save_changes": "\u062d\u0641\u0638 \u0627\u0644\u062a\u063a\u064a\u064a\u0631\u0627\u062a",
|
||||
"default_group_title_name": "(\u063a\u064a\u0631 \u0645\u062c\u0645\u0639)",
|
||||
"piggy_bank": "\u062d\u0635\u0627\u0644\u0629",
|
||||
"profile_oauth_client_secret_title": "\u0633\u0631 \u0627\u0644\u0639\u0645\u064a\u0644",
|
||||
"profile_oauth_client_secret_expl": "\u0647\u0630\u0627 \u0647\u0648 \u0633\u0631 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u062c\u062f\u064a\u062f \u0627\u0644\u062e\u0627\u0635 \u0628\u0643. \u0647\u0630\u0647 \u0647\u064a \u0627\u0644\u0645\u0631\u0629 \u0627\u0644\u0648\u062d\u064a\u062f\u0629 \u0627\u0644\u062a\u064a \u0633\u064a\u0638\u0647\u0631 \u0641\u064a\u0647\u0627 \u0641\u0644\u0627 \u062a\u0641\u0642\u062f\u0647! \u064a\u0645\u0643\u0646\u0643 \u0627\u0644\u0622\u0646 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0647\u0630\u0627 \u0627\u0644\u0633\u0631 \u0644\u0625\u062c\u0631\u0627\u0621 \u0637\u0644\u0628\u0627\u062a API.",
|
||||
"profile_oauth_confidential": "\u0633\u0631\u064a",
|
||||
"profile_oauth_confidential_help": "\u064a\u062a\u0637\u0644\u0628 \u0645\u0646 \u0627\u0644\u0639\u0645\u064a\u0644 \u0627\u0644\u0645\u0635\u0627\u062f\u0642\u0629 \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0633\u0631. \u064a\u0645\u0643\u0646 \u0644\u0644\u0639\u0645\u0644\u0627\u0621 \u0627\u0644\u0633\u0631\u064a\u064a\u0646 \u0627\u0644\u0627\u062d\u062a\u0641\u0627\u0638 \u0628\u0628\u064a\u0627\u0646\u0627\u062a \u0627\u0644\u0627\u0639\u062a\u0645\u0627\u062f \u0628\u0637\u0631\u064a\u0642\u0629 \u0622\u0645\u0646\u0629 \u062f\u0648\u0646 \u0643\u0634\u0641\u0647\u0627 \u0644\u0623\u0637\u0631\u0627\u0641 \u063a\u064a\u0631 \u0645\u0635\u0631\u062d \u0644\u0647\u0627. \u0627\u0644\u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0627\u0644\u0639\u0627\u0645\u0629 \u0645\u062b\u0644 \u062a\u0637\u0628\u064a\u0642\u0627\u062a \u0633\u0637\u062d \u0627\u0644\u0645\u0643\u062a\u0628 \u0627\u0644\u0623\u0633\u0627\u0633\u064a\u0629 \u0623\u0648 \u062a\u0637\u0628\u064a\u0642\u0627\u062a SPA JavaScript \u063a\u064a\u0631 \u0642\u0627\u062f\u0631\u0629 \u0639\u0644\u0649 \u0627\u0644\u0627\u062d\u062a\u0641\u0627\u0638 \u0628\u0627\u0644\u0623\u0633\u0631\u0627\u0631 \u0628\u0623\u0645\u0627\u0646.",
|
||||
"multi_account_warning_unknown": "\u0627\u0639\u062a\u0645\u0627\u062f\u0627\u064b \u0639\u0644\u0649 \u0646\u0648\u0639 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u0627\u0644\u062a\u064a \u062a\u0646\u0634\u0626\u0647\u0627\u060c \u0642\u062f \u064a\u062a\u0645 \u062a\u062c\u0627\u0648\u0632 \u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0635\u062f\u0631 \u0648\/\u0623\u0648 \u0627\u0644\u0648\u062c\u0647\u0629 \u0641\u064a \u0627\u0644\u062a\u0642\u0633\u064a\u0645\u0627\u062a \u0627\u0644\u0644\u0627\u062d\u0642\u0629 \u0628\u0645\u0627 \u0647\u0648 \u0645\u062d\u062f\u062f \u0641\u064a \u0623\u0648\u0644 \u062a\u0642\u0633\u064a\u0645 \u0644\u0644\u0645\u0639\u0627\u0645\u0644\u0629.",
|
||||
"multi_account_warning_withdrawal": "\u0636\u0639 \u0641\u064a \u0627\u0639\u062a\u0628\u0627\u0631\u0643 \u0623\u0646 \u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0635\u062f\u0631 \u0641\u064a \u0627\u0644\u062a\u0642\u0633\u064a\u0645\u0627\u062a \u0627\u0644\u0644\u0627\u062d\u0642\u0629 \u0633\u064a\u062a\u0645 \u062a\u062c\u0627\u0648\u0632\u0647 \u0628\u0645\u0627 \u0647\u0648 \u0645\u062d\u062f\u062f \u0641\u064a \u0623\u0648\u0644 \u062a\u0642\u0633\u064a\u0645 \u0644\u0644\u0633\u062d\u0628.",
|
||||
"multi_account_warning_deposit": "\u0636\u0639 \u0641\u064a \u0627\u0639\u062a\u0628\u0627\u0631\u0643 \u0623\u0646 \u062d\u0633\u0627\u0628 \u0627\u0644\u0648\u062c\u0647\u0629 \u0641\u064a \u0627\u0644\u062a\u0642\u0633\u064a\u0645\u0627\u062a \u0627\u0644\u0644\u0627\u062d\u0642\u0629 \u0633\u064a\u062a\u0645 \u062a\u062c\u0627\u0648\u0632\u0647 \u0628\u0645\u0627 \u0647\u0648 \u0645\u062d\u062f\u062f \u0641\u064a \u0623\u0648\u0644 \u062a\u0642\u0633\u064a\u0645 \u0644\u0644\u0625\u064a\u062f\u0627\u0639.",
|
||||
"multi_account_warning_transfer": "\u0636\u0639 \u0641\u064a \u0627\u0639\u062a\u0628\u0627\u0631\u0643 \u0623\u0646 \u062d\u0633\u0627\u0628 \u0627\u0644\u0645\u0635\u062f\u0631 + \u0627\u0644\u0648\u062c\u0647\u0629 \u0641\u064a \u0627\u0644\u062a\u0642\u0633\u064a\u0645\u0627\u062a \u0627\u0644\u0644\u0627\u062d\u0642\u0629 \u0633\u064a\u062a\u0645 \u062a\u062c\u0627\u0648\u0632\u0647\u0645\u0627 \u0628\u0645\u0627 \u0647\u0648 \u0645\u062d\u062f\u062f \u0641\u064a \u0623\u0648\u0644 \u062a\u0642\u0633\u064a\u0645 \u0644\u0644\u062a\u062d\u0648\u064a\u0644.",
|
||||
"webhook_trigger_STORE_TRANSACTION": "\u0628\u0639\u062f \u0625\u0646\u0634\u0627\u0621 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"webhook_trigger_UPDATE_TRANSACTION": "\u0628\u0639\u062f \u062a\u062d\u062f\u064a\u062b \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"webhook_trigger_DESTROY_TRANSACTION": "\u0628\u0639\u062f \u062d\u0630\u0641 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"webhook_response_TRANSACTIONS": "\u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629",
|
||||
"webhook_response_ACCOUNTS": "\u062a\u0641\u0627\u0635\u064a\u0644 \u0627\u0644\u062d\u0633\u0627\u0628",
|
||||
"webhook_response_none_NONE": "\u0644\u0627 \u062a\u0648\u062c\u062f \u062a\u0641\u0627\u0635\u064a\u0644",
|
||||
"webhook_delivery_JSON": "JSON",
|
||||
"actions": "\u0627\u0644\u0625\u062c\u0631\u0627\u0621\u0627\u062a",
|
||||
"meta_data": "\u0628\u064a\u0627\u0646\u0627\u062a \u0648\u0635\u0641\u064a\u0629",
|
||||
"webhook_messages": "\u0631\u0633\u0627\u0644\u0629 \u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"inactive": "\u063a\u064a\u0631 \u0646\u0634\u0637",
|
||||
"no_webhook_messages": "\u0644\u0627 \u062a\u0648\u062c\u062f \u0631\u0633\u0627\u0626\u0644 \u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"inspect": "\u062a\u0641\u0642\u062f",
|
||||
"create_new_webhook": "\u0625\u0646\u0634\u0627\u0621 \u0648\u064a\u0628 \u0647\u0648\u0643 \u062c\u062f\u064a\u062f",
|
||||
"webhooks": "\u0648\u064a\u0628 \u0647\u0648\u0643\u0633",
|
||||
"webhook_trigger_form_help": "\u062d\u062f\u062f \u0627\u0644\u062d\u062f\u062b \u0627\u0644\u0630\u064a \u0633\u064a\u0634\u063a\u0644 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"webhook_response_form_help": "\u062d\u062f\u062f \u0645\u0627 \u064a\u062c\u0628 \u0623\u0646 \u064a\u0631\u0633\u0644\u0647 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643 \u0625\u0644\u0649 \u0627\u0644\u0631\u0627\u0628\u0637.",
|
||||
"webhook_delivery_form_help": "\u062d\u062f\u062f \u0623\u064a \u0635\u064a\u063a\u0629 \u064a\u062c\u0628 \u0623\u0646 \u064a\u0631\u0633\u0644 \u0628\u0647\u0627 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643 \u0627\u0644\u0628\u064a\u0627\u0646\u0627\u062a.",
|
||||
"webhook_active_form_help": "\u064a\u062c\u0628 \u0623\u0646 \u064a\u0643\u0648\u0646 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643 \u0646\u0634\u0637\u0627\u064b \u0648\u0625\u0644\u0627 \u0644\u0646 \u064a\u062a\u0645 \u0627\u0633\u062a\u062f\u0639\u0627\u0624\u0647.",
|
||||
"edit_webhook_js": "\u062a\u0639\u062f\u064a\u0644 \u0648\u064a\u0628 \u0647\u0648\u0643 \"{title}\"",
|
||||
"webhook_was_triggered": "\u062a\u0645 \u062a\u0634\u063a\u064a\u0644 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643 \u0639\u0644\u0649 \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629 \u0627\u0644\u0645\u062d\u062f\u062f\u0629. \u064a\u0631\u062c\u0649 \u0627\u0644\u0627\u0646\u062a\u0638\u0627\u0631 \u062d\u062a\u0649 \u062a\u0638\u0647\u0631 \u0627\u0644\u0646\u062a\u0627\u0626\u062c.",
|
||||
"view_message": "\u0639\u0631\u0636 \u0627\u0644\u0631\u0633\u0627\u0644\u0629",
|
||||
"view_attempts": "\u0639\u0631\u0636 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0627\u062a \u0627\u0644\u0641\u0627\u0634\u0644\u0629",
|
||||
"message_content_title": "\u0645\u062d\u062a\u0648\u0649 \u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"message_content_help": "\u0647\u0630\u0627 \u0647\u0648 \u0645\u062d\u062a\u0648\u0649 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0627\u0644\u062a\u064a \u062a\u0645 \u0625\u0631\u0633\u0627\u0644\u0647\u0627 (\u0623\u0648 \u0645\u062d\u0627\u0648\u0644\u0629 \u0625\u0631\u0633\u0627\u0644\u0647\u0627) \u0628\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0647\u0630\u0627 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643.",
|
||||
"attempt_content_title": "\u0645\u062d\u0627\u0648\u0644\u0627\u062a \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"attempt_content_help": "\u0647\u0630\u0647 \u0647\u064a \u062c\u0645\u064a\u0639 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0627\u062a \u063a\u064a\u0631 \u0627\u0644\u0646\u0627\u062c\u062d\u0629 \u0644\u0647\u0630\u0647 \u0627\u0644\u0631\u0633\u0627\u0644\u0629 \u0644\u0625\u0631\u0633\u0627\u0644\u0647\u0627 \u0625\u0644\u0649 \u0627\u0644\u0631\u0627\u0628\u0637 \u0627\u0644\u0645\u062d\u062f\u062f. \u0628\u0639\u062f \u0641\u062a\u0631\u0629\u060c \u0633\u064a\u062a\u0648\u0642\u0641 Firefly III \u0639\u0646 \u0627\u0644\u0645\u062d\u0627\u0648\u0644\u0629.",
|
||||
"no_attempts": "\u0644\u0627 \u062a\u0648\u062c\u062f \u0645\u062d\u0627\u0648\u0644\u0627\u062a \u063a\u064a\u0631 \u0646\u0627\u062c\u062d\u0629. \u0647\u0630\u0627 \u0623\u0645\u0631 \u062c\u064a\u062f!",
|
||||
"webhook_attempt_at": "\u0645\u062d\u0627\u0648\u0644\u0629 \u0641\u064a {moment}",
|
||||
"logs": "\u0627\u0644\u0633\u062c\u0644\u0627\u062a",
|
||||
"response": "\u0627\u0644\u0627\u0633\u062a\u062c\u0627\u0628\u0629",
|
||||
"visit_webhook_url": "\u0632\u064a\u0627\u0631\u0629 \u0631\u0627\u0628\u0637 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"reset_webhook_secret": "\u0625\u0639\u0627\u062f\u0629 \u062a\u0639\u064a\u064a\u0646 \u0633\u0631 \u0627\u0644\u0648\u064a\u0628 \u0647\u0648\u0643",
|
||||
"header_exchange_rates": "\u0623\u0633\u0639\u0627\u0631 \u0627\u0644\u0635\u0631\u0641",
|
||||
"exchange_rates_intro": "\u064a\u062f\u0639\u0645 Firefly III \u062a\u0646\u0632\u064a\u0644 \u0648\u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0623\u0633\u0639\u0627\u0631 \u0627\u0644\u0635\u0631\u0641. \u0627\u0642\u0631\u0623 \u0627\u0644\u0645\u0632\u064a\u062f \u0639\u0646 \u0630\u0644\u0643 \u0641\u064a <a href=\"https:\/\/docs.firefly-iii.org\/explanation\/financial-concepts\/exchange-rates\/\">\u0627\u0644\u0648\u062b\u0627\u0626\u0642<\/a>.",
|
||||
"exchange_rates_from_to": "\u0628\u064a\u0646 {from} \u0648{to} (\u0648\u0628\u0627\u0644\u0639\u0643\u0633)",
|
||||
"exchange_rates_intro_rates": "\u064a\u0633\u062a\u062e\u062f\u0645 Firefly III \u0623\u0633\u0639\u0627\u0631 \u0627\u0644\u0635\u0631\u0641 \u0627\u0644\u062a\u0627\u0644\u064a\u0629. \u064a\u062a\u0645 \u062d\u0633\u0627\u0628 \u0627\u0644\u0639\u0643\u0633 \u062a\u0644\u0642\u0627\u0626\u064a\u0627\u064b \u0625\u0630\u0627 \u0644\u0645 \u064a\u062a\u0645 \u062a\u0648\u0641\u064a\u0631\u0647. \u0625\u0630\u0627 \u0644\u0645 \u064a\u0648\u062c\u062f \u0633\u0639\u0631 \u0635\u0631\u0641 \u0644\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0645\u0639\u0627\u0645\u0644\u0629\u060c \u0633\u064a\u0639\u0648\u062f Firefly III \u0628\u0627\u0644\u0632\u0645\u0646 \u0644\u0644\u0639\u062b\u0648\u0631 \u0639\u0644\u0649 \u0648\u0627\u062d\u062f. \u0625\u0630\u0627 \u0644\u0645 \u064a\u0648\u062c\u062f \u0623\u064a \u0633\u0639\u0631\u060c \u0633\u064a\u062a\u0645 \u0627\u0633\u062a\u062e\u062f\u0627\u0645 \u0627\u0644\u0633\u0639\u0631 \"1\".",
|
||||
"header_exchange_rates_rates": "\u0623\u0633\u0639\u0627\u0631 \u0627\u0644\u0635\u0631\u0641",
|
||||
"header_exchange_rates_table": "\u062c\u062f\u0648\u0644 \u0623\u0633\u0639\u0627\u0631 \u0627\u0644\u0635\u0631\u0641",
|
||||
"help_rate_form": "\u0641\u064a \u0647\u0630\u0627 \u0627\u0644\u064a\u0648\u0645\u060c \u0643\u0645 {to} \u0633\u062a\u062d\u0635\u0644 \u0645\u0642\u0627\u0628\u0644 \u0648\u0627\u062d\u062f {from}\u061f",
|
||||
"add_new_rate": "\u0625\u0636\u0627\u0641\u0629 \u0633\u0639\u0631 \u0635\u0631\u0641 \u062c\u062f\u064a\u062f",
|
||||
"save_new_rate": "\u062d\u0641\u0638 \u0633\u0639\u0631 \u062c\u062f\u064a\u062f"
|
||||
},
|
||||
"form": {
|
||||
"url": "URL",
|
||||
"active": "Active",
|
||||
"interest_date": "Interest date",
|
||||
"administration_currency": "Primary currency",
|
||||
"title": "Title",
|
||||
"date": "Date",
|
||||
"book_date": "Book date",
|
||||
"process_date": "Processing date",
|
||||
"due_date": "Due date",
|
||||
"foreign_amount": "Foreign amount",
|
||||
"payment_date": "Payment date",
|
||||
"invoice_date": "Invoice date",
|
||||
"internal_reference": "Internal reference",
|
||||
"webhook_response": "Response",
|
||||
"webhook_trigger": "Trigger",
|
||||
"webhook_delivery": "Delivery",
|
||||
"from_currency_to_currency": "{from} → {to}",
|
||||
"to_currency_from_currency": "{to} → {from}",
|
||||
"rate": "Rate"
|
||||
},
|
||||
"list": {
|
||||
"title": "Title",
|
||||
"active": "Is active?",
|
||||
"primary_currency": "Primary currency",
|
||||
"trigger": "Trigger",
|
||||
"response": "Response",
|
||||
"delivery": "Delivery",
|
||||
"url": "URL",
|
||||
"secret": "Secret"
|
||||
},
|
||||
"config": {
|
||||
"html_language": "ar",
|
||||
"date_time_fns": "MMMM do, yyyy @ HH:mm:ss"
|
||||
}
|
||||
}
|
@@ -3,8 +3,8 @@
|
||||
"administrations_page_title": "Ustawienia finansowe",
|
||||
"administrations_index_menu": "Ustawienia finansowe",
|
||||
"expires_at": "Expires at",
|
||||
"temp_administrations_introduction": "Firefly III will soon get the ability to manage multiple financial administrations. Right now, you only have the one. You can set the title of this administration and its primary currency. This replaces the previous setting where you would set your \"default currency\". This setting is now tied to the financial administration and can be different per administration.",
|
||||
"administration_currency_form_help": "It may take a long time for the page to load if you change the primary currency because transaction may need to be converted to your (new) primary currency.",
|
||||
"temp_administrations_introduction": "Firefly III wkr\u00f3tce uzyska mo\u017cliwo\u015b\u0107 zarz\u0105dzania wieloma ustawieniami finansowymi. W tej chwili jest tylko jedno domy\u015blne ustawienie. Mo\u017cesz ustawi\u0107 jego tytu\u0142 i walut\u0119 g\u0142\u00f3wn\u0105. To zast\u0119puje poprzednie ustawienia, w kt\u00f3rym mo\u017cna by\u0142o ustawi\u0107 \"domy\u015bln\u0105 walut\u0119\". Jest ona obecnie powi\u0105zana z wybranym ustawieniem finansowym i mo\u017ce by\u0107 zmienione w tej zak\u0142adce.",
|
||||
"administration_currency_form_help": "Wczytywanie strony mo\u017ce zaj\u0105\u0107 du\u017co czasu, je\u015bli zmienisz walut\u0119 g\u0142\u00f3wn\u0105, poniewa\u017c transakcja mo\u017ce wymaga\u0107 przewalutowania na (now\u0105) walut\u0119 g\u0142\u00f3wn\u0105.",
|
||||
"administrations_page_edit_sub_title_js": "Edytuj ustawienia finansowe \"{title}\"",
|
||||
"table": "Tabela",
|
||||
"welcome_back": "Co jest grane?",
|
||||
@@ -102,7 +102,7 @@
|
||||
"profile_oauth_client_secret_title": "Sekret klienta",
|
||||
"profile_oauth_client_secret_expl": "Oto tw\u00f3j nowy sekret klienta. Jest to jedyny raz, gdy zostanie wy\u015bwietlony, wi\u0119c nie zgub go! Mo\u017cesz teraz u\u017cy\u0107 tego sekretu, aby wykona\u0107 zapytania API.",
|
||||
"profile_oauth_confidential": "Poufne",
|
||||
"profile_oauth_confidential_help": "Require the client to authenticate with a secret. Confidential clients can hold credentials in a secure way without exposing them to unauthorized parties. Public applications, such as primary desktop or JavaScript SPA applications, are unable to hold secrets securely.",
|
||||
"profile_oauth_confidential_help": "Wymagaj od klienta uwierzytelnienia za pomoc\u0105 sekretu. Poufni klienci mog\u0105 przechowywa\u0107 po\u015bwiadczenia w bezpieczny spos\u00f3b bez nara\u017cania ich na dost\u0119p przez nieuprawnione strony. Publiczne aplikacje, takie jak natywne aplikacje desktopowe lub JavaScript SPA, nie s\u0105 w stanie bezpiecznie trzyma\u0107 sekret\u00f3w.",
|
||||
"multi_account_warning_unknown": "W zale\u017cno\u015bci od rodzaju transakcji, kt\u00f3r\u0105 tworzysz, konto \u017ar\u00f3d\u0142owe i\/lub docelowe kolejnych podzia\u0142\u00f3w mo\u017ce zosta\u0107 ustawione na konto zdefiniowane w pierwszym podziale transakcji.",
|
||||
"multi_account_warning_withdrawal": "Pami\u0119taj, \u017ce konto \u017ar\u00f3d\u0142owe kolejnych podzia\u0142\u00f3w zostanie ustawione na konto zdefiniowane w pierwszym podziale wyp\u0142aty.",
|
||||
"multi_account_warning_deposit": "Pami\u0119taj, \u017ce konto docelowe kolejnych podzia\u0142\u00f3w zostanie ustawione na konto zdefiniowane w pierwszym podziale wp\u0142aty.",
|
||||
@@ -154,7 +154,7 @@
|
||||
"url": "URL",
|
||||
"active": "Aktywny",
|
||||
"interest_date": "Data odsetek",
|
||||
"administration_currency": "Waluta podstawowa",
|
||||
"administration_currency": "Waluta g\u0142\u00f3wna",
|
||||
"title": "Tytu\u0142",
|
||||
"date": "Data",
|
||||
"book_date": "Data ksi\u0119gowania",
|
||||
@@ -174,7 +174,7 @@
|
||||
"list": {
|
||||
"title": "Tytu\u0142",
|
||||
"active": "Jest aktywny?",
|
||||
"primary_currency": "Waluta podstawowa",
|
||||
"primary_currency": "Waluta g\u0142\u00f3wna",
|
||||
"trigger": "Wyzwalacz",
|
||||
"response": "Odpowied\u017a",
|
||||
"delivery": "Dor\u0119czenie",
|
||||
|
@@ -183,6 +183,6 @@
|
||||
},
|
||||
"config": {
|
||||
"html_language": "sv",
|
||||
"date_time_fns": "MMMM do, yyyy @ HH:mm:ss"
|
||||
"date_time_fns": "D MMMM YYYY @ HH:mm:ss"
|
||||
}
|
||||
}
|
@@ -952,12 +952,12 @@ return [
|
||||
'rule_trigger_journal_id_choice' => 'Transaction journal ID is..',
|
||||
'rule_trigger_journal_id' => 'Transaction journal ID is ":trigger_value"',
|
||||
'rule_trigger_any_external_url' => 'Transaction has an (any) external URL',
|
||||
'rule_trigger_any_external_url_choice' => 'Transaction has an (any) external URL',
|
||||
'rule_trigger_any_external_url_choice' => 'Has an (any) external URL',
|
||||
'rule_trigger_any_external_id' => 'Transaction has an (any) external ID',
|
||||
'rule_trigger_any_external_id_choice' => 'Transaction has an (any) external ID',
|
||||
'rule_trigger_no_external_url_choice' => 'Transaction has no external URL',
|
||||
'rule_trigger_any_external_id_choice' => 'Has an (any) external ID',
|
||||
'rule_trigger_no_external_url_choice' => 'Has no external URL',
|
||||
'rule_trigger_no_external_url' => 'Transaction has no external URL',
|
||||
'rule_trigger_no_external_id_choice' => 'Transaction has no external ID',
|
||||
'rule_trigger_no_external_id_choice' => 'Has no external ID',
|
||||
'rule_trigger_no_external_id' => 'Transaction has no external ID',
|
||||
'rule_trigger_id_choice' => 'Transaction ID is..',
|
||||
'rule_trigger_id' => 'Transaction ID is ":trigger_value"',
|
||||
@@ -1105,7 +1105,7 @@ return [
|
||||
'rule_trigger_not_tag_is' => 'Tag is not ":trigger_value"',
|
||||
'rule_trigger_not_tag_is_not' => 'Tag is ":trigger_value"',
|
||||
'rule_trigger_not_description_is' => 'Description is not ":trigger_value"',
|
||||
'rule_trigger_not_description_contains' => 'Description does not contain',
|
||||
'rule_trigger_not_description_contains' => 'Description does not contain ":trigger_value"',
|
||||
'rule_trigger_not_description_ends' => 'Description does not end with ":trigger_value"',
|
||||
'rule_trigger_not_description_starts' => 'Description does not start with ":trigger_value"',
|
||||
'rule_trigger_not_notes_is' => 'Notes are not ":trigger_value"',
|
||||
@@ -2793,6 +2793,7 @@ return [
|
||||
'recurring_monthly' => 'Every month on the :dayOfMonth(st/nd/rd/th) day',
|
||||
'recurring_monthly_skip' => 'Every :skip(st/nd/rd/th) month on the :dayOfMonth(st/nd/rd/th) day',
|
||||
'recurring_ndom' => 'Every month on the :dayOfMonth(st/nd/rd/th) :weekday',
|
||||
'recurring_ndom_skip' => 'Every :skip(st/nd/rd/th) month on the :dayOfMonth(st/nd/rd/th) :weekday',
|
||||
'recurring_yearly' => 'Every year on :date',
|
||||
'overview_for_recurrence' => 'Overview for recurring transaction ":title"',
|
||||
'warning_duplicates_repetitions' => 'In rare instances, dates appear twice in this list. This can happen when multiple repetitions collide. Firefly III will always generate one transaction per day.',
|
||||
|
1
resources/locales/ar_SA/locales.json
Normal file
1
resources/locales/ar_SA/locales.json
Normal file
File diff suppressed because one or more lines are too long
@@ -34,6 +34,7 @@
|
||||
{{ CurrencyForm.currencyList('auto_budget_currency_id', autoBudget.transaction_currency_id) }}
|
||||
{{ ExpandedForm.amountNoCurrency('auto_budget_amount', preFilled.auto_budget_amount) }}
|
||||
{{ ExpandedForm.select('auto_budget_period', autoBudgetPeriods, autoBudget.period) }}
|
||||
{{ ExpandedForm.textarea('notes',preFilled.notes,{helpText: trans('firefly.field_supports_markdown')}) }}
|
||||
{{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }}
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -346,9 +346,11 @@
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li><a href="{{ route('transactions.edit', [group.id]) }}"><span
|
||||
class="fa fa-fw fa-pencil"></span> {{ 'edit'|_ }}</a></li>
|
||||
{% if transaction.transaction_type_type != 'Reconciliation' and transaction.transaction_type_type != 'Opening balance' and transaction.transaction_type_type != 'Liability credit' %}
|
||||
{% if transaction.transaction_type_type != 'Opening balance' and transaction.transaction_type_type != 'Liability credit' %}
|
||||
<li><a href="{{ route('transactions.delete', [group.id]) }}"><span
|
||||
class="fa fa-fw fa-trash"></span> {{ 'delete'|_ }}</a></li>
|
||||
{% endif %}
|
||||
{% if transaction.transaction_type_type != 'Reconciliation' and transaction.transaction_type_type != 'Opening balance' and transaction.transaction_type_type != 'Liability credit' %}
|
||||
<li><a href="#" data-id="{{ group.id }}" class="clone-transaction"><span
|
||||
class="fa fa-copy fa-fw"></span> {{ 'clone'|_ }}</a></li>
|
||||
<li><a href="#" data-id="{{ group.id }}" class="clone-transaction-and-edit"><span
|
||||
|
73
resources/views/test/api-test.twig
Normal file
73
resources/views/test/api-test.twig
Normal file
@@ -0,0 +1,73 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Firefly III API test</title>
|
||||
<base href="{{ route('index', null, true) }}/">
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
Hi there,
|
||||
</p>
|
||||
<p>
|
||||
This page is created to do some basic API testing. It's not very exciting, is it?
|
||||
</p>
|
||||
<script src="v1/js/app.js?v={{ FF_VERSION }}" type="text/javascript" nonce="{{ JS_NONCE }}"></script>
|
||||
<script type="text/javascript" nonce="{{ JS_NONCE }}">
|
||||
$(function () {
|
||||
"use strict";
|
||||
console.log('Hello from the API test page!');
|
||||
$.ajax({
|
||||
url: 'api/v1/accounts?size=50&date=2025-08-06',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
$.ajax({
|
||||
url: 'api/v1/available-budgets?size=50&date=2025-08-06',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
$.ajax({
|
||||
url: 'api/v1/budgets?size=50&date=2025-08-06&start=2025-08-01&end=2025-08-31',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
$.ajax({
|
||||
url: 'api/v1/budgets/1/limits?size=50&date=2025-08-06&start=2025-08-01&end=2025-08-31',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
$.ajax({
|
||||
url: 'api/v1/categories?size=50&date=2025-08-06&start=2025-08-01&end=2025-08-31',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
$.ajax({
|
||||
url: 'api/v1/bills?size=50&date=2025-08-06&start=2025-08-01&end=2025-08-31',
|
||||
type: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -1,2 +0,0 @@
|
||||
list-length: {{ listLength }}
|
||||
user-email: {{ Auth.user.email }}
|
@@ -120,6 +120,7 @@ Route::group(
|
||||
Route::get('flush', ['uses' => 'DebugController@flush', 'as' => 'flush']);
|
||||
Route::get('routes', ['uses' => 'DebugController@routes', 'as' => 'routes']);
|
||||
Route::get('debug', 'DebugController@index')->name('debug');
|
||||
Route::get('debug/api-test', 'DebugController@apiTest')->name('api-test');
|
||||
}
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user