mirror of
				https://github.com/firefly-iii/firefly-iii.git
				synced 2025-10-31 02:36:28 +00:00 
			
		
		
		
	Give bills groups too.
This commit is contained in:
		| @@ -27,6 +27,7 @@ namespace FireflyIII\Factory; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups; | ||||
| use FireflyIII\Services\Internal\Support\BillServiceTrait; | ||||
| use FireflyIII\User; | ||||
| use Illuminate\Database\QueryException; | ||||
| @@ -37,7 +38,7 @@ use Log; | ||||
|  */ | ||||
| class BillFactory | ||||
| { | ||||
|     use BillServiceTrait; | ||||
|     use BillServiceTrait, CreatesObjectGroups; | ||||
|  | ||||
|     /** @var User */ | ||||
|     private $user; | ||||
| @@ -97,6 +98,24 @@ class BillFactory | ||||
|             $this->updateNote($bill, $data['notes']); | ||||
|         } | ||||
|  | ||||
|         $objectGroupTitle = $data['object_group'] ?? ''; | ||||
|         if ('' !== $objectGroupTitle) { | ||||
|             $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); | ||||
|             if (null !== $objectGroup) { | ||||
|                 $bill->objectGroups()->sync([$objectGroup->id]); | ||||
|                 $bill->save(); | ||||
|             } | ||||
|         } | ||||
|         // try also with ID: | ||||
|         $objectGroupId = (int) ($data['object_group_id'] ?? 0); | ||||
|         if (0 !== $objectGroupId) { | ||||
|             $objectGroup = $this->findObjectGroupById($objectGroupId); | ||||
|             if (null !== $objectGroup) { | ||||
|                 $bill->objectGroups()->sync([$objectGroup->id]); | ||||
|                 $bill->save(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $bill; | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										130
									
								
								app/Http/Controllers/Bill/CreateController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								app/Http/Controllers/Bill/CreateController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * CreateController.php | ||||
|  * Copyright (c) 2020 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers\Bill; | ||||
|  | ||||
|  | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; | ||||
| use FireflyIII\Http\Controllers\Controller; | ||||
| use FireflyIII\Http\Requests\BillStoreRequest; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Http\Request; | ||||
|  | ||||
| /** | ||||
|  * Class CreateController | ||||
|  */ | ||||
| class CreateController extends Controller | ||||
| { | ||||
|     private AttachmentHelperInterface $attachments; | ||||
|     private BillRepositoryInterface   $repository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->attachments = app(AttachmentHelperInterface::class); | ||||
|                 $this->repository  = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a new bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * | ||||
|      * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View | ||||
|      */ | ||||
|     public function create(Request $request) | ||||
|     { | ||||
|         $periods = []; | ||||
|         /** @var array $billPeriods */ | ||||
|         $billPeriods = config('firefly.bill_periods'); | ||||
|         foreach ($billPeriods as $current) { | ||||
|             $periods[$current] = strtolower((string) trans('firefly.repeat_freq_' . $current)); | ||||
|         } | ||||
|         $subTitle        = (string) trans('firefly.create_new_bill'); | ||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); | ||||
|  | ||||
|         // put previous url in session if not redirect from store (not "create another"). | ||||
|         if (true !== session('bills.create.fromStore')) { | ||||
|             $this->rememberPreviousUri('bills.create.uri'); | ||||
|         } | ||||
|         $request->session()->forget('bills.create.fromStore'); | ||||
|  | ||||
|         return view('bills.create', compact('periods', 'subTitle', 'defaultCurrency')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Store a new bill. | ||||
|      * | ||||
|      * @param BillStoreRequest $request | ||||
|      * | ||||
|      * @return RedirectResponse | ||||
|      * | ||||
|      */ | ||||
|     public function store(BillStoreRequest $request): RedirectResponse | ||||
|     { | ||||
|         $billData           = $request->getBillData(); | ||||
|         $billData['active'] = true; | ||||
|         try { | ||||
|             $bill = $this->repository->store($billData); | ||||
|         } catch (FireflyException $e) { | ||||
|             Log::error($e->getMessage()); | ||||
|             $request->session()->flash('error', (string) trans('firefly.bill_store_error')); | ||||
|  | ||||
|             return redirect(route('bills.create'))->withInput(); | ||||
|         } | ||||
|         $request->session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         /** @var array $files */ | ||||
|         $files = $request->hasFile('attachments') ? $request->file('attachments') : null; | ||||
|         if (null !== $files && !auth()->user()->hasRole('demo')) { | ||||
|             $this->attachments->saveAttachmentsForModel($bill, $files); | ||||
|         } | ||||
|         if (null !== $files && auth()->user()->hasRole('demo')) { | ||||
|             session()->flash('info', (string) trans('firefly.no_att_demo_user')); | ||||
|         } | ||||
|  | ||||
|         if (count($this->attachments->getMessages()->get('attachments')) > 0) { | ||||
|             $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore | ||||
|         } | ||||
|  | ||||
|         return redirect(route('rules.create-from-bill', [$bill->id])); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										99
									
								
								app/Http/Controllers/Bill/DeleteController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								app/Http/Controllers/Bill/DeleteController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * DeleteController.php | ||||
|  * Copyright (c) 2020 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers\Bill; | ||||
|  | ||||
|  | ||||
| use FireflyIII\Http\Controllers\Controller; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use Illuminate\Contracts\View\Factory; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Http\Request; | ||||
| use Illuminate\Routing\Redirector; | ||||
| use Illuminate\View\View; | ||||
|  | ||||
| /** | ||||
|  * Class DeleteController | ||||
|  */ | ||||
| class DeleteController extends Controller | ||||
| { | ||||
|     private BillRepositoryInterface $repository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         app('view')->share('showBudget', true); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->repository = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|     /** | ||||
|      * Delete a bill. | ||||
|      * | ||||
|      * @param Bill $bill | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function delete(Bill $bill) | ||||
|     { | ||||
|         // put previous url in session | ||||
|         $this->rememberPreviousUri('bills.delete.uri'); | ||||
|         $subTitle = (string) trans('firefly.delete_bill', ['name' => $bill->name]); | ||||
|  | ||||
|         return view('bills.delete', compact('bill', 'subTitle')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Destroy a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return RedirectResponse|Redirector | ||||
|      */ | ||||
|     public function destroy(Request $request, Bill $bill) | ||||
|     { | ||||
|         $name = $bill->name; | ||||
|         $this->repository->destroy($bill); | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         return redirect($this->getPreviousUri('bills.delete.uri')); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										155
									
								
								app/Http/Controllers/Bill/EditController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								app/Http/Controllers/Bill/EditController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * EditController.php | ||||
|  * Copyright (c) 2020 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers\Bill; | ||||
|  | ||||
|  | ||||
| use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; | ||||
| use FireflyIII\Http\Controllers\Controller; | ||||
| use FireflyIII\Http\Requests\BillUpdateRequest; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Http\Request; | ||||
|  | ||||
| /** | ||||
|  * Class EditController | ||||
|  */ | ||||
| class EditController extends Controller | ||||
| { | ||||
|     private AttachmentHelperInterface $attachments; | ||||
|     private BillRepositoryInterface   $repository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->attachments = app(AttachmentHelperInterface::class); | ||||
|                 $this->repository  = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Edit a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\View\View | ||||
|      */ | ||||
|     public function edit(Request $request, Bill $bill) | ||||
|     { | ||||
|         $periods = []; | ||||
|         /** @var array $billPeriods */ | ||||
|         $billPeriods = config('firefly.bill_periods'); | ||||
|  | ||||
|         foreach ($billPeriods as $current) { | ||||
|             $periods[$current] = (string) trans('firefly.' . $current); | ||||
|         } | ||||
|  | ||||
|         $subTitle = (string) trans('firefly.edit_bill', ['name' => $bill->name]); | ||||
|  | ||||
|         // put previous url in session if not redirect from store (not "return_to_edit"). | ||||
|         if (true !== session('bills.edit.fromUpdate')) { | ||||
|             $this->rememberPreviousUri('bills.edit.uri'); | ||||
|         } | ||||
|  | ||||
|         $currency         = app('amount')->getDefaultCurrency(); | ||||
|         $bill->amount_min = round((float) $bill->amount_min, $currency->decimal_places); | ||||
|         $bill->amount_max = round((float) $bill->amount_max, $currency->decimal_places); | ||||
|         $rules            = $this->repository->getRulesForBill($bill); | ||||
|         $defaultCurrency  = app('amount')->getDefaultCurrency(); | ||||
|  | ||||
|         // code to handle active-checkboxes | ||||
|         $hasOldInput = null !== $request->old('_token'); | ||||
|  | ||||
|         $preFilled = [ | ||||
|             'notes'                   => $this->repository->getNoteText($bill), | ||||
|             'transaction_currency_id' => $bill->transaction_currency_id, | ||||
|             'active'                  => $hasOldInput ? (bool) $request->old('active') : $bill->active, | ||||
|             'object_group'            => $bill->objectGroups->first() ? $bill->objectGroups->first()->title : '', | ||||
|         ]; | ||||
|  | ||||
|         $request->session()->flash('preFilled', $preFilled); | ||||
|         $request->session()->forget('bills.edit.fromUpdate'); | ||||
|  | ||||
|         return view('bills.edit', compact('subTitle', 'periods', 'rules', 'bill', 'defaultCurrency', 'preFilled')); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Update a bill. | ||||
|      * | ||||
|      * @param BillUpdateRequest $request | ||||
|      * @param Bill            $bill | ||||
|      * | ||||
|      * @return RedirectResponse | ||||
|      */ | ||||
|     public function update(BillUpdateRequest $request, Bill $bill): RedirectResponse | ||||
|     { | ||||
|         $billData = $request->getBillData(); | ||||
|         $bill     = $this->repository->update($bill, $billData); | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans('firefly.updated_bill', ['name' => $bill->name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         /** @var array $files */ | ||||
|         $files = $request->hasFile('attachments') ? $request->file('attachments') : null; | ||||
|         if (null !== $files && !auth()->user()->hasRole('demo')) { | ||||
|             $this->attachments->saveAttachmentsForModel($bill, $files); | ||||
|         } | ||||
|         if (null !== $files && auth()->user()->hasRole('demo')) { | ||||
|             session()->flash('info',(string)trans('firefly.no_att_demo_user')); | ||||
|         } | ||||
|  | ||||
|         // flash messages | ||||
|         if (count($this->attachments->getMessages()->get('attachments')) > 0) { | ||||
|             $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore | ||||
|         } | ||||
|         $redirect = redirect($this->getPreviousUri('bills.edit.uri')); | ||||
|  | ||||
|         if (1 === (int) $request->get('return_to_edit')) { | ||||
|             // @codeCoverageIgnoreStart | ||||
|             $request->session()->put('bills.edit.fromUpdate', true); | ||||
|  | ||||
|             $redirect = redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]); | ||||
|             // @codeCoverageIgnoreEnd | ||||
|         } | ||||
|  | ||||
|         return $redirect; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										171
									
								
								app/Http/Controllers/Bill/IndexController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								app/Http/Controllers/Bill/IndexController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,171 @@ | ||||
| <?php | ||||
|  | ||||
| /** | ||||
|  * IndexController.php | ||||
|  * Copyright (c) 2020 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers\Bill; | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Http\Controllers\Controller; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use FireflyIII\Transformers\BillTransformer; | ||||
| use Symfony\Component\HttpFoundation\ParameterBag; | ||||
|  | ||||
| /** | ||||
|  * Class IndexController | ||||
|  */ | ||||
| class IndexController extends Controller | ||||
| { | ||||
|     private BillRepositoryInterface $repository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->repository = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show all bills. | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $start      = session('start'); | ||||
|         $end        = session('end'); | ||||
|         $collection = $this->repository->getBills(); | ||||
|         $total      = $collection->count(); | ||||
|  | ||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); | ||||
|         $parameters      = new ParameterBag; | ||||
|         $parameters->set('start', $start); | ||||
|         $parameters->set('end', $end); | ||||
|  | ||||
|         /** @var BillTransformer $transformer */ | ||||
|         $transformer = app(BillTransformer::class); | ||||
|         $transformer->setParameters($parameters); | ||||
|  | ||||
|         // loop all bills, convert to array and add rules and stuff. | ||||
|         $rules = $this->repository->getRulesForBills($collection); | ||||
|  | ||||
|         // make bill groups: | ||||
|         $bills = [ | ||||
|             0 => [ // the index is the order, not the ID. | ||||
|                    'object_group_id'    => 0, | ||||
|                    'object_group_title' => (string) trans('firefly.default_group_title_name'), | ||||
|                    'bills'              => [], | ||||
|             ], | ||||
|         ]; | ||||
|  | ||||
|  | ||||
|         /** @var Bill $bill */ | ||||
|         foreach ($collection as $bill) { | ||||
|             $array      = $transformer->transform($bill); | ||||
|             $groupOrder = (int) $array['object_group_order']; | ||||
|             // make group array if necessary: | ||||
|             $bills[$groupOrder] = $bills[$groupOrder] ?? [ | ||||
|                     'object_group_id'    => $array['object_group_id'], | ||||
|                     'object_group_title' => $array['object_group_title'], | ||||
|                     'bills'              => [], | ||||
|                 ]; | ||||
|  | ||||
|             $nextExpectedMatch                 = new Carbon($array['next_expected_match']); | ||||
|             $array['next_expected_match_diff'] = $nextExpectedMatch->isToday() | ||||
|                 ? trans('firefly.today') | ||||
|                 : $nextExpectedMatch->diffForHumans( | ||||
|                     today(), Carbon::DIFF_RELATIVE_TO_NOW | ||||
|                 ); | ||||
|             $currency                          = $bill->transactionCurrency ?? $defaultCurrency; | ||||
|             $array['currency_id']              = $currency->id; | ||||
|             $array['currency_name']            = $currency->name; | ||||
|             $array['currency_symbol']          = $currency->symbol; | ||||
|             $array['currency_code']            = $currency->code; | ||||
|             $array['currency_decimal_places']  = $currency->decimal_places; | ||||
|             $array['attachments']              = $this->repository->getAttachments($bill); | ||||
|             $array['rules']                    = $rules[$bill['id']] ?? []; | ||||
|             $bills[$groupOrder]['bills'][]     = $array; | ||||
|         } | ||||
|  | ||||
|         // order by key | ||||
|         ksort($bills); | ||||
|  | ||||
|         // summarise per currency / per group. | ||||
|         $sums = $this->getSums($bills); | ||||
|  | ||||
|         return view('bills.index', compact('bills', 'sums', 'total')); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * @param array $bills | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     private function getSums(array $bills): array | ||||
|     { | ||||
|         $sums = []; | ||||
|  | ||||
|         /** @var array $group */ | ||||
|         foreach ($bills as $groupOrder => $group) { | ||||
|             /** @var array $bill */ | ||||
|             foreach ($group['bills'] as $bill) { | ||||
|                 if (false === $bill['active']) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 if (0 === count($bill['pay_dates'])) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 /** @var TransactionCurrency $currency */ | ||||
|                 $currencyId                     = $bill['currency_id']; | ||||
|                 $sums[$groupOrder][$currencyId] = $sums[$groupOrder][$currencyId] ?? [ | ||||
|                         'currency_id'             => $currencyId, | ||||
|                         'currency_code'           => $bill['currency_code'], | ||||
|                         'currency_name'           => $bill['currency_name'], | ||||
|                         'currency_symbol'         => $bill['currency_symbol'], | ||||
|                         'currency_decimal_places' => $bill['currency_decimal_places'], | ||||
|                         'avg'                     => '0', | ||||
|                     ]; | ||||
|  | ||||
|                 $avg                                   = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); | ||||
|                 $avg                                   = bcmul($avg, (string) count($bill['pay_dates'])); | ||||
|                 $sums[$groupOrder][$currencyId]['avg'] = bcadd($sums[$groupOrder][$currencyId]['avg'], $avg); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $sums; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										195
									
								
								app/Http/Controllers/Bill/ShowController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								app/Http/Controllers/Bill/ShowController.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| <?php | ||||
| /** | ||||
|  * ShowController.php | ||||
|  * Copyright (c) 2020 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers\Bill; | ||||
|  | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||
| use FireflyIII\Http\Controllers\Controller; | ||||
| use FireflyIII\Models\Attachment; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use FireflyIII\TransactionRules\TransactionMatcher; | ||||
| use FireflyIII\Transformers\AttachmentTransformer; | ||||
| use FireflyIII\Transformers\BillTransformer; | ||||
| use Illuminate\Contracts\View\Factory; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Http\Request; | ||||
| use Illuminate\Routing\Redirector; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\View\View; | ||||
| use League\Fractal\Manager; | ||||
| use League\Fractal\Resource\Item; | ||||
| use League\Fractal\Serializer\DataArraySerializer; | ||||
| use Symfony\Component\HttpFoundation\ParameterBag; | ||||
|  | ||||
| /** | ||||
|  * Class ShowController | ||||
|  */ | ||||
| class ShowController extends Controller | ||||
| { | ||||
|     private BillRepositoryInterface $repository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         app('view')->share('showBudget', true); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->repository = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|     /** | ||||
|      * Rescan bills for transactions. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @return RedirectResponse|Redirector | ||||
|      */ | ||||
|     public function rescan(Request $request, Bill $bill) | ||||
|     { | ||||
|         $total = 0; | ||||
|         if (false === $bill->active) { | ||||
|             $request->session()->flash('warning', (string) trans('firefly.cannot_scan_inactive_bill')); | ||||
|  | ||||
|             return redirect(route('bills.show', [$bill->id])); | ||||
|         } | ||||
|         $set = new Collection; | ||||
|         if (true === $bill->active) { | ||||
|             $set   = $this->repository->getRulesForBill($bill); | ||||
|             $total = 0; | ||||
|         } | ||||
|         if (0 === $set->count()) { | ||||
|             $request->session()->flash('error', (string) trans('firefly.no_rules_for_bill')); | ||||
|  | ||||
|             return redirect(route('bills.show', [$bill->id])); | ||||
|         } | ||||
|  | ||||
|         // unlink all journals: | ||||
|         $this->repository->unlinkAll($bill); | ||||
|  | ||||
|         foreach ($set as $rule) { | ||||
|             // simply fire off all rules? | ||||
|             /** @var TransactionMatcher $matcher */ | ||||
|             $matcher = app(TransactionMatcher::class); | ||||
|             $matcher->setSearchLimit(100000); // large upper limit | ||||
|             $matcher->setTriggeredLimit(100000); // large upper limit | ||||
|             $matcher->setRule($rule); | ||||
|             $matchingTransactions = $matcher->findTransactionsByRule(); | ||||
|             $total                += count($matchingTransactions); | ||||
|             $this->repository->linkCollectionToBill($bill, $matchingTransactions); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total)); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         return redirect(route('bills.show', [$bill->id])); | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Show a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function show(Request $request, Bill $bill) | ||||
|     { | ||||
|         // add info about rules: | ||||
|         $rules    = $this->repository->getRulesForBill($bill); | ||||
|         $subTitle = $bill->name; | ||||
|         /** @var Carbon $start */ | ||||
|         $start = session('start'); | ||||
|         /** @var Carbon $end */ | ||||
|         $end            = session('end'); | ||||
|         $year           = $start->year; | ||||
|         $page           = (int) $request->get('page'); | ||||
|         $pageSize       = (int) app('preferences')->get('listPageSize', 50)->data; | ||||
|         $yearAverage    = $this->repository->getYearAverage($bill, $start); | ||||
|         $overallAverage = $this->repository->getOverallAverage($bill); | ||||
|         $manager        = new Manager(); | ||||
|         $manager->setSerializer(new DataArraySerializer()); | ||||
|         $manager->parseIncludes(['attachments', 'notes']); | ||||
|  | ||||
|         // Make a resource out of the data and | ||||
|         $parameters = new ParameterBag(); | ||||
|         $parameters->set('start', $start); | ||||
|         $parameters->set('end', $end); | ||||
|  | ||||
|         /** @var BillTransformer $transformer */ | ||||
|         $transformer = app(BillTransformer::class); | ||||
|         $transformer->setParameters($parameters); | ||||
|  | ||||
|         $resource                   = new Item($bill, $transformer, 'bill'); | ||||
|         $object                     = $manager->createData($resource)->toArray(); | ||||
|         $object['data']['currency'] = $bill->transactionCurrency; | ||||
|  | ||||
|         /** @var GroupCollectorInterface $collector */ | ||||
|         $collector = app(GroupCollectorInterface::class); | ||||
|         $collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation() | ||||
|                   ->withCategoryInformation()->withAccountInformation(); | ||||
|         $groups = $collector->getPaginatedGroups(); | ||||
|         $groups->setPath(route('bills.show', [$bill->id])); | ||||
|  | ||||
|         // transform any attachments as well. | ||||
|         $collection  = $this->repository->getAttachments($bill); | ||||
|         $attachments = new Collection; | ||||
|  | ||||
|         // @codeCoverageIgnoreStart | ||||
|         if ($collection->count() > 0) { | ||||
|             /** @var AttachmentTransformer $transformer */ | ||||
|             $transformer = app(AttachmentTransformer::class); | ||||
|             $attachments = $collection->each( | ||||
|                 static function (Attachment $attachment) use ($transformer) { | ||||
|                     return $transformer->transform($attachment); | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // @codeCoverageIgnoreEnd | ||||
|  | ||||
|  | ||||
|         return view('bills.show', compact('attachments', 'groups', 'rules', 'yearAverage', 'overallAverage', 'year', 'object', 'bill', 'subTitle')); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -1,483 +0,0 @@ | ||||
| <?php | ||||
| /** | ||||
|  * BillController.php | ||||
|  * Copyright (c) 2019 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Controllers; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Exceptions\FireflyException; | ||||
| use FireflyIII\Helpers\Attachments\AttachmentHelperInterface; | ||||
| use FireflyIII\Helpers\Collector\GroupCollectorInterface; | ||||
| use FireflyIII\Http\Requests\BillFormRequest; | ||||
| use FireflyIII\Models\Attachment; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use FireflyIII\TransactionRules\TransactionMatcher; | ||||
| use FireflyIII\Transformers\AttachmentTransformer; | ||||
| use FireflyIII\Transformers\BillTransformer; | ||||
| use Illuminate\Contracts\View\Factory; | ||||
| use Illuminate\Http\RedirectResponse; | ||||
| use Illuminate\Http\Request; | ||||
| use Illuminate\Routing\Redirector; | ||||
| use Illuminate\Support\Collection; | ||||
| use Illuminate\View\View; | ||||
| use League\Fractal\Manager; | ||||
| use League\Fractal\Resource\Item; | ||||
| use League\Fractal\Serializer\DataArraySerializer; | ||||
| use Log; | ||||
| use Symfony\Component\HttpFoundation\ParameterBag; | ||||
|  | ||||
| /** | ||||
|  * Class BillController. | ||||
|  * | ||||
|  */ | ||||
| class BillController extends Controller | ||||
| { | ||||
|     /** @var AttachmentHelperInterface Helper for attachments. */ | ||||
|     private $attachments; | ||||
|     /** @var BillRepositoryInterface Bill repository */ | ||||
|     private $billRepository; | ||||
|  | ||||
|     /** | ||||
|      * BillController constructor. | ||||
|      * | ||||
|      * @codeCoverageIgnore | ||||
|      */ | ||||
|     public function __construct() | ||||
|     { | ||||
|         parent::__construct(); | ||||
|  | ||||
|         app('view')->share('showBudget', true); | ||||
|  | ||||
|         $this->middleware( | ||||
|             function ($request, $next) { | ||||
|                 app('view')->share('title', (string) trans('firefly.bills')); | ||||
|                 app('view')->share('mainTitleIcon', 'fa-calendar-o'); | ||||
|                 $this->attachments    = app(AttachmentHelperInterface::class); | ||||
|                 $this->billRepository = app(BillRepositoryInterface::class); | ||||
|  | ||||
|                 return $next($request); | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Create a new bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function create(Request $request) | ||||
|     { | ||||
|         $periods = []; | ||||
|         /** @var array $billPeriods */ | ||||
|         $billPeriods = config('firefly.bill_periods'); | ||||
|         foreach ($billPeriods as $current) { | ||||
|             $periods[$current] = strtolower((string) trans('firefly.repeat_freq_' . $current)); | ||||
|         } | ||||
|         $subTitle        = (string) trans('firefly.create_new_bill'); | ||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); | ||||
|  | ||||
|         // put previous url in session if not redirect from store (not "create another"). | ||||
|         if (true !== session('bills.create.fromStore')) { | ||||
|             $this->rememberPreviousUri('bills.create.uri'); | ||||
|         } | ||||
|         $request->session()->forget('bills.create.fromStore'); | ||||
|  | ||||
|         return view('bills.create', compact('periods', 'subTitle', 'defaultCurrency')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Delete a bill. | ||||
|      * | ||||
|      * @param Bill $bill | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function delete(Bill $bill) | ||||
|     { | ||||
|         // put previous url in session | ||||
|         $this->rememberPreviousUri('bills.delete.uri'); | ||||
|         $subTitle = (string) trans('firefly.delete_bill', ['name' => $bill->name]); | ||||
|  | ||||
|         return view('bills.delete', compact('bill', 'subTitle')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Destroy a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return RedirectResponse|Redirector | ||||
|      */ | ||||
|     public function destroy(Request $request, Bill $bill) | ||||
|     { | ||||
|         $name = $bill->name; | ||||
|         $this->billRepository->destroy($bill); | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans('firefly.deleted_bill', ['name' => $name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         return redirect($this->getPreviousUri('bills.delete.uri')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Edit a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function edit(Request $request, Bill $bill) | ||||
|     { | ||||
|         $periods = []; | ||||
|         /** @var array $billPeriods */ | ||||
|         $billPeriods = config('firefly.bill_periods'); | ||||
|  | ||||
|         foreach ($billPeriods as $current) { | ||||
|             $periods[$current] = (string) trans('firefly.' . $current); | ||||
|         } | ||||
|  | ||||
|         $subTitle = (string) trans('firefly.edit_bill', ['name' => $bill->name]); | ||||
|  | ||||
|         // put previous url in session if not redirect from store (not "return_to_edit"). | ||||
|         if (true !== session('bills.edit.fromUpdate')) { | ||||
|             $this->rememberPreviousUri('bills.edit.uri'); | ||||
|         } | ||||
|  | ||||
|         $currency         = app('amount')->getDefaultCurrency(); | ||||
|         $bill->amount_min = round((float) $bill->amount_min, $currency->decimal_places); | ||||
|         $bill->amount_max = round((float) $bill->amount_max, $currency->decimal_places); | ||||
|         $rules            = $this->billRepository->getRulesForBill($bill); | ||||
|         $defaultCurrency  = app('amount')->getDefaultCurrency(); | ||||
|  | ||||
|         // code to handle active-checkboxes | ||||
|         $hasOldInput = null !== $request->old('_token'); | ||||
|  | ||||
|         $preFilled = [ | ||||
|             'notes'                   => $this->billRepository->getNoteText($bill), | ||||
|             'transaction_currency_id' => $bill->transaction_currency_id, | ||||
|             'active'                  => $hasOldInput ? (bool) $request->old('active') : $bill->active, | ||||
|         ]; | ||||
|  | ||||
|         $request->session()->flash('preFilled', $preFilled); | ||||
|         $request->session()->forget('bills.edit.fromUpdate'); | ||||
|  | ||||
|         return view('bills.edit', compact('subTitle', 'periods', 'rules', 'bill', 'defaultCurrency', 'preFilled')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show all bills. | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function index() | ||||
|     { | ||||
|         $start           = session('start'); | ||||
|         $end             = session('end'); | ||||
|         $unfiltered      = $this->billRepository->getBills(); | ||||
|  | ||||
|         $defaultCurrency = app('amount')->getDefaultCurrency(); | ||||
|         $parameters      = new ParameterBag(); | ||||
|         $parameters->set('start', $start); | ||||
|         $parameters->set('end', $end); | ||||
|  | ||||
|         /** @var BillTransformer $transformer */ | ||||
|         $transformer = app(BillTransformer::class); | ||||
|         $transformer->setParameters($parameters); | ||||
|  | ||||
|         /** @var Collection $bills */ | ||||
|         $bills = $unfiltered->map( | ||||
|             function (Bill $bill) use ($transformer, $defaultCurrency) { | ||||
|                 $return                             = $transformer->transform($bill); | ||||
|                 $nextExpectedMatch                  = new Carbon($return['next_expected_match']); | ||||
|                 $return['next_expected_match_diff'] = $nextExpectedMatch->isToday() | ||||
|                     ? trans('firefly.today') | ||||
|                     : $nextExpectedMatch->diffForHumans( | ||||
|                         today(), Carbon::DIFF_RELATIVE_TO_NOW | ||||
|                     ); | ||||
|                 $currency                           = $bill->transactionCurrency ?? $defaultCurrency; | ||||
|                 $return['currency_id']              = $currency->id; | ||||
|                 $return['currency_name']            = $currency->name; | ||||
|                 $return['currency_symbol']          = $currency->symbol; | ||||
|                 $return['currency_code']            = $currency->code; | ||||
|                 $return['currency_decimal_places']  = $currency->decimal_places; | ||||
|                 $return['attachments']              = $this->billRepository->getAttachments($bill); | ||||
|  | ||||
|                 return $return; | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         // add info about rules: | ||||
|         $rules = $this->billRepository->getRulesForBills($unfiltered); | ||||
|         $bills = $bills->map( | ||||
|             static function (array $bill) use ($rules) { | ||||
|                 $bill['rules'] = $rules[$bill['id']] ?? []; | ||||
|  | ||||
|                 return $bill; | ||||
|             } | ||||
|         ); | ||||
|  | ||||
|         // summarise per currency: | ||||
|         $sums = $this->getSums($bills); | ||||
|  | ||||
|         return view('bills.index', compact('bills', 'sums')); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Rescan bills for transactions. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @throws FireflyException | ||||
|      * @return RedirectResponse|Redirector | ||||
|      */ | ||||
|     public function rescan(Request $request, Bill $bill) | ||||
|     { | ||||
|         $total = 0; | ||||
|         if (false === $bill->active) { | ||||
|             $request->session()->flash('warning', (string) trans('firefly.cannot_scan_inactive_bill')); | ||||
|  | ||||
|             return redirect(route('bills.show', [$bill->id])); | ||||
|         } | ||||
|         $set = new Collection; | ||||
|         if (true === $bill->active) { | ||||
|             $set   = $this->billRepository->getRulesForBill($bill); | ||||
|             $total = 0; | ||||
|         } | ||||
|         if (0 === $set->count()) { | ||||
|             $request->session()->flash('error', (string) trans('firefly.no_rules_for_bill')); | ||||
|  | ||||
|             return redirect(route('bills.show', [$bill->id])); | ||||
|         } | ||||
|  | ||||
|         // unlink all journals: | ||||
|         $this->billRepository->unlinkAll($bill); | ||||
|  | ||||
|         foreach ($set as $rule) { | ||||
|             // simply fire off all rules? | ||||
|             /** @var TransactionMatcher $matcher */ | ||||
|             $matcher = app(TransactionMatcher::class); | ||||
|             $matcher->setSearchLimit(100000); // large upper limit | ||||
|             $matcher->setTriggeredLimit(100000); // large upper limit | ||||
|             $matcher->setRule($rule); | ||||
|             $matchingTransactions = $matcher->findTransactionsByRule(); | ||||
|             $total                += count($matchingTransactions); | ||||
|             $this->billRepository->linkCollectionToBill($bill, $matchingTransactions); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans_choice('firefly.rescanned_bill', $total)); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         return redirect(route('bills.show', [$bill->id])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Show a bill. | ||||
|      * | ||||
|      * @param Request $request | ||||
|      * @param Bill    $bill | ||||
|      * | ||||
|      * @return Factory|View | ||||
|      */ | ||||
|     public function show(Request $request, Bill $bill) | ||||
|     { | ||||
|         // add info about rules: | ||||
|         $rules    = $this->billRepository->getRulesForBill($bill); | ||||
|         $subTitle = $bill->name; | ||||
|         /** @var Carbon $start */ | ||||
|         $start = session('start'); | ||||
|         /** @var Carbon $end */ | ||||
|         $end            = session('end'); | ||||
|         $year           = $start->year; | ||||
|         $page           = (int) $request->get('page'); | ||||
|         $pageSize       = (int) app('preferences')->get('listPageSize', 50)->data; | ||||
|         $yearAverage    = $this->billRepository->getYearAverage($bill, $start); | ||||
|         $overallAverage = $this->billRepository->getOverallAverage($bill); | ||||
|         $manager        = new Manager(); | ||||
|         $manager->setSerializer(new DataArraySerializer()); | ||||
|         $manager->parseIncludes(['attachments', 'notes']); | ||||
|  | ||||
|         // Make a resource out of the data and | ||||
|         $parameters = new ParameterBag(); | ||||
|         $parameters->set('start', $start); | ||||
|         $parameters->set('end', $end); | ||||
|  | ||||
|         /** @var BillTransformer $transformer */ | ||||
|         $transformer = app(BillTransformer::class); | ||||
|         $transformer->setParameters($parameters); | ||||
|  | ||||
|         $resource                   = new Item($bill, $transformer, 'bill'); | ||||
|         $object                     = $manager->createData($resource)->toArray(); | ||||
|         $object['data']['currency'] = $bill->transactionCurrency; | ||||
|  | ||||
|         /** @var GroupCollectorInterface $collector */ | ||||
|         $collector = app(GroupCollectorInterface::class); | ||||
|         $collector->setBill($bill)->setLimit($pageSize)->setPage($page)->withBudgetInformation() | ||||
|                   ->withCategoryInformation()->withAccountInformation(); | ||||
|         $groups = $collector->getPaginatedGroups(); | ||||
|         $groups->setPath(route('bills.show', [$bill->id])); | ||||
|  | ||||
|         // transform any attachments as well. | ||||
|         $collection  = $this->billRepository->getAttachments($bill); | ||||
|         $attachments = new Collection; | ||||
|  | ||||
|         // @codeCoverageIgnoreStart | ||||
|         if ($collection->count() > 0) { | ||||
|             /** @var AttachmentTransformer $transformer */ | ||||
|             $transformer = app(AttachmentTransformer::class); | ||||
|             $attachments = $collection->each( | ||||
|                 static function (Attachment $attachment) use ($transformer) { | ||||
|                     return $transformer->transform($attachment); | ||||
|                 } | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // @codeCoverageIgnoreEnd | ||||
|  | ||||
|  | ||||
|         return view('bills.show', compact('attachments', 'groups', 'rules', 'yearAverage', 'overallAverage', 'year', 'object', 'bill', 'subTitle')); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /** | ||||
|      * Store a new bill. | ||||
|      * | ||||
|      * @param BillFormRequest $request | ||||
|      * | ||||
|      * @return RedirectResponse | ||||
|      * | ||||
|      */ | ||||
|     public function store(BillFormRequest $request): RedirectResponse | ||||
|     { | ||||
|         $billData           = $request->getBillData(); | ||||
|         $billData['active'] = true; | ||||
|         try { | ||||
|             $bill = $this->billRepository->store($billData); | ||||
|         } catch (FireflyException $e) { | ||||
|             Log::error($e->getMessage()); | ||||
|             $request->session()->flash('error', (string) trans('firefly.bill_store_error')); | ||||
|  | ||||
|             return redirect(route('bills.create'))->withInput(); | ||||
|         } | ||||
|         $request->session()->flash('success', (string) trans('firefly.stored_new_bill', ['name' => $bill->name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         /** @var array $files */ | ||||
|         $files = $request->hasFile('attachments') ? $request->file('attachments') : null; | ||||
|         if (null !== $files && !auth()->user()->hasRole('demo')) { | ||||
|             $this->attachments->saveAttachmentsForModel($bill, $files); | ||||
|         } | ||||
|         if (null !== $files && auth()->user()->hasRole('demo')) { | ||||
|             session()->flash('info',(string)trans('firefly.no_att_demo_user')); | ||||
|         } | ||||
|  | ||||
|         if (count($this->attachments->getMessages()->get('attachments')) > 0) { | ||||
|             $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore | ||||
|         } | ||||
|  | ||||
|         return redirect(route('rules.create-from-bill', [$bill->id])); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Update a bill. | ||||
|      * | ||||
|      * @param BillFormRequest $request | ||||
|      * @param Bill            $bill | ||||
|      * | ||||
|      * @return RedirectResponse | ||||
|      */ | ||||
|     public function update(BillFormRequest $request, Bill $bill): RedirectResponse | ||||
|     { | ||||
|         $billData = $request->getBillData(); | ||||
|         $bill     = $this->billRepository->update($bill, $billData); | ||||
|  | ||||
|         $request->session()->flash('success', (string) trans('firefly.updated_bill', ['name' => $bill->name])); | ||||
|         app('preferences')->mark(); | ||||
|  | ||||
|         /** @var array $files */ | ||||
|         $files = $request->hasFile('attachments') ? $request->file('attachments') : null; | ||||
|         if (null !== $files && !auth()->user()->hasRole('demo')) { | ||||
|             $this->attachments->saveAttachmentsForModel($bill, $files); | ||||
|         } | ||||
|         if (null !== $files && auth()->user()->hasRole('demo')) { | ||||
|             session()->flash('info',(string)trans('firefly.no_att_demo_user')); | ||||
|         } | ||||
|  | ||||
|         // flash messages | ||||
|         if (count($this->attachments->getMessages()->get('attachments')) > 0) { | ||||
|             $request->session()->flash('info', $this->attachments->getMessages()->get('attachments')); // @codeCoverageIgnore | ||||
|         } | ||||
|         $redirect = redirect($this->getPreviousUri('bills.edit.uri')); | ||||
|  | ||||
|         if (1 === (int) $request->get('return_to_edit')) { | ||||
|             // @codeCoverageIgnoreStart | ||||
|             $request->session()->put('bills.edit.fromUpdate', true); | ||||
|  | ||||
|             $redirect = redirect(route('bills.edit', [$bill->id]))->withInput(['return_to_edit' => 1]); | ||||
|             // @codeCoverageIgnoreEnd | ||||
|         } | ||||
|  | ||||
|         return $redirect; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @param Collection $bills | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     private function getSums(Collection $bills): array | ||||
|     { | ||||
|         $sums = []; | ||||
|  | ||||
|         /** @var array $bill */ | ||||
|         foreach ($bills as $bill) { | ||||
|             if (false === $bill['active']) { | ||||
|                 continue; | ||||
|             } | ||||
|             if (0 === count($bill['pay_dates'])) { | ||||
|                 continue; | ||||
|             } | ||||
|             /** @var TransactionCurrency $currency */ | ||||
|             $currencyId        = $bill['currency_id']; | ||||
|             $sums[$currencyId] = $sums[$currencyId] ?? [ | ||||
|                     'currency_id'             => $currencyId, | ||||
|                     'currency_code'           => $bill['currency_code'], | ||||
|                     'currency_name'           => $bill['currency_name'], | ||||
|                     'currency_symbol'         => $bill['currency_symbol'], | ||||
|                     'currency_decimal_places' => $bill['currency_decimal_places'], | ||||
|                     'avg'                     => '0', | ||||
|                 ]; | ||||
|  | ||||
|             $avg                      = bcdiv(bcadd((string) $bill['amount_min'], (string) $bill['amount_max']), '2'); | ||||
|             $avg                      = bcmul($avg, (string) count($bill['pay_dates'])); | ||||
|             $sums[$currencyId]['avg'] = bcadd($sums[$currencyId]['avg'], $avg); | ||||
|         } | ||||
|  | ||||
|         return $sums; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										81
									
								
								app/Http/Requests/BillStoreRequest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								app/Http/Requests/BillStoreRequest.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | ||||
| <?php | ||||
| /** | ||||
|  * BillStoreRequest.php | ||||
|  * Copyright (c) 2019 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
|  * | ||||
|  * This program is free software: you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU Affero General Public License as | ||||
|  * published by the Free Software Foundation, either version 3 of the | ||||
|  * License, or (at your option) any later version. | ||||
|  * | ||||
|  * This program 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 Affero General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Affero General Public License | ||||
|  * along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
|  */ | ||||
| declare(strict_types=1); | ||||
|  | ||||
| namespace FireflyIII\Http\Requests; | ||||
|  | ||||
| /** | ||||
|  * Class BillStoreRequest. | ||||
|  */ | ||||
| class BillStoreRequest extends Request | ||||
| { | ||||
|     /** | ||||
|      * Verify the request. | ||||
|      * | ||||
|      * @return bool | ||||
|      */ | ||||
|     public function authorize(): bool | ||||
|     { | ||||
|         // Only allow logged in users | ||||
|         return auth()->check(); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Returns the data required by the controller. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function getBillData(): array | ||||
|     { | ||||
|         return [ | ||||
|             'name'          => $this->string('name'), | ||||
|             'amount_min'    => $this->string('amount_min'), | ||||
|             'currency_id'   => $this->integer('transaction_currency_id'), | ||||
|             'currency_code' => '', | ||||
|             'amount_max'    => $this->string('amount_max'), | ||||
|             'date'          => $this->date('date'), | ||||
|             'repeat_freq'   => $this->string('repeat_freq'), | ||||
|             'skip'          => $this->integer('skip'), | ||||
|             'notes'         => $this->nlString('notes'), | ||||
|             'active'        => $this->boolean('active'), | ||||
|             'object_group'  => $this->string('object_group'), | ||||
|         ]; | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Rules for this request. | ||||
|      * | ||||
|      * @return array | ||||
|      */ | ||||
|     public function rules(): array | ||||
|     { | ||||
|         return [ | ||||
|             'name'                    => 'required|between:1,255|uniqueObjectForUser:bills,name', | ||||
|             'amount_min'              => 'required|numeric|more:0|max:1000000000', | ||||
|             'amount_max'              => 'required|numeric|more:0|max:1000000000', | ||||
|             'transaction_currency_id' => 'required|exists:transaction_currencies,id', | ||||
|             'date'                    => 'required|date', | ||||
|             'repeat_freq'             => 'required|in:weekly,monthly,quarterly,half-year,yearly', | ||||
|             'skip'                    => 'required|between:0,31', | ||||
|             'active'                  => 'boolean', | ||||
|         ]; | ||||
|     } | ||||
| } | ||||
| @@ -1,6 +1,6 @@ | ||||
| <?php | ||||
| /** | ||||
|  * BillFormRequest.php | ||||
|  * BillUpdateRequest.php | ||||
|  * Copyright (c) 2019 james@firefly-iii.org | ||||
|  * | ||||
|  * This file is part of Firefly III (https://github.com/firefly-iii). | ||||
| @@ -25,9 +25,9 @@ namespace FireflyIII\Http\Requests; | ||||
| use FireflyIII\Models\Bill; | ||||
| 
 | ||||
| /** | ||||
|  * Class BillFormRequest. | ||||
|  * Class BillUpdateRequest. | ||||
|  */ | ||||
| class BillFormRequest extends Request | ||||
| class BillUpdateRequest extends Request | ||||
| { | ||||
|     /** | ||||
|      * Verify the request. | ||||
| @@ -58,6 +58,7 @@ class BillFormRequest extends Request | ||||
|             'skip'          => $this->integer('skip'), | ||||
|             'notes'         => $this->nlString('notes'), | ||||
|             'active'        => $this->boolean('active'), | ||||
|             'object_group'  => $this->string('object_group'), | ||||
|         ]; | ||||
|     } | ||||
| 
 | ||||
| @@ -68,15 +69,11 @@ class BillFormRequest extends Request | ||||
|      */ | ||||
|     public function rules(): array | ||||
|     { | ||||
|         $nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name'; | ||||
|         /** @var Bill $bill */ | ||||
|         $bill = $this->route()->parameter('bill'); | ||||
|         if (null !== $bill) { | ||||
|             $nameRule = 'required|between:1,255|uniqueObjectForUser:bills,name,' . $bill->id; | ||||
|         } | ||||
|         // is OK
 | ||||
|         $rules = [ | ||||
|             'name'                    => $nameRule, | ||||
| 
 | ||||
|         return [ | ||||
|             'name'                    => sprintf('required|between:1,255|uniqueObjectForUser:bills,name,%d', $bill->id), | ||||
|             'amount_min'              => 'required|numeric|more:0|max:1000000000', | ||||
|             'amount_max'              => 'required|numeric|more:0|max:1000000000', | ||||
|             'transaction_currency_id' => 'required|exists:transaction_currencies,id', | ||||
| @@ -85,7 +82,5 @@ class BillFormRequest extends Request | ||||
|             'skip'                    => 'required|between:0,31', | ||||
|             'active'                  => 'boolean', | ||||
|         ]; | ||||
| 
 | ||||
|         return $rules; | ||||
|     } | ||||
| } | ||||
| @@ -161,6 +161,14 @@ class Bill extends Model | ||||
|         return $this->morphMany(Note::class, 'noteable'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Get all of the tags for the post. | ||||
|      */ | ||||
|     public function objectGroups() | ||||
|     { | ||||
|         return $this->morphToMany(ObjectGroup::class, 'object_groupable'); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * @codeCoverageIgnore | ||||
|      * | ||||
|   | ||||
| @@ -29,6 +29,7 @@ use FireflyIII\Models\Rule; | ||||
| use FireflyIII\Models\RuleTrigger; | ||||
| use FireflyIII\Models\TransactionCurrency; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use FireflyIII\Repositories\ObjectGroup\CreatesObjectGroups; | ||||
| use FireflyIII\Services\Internal\Support\BillServiceTrait; | ||||
| use Illuminate\Support\Collection; | ||||
| use Log; | ||||
| @@ -39,7 +40,9 @@ use Log; | ||||
|  */ | ||||
| class BillUpdateService | ||||
| { | ||||
|     use BillServiceTrait; | ||||
|     use BillServiceTrait, CreatesObjectGroups; | ||||
|  | ||||
|     protected $user; | ||||
|  | ||||
|     /** | ||||
|      * Constructor. | ||||
| @@ -59,6 +62,7 @@ class BillUpdateService | ||||
|      */ | ||||
|     public function update(Bill $bill, array $data): Bill | ||||
|     { | ||||
|         $this->user = $bill->user; | ||||
|         /** @var TransactionCurrencyFactory $factory */ | ||||
|         $factory = app(TransactionCurrencyFactory::class); | ||||
|         /** @var TransactionCurrency $currency */ | ||||
| @@ -103,6 +107,25 @@ class BillUpdateService | ||||
|         $this->updateBillActions($bill, $oldData['name'], $data['name']); | ||||
|         $this->updateBillTriggers($bill, $oldData, $data); | ||||
|  | ||||
|         // update using name: | ||||
|         $objectGroupTitle = $data['object_group'] ?? ''; | ||||
|         if ('' !== $objectGroupTitle) { | ||||
|             $objectGroup = $this->findOrCreateObjectGroup($objectGroupTitle); | ||||
|             if (null !== $objectGroup) { | ||||
|                 $bill->objectGroups()->sync([$objectGroup->id]); | ||||
|                 $bill->save(); | ||||
|             } | ||||
|         } | ||||
|         // try also with ID: | ||||
|         $objectGroupId = (int) ($data['object_group_id'] ?? 0); | ||||
|         if (0 !== $objectGroupId) { | ||||
|             $objectGroup = $this->findObjectGroupById($objectGroupId); | ||||
|             if (null !== $objectGroup) { | ||||
|                 $bill->objectGroups()->sync([$objectGroup->id]); | ||||
|                 $bill->save(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return $bill; | ||||
|     } | ||||
|  | ||||
|   | ||||
| @@ -25,6 +25,7 @@ namespace FireflyIII\Transformers; | ||||
|  | ||||
| use Carbon\Carbon; | ||||
| use FireflyIII\Models\Bill; | ||||
| use FireflyIII\Models\ObjectGroup; | ||||
| use FireflyIII\Models\TransactionJournal; | ||||
| use FireflyIII\Repositories\Bill\BillRepositoryInterface; | ||||
| use Illuminate\Support\Collection; | ||||
| @@ -67,6 +68,18 @@ class BillTransformer extends AbstractTransformer | ||||
|         $notes    = $this->repository->getNoteText($bill); | ||||
|         $notes    = '' === $notes ? null : $notes; | ||||
|         $this->repository->setUser($bill->user); | ||||
|  | ||||
|         $objectGroupId    = null; | ||||
|         $objectGroupOrder = null; | ||||
|         $objectGroupTitle = null; | ||||
|         /** @var ObjectGroup $objectGroup */ | ||||
|         $objectGroup = $bill->objectGroups->first(); | ||||
|         if (null !== $objectGroup) { | ||||
|             $objectGroupId    = (int) $objectGroup->id; | ||||
|             $objectGroupOrder = (int) $objectGroup->order; | ||||
|             $objectGroupTitle = $objectGroup->title; | ||||
|         } | ||||
|  | ||||
|         $data = [ | ||||
|             'id'                      => (int)$bill->id, | ||||
|             'created_at'              => $bill->created_at->toAtomString(), | ||||
| @@ -86,6 +99,9 @@ class BillTransformer extends AbstractTransformer | ||||
|             'next_expected_match'     => $paidData['next_expected_match'], | ||||
|             'pay_dates'               => $payDates, | ||||
|             'paid_dates'              => $paidData['paid_dates'], | ||||
|             'object_group_id'         => $objectGroupId, | ||||
|             'object_group_order'      => $objectGroupOrder, | ||||
|             'object_group_title'      => $objectGroupTitle, | ||||
|             'links'                   => [ | ||||
|                 [ | ||||
|                     'rel' => 'self', | ||||
|   | ||||
| @@ -35,6 +35,7 @@ | ||||
|                         {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} | ||||
|                         {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} | ||||
|                         {{ ExpandedForm.integer('skip',0) }} | ||||
|                         {{ ExpandedForm.objectGroup() }} | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
| @@ -72,4 +73,8 @@ | ||||
|     <script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/lib/jquery-ui.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/ff/bills/create.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|  | ||||
|     {# auto complete for object groups #} | ||||
|     <script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/ff/object-groups/create-edit.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -41,6 +41,7 @@ | ||||
|                     {{ ExpandedForm.textarea('notes',null,{helpText: trans('firefly.field_supports_markdown')}) }} | ||||
|                     {{ ExpandedForm.file('attachments[]', {'multiple': 'multiple','helpText': trans('firefly.upload_max_file_size', {'size': uploadSize|filesize}) }) }} | ||||
|                     {{ ExpandedForm.integer('skip') }} | ||||
|                     {{ ExpandedForm.objectGroup() }} | ||||
|                     {# only correct way to do active checkbox #} | ||||
|                     {{ ExpandedForm.checkbox('active', 1) }} | ||||
|  | ||||
| @@ -78,4 +79,8 @@ | ||||
|     <script type="text/javascript" src="v1/js/lib/modernizr-custom.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/lib/jquery-ui.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/ff/accounts/edit.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|  | ||||
|     {# auto complete for object groups #} | ||||
|     <script type="text/javascript" src="v1/js/lib/typeahead/typeahead.bundle.min.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
|     <script type="text/javascript" src="v1/js/ff/object-groups/create-edit.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| {% endblock %} | ||||
|  | ||||
| {% block content %} | ||||
|     {% if bills.count == 0 %} | ||||
|     {% if total == 0 %} | ||||
|         {% include 'partials.empty' with {objectType: 'default', type: 'bills',route: route('bills.create')} %} | ||||
|     {% else %} | ||||
| <div class="row"> | ||||
| @@ -38,7 +38,6 @@ | ||||
| {% endblock %} | ||||
|  | ||||
| {% block styles %} | ||||
|     <link href="v1/css/bootstrap-sortable.css?v={{ FF_VERSION }}" type="text/css" rel="stylesheet" media="all"> | ||||
| {% endblock %} | ||||
|  | ||||
| {% block scripts %} | ||||
| @@ -46,5 +45,4 @@ | ||||
|         var start = '2018-01-01'; | ||||
|         var end = '2018-01-31'; | ||||
|     </script> | ||||
|     <script type="text/javascript" src="v1/js/lib/bootstrap-sortable.js?v={{ FF_VERSION }}" nonce="{{ JS_NONCE }}"></script> | ||||
| {% endblock %} | ||||
|   | ||||
| @@ -1,27 +1,38 @@ | ||||
| <div style="padding-left:8px;"> | ||||
|     {{ paginator.render|raw }} | ||||
| </div> | ||||
| <table class="table table-hover sortable"> | ||||
| <table class="table table-hover"> | ||||
|     <thead> | ||||
|     <tr> | ||||
|         <th class="hidden-sm hidden-xs" data-defaultsort="disabled"> </th> | ||||
|         <th data-defaultsign="az">{{ trans('list.name') }}</th> | ||||
|         <th data-defaultsort="disabled" class="hidden-sm hidden-md hidden-xs">{{ trans('list.linked_to_rules') }}</th> | ||||
|         <th data-defaultsign="_19" style="text-align: right;">{{ trans('list.matchingAmount') }}</th> | ||||
|         <th data-defaultsign="month" class="hidden-sm hidden-xs">{{ trans('list.paid_current_period') }}</th> | ||||
|         <th data-defaultsign="month" data-dateformat="{{ madMomentJS }}" class="hidden-sm hidden-xs">{{ trans('list.next_expected_match') }}</th> | ||||
|         <th data-defaultsign="az" class="hidden-sm hidden-xs">{{ trans('list.repeat_freq') }}</th> | ||||
|         <th class="hidden-sm hidden-xs"> </th> | ||||
|         <th class="hidden-sm hidden-xs"> </th> | ||||
|         <th>{{ trans('list.name') }}</th> | ||||
|         <th class="hidden-sm hidden-md hidden-xs">{{ trans('list.linked_to_rules') }}</th> | ||||
|         <th style="text-align: right;">{{ trans('list.matchingAmount') }}</th> | ||||
|         <th class="hidden-sm hidden-xs">{{ trans('list.paid_current_period') }}</th> | ||||
|         <th class="hidden-sm hidden-xs">{{ trans('list.next_expected_match') }}</th> | ||||
|         <th class="hidden-sm hidden-xs">{{ trans('list.repeat_freq') }}</th> | ||||
|     </tr> | ||||
|     </thead> | ||||
|     <tbody> | ||||
|     {% for entry in bills %} | ||||
|     {% for objectGroupOrder, objectGroup in bills %} | ||||
|         {% if objectGroup.bills|length > 0 %} | ||||
|             <tbody class="bill-connected-list" {% if objectGroupOrder != 0 %}data-title="{{ objectGroup.object_group_title }}" {% else %}data-title=""{% endif %}> | ||||
|             <tr> | ||||
|                 <td class="hidden-sm hidden-xs"> </td> | ||||
|                 <td class="hidden-sm hidden-xs"> </td> | ||||
|                 <td colspan="6"><small>{{ objectGroup.object_group_title }}</small></td> | ||||
|             </tr> | ||||
|             {% for entry in objectGroup.bills %} | ||||
|                 <tr{% if not entry.active %} data-disablesort="true"{% endif %}> | ||||
|                     <td class="hidden-sm hidden-xs"> | ||||
|                         <i class="fa fa-fw fa-bars bill-handle"></i> | ||||
|                     </td> | ||||
|                     <td class="hidden-sm hidden-xs"> | ||||
|                         <div class="btn-group btn-group-xs edit_tr_buttons"><a href="{{ route('bills.edit',entry.id) }}" class="btn btn-default btn-xs"><i | ||||
|                                         class="fa fa-fw fa-pencil"></i></a><a href="{{ route('bills.delete',entry.id) }}" class="btn btn-danger btn-xs"><i | ||||
|                                         class="fa fa-fw fa-trash-o"></i></a></div> | ||||
|                     </td> | ||||
|             <td data-value="{{ entry.name }}"> | ||||
|                     <td> | ||||
|                         {% if not entry.active %} | ||||
|                             <i class="fa fa-fw fa-ban"></i> | ||||
|                         {% endif %} | ||||
| @@ -46,7 +57,7 @@ | ||||
|                             </ul> | ||||
|                         {% endif %} | ||||
|                     </td> | ||||
|             <td data-value="{{ entry.amount_min }}" style="text-align: right;"> | ||||
|                     <td style="text-align: right;"> | ||||
|                 <span style="margin-right:5px;" | ||||
|                       title="{{ formatAmountBySymbol(entry.amount_min, entry.currency_symbol, entry.currency_decimal_places, false)|escape }} -- {{ formatAmountBySymbol(entry.amount_max, entry.currency_symbol, entry.currency_decimal_places, false)|escape }}" | ||||
|                 > | ||||
| @@ -60,10 +71,10 @@ | ||||
|                     bill is active. | ||||
|                     #} | ||||
|                     {% if entry.paid_dates|length == 0 and entry.pay_dates|length == 0 and entry.active %} | ||||
|                 <td class="paid_in_period text-muted" data-value="0001-01-01"> | ||||
|                         <td class="paid_in_period text-muted"> | ||||
|                             {{ trans('firefly.not_expected_period') }} | ||||
|                         </td> | ||||
|                 <td class="expected_in_period hidden-sm hidden-xs" data-value="{{ entry.next_expected_match }}"> | ||||
|                         <td class="expected_in_period hidden-sm hidden-xs"> | ||||
|                             {{ formatDate(entry.next_expected_match, monthAndDayFormat) }} | ||||
|                         </td> | ||||
|                     {% endif %} | ||||
| @@ -74,10 +85,10 @@ | ||||
|                     bill is active | ||||
|                     #} | ||||
|                     {% if entry.paid_dates|length == 0 and entry.pay_dates|length > 0 and entry.active %} | ||||
|                 <td class="paid_in_period text-danger" data-value="0002-00-00"> | ||||
|                         <td class="paid_in_period text-danger"> | ||||
|                             {{ trans('firefly.bill_expected_date', {date: entry.next_expected_match_diff }) }} | ||||
|                         </td> | ||||
|                 <td class="expected_in_period hidden-sm hidden-xs" data-value="{{ entry.next_expected_match }}"> | ||||
|                         <td class="expected_in_period hidden-sm hidden-xs"> | ||||
|                             {% for date in entry.pay_dates %} | ||||
|                                 {{ formatDate(date, monthAndDayFormat) }}<br> | ||||
|                             {% endfor %} | ||||
| @@ -90,7 +101,7 @@ | ||||
|                     Don't care about pay_dates. | ||||
|                     #} | ||||
|                     {% if entry.paid_dates|length > 0 and entry.active %} | ||||
|                 <td class="paid_in_period text-success" data-value="{{ entry.paid_dates[0].date }}"> | ||||
|                         <td class="paid_in_period text-success"> | ||||
|                             {% for currentPaid in entry.paid_dates %} | ||||
|                                 <a href="{{ route('transactions.show',currentPaid.transaction_group_id) }}"> | ||||
|                                     {{ formatDate(currentPaid.date, monthAndDayFormat) }} | ||||
| @@ -98,18 +109,18 @@ | ||||
|                                 <br/> | ||||
|                             {% endfor %} | ||||
|                         </td> | ||||
|                 <td class="expected_in_period hidden-sm hidden-xs" data-value="{{ entry.next_expected_match }}"> | ||||
|                         <td class="expected_in_period hidden-sm hidden-xs"> | ||||
|                             {{ formatDate(entry.next_expected_match, monthAndDayFormat) }} | ||||
|                         </td> | ||||
|                     {% endif %} | ||||
|                     {# bill is not active #} | ||||
|                     {% if not entry.active %} | ||||
|                 <td class="paid_in_period text-muted" data-value="3000-01-01"> | ||||
|                         <td class="paid_in_period text-muted"> | ||||
|                             ~ | ||||
|                         </td> | ||||
|                 <td class="expected_in_period text-muted hidden-sm hidden-xs" data-value="3001-01-01">~</td> | ||||
|                         <td class="expected_in_period text-muted hidden-sm hidden-xs">~</td> | ||||
|                     {% endif %} | ||||
|             <td class="hidden-sm hidden-xs" data-value="{{ entry.repeat_freq }}{{ entry.skip }}"> | ||||
|                     <td class="hidden-sm hidden-xs"> | ||||
|                         {{ ('repeat_freq_'~entry.repeat_freq)|_ }} | ||||
|                         {% if entry.skip > 0 %} | ||||
|                             {{ 'skips_over'|_ }} {{ entry.skip }} | ||||
| @@ -117,22 +128,25 @@ | ||||
|                     </td> | ||||
|                 </tr> | ||||
|             {% endfor %} | ||||
|     </tbody> | ||||
|     <tfoot> | ||||
|     {% for sum in sums %} | ||||
|             {% for sum in sums[objectGroupOrder] %} | ||||
|             <tr> | ||||
|             <td style="text-align:right;" colspan="3"> | ||||
|                 {{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'active_exp_bills_only'|_ }})<br /> | ||||
|                 <td class="hidden-sm hidden-xs"> </td> <!-- handle --> | ||||
|                 <td class="hidden-sm hidden-xs"> </td> <!-- buttons --> | ||||
|                 <td colspan="2" style="text-align: right;"> <!-- title --> | ||||
|                     <small>{{ 'sum'|_ }} ({{ sum.currency_name }}) ({{ 'active_exp_bills_only'|_ }})</small> | ||||
|                 </td> | ||||
|             <td style="text-align:right;" colspan="1"> | ||||
|             <span style="margin-right:5px;"> | ||||
|                 <td style="text-align: right;"> <!-- amount --> | ||||
|                         {{ formatAmountBySymbol(sum.avg, sum.currency_symbol, sum.currency_decimal_places) }} | ||||
|             </span> | ||||
|                 </td> | ||||
|             <td colspan="6"> </td> | ||||
|                 <td> </td> <!-- paid in period --> | ||||
|                 <td class="hidden-sm hidden-xs"> </td> <!-- next expected match --> | ||||
|                 <td class="hidden-sm hidden-xs"> </td><!-- repeats --> | ||||
|             </tr> | ||||
|             {% endfor %} | ||||
|     </tfoot> | ||||
|             </tbody> | ||||
|         {% endif %} | ||||
|     {% endfor %} | ||||
|  | ||||
| </table> | ||||
| <div style="padding-left:8px;"> | ||||
|     {{ paginator.render|raw }} | ||||
|   | ||||
| @@ -45,6 +45,9 @@ | ||||
|                                         {% for piggyBank in objectGroup.piggyBanks %} | ||||
|                                             - {{ 'piggy_bank'|_ }}: <a href="{{ route('piggy-banks.show', [piggyBank.id]) }}">{{ piggyBank.name }}</a><br> | ||||
|                                         {% endfor %} | ||||
|                                         {% for bill in objectGroup.bills %} | ||||
|                                             - {{ 'bill'|_ }}: <a href="{{ route('bills.show', [bill.id]) }}">{{ bill.name }}</a><br> | ||||
|                                         {% endfor %} | ||||
|                                     </td> | ||||
|                                     <td> | ||||
|                                         <div class="btn-group btn-group-sm"> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user