Refactor and split category repository.

This commit is contained in:
James Cole 2019-08-27 10:52:07 +02:00
parent 7eb9086a28
commit e5269bb312
12 changed files with 989 additions and 715 deletions

View File

@ -28,6 +28,8 @@ use Carbon\Carbon;
use FireflyIII\Api\V1\Controllers\Controller;
use FireflyIII\Api\V1\Requests\DateRequest;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use FireflyIII\User;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Collection;
@ -40,8 +42,15 @@ class CategoryController extends Controller
/** @var CategoryRepositoryInterface */
private $categoryRepository;
/** @var OperationsRepositoryInterface */
private $opsRepository;
/** @var NoCategoryRepositoryInterface */
private $noCatRepository;
/**
* AccountController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
@ -52,7 +61,11 @@ class CategoryController extends Controller
/** @var User $user */
$user = auth()->user();
$this->categoryRepository = app(CategoryRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
$this->noCatRepository = app(NoCategoryRepositoryInterface::class);
$this->categoryRepository->setUser($user);
$this->opsRepository->setUser($user);
$this->noCatRepository->setUser($user);
return $next($request);
}
@ -78,8 +91,8 @@ class CategoryController extends Controller
$tempData = [];
$spent = $this->categoryRepository->spentInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$earned = $this->categoryRepository->earnedInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$spent = $this->opsRepository->spentInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$earned = $this->opsRepository->earnedInPeriodPerCurrency(new Collection, new Collection, $start, $end);
$categories = [];
// earned:
@ -110,7 +123,7 @@ class CategoryController extends Controller
}
// earned with no category:
$noCategory = $this->categoryRepository->earnedInPeriodPcWoCategory(new Collection, $start, $end);
$noCategory = $this->noCatRepository->earnedInPeriodPcWoCategory(new Collection, $start, $end);
foreach ($noCategory as $currencyId => $income) {
$categoryName = (string)trans('firefly.no_category');
// find or make set for currency:
@ -164,7 +177,9 @@ class CategoryController extends Controller
}
// spent with no category
$noCategory = $this->categoryRepository->spentInPeriodPcWoCategory(new Collection, $start, $end);
$noCategory = $this->noCatRepository->spentInPeriodPcWoCategory(new Collection, $start, $end);
foreach ($noCategory as $currencyId => $expense) {
$categoryName = (string)trans('firefly.no_category');
// find or make set for currency:

View File

@ -31,6 +31,8 @@ use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionCurrency;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use FireflyIII\Repositories\Currency\CurrencyRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Chart\Category\WholePeriodChartGenerator;
@ -52,6 +54,7 @@ class CategoryController extends Controller
/**
* CategoryController constructor.
*
* @codeCoverageIgnore
*/
public function __construct()
@ -81,10 +84,10 @@ class CategoryController extends Controller
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('preferences')->get('viewRange', '1M')->data;
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
$start = $repository->firstUseDate($category) ?? $this->getDate();
$range = app('preferences')->get('viewRange', '1M')->data;
$start = app('navigation')->startOfPeriod($start, $range);
$end = $this->getDate();
Log::debug(sprintf('Full range is %s to %s', $start->format('Y-m-d'), $end->format('Y-m-d')));
@ -101,12 +104,9 @@ class CategoryController extends Controller
/**
* Shows the category chart on the front page.
*
* @param CategoryRepositoryInterface $repository
* @param AccountRepositoryInterface $accountRepository
*
* @return JsonResponse
*/
public function frontPage(CategoryRepositoryInterface $repository, AccountRepositoryInterface $accountRepository): JsonResponse
public function frontPage(): JsonResponse
{
$start = session('start', Carbon::now()->startOfMonth());
$end = session('end', Carbon::now()->endOfMonth());
@ -122,7 +122,19 @@ class CategoryController extends Controller
// currency repos:
/** @var CurrencyRepositoryInterface $currencyRepository */
$currencyRepository = app(CurrencyRepositoryInterface::class);
$currencies = [];
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
/** @var NoCategoryRepositoryInterface $noCatRepository */
$noCatRepository = app(NoCategoryRepositoryInterface::class);
$currencies = [];
$chartData = [];
@ -132,7 +144,7 @@ class CategoryController extends Controller
/** @var Category $category */
foreach ($categories as $category) {
$spentArray = $repository->spentInPeriodPerCurrency(new Collection([$category]), $accounts, $start, $end);
$spentArray = $opsRepository->spentInPeriodPerCurrency(new Collection([$category]), $accounts, $start, $end);
foreach ($spentArray as $categoryId => $spentInfo) {
foreach ($spentInfo['spent'] as $currencyId => $row) {
$spent = $row['spent'];
@ -150,7 +162,7 @@ class CategoryController extends Controller
}
// no category per currency:
$noCategory = $repository->spentInPeriodPcWoCategory(new Collection, $start, $end);
$noCategory = $noCatRepository->spentInPeriodPcWoCategory(new Collection, $start, $end);
foreach ($noCategory as $currencyId => $spent) {
$currencies[$currencyId] = $currencies[$currencyId] ?? $currencyRepository->findNull($currencyId);
$tempData[] = [
@ -212,13 +224,16 @@ class CategoryController extends Controller
$cache->addProperty($accounts->pluck('id')->toArray());
$cache->addProperty($category);
if ($cache->has()) {
return response()->json($cache->get());// @codeCoverageIgnore
return response()->json($cache->get());// @codeCoverageIgnore
}
$repository = app(CategoryRepositoryInterface::class);
$expenses = $repository->periodExpenses(new Collection([$category]), $accounts, $start, $end);
$income = $repository->periodIncome(new Collection([$category]), $accounts, $start, $end);
$periods = app('navigation')->listOfPeriods($start, $end);
$chartData = [
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
$expenses = $opsRepository->periodExpenses(new Collection([$category]), $accounts, $start, $end);
$income = $opsRepository->periodIncome(new Collection([$category]), $accounts, $start, $end);
$periods = app('navigation')->listOfPeriods($start, $end);
$chartData = [
[
'label' => (string)trans('firefly.spent'),
'entries' => [],
@ -256,8 +271,6 @@ class CategoryController extends Controller
}
/**
* Chart for period for transactions without a category.
*
@ -279,11 +292,14 @@ class CategoryController extends Controller
if ($cache->has()) {
return response()->json($cache->get()); // @codeCoverageIgnore
}
$repository = app(CategoryRepositoryInterface::class);
$expenses = $repository->periodExpensesNoCategory($accounts, $start, $end);
$income = $repository->periodIncomeNoCategory($accounts, $start, $end);
$periods = app('navigation')->listOfPeriods($start, $end);
$chartData = [
/** @var NoCategoryRepositoryInterface $noCatRepository */
$noCatRepository = app(NoCategoryRepositoryInterface::class);
$expenses = $noCatRepository->periodExpensesNoCategory($accounts, $start, $end);
$income = $noCatRepository->periodIncomeNoCategory($accounts, $start, $end);
$periods = app('navigation')->listOfPeriods($start, $end);
$chartData = [
[
'label' => (string)trans('firefly.spent'),
'entries' => [],

View File

@ -26,6 +26,8 @@ use Carbon\Carbon;
use FireflyIII\Http\Controllers\Controller;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use FireflyIII\Support\CacheProperties;
use FireflyIII\Support\Http\Controllers\BasicDataSupport;
use Illuminate\Support\Collection;
@ -60,9 +62,13 @@ class CategoryController extends Controller
}
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
$categories = $repository->getCategories();
$data = $repository->periodExpenses($categories, $accounts, $start, $end);
$data[0] = $repository->periodExpensesNoCategory($accounts, $start, $end);
$data = $opsRepository->periodExpenses($categories, $accounts, $start, $end);
$data[0] = $opsRepository->periodExpensesNoCategory($accounts, $start, $end);
$report = $this->filterPeriodReport($data);
// depending on the carbon format (a reliable way to determine the general date difference)
@ -114,9 +120,16 @@ class CategoryController extends Controller
}
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
/** @var NoCategoryRepositoryInterface $noCatRepository */
$noCatRepository = app(NoCategoryRepositoryInterface::class);
$categories = $repository->getCategories();
$data = $repository->periodIncome($categories, $accounts, $start, $end);
$data[0] = $repository->periodIncomeNoCategory($accounts, $start, $end);
$data = $opsRepository->periodIncome($categories, $accounts, $start, $end);
$data[0] = $noCatRepository->periodIncomeNoCategory($accounts, $start, $end);
$report = $this->filterPeriodReport($data);
// depending on the carbon format (a reliable way to determine the general date difference)
@ -169,6 +182,10 @@ class CategoryController extends Controller
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
$categories = $repository->getCategories();
$report = [
'categories' => [],
@ -176,8 +193,8 @@ class CategoryController extends Controller
];
/** @var Category $category */
foreach ($categories as $category) {
$spent = $repository->spentInPeriod($category, $accounts, $start, $end);
$earned = $repository->earnedInPeriod($category, $accounts, $start, $end);
$spent = $opsRepository->spentInPeriod($category, $accounts, $start, $end);
$earned = $opsRepository->earnedInPeriod($category, $accounts, $start, $end);
if (0 === count($spent) && 0 === count($earned)) {
continue;
}

View File

@ -24,6 +24,10 @@ namespace FireflyIII\Providers;
use FireflyIII\Repositories\Category\CategoryRepository;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\NoCategoryRepository;
use FireflyIII\Repositories\Category\NoCategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepository;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use Illuminate\Foundation\Application;
use Illuminate\Support\ServiceProvider;
@ -47,7 +51,7 @@ class CategoryServiceProvider extends ServiceProvider
{
$this->app->bind(
CategoryRepositoryInterface::class,
function (Application $app) {
static function (Application $app) {
/** @var CategoryRepository $repository */
$repository = app(CategoryRepository::class);
if ($app->auth->check()) {
@ -57,5 +61,31 @@ class CategoryServiceProvider extends ServiceProvider
return $repository;
}
);
$this->app->bind(
OperationsRepositoryInterface::class,
static function (Application $app) {
/** @var OperationsRepository $repository */
$repository = app(OperationsRepository::class);
if ($app->auth->check()) {
$repository->setUser(auth()->user());
}
return $repository;
}
);
$this->app->bind(
NoCategoryRepositoryInterface::class,
static function (Application $app) {
/** @var NoCategoryRepository $repository */
$repository = app(NoCategoryRepository::class);
if ($app->auth->check()) {
$repository->setUser(auth()->user());
}
return $repository;
}
);
}
}

View File

@ -24,22 +24,15 @@ namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Factory\CategoryFactory;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\Services\Internal\Destroy\CategoryDestroyService;
use FireflyIII\Services\Internal\Update\CategoryUpdateService;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
use Navigation;
/**
* Class CategoryRepository.
*
*
*
*
*/
class CategoryRepository implements CategoryRepositoryInterface
{
@ -73,175 +66,29 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
* Find a category.
*
* @return array
* @param string $name
*
* @return Category|null
*/
public function earnedInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array
public function findByName(string $name): ?Category
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$categories = $this->user->categories()->get(['categories.*']);
// TODO no longer need to loop like this
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setCategory($category);
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
// collect and group results:
$array = $collector->getExtractedJournals();
$return = [];
foreach ($array as $journal) {
$currencyCode = $journal['currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'earned' => '0',
];
foreach ($categories as $category) {
if ($category->name === $name) {
return $category;
}
// also extract foreign currency information:
if (null !== $journal['foreign_currency_id']) {
$currencyCode = $journal['foreign_currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['foreign_currency_id'],
'currency_code' => $journal['foreign_currency_code'],
'currency_name' => $journal['foreign_currency_name'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
'earned' => '0',
];
}
$return[$currencyCode]['earned'] = bcadd($return[$currencyCode]['earned'], app('steam')->positive($journal['foreign_amount']));
}
$return[$currencyCode]['earned'] = bcadd($return[$currencyCode]['earned'], app('steam')->positive($journal['amount']));
}
return $return;
return null;
}
/**
* A very cryptic method name that means:
*
* Get me the amount earned in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->withoutCategory();
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$journals = $collector->getExtractedJournals();
$return = [];
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'earned' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['earned'] = bcadd($return[$currencyId]['earned'], $journal['amount']);
}
return $return;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
if ($categories->count() > 0) {
$collector->setCategories($categories);
}
if (0 === $categories->count()) {
$collector->setCategories($this->getCategories());
}
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$journals = $collector->getExtractedJournals();
$return = [];
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$currencyId = (int)$journal['currency_id'];
$name = $journal['category_name'];
// make array for category:
if (!isset($return[$categoryId])) {
$return[$categoryId] = [
'name' => $name,
'earned' => [],
];
}
if (!isset($return[$categoryId]['earned'][$currencyId])) {
$return[$categoryId]['earned'][$currencyId] = [
'earned' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$categoryId]['earned'][$currencyId]['earned']
= bcadd($return[$categoryId]['earned'][$currencyId]['earned'], $journal['amount']);
}
return $return;
}
/**
* Returns a list of all the categories belonging to a user.
*
* @return Collection
*/
public function getCategories(): Collection
{
/** @var Collection $set */
$set = $this->user->categories()->orderBy('name', 'ASC')->get();
return $set;
}
/**
* @param int|null $categoryId
* @param int|null $categoryId
* @param string|null $categoryName
*
* @return Category|null
@ -279,46 +126,6 @@ class CategoryRepository implements CategoryRepositoryInterface
return $this->user->categories()->find($categoryId);
}
/**
* Find a category.
*
* @param string $name
*
* @return Category|null
*/
public function findByName(string $name): ?Category
{
$categories = $this->user->categories()->get(['categories.*']);
// TODO no longer need to loop like this
foreach ($categories as $category) {
if ($category->name === $name) {
return $category;
}
}
return null;
}
/**
* @param array $data
*
* @return Category
*/
public function store(array $data): Category
{
/** @var CategoryFactory $factory */
$factory = app(CategoryFactory::class);
$factory->setUser($this->user);
return $factory->findOrCreate(null, $data['name']);
}
/**
* @param Category $category
*
@ -360,7 +167,20 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* @param Category $category
* Returns a list of all the categories belonging to a user.
*
* @return Collection
*/
public function getCategories(): Collection
{
/** @var Collection $set */
$set = $this->user->categories()->orderBy('name', 'ASC')->get();
return $set;
}
/**
* @param Category $category
* @param Collection $accounts
*
* @return Carbon|null
@ -389,174 +209,6 @@ class CategoryRepository implements CategoryRepositoryInterface
return $lastJournalDate;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals();
// loop transactions:
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$date = $journal['date']->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $journal['amount']);
}
return $data;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withAccountInformation();
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
$collector->withoutCategory();
$journals = $collector->getExtractedJournals();
$result = [
'entries' => [],
'name' => (string)trans('firefly.no_category'),
'sum' => '0',
];
/** @var array $journal */
foreach ($journals as $journal) {
$date = $journal['date']->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], $journal['amount']);
}
return $result;
}
/**
* TODO not multi currency aware.
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->withAccountInformation();
$journals = $collector->getExtractedJournals();
// loop transactions:
/** @var array $journal */
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$date = $journal['date']->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', bcmul($journal['amount'],'-1'));
}
return $data;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
Log::debug('Now in periodIncomeNoCategory()');
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withAccountInformation();
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
$collector->withoutCategory();
$journals = $collector->getExtractedJournals();
$result = [
'entries' => [],
'name' => (string)trans('firefly.no_category'),
'sum' => '0',
];
Log::debug('Looping transactions..');
foreach ($journals as $journal) {
$date = $journal['date']->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], bcmul($journal['amount'],'-1'));
}
Log::debug('Done looping transactions..');
Log::debug('Finished periodIncomeNoCategory()');
return $result;
}
/**
* @param string $query
*
@ -581,166 +233,22 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* Returns the amount spent in a category, for a set of accounts, in a specific period.
* @param array $data
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @return Category
*/
public function spentInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array
public function store(array $data): Category
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setCategory($category);
/** @var CategoryFactory $factory */
$factory = app(CategoryFactory::class);
$factory->setUser($this->user);
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
// collect and group results:
$array = $collector->getExtractedJournals();
$return = [];
foreach ($array as $journal) {
$currencyCode = $journal['currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'spent' => '0',
];
}
// also extract foreign currency information:
if (null !== $journal['foreign_currency_id']) {
$currencyCode = $journal['foreign_currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['foreign_currency_id'],
'currency_code' => $journal['foreign_currency_code'],
'currency_name' => $journal['foreign_currency_name'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
'spent' => '0',
];
}
$return[$currencyCode]['spent'] = bcadd($return[$currencyCode]['spent'], $journal['foreign_amount']);
}
$return[$currencyCode]['spent'] = bcadd($return[$currencyCode]['spent'], $journal['amount']);
}
return $return;
}
/**
* A very cryptic method name that means:
*
* Get me the amount spent in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory();
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$set = $collector->getExtractedJournals();
$return = [];
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = (int)$journal['currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'spent' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']);
}
return $return;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
if ($categories->count() > 0) {
$collector->setCategories($categories);
}
if (0 === $categories->count()) {
$collector->setCategories($this->getCategories());
}
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$set = $collector->getExtractedJournals();
$return = [];
/** @var array $journal */
foreach ($set as $journal) {
$categoryId = (int)$journal['category_id'];
$currencyId = (int)$journal['currency_id'];
$name = $journal['category_name'];
// make array for category:
if (!isset($return[$categoryId])) {
$return[$categoryId] = [
'name' => $name,
'spent' => [],
];
}
if (!isset($return[$categoryId]['spent'][$currencyId])) {
$return[$categoryId]['spent'][$currencyId] = [
'spent' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$categoryId]['spent'][$currencyId]['spent']
= bcadd($return[$categoryId]['spent'][$currencyId]['spent'], $journal['amount']);
}
return $return;
return $factory->findOrCreate(null, $data['name']);
}
/**
* @param Category $category
* @param array $data
* @param array $data
*
* @return Category
*/
@ -752,25 +260,6 @@ class CategoryRepository implements CategoryRepositoryInterface
return $service->update($category, $data);
}
/**
* TODO does not take currencies into account.
*
* @param array $journals
*
* @return string
*/
private function sumJournals(array $journals): string
{
$sum = '0';
/** @var array $journal */
foreach ($journals as $journal) {
$amount = (string)$journal['amount'];
$sum = bcadd($sum, $amount);
}
return $sum;
}
/**
* @param Category $category
*
@ -809,7 +298,7 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* @param Category $category
* @param Category $category
* @param Collection $accounts
*
* @return Carbon|null
@ -833,7 +322,7 @@ class CategoryRepository implements CategoryRepositoryInterface
}
/**
* @param Category $category
* @param Category $category
* @param Collection $accounts
*
* @return Carbon|null
@ -857,4 +346,5 @@ class CategoryRepository implements CategoryRepositoryInterface
return null;
}
}

View File

@ -33,14 +33,6 @@ use Illuminate\Support\Collection;
interface CategoryRepositoryInterface
{
/**
* @param int|null $categoryId
* @param string|null $categoryName
*
* @return Category|null
*/
public function findCategory( ?int $categoryId, ?string $categoryName): ?Category;
/**
* @param Category $category
*
@ -48,41 +40,6 @@ interface CategoryRepositoryInterface
*/
public function destroy(Category $category): bool;
/**
* Returns the amount earned in a category, for a set of accounts, in a specific period.
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* A very cryptic method name that means:
*
* Get me the amount earned in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* Find a category.
*
@ -92,6 +49,14 @@ interface CategoryRepositoryInterface
*/
public function findByName(string $name): ?Category;
/**
* @param int|null $categoryId
* @param string|null $categoryName
*
* @return Category|null
*/
public function findCategory(?int $categoryId, ?string $categoryName): ?Category;
/**
* Find a category or return NULL
*
@ -124,8 +89,6 @@ interface CategoryRepositoryInterface
*/
public function getCategories(): Collection;
/**
* Return most recent transaction(journal) date or null when never used before.
*
@ -136,52 +99,6 @@ interface CategoryRepositoryInterface
*/
public function lastUseDate(Category $category, Collection $accounts): ?Carbon;
/**
* TODO not multi-currency
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* TODO not multi-currency
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* TODO not multi-currency
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* TODO not multi-currency
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param string $query
*
@ -189,48 +106,11 @@ interface CategoryRepositoryInterface
*/
public function searchCategory(string $query): Collection;
/**
* @param User $user
*/
public function setUser(User $user);
/**
* Returns the amount spent in a category, for a set of accounts, in a specific period.
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* A very cryptic method name that means:
*
* Get me the amount spent in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param array $data
*

View File

@ -0,0 +1,228 @@
<?php
/**
* NoCategoryRepository.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
*
* Class NoCategoryRepository
*/
class NoCategoryRepository implements NoCategoryRepositoryInterface
{
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* A very cryptic method name that means:
*
* Get me the amount earned in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->withoutCategory();
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$journals = $collector->getExtractedJournals();
$return = [];
foreach ($journals as $journal) {
$currencyId = (int)$journal['currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'earned' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['earned'] = bcadd($return[$currencyId]['earned'], $journal['amount']);
}
return $return;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withAccountInformation();
$collector->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER]);
$collector->withoutCategory();
$journals = $collector->getExtractedJournals();
$result = [
'entries' => [],
'name' => (string)trans('firefly.no_category'),
'sum' => '0',
];
/** @var array $journal */
foreach ($journals as $journal) {
$date = $journal['date']->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], $journal['amount']);
}
return $result;
}
/**
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
Log::debug('Now in periodIncomeNoCategory()');
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end)->withAccountInformation();
$collector->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER]);
$collector->withoutCategory();
$journals = $collector->getExtractedJournals();
$result = [
'entries' => [],
'name' => (string)trans('firefly.no_category'),
'sum' => '0',
];
Log::debug('Looping transactions..');
foreach ($journals as $journal) {
$date = $journal['date']->format($carbonFormat);
if (!isset($result['entries'][$date])) {
$result['entries'][$date] = '0';
}
$result['entries'][$date] = bcadd($result['entries'][$date], bcmul($journal['amount'],'-1'));
}
Log::debug('Done looping transactions..');
Log::debug('Finished periodIncomeNoCategory()');
return $result;
}
/**
* A very cryptic method name that means:
*
* Get me the amount spent in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->withoutCategory();
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$set = $collector->getExtractedJournals();
$return = [];
/** @var array $journal */
foreach ($set as $journal) {
$currencyId = (int)$journal['currency_id'];
if (!isset($return[$currencyId])) {
$return[$currencyId] = [
'spent' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$currencyId]['spent'] = bcadd($return[$currencyId]['spent'], $journal['amount']);
}
return $return;
}
}

