mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-30 06:50:49 +00:00 
			
		
		
		
	Journal collector may not have been a bad idea after all!
This commit is contained in:
		
							
								
								
									
										360
									
								
								app/Helpers/Collector/JournalCollector.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								app/Helpers/Collector/JournalCollector.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,360 @@ | ||||
| <?php | ||||
| declare(strict_types = 1); | ||||
|  | ||||
| namespace FireflyIII\Helpers\Collector; | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use Crypt; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Models\Transaction; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Database\Eloquent\Builder as EloquentBuilder; | ||||
| use Illuminate\Pagination\LengthAwarePaginator; | ||||
| use Illuminate\Support\Collection; | ||||
| use Log; | ||||
|  | ||||
| /** | ||||
|  * Maybe this is a good idea after all... | ||||
|  * | ||||
|  * Class JournalCollector | ||||
|  * | ||||
|  * @package FireflyIII\Helpers\Collector | ||||
|  */ | ||||
| class JournalCollector | ||||
| { | ||||
|  | ||||
|     /** @var  int */ | ||||
|     private $count = 0; | ||||
|  | ||||
|     /** @var array */ | ||||
|     private $fields | ||||
|         = [ | ||||
|             'transaction_journals.id as journal_id', | ||||
|             'transaction_journals.description', | ||||
|             'transaction_journals.date', | ||||
|             'transaction_journals.encrypted', | ||||
|             //'transaction_journals.transaction_currency_id', | ||||
|             'transaction_currencies.code as transaction_currency_code', | ||||
|             //'transaction_currencies.symbol as transaction_currency_symbol', | ||||
|             'transaction_types.type as transaction_type_type', | ||||
|             'transaction_journals.bill_id', | ||||
|             'bills.name as bill_name', | ||||
|             'transactions.id as id', | ||||
|             'transactions.amount as transaction_amount', | ||||
|             'transactions.description as transaction_description', | ||||
|             'transactions.account_id', | ||||
|             'transactions.identifier', | ||||
|             'transactions.transaction_journal_id', | ||||
|             'accounts.name as account_name', | ||||
|             'accounts.encrypted as account_encrypted', | ||||
|             'account_types.type as account_type', | ||||
|  | ||||
|         ]; | ||||
|     /** @var  int */ | ||||
|     private $limit; | ||||
|     /** @var  int */ | ||||
|     private $offset; | ||||
|     /** @var int */ | ||||
|     private $page = 1; | ||||
|     /** @var EloquentBuilder */ | ||||
|     private $query; | ||||
|     /** @var bool */ | ||||
|     private $run = false; | ||||
|     /** @var User */ | ||||
|     private $user; | ||||
|  | ||||
|     /** | ||||
|      * JournalCollector constructor. | ||||
|      * | ||||
|      * @param User $user | ||||
|      */ | ||||
|     public function __construct(User $user) | ||||
|     { | ||||
|         $this->user  = $user; | ||||
|         $this->query = $this->startQuery(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return int | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function count(): int | ||||
|     { | ||||
|         if ($this->run === true) { | ||||
|             throw new FireflyException('Cannot count after run in JournalCollector.'); | ||||
|         } | ||||
|  | ||||
|         $countQuery = clone $this->query; | ||||
|  | ||||
|         // dont need some fields: | ||||
|         $countQuery->getQuery()->limit      = null; | ||||
|         $countQuery->getQuery()->offset     = null; | ||||
|         $countQuery->getQuery()->unionLimit = null; | ||||
|         $countQuery->getQuery()->groups     = null; | ||||
|         $countQuery->groupBy('accounts.user_id'); | ||||
|         $this->count = $countQuery->count(); | ||||
|  | ||||
|         return $this->count; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getJournals(): Collection | ||||
|     { | ||||
|         $this->run = true; | ||||
|         $set       = $this->query->get($this->fields); | ||||
|  | ||||
|         // loop for decryption. | ||||
|         $set->each( | ||||
|             function (Transaction $transaction) { | ||||
|                 $transaction->date        = new Carbon($transaction->date); | ||||
|                 $transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description; | ||||
|                 $transaction->bill_name   = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : ''; | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         return $set; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * It might be worth it to expand this query to include all account information required. | ||||
|      * | ||||
|      * @param Collection $accounts | ||||
|      * @param array      $types | ||||
|      * @param Carbon     $start | ||||
|      * @param Carbon     $end | ||||
|      * | ||||
|      * @return Collection | ||||
|      */ | ||||
|     public function getJournalsInPeriod(Collection $accounts, array $types, Carbon $start, Carbon $end): Collection | ||||
|     { | ||||
|         $accountIds = $accounts->pluck('id')->toArray(); | ||||
|         $query      = Transaction | ||||
|             ::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') | ||||
|             ->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id') | ||||
|             ->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id') | ||||
|             ->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id') | ||||
|             ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') | ||||
|             ->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id') | ||||
|             ->whereIn('transactions.account_id', $accountIds) | ||||
|             ->whereNull('transactions.deleted_at') | ||||
|             ->whereNull('transaction_journals.deleted_at') | ||||
|             ->where('transaction_journals.date', '>=', $start->format('Y-m-d')) | ||||
|             ->where('transaction_journals.date', '<=', $end->format('Y-m-d')) | ||||
|             ->where('transaction_journals.user_id', $this->user->id) | ||||
|             ->orderBy('transaction_journals.date', 'DESC') | ||||
|             ->orderBy('transaction_journals.order', 'ASC') | ||||
|             ->orderBy('transaction_journals.id', 'DESC'); | ||||
|  | ||||
|         if (count($types) > 0) { | ||||
|             $query->whereIn('transaction_types.type', $types); | ||||
|         } | ||||
|  | ||||
|         $set = $query->get( | ||||
|             [ | ||||
|                 'transaction_journals.id as journal_id', | ||||
|                 'transaction_journals.description', | ||||
|                 'transaction_journals.date', | ||||
|                 'transaction_journals.encrypted', | ||||
|                 //'transaction_journals.transaction_currency_id', | ||||
|                 'transaction_currencies.code as transaction_currency_code', | ||||
|                 //'transaction_currencies.symbol as transaction_currency_symbol', | ||||
|                 'transaction_types.type as transaction_type_type', | ||||
|                 'transaction_journals.bill_id', | ||||
|                 'bills.name as bill_name', | ||||
|                 'transactions.id as id', | ||||
|                 'transactions.amount as transaction_amount', | ||||
|                 'transactions.description as transaction_description', | ||||
|                 'transactions.account_id', | ||||
|                 'transactions.identifier', | ||||
|                 'transactions.transaction_journal_id', | ||||
|                 'accounts.name as account_name', | ||||
|                 'accounts.encrypted as account_encrypted', | ||||
|                 'account_types.type as account_type', | ||||
|  | ||||
|             ] | ||||
|         ); | ||||
|  | ||||
|         // loop for decryption. | ||||
|         $set->each( | ||||
|             function (Transaction $transaction) { | ||||
|                 $transaction->date        = new Carbon($transaction->date); | ||||
|                 $transaction->description = intval($transaction->encrypted) === 1 ? Crypt::decrypt($transaction->description) : $transaction->description; | ||||
|                 $transaction->bill_name   = !is_null($transaction->bill_name) ? Crypt::decrypt($transaction->bill_name) : ''; | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         return $set; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return LengthAwarePaginator | ||||
|      * @throws FireflyException | ||||
|      */ | ||||
|     public function getPaginatedJournals():LengthAwarePaginator | ||||
|     { | ||||
|         if ($this->run === true) { | ||||
|             throw new FireflyException('Cannot getPaginatedJournals after run in JournalCollector.'); | ||||
|         } | ||||
|         $this->count(); | ||||
|         $set      = $this->getJournals(); | ||||
|         $journals = new LengthAwarePaginator($set, $this->count, $this->limit, $this->page); | ||||
|  | ||||
|         return $journals; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Collection $accounts | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setAccounts(Collection $accounts): JournalCollector | ||||
|     { | ||||
|         if ($accounts->count() > 0) { | ||||
|             $accountIds = $accounts->pluck('id')->toArray(); | ||||
|             $this->query->whereIn('transactions.account_id', $accountIds); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $limit | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setLimit(int $limit): JournalCollector | ||||
|     { | ||||
|         $this->limit = $limit; | ||||
|         $this->query->limit($limit); | ||||
|         Log::debug(sprintf('Set limit to %d', $limit)); | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $offset | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setOffset(int $offset): JournalCollector | ||||
|     { | ||||
|         $this->offset = $offset; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param int $page | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setPage(int $page): JournalCollector | ||||
|     { | ||||
|         $this->page = $page; | ||||
|  | ||||
|         if ($page > 0) { | ||||
|             $page--; | ||||
|         } | ||||
|         Log::debug(sprintf('Page is %d', $page)); | ||||
|  | ||||
|         if (!is_null($this->limit)) { | ||||
|             $offset       = ($this->limit * $page); | ||||
|             $this->offset = $offset; | ||||
|             $this->query->skip($offset); | ||||
|             Log::debug(sprintf('Changed offset to %d', $offset)); | ||||
|         } | ||||
|         if (is_null($this->limit)) { | ||||
|             Log::debug('The limit is zero, cannot set the page.'); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Carbon $start | ||||
|      * @param Carbon $end | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setRange(Carbon $start, Carbon $end): JournalCollector | ||||
|     { | ||||
|         if ($start <= $end) { | ||||
|             $this->query->where('transaction_journals.date', '>=', $start->format('Y-m-d')); | ||||
|             $this->query->where('transaction_journals.date', '<=', $end->format('Y-m-d')); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Collection $accounts | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setDestinationAccounts(Collection $accounts): JournalCollector | ||||
|     { | ||||
|         if ($accounts->count() > 0) { | ||||
|             $accountIds = $accounts->pluck('id')->toArray(); | ||||
|             $this->query->whereIn('transactions.account_id', $accountIds); | ||||
|             $this->query->where('transactions.amount', '>', 0); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Collection $accounts | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setSourceAccounts(Collection $accounts): JournalCollector | ||||
|     { | ||||
|         if ($accounts->count() > 0) { | ||||
|             $accountIds = $accounts->pluck('id')->toArray(); | ||||
|             $this->query->whereIn('transactions.account_id', $accountIds); | ||||
|             $this->query->where('transactions.amount', '<', 0); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param array $types | ||||
|      * | ||||
|      * @return JournalCollector | ||||
|      */ | ||||
|     public function setTypes(array $types): JournalCollector | ||||
|     { | ||||
|         if (count($types) > 0) { | ||||
|             $this->query->whereIn('transaction_types.type', $types); | ||||
|         } | ||||
|  | ||||
|         return $this; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @return EloquentBuilder | ||||
|      */ | ||||
|     private function startQuery(): EloquentBuilder | ||||
|     { | ||||
|  | ||||
|         $query = Transaction | ||||
|             ::leftJoin('transaction_journals', 'transaction_journals.id', '=', 'transactions.transaction_journal_id') | ||||
|             ->leftJoin('transaction_currencies', 'transaction_currencies.id', 'transaction_journals.transaction_currency_id') | ||||
|             ->leftJoin('transaction_types', 'transaction_types.id', 'transaction_journals.transaction_type_id') | ||||
|             ->leftJoin('bills', 'bills.id', 'transaction_journals.bill_id') | ||||
|             ->leftJoin('accounts', 'accounts.id', '=', 'transactions.account_id') | ||||
|             ->leftJoin('account_types', 'accounts.account_type_id', 'account_types.id') | ||||
|             ->whereNull('transactions.deleted_at') | ||||
|             ->whereNull('transaction_journals.deleted_at') | ||||
|             ->where('transaction_journals.user_id', $this->user->id) | ||||
|             ->orderBy('transaction_journals.date', 'DESC') | ||||
|             ->orderBy('transaction_journals.order', 'ASC') | ||||
|             ->orderBy('transaction_journals.id', 'DESC'); | ||||
|  | ||||
|         return $query; | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -15,6 +15,7 @@ namespace FireflyIII\Http\Controllers; | ||||
| use Amount; | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Helpers\Collector\JournalCollector; | ||||
| use FireflyIII\Models\AccountType; | ||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||
| use FireflyIII\Repositories\Account\AccountTaskerInterface; | ||||
| @@ -270,17 +271,20 @@ class JsonController extends Controller | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param JournalTaskerInterface     $tasker | ||||
|      * @param                            $what | ||||
|      * @param $what | ||||
|      * | ||||
|      * @return \Symfony\Component\HttpFoundation\Response | ||||
|      * @return \Illuminate\Http\JsonResponse | ||||
|      */ | ||||
|     public function transactionJournals(JournalTaskerInterface $tasker, $what) | ||||
|     public function transactionJournals($what) | ||||
|     { | ||||
|         $descriptions = []; | ||||
|         $type         = config('firefly.transactionTypesByWhat.' . $what); | ||||
|         $types        = [$type]; | ||||
|         $journals     = $tasker->getJournals($types, 1, 50); | ||||
|  | ||||
|         // use journal collector instead: | ||||
|         $collector     = new JournalCollector(auth()->user()); | ||||
|         $collector->setTypes($types)->setLimit(100)->setPage(1); | ||||
|         $journals = $collector->getJournals(); | ||||
|         foreach ($journals as $j) { | ||||
|             $descriptions[] = $j->description; | ||||
|         } | ||||
|   | ||||
| @@ -14,7 +14,10 @@ declare(strict_types = 1); | ||||
| namespace FireflyIII\Http\Controllers; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Helpers\Collector\JournalCollector; | ||||
| use FireflyIII\Models\AccountType; | ||||
| use FireflyIII\Models\TransactionJournal; | ||||
| use FireflyIII\Repositories\Account\AccountRepositoryInterface; | ||||
| use FireflyIII\Repositories\Journal\JournalRepositoryInterface; | ||||
| use FireflyIII\Repositories\Journal\JournalTaskerInterface; | ||||
| use Illuminate\Http\Request; | ||||
| @@ -49,21 +52,35 @@ class TransactionController extends Controller | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Request                $request | ||||
|      * @param JournalTaskerInterface $tasker | ||||
|      * @param string                 $what | ||||
|      * @param Request                    $request | ||||
|      * @param AccountRepositoryInterface $repository | ||||
|      * @param string                     $what | ||||
|      * | ||||
|      * @return View | ||||
|      */ | ||||
|     public function index(Request $request, JournalTaskerInterface $tasker, string $what) | ||||
|     public function index(Request $request, AccountRepositoryInterface $repository, string $what) | ||||
|     { | ||||
|         $pageSize     = intval(Preferences::get('transactionPageSize', 50)->data); | ||||
|         $subTitleIcon = config('firefly.transactionIconsByWhat.' . $what); | ||||
|         $types        = config('firefly.transactionTypesByWhat.' . $what); | ||||
|         $subTitle     = trans('firefly.title_' . $what); | ||||
|         $page         = intval($request->get('page')); | ||||
|         $journals     = $tasker->getJournals($types, $page, $pageSize); | ||||
|         $pageSize      = intval(Preferences::get('transactionPageSize', 50)->data); | ||||
|         $subTitleIcon  = config('firefly.transactionIconsByWhat.' . $what); | ||||
|         $types         = config('firefly.transactionTypesByWhat.' . $what); | ||||
|         $subTitle      = trans('firefly.title_' . $what); | ||||
|         $page          = intval($request->get('page')); | ||||
|         $assetAccounts = $repository->getAccountsByType([AccountType::DEFAULT, AccountType::ASSET]); | ||||
|         $collector     = new JournalCollector(auth()->user()); | ||||
|         $collector->setTypes($types)->setLimit($pageSize)->setPage($page); | ||||
|  | ||||
|         // depending on the view, we filter the collector to grab the right stuff. | ||||
|         switch ($what) { | ||||
|             default: | ||||
|                 $collector->setAccounts($assetAccounts); | ||||
|                 break; | ||||
|             case 'transfer': | ||||
|             case 'transfers': | ||||
|                 $collector->setDestinationAccounts($assetAccounts); | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         $journals = $collector->getPaginatedJournals(); | ||||
|         $journals->setPath('transactions/' . $what); | ||||
|  | ||||
|         return view('transactions.index', compact('subTitle', 'what', 'subTitleIcon', 'journals')); | ||||
|   | ||||
| @@ -1,5 +1,12 @@ | ||||
| {{ journals.render|raw }} | ||||
|  | ||||
| {% if journals.count == 0 %} | ||||
| <p> | ||||
|     <em>{{ 'nothing_to_display'|_ }}</em> | ||||
| </p> | ||||
| {% endif %} | ||||
|  | ||||
| {% if journals.count > 0 %} | ||||
| <table class="table table-hover table-compressed {% if sorting %}sortable-table{% endif %}"> | ||||
|     <thead> | ||||
|     <tr class="ignore"> | ||||
| @@ -130,3 +137,4 @@ | ||||
|     var edit_selected_txt = "{{ 'edit_selected'|_ }}"; | ||||
|     var delete_selected_txt = "{{ 'delete_selected'|_ }}"; | ||||
| </script> | ||||
| {% endif %} | ||||
| @@ -12,7 +12,7 @@ | ||||
|                     <h3 class="box-title">{{ subTitle }}</h3> | ||||
|                 </div> | ||||
|                 <div class="box-body"> | ||||
|                     {% include 'list.journals' %} | ||||
|                     {% include 'list.journals-tasker' %} | ||||
|                 </div> | ||||
|             </div> | ||||
|         </div> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user