View File

@ -0,0 +1,99 @@
<?php
/**
* NoCategoryRepositoryInterface.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Interface NoCategoryRepositoryInterface
*
* @package FireflyIII\Repositories\Category
*/
interface NoCategoryRepositoryInterface
{
/**
* @param User $user
*/
public function setUser(User $user): void;
/**
* A very cryptic method name that means:
*
* Get me the amount earned in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function earnedInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* TODO not multi-currency
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function periodExpensesNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* TODO not multi-currency
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function periodIncomeNoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
/**
* A very cryptic method name that means:
*
* Get me the amount spent in this period, grouped per currency, where no category was set.
*
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*
*/
public function spentInPeriodPcWoCategory(Collection $accounts, Carbon $start, Carbon $end): array;
}

View File

@ -0,0 +1,375 @@
<?php
/**
* OperationsRepository.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Helpers\Collector\GroupCollectorInterface;
use FireflyIII\Models\Category;
use FireflyIII\Models\TransactionType;
use FireflyIII\User;
use Illuminate\Support\Collection;
use Log;
/**
*
* Class OperationsRepository
*/
class OperationsRepository implements OperationsRepositoryInterface
{
/** @var User */
private $user;
/**
* Constructor.
*/
public function __construct()
{
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
}
/**
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT])->setCategory($category);
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
// collect and group results:
$array = $collector->getExtractedJournals();
$return = [];
foreach ($array as $journal) {
$currencyCode = $journal['currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'earned' => '0',
];
}
// also extract foreign currency information:
if (null !== $journal['foreign_currency_id']) {
$currencyCode = $journal['foreign_currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['foreign_currency_id'],
'currency_code' => $journal['foreign_currency_code'],
'currency_name' => $journal['foreign_currency_name'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
'earned' => '0',
];
}
$return[$currencyCode]['earned'] = bcadd($return[$currencyCode]['earned'], app('steam')->positive($journal['foreign_amount']));
}
$return[$currencyCode]['earned'] = bcadd($return[$currencyCode]['earned'], app('steam')->positive($journal['amount']));
}
return $return;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function earnedInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::DEPOSIT]);
if ($categories->count() > 0) {
$collector->setCategories($categories);
}
if (0 === $categories->count()) {
$collector->setCategories($this->getCategories());
}
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$journals = $collector->getExtractedJournals();
$return = [];
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$currencyId = (int)$journal['currency_id'];
$name = $journal['category_name'];
// make array for category:
if (!isset($return[$categoryId])) {
$return[$categoryId] = [
'name' => $name,
'earned' => [],
];
}
if (!isset($return[$categoryId]['earned'][$currencyId])) {
$return[$categoryId]['earned'][$currencyId] = [
'earned' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$categoryId]['earned'][$currencyId]['earned']
= bcadd($return[$categoryId]['earned'][$currencyId]['earned'], $journal['amount']);
}
return $return;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::WITHDRAWAL, TransactionType::TRANSFER])
->withAccountInformation()->withCategoryInformation();
$journals = $collector->getExtractedJournals();
// loop transactions:
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$date = $journal['date']->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', $journal['amount']);
}
return $data;
}
/**
* TODO not multi currency aware.
*
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
$carbonFormat = Navigation::preferredCarbonFormat($start, $end);
$data = [];
// prep data array:
/** @var Category $category */
foreach ($categories as $category) {
$data[$category->id] = [
'name' => $category->name,
'sum' => '0',
'entries' => [],
];
}
// get all transactions:
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setAccounts($accounts)->setRange($start, $end);
$collector->setCategories($categories)->setTypes([TransactionType::DEPOSIT, TransactionType::TRANSFER])
->withAccountInformation();
$journals = $collector->getExtractedJournals();
// loop transactions:
/** @var array $journal */
foreach ($journals as $journal) {
$categoryId = (int)$journal['category_id'];
$date = $journal['date']->format($carbonFormat);
$data[$categoryId]['entries'][$date] = bcadd($data[$categoryId]['entries'][$date] ?? '0', bcmul($journal['amount'], '-1'));
}
return $data;
}
/**
* @param User $user
*/
public function setUser(User $user): void
{
$this->user = $user;
}
/**
* Returns the amount spent in a category, for a set of accounts, in a specific period.
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL])->setCategory($category);
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
// collect and group results:
$array = $collector->getExtractedJournals();
$return = [];
foreach ($array as $journal) {
$currencyCode = $journal['currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['currency_id'],
'currency_code' => $journal['currency_code'],
'currency_name' => $journal['currency_name'],
'currency_symbol' => $journal['currency_symbol'],
'currency_decimal_places' => $journal['currency_decimal_places'],
'spent' => '0',
];
}
// also extract foreign currency information:
if (null !== $journal['foreign_currency_id']) {
$currencyCode = $journal['foreign_currency_code'];
if (!isset($return[$currencyCode])) {
$return[$currencyCode] = [
'currency_id' => $journal['foreign_currency_id'],
'currency_code' => $journal['foreign_currency_code'],
'currency_name' => $journal['foreign_currency_name'],
'currency_symbol' => $journal['foreign_currency_symbol'],
'currency_decimal_places' => $journal['foreign_currency_decimal_places'],
'spent' => '0',
];
}
$return[$currencyCode]['spent'] = bcadd($return[$currencyCode]['spent'], $journal['foreign_amount']);
}
$return[$currencyCode]['spent'] = bcadd($return[$currencyCode]['spent'], $journal['amount']);
}
return $return;
}
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
*/
public function spentInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array
{
/** @var GroupCollectorInterface $collector */
$collector = app(GroupCollectorInterface::class);
$collector->setUser($this->user);
$collector->setRange($start, $end)->setTypes([TransactionType::WITHDRAWAL]);
if ($categories->count() > 0) {
$collector->setCategories($categories);
}
if (0 === $categories->count()) {
$collector->setCategories($this->getCategories());
}
if ($accounts->count() > 0) {
$collector->setAccounts($accounts);
}
$set = $collector->getExtractedJournals();
$return = [];
/** @var array $journal */
foreach ($set as $journal) {
$categoryId = (int)$journal['category_id'];
$currencyId = (int)$journal['currency_id'];
$name = $journal['category_name'];
// make array for category:
if (!isset($return[$categoryId])) {
$return[$categoryId] = [
'name' => $name,
'spent' => [],
];
}
if (!isset($return[$categoryId]['spent'][$currencyId])) {
$return[$categoryId]['spent'][$currencyId] = [
'spent' => '0',
'currency_id' => $currencyId,
'currency_symbol' => $journal['currency_symbol'],
'currency_code' => $journal['currency_code'],
'currency_decimal_places' => $journal['currency_decimal_places'],
];
}
$return[$categoryId]['spent'][$currencyId]['spent']
= bcadd($return[$categoryId]['spent'][$currencyId]['spent'], $journal['amount']);
}
return $return;
}
}

View File

@ -0,0 +1,114 @@
<?php
/**
* OperationsRepositoryInterface.php
* Copyright (c) 2019 thegrumpydictator@gmail.com
*
* This file is part of Firefly III.
*
* Firefly III is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Firefly III is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Firefly III. If not, see <http://www.gnu.org/licenses/>.
*/
declare(strict_types=1);
namespace FireflyIII\Repositories\Category;
use Carbon\Carbon;
use FireflyIII\Models\Category;
use FireflyIII\User;
use Illuminate\Support\Collection;
/**
* Interface OperationsRepositoryInterface
*
* @package FireflyIII\Repositories\Category
*/
interface OperationsRepositoryInterface
{
/**
* Returns the amount earned in a category, for a set of accounts, in a specific period.
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*
*/
public function earnedInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function earnedInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function periodExpenses(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function periodIncome(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param User $user
*/
public function setUser(User $user): void;
/**
* Returns the amount spent in a category, for a set of accounts, in a specific period.
*
* @param Category $category
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*
*/
public function spentInPeriod(Category $category, Collection $accounts, Carbon $start, Carbon $end): array;
/**
* @param Collection $categories
* @param Collection $accounts
* @param Carbon $start
* @param Carbon $end
*
* @return array
* @deprecated
*/
public function spentInPeriodPerCurrency(Collection $categories, Collection $accounts, Carbon $start, Carbon $end): array;
}

View File

@ -27,6 +27,7 @@ use FireflyIII\Models\AccountType;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Account\AccountRepositoryInterface;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
/**
* Class WholePeriodChartGenerator
@ -45,6 +46,9 @@ class WholePeriodChartGenerator
/** @var CategoryRepositoryInterface $repository */
$repository = app(CategoryRepositoryInterface::class);
/** @var OperationsRepositoryInterface $opsRepository */
$opsRepository = app(OperationsRepositoryInterface::class);
/** @var AccountRepositoryInterface $accountRepository */
$accountRepository = app(AccountRepositoryInterface::class);
@ -61,8 +65,8 @@ class WholePeriodChartGenerator
while ($current <= $end) {
$key = $current->format('Y-m-d');
$currentEnd = app('navigation')->endOfPeriod($current, $step);
$spent[$key] = $repository->spentInPeriod($category, $accounts, $current, $currentEnd);
$earned[$key] = $repository->earnedInPeriod($category, $accounts, $current, $currentEnd);
$spent[$key] = $opsRepository->spentInPeriod($category, $accounts, $current, $currentEnd);
$earned[$key] = $opsRepository->earnedInPeriod($category, $accounts, $current, $currentEnd);
$current = app('navigation')->addPeriod($current, $step, 0);
}
$currencies = $this->extractCurrencies($spent) + $this->extractCurrencies($earned);

View File

@ -26,6 +26,7 @@ namespace FireflyIII\Transformers;
use FireflyIII\Models\Category;
use FireflyIII\Repositories\Category\CategoryRepositoryInterface;
use FireflyIII\Repositories\Category\OperationsRepositoryInterface;
use Illuminate\Support\Collection;
use Log;
@ -34,6 +35,8 @@ use Log;
*/
class CategoryTransformer extends AbstractTransformer
{
/** @var OperationsRepositoryInterface */
private $opsRepository;
/** @var CategoryRepositoryInterface */
private $repository;
@ -44,7 +47,8 @@ class CategoryTransformer extends AbstractTransformer
*/
public function __construct()
{
$this->repository = app(CategoryRepositoryInterface::class);
$this->repository = app(CategoryRepositoryInterface::class);
$this->opsRepository = app(OperationsRepositoryInterface::class);
if ('testing' === config('app.env')) {
Log::warning(sprintf('%s should not be instantiated in the TEST environment!', get_class($this)));
}
@ -60,13 +64,15 @@ class CategoryTransformer extends AbstractTransformer
public function transform(Category $category): array
{
$this->repository->setUser($category->user);
$this->opsRepository->setUser($category->user);
$spent = [];
$earned = [];
$start = $this->parameters->get('start');
$end = $this->parameters->get('end');
if (null !== $start && null !== $end) {
$earned = array_values($this->repository->earnedInPeriod($category, new Collection, $start, $end));
$spent = array_values($this->repository->spentInPeriod($category, new Collection, $start, $end));
$earned = array_values($this->opsRepository->earnedInPeriod($category, new Collection, $start, $end));
$spent = array_values($this->opsRepository->spentInPeriod($category, new Collection, $start, $end));
}
$data = [
'id' => (int)$category->id,