HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/MdnDirecteur/hours.komma.cloud/app/Komma/Projects/ProjectService.php
<?php

namespace App\Komma\Projects;


use Carbon\Carbon;
use App\Komma\Messages\MessageController;
use App\Komma\ProjectWorkers\ProjectWorker;
use App\Komma\Hours\HourService;
use App\Komma\Settings\Subprojecttemplates\SubprojectTemplate;
use App\Komma\Settings\Subprojecttemplates\SubprojectTemplateService;
use App\Komma\Subprojects\Subproject;
use App\Komma\Subprojects\SubprojectService;
use App\Komma\Tasks\Task;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\View\View;

class ProjectService
{
    /**
     * @var ProjectRepository
     */
    private $projectRepository;
    private $messageController;
    private $subprojectService;
    private $hourService;
    private $subprojectTemplateService;

    public function __construct(
        ProjectRepository $projectRepository,
        MessageController $messageController,
        SubprojectService $subprojectService,
        HourService $hourService,
        SubprojectTemplateService $subprojectTemplateService
    ) {
        $this->projectRepository = $projectRepository;
        $this->messageController = $messageController;
        $this->subprojectService = $subprojectService;
        $this->hourService = $hourService;
        $this->subprojectTemplateService = $subprojectTemplateService;
    }

    public function getProject($id)
    {
        return Project::with([
            'Subprojects',
            'Subprojects.SubprojectTemplate',
            'Subprojects.TaskTemplates',
            'Subprojects.Tasks.TaskTemplate',
            'Subprojects.Tasks.Hours',
        ])->where('archived', '0')
            ->find($id);
    }

    /**
     * @param $project
     * @param $begin
     * @param $end
     * @param $user
     * @return array
     */
    public function filterProjectHours($project, $begin, $end, $user, $isShowPage)
    {
        //create empty array users
        $users = [];
        $workers = [];

        if($isShowPage) {
            //loop trough all subprojects
            foreach ($project->Subprojects as $index => $subproject) {

                // Set the relation project on the subproject, this we don't have to load is
                $subproject->setRelation('Project', $project);

                //put all workers in array
                $users[] = $this->filterSubprojectHours($subproject, $begin, $end, $user)['workers'];
            }

            //group all users
            foreach ($users as $items) {
                foreach ($items as $user => $value) {
                    $workers[$user] = 0;
                }
            }
        }

        //return
        return compact('project', 'workers');
    }


    /**
     * @param $subproject
     * @param $begin
     * @param $end
     * @param $user
     * @return array
     */
    public function filterSubprojectHours($subproject, $begin, $end, $user)
    {
        //create empty array users
        $users = [];
        $workers = [];
        //create correct begin and end date
        $begin = Carbon::parse($begin)->toDateString() . " 00:00:00";
        $end = Carbon::parse($end)->toDateString() . " 00:00:00";

        $subproject->loadMissing('Tasks', 'Tasks.Hours', 'Tasks.Hours.User');

        //loop though all tasks
        foreach ($subproject->Tasks as $task) {
            foreach ($task->Hours as $key => $hour) {
                //store all names of users in array
                $users[] = $hour->User->name;

                //check if hour date is between begin and end date
                if ($hour->date >= $begin and $hour->date <= $end) {
                    //check if user match with chosen user
                    if (!empty($user) && $hour->user->name != $user) {
                        //remove hour from collection
                        unset($task->hours[$key]);
                    }
                } else {
                    //remove hour from collection
                    unset($task->hours[$key]);
                }
            }
        }

        //group all users
        foreach ($users as $value) {
            $workers[$value] = 0;
        }

        //return
        return compact('subproject', 'workers');
    }


    /**
     * Associate relations to reduce query amount
     *
     * @param String $projectId
     * @return Project
     */
    public function eagerLoadProject($projectId)
    {
        // Fetch project with all relations
        $project = $this->projectRepository->fullProject($projectId);

        // Associate other relations to reduce query amount
        foreach ($project->Subprojects as $subproject) {
            // Add project relation to subproject
            $subproject->Project()->associate($project);

            // Loop through expenses
            foreach ($subproject->Expenses as $expense) {
                // Add subproject relation to expense
                $expense->Subproject()->associate($subproject);
            }
        }
        return $project;

    }


    /**
     * @param $project
     * @return string
     */
    public function createAllData($project)
    {
        //create empty array's
        $data_billable = [];
        $data_notBillable = [];
        $workers = [];

        //get data for graphs
        //loop trough subprojects in project
        foreach ($project->Subprojects as $subproject) {
            //loop trough tasks in subproject
            foreach ($subproject->Tasks as $task) {
                //loop trough hours of task
                foreach ($task->Hours as $hour) {
                    //create date string
                    $date = Carbon::parse($hour->date)->subMonth()->toDateString();

                    //if key not exist
                    if (!isset($data_billable[$date])) {
                        $data_billable[$date] = 0;
                    }
                    if (!isset($data_notBillable[$date])) {
                        $data_notBillable[$date] = 0;
                    }

                    //sum billable or not billeble hours
                    if ($hour->billable == 1 and $hour->exceed_subproject == 0) {
                        $data_billable[$date] += (float)$hour->value;
                    } else {
                        $data_notBillable[$date] += (float)$hour->value;
                    }

                    //if key not exist
                    if (!isset($workers[$hour->User->name])) {
                        $workers[$hour->User->name] = 0;
                    }
                    //sum hours of user
                    $workers[$hour->User->name] += (float)$hour->value;
                }
            }
        }

        //sort by date
        $data_billable = Arr::sortRecursive($data_billable);
        $data_notBillable = Arr::sortRecursive($data_notBillable);

        //get total values
        $sum_billable = array_sum($data_billable);
        $sum_not_billable = array_sum($data_notBillable);

        //create data string for graphs
        //create empty string
        $graph = "";
        //loop trough array
        foreach ($data_billable as $index => $data) {
            //create correct date
            $date = str_replace("-", ", ", $index);
            $date = str_replace("00:00:00", "", $date);
            //create graph string
            $graph = $graph . '[new Date(' . $date . '), ' . $data . ', ' . $data_notBillable[$index] . '],';
        }

        //return
        return compact('graph', 'sum_billable', 'sum_not_billable', 'workers');
    }


    /**
     * @param $action
     * @param $search
     * @return mixed
     */
    public function action($action, $search)
    {
        // get query for all projects
        $projects = $this->projectRepository->allProjects($search);

        if(!Auth::user()->isAdmin()) $projects = $this->filterExcludedUsers($projects);

        //total objects per page
        $paginate = 10;

        // Get all projects
        if ($action == "all") {

            return $projects->withTrashed()->paginate($paginate);

        } // Get all deleted projects
        elseif ($action == "deleted") {

            return $projects->onlyTrashed()->paginate($paginate);

        } // Get all projects to be processed
        elseif ($action == "toBeProcessed") {

            return $projects->where('archived', '1')->where('calculated', '0')->paginate($paginate);

        } // Get all processed projects
        elseif ($action == "processed") {

            return $projects->where('archived', '1')->where('calculated', '1')->paginate($paginate);

        } // get all without pagination
        elseif ($action == "list") {
            return $projects->where('archived', '0')->get();
        }// Get all active projects
        else {
            return $projects->where('archived', '0')->paginate($paginate);
        }


    }

    /**
     * @param $projects
     * @return array
     */
    public function getBudgetsProjects($collection)
    {
        $budgets = [];

        //loop trough projects of company
        foreach ($collection as $project) {
            //put all budgets in object array
            $budgets[] = (object)$this->getBudgets($project);
        }

        return $budgets;

    }

    /**
     * @param Project $project
     * @return array
     */
    public function getBudgets(Project $project)
    {
        $projectHours = [
            'totalBillWithBudget' => 0,
            'totalBillWithoutBudget' => 0,
            'totalNotBillWithBudget' => 0,
            'totalNotBillWithoutBudget' => 0,
            'totalExceedsSubproject' => 0,
            'totalHours' => 0,
            'totalHoursInBudget' => 0,
            'actualRate' => 0,
            'count' => 0
        ];

        $sumBudgets = 0;

        $project->loadMissing('Subprojects', 'Subprojects.Tasks');

        //loop trough subprojects of project
        foreach ($project->Subprojects as $subproject) {

            //loop trough project values
            $sumBudgets += $subproject->budget;

            // Set the relation project on the subproject, this we don't have to load is
            $subproject->setRelation('Project', $project);

            foreach ($this->subprojectService->getBudget($subproject) as $id => $value) {
                $projectHours[$id] += $value;
            }
        }

        $projectHours['actualRate'] = empty($projectHours['count']) ? 0 : $projectHours['actualRate'] / $projectHours['count'];
        $projectHours['budget'] = $project->Subprojects->sum('budget');
        $projectHours['hoursLeftInBudget'] = $projectHours['budget'] - ($projectHours['totalHoursInBudget']);

        //return
        return compact('projectHours');
    }

    /**
     * @param $project
     * @return array
     */
    public function allSubprojectHours($project)
    {
        //create empty string
        $subprojectHours = [];

        //loop trough subprojects of project
        foreach ($project->Subprojects as $subproject) {
            $subprojectHours[] = (object)$this->subprojectService->getSubProjectHours($subproject);
        }
        //return array
        return $subprojectHours;
    }


    /**
     * @param $project
     * @return number
     */
    public function sumExpenses($project)
    {
        //create empty array
        $sumExpense = [0];
        $sumNotBilled = [0];

        //loop trough subprojects of project
        foreach ($project->Subprojects as $subprojects) {
            //loop trough expenses of subproject
            foreach ($subprojects->Expenses as $expense) {
                //put expenses total in array
                $sumExpense[] = $expense->value * $expense->costs;
                if (empty($expense->billed_at) || $expense->billed_at == '0000-00-00 00:00:00') {
                    $sumNotBilled[] = $expense->value * $expense->costs;
                }
            }
        }

        //return sum array
        return ['total' => array_sum($sumExpense), 'notBilled' => array_sum($sumNotBilled)];
    }


    /**
     * @param $project
     * @return array
     */
    public function getFirstDateProject($project)
    {
        $arrays = [];
        $hours = [];
        //loop though subprojects
        foreach ($project->Subprojects as $subprojects) {
            $arrays[] = $this->getFirstDateSubproject($subprojects);
        }

        //loop though array
        foreach ($arrays as $dates) {
            //loop though array
            foreach ($dates as $date) {
                //make one array
                $hours[] = $date;
            }
        }
        usort($hours, function ($a, $b) {
            return strtotime($a) - strtotime($b);
        });

        //return all dates
        return $hours;
    }


    /**
     * @param $subprojects
     * @return array
     */
    public function getFirstDateSubproject($subprojects)
    {
        //create empty array
        $hours = [];

        //loop though tasks
        foreach ($subprojects->Tasks as $task) {
            //loop though hours
            foreach ($task->Hours as $hour) {
                //store all hour dates
                $hours[] = Carbon::parse($hour->date)->format('d-m-Y');
            }
        }

        usort($hours, function ($a, $b) {
            return strtotime($a) - strtotime($b);
        });

        //return all dates
        return $hours;
    }


    /**
     * @param $request
     * @return mixed
     */
    public function storeProject(Request $request)
    {
        $project = \DB::transaction(function () use ($request) {
            //get all subproject templates
            $subprojectTemplates = SubprojectTemplate::orderBy('name', 'asc')->get();

            //replace . with , for dashboard
            //store project
            $project = new Project();
            $project->company_id = $request->company;
            $project->project_template_id = $request->project;
            $project->name = $request->name;
            $project->hourly_rate = $request->hourlyRate;
            $project->billable = !$request->internal;
            $project->internal = $request->internal;
            $project->excluded_users = implode(",", $request->excluded_users);
            $project->reserved = isset($request->reserved) ? $request->reserved : 1;
            $project->create_every_x_months = !empty($request->monthly_project) ? 1 : null;
            $project->save();

            //make user project owner
            $projectWorker = new ProjectWorker();
            $projectWorker->project_id = $project->id;
            $projectWorker->user_id = $request->projectManager;
            $projectWorker->role_id = 1;
            $projectWorker->save();

            if(empty($request->subprojects) || count($request->subprojects) == 0) {
                abort(422, "Vul minstens 1 deelproject in!", ['pjax-error-test' => "Vul minstens 1 deelproject in!"]);
            }

            //loop trough related subprojects
            foreach ($request->subprojects as $key => $subproject) {
                if (!array_key_exists("billable",$subproject)) {
                    abort(422, "Vul de facturabelheid voor alle deelprojecten in!", ['pjax-error-test' => "Vul de facturabelheid voor alle deelprojecten in!"]);
                }
                if($project->internal == "1" && $subproject['hourlyRate'] != "0") {
                    abort(422, "Bij een intern project moeten alle uurprijzen 0 zijn!", ['pjax-error-test' => "Bij een intern project moeten alle uurprijzen 0 zijn!"]);
                }

                if($subproject['billable'] == "1" && $subproject['hourlyRate'] == "0") {
                    abort(422, "Bij een facturabel deelproject moet de uurprijs hoger zijn dan 0!", ['pjax-error-test' => "Bij een facturabel deelproject moet de uurprijs hoger zijn dan 0!"]);
                }

                if($subproject['billable'] == "0" && $subproject['hourlyRate']  != "0") {
                    abort(422, "Bij een niet-facturabel deelproject moet de uurprijs 0 zijn!", ['pjax-error-test' => "Bij een facturabel deelproject moet de uurprijs hoger zijn dan 0!"]);
                }

                //if standard template does exist
                if ($getSubproject = $subprojectTemplates->where('name',
                    $subproject['name'])->first()) { // and !empty($request->all()[str_replace(' ', '_', $subproject) . '-checkbox'])) {

                    //go to store subproject
                    $this->storeRelatedSubproject($request, $subproject, $getSubproject, $project);

                    //if not exist
                } else { //if (!empty($request->all()[str_replace(' ', '_', $subproject) . '-checkbox'])) {
                    //create standard template
                    $getSubproject = $this->createIfNotExist($subprojectTemplates);

                    //go to store subproject
                    $this->storeRelatedSubproject($request, $subproject, $getSubproject, $project);
                }
            }

            //message + activity
            $this->messageController->create("Nieuw project", Project::find($project->id));

            //return project
            return $project;
        });
        //return project
        return $project;
    }


    /**
     * @param $request
     * @param $subproject
     * @param $getSubproject
     * @param $project
     * @param null $budget
     */
    public function storeRelatedSubproject(
        Request $request = null,
        $subproject,
        $getSubproject,
        $project,
        $budget = null
    ) {

        //get budget
        if (!empty($request) && empty($budget)) {
            $budget = $subproject['budget'];
        }

        //make $request array to store subproject
        $subprojectData = ['subproject' => $getSubproject->id];
        $subprojectData += ['project' => $project->id];
        $subprojectData += ['name' => $subproject['name']];
        $subprojectData += ['budget' => $budget];
        $subprojectData += ['billable' => $subproject['billable']];
        $subprojectData += ['hourly_rate' => $subproject['hourlyRate']];
        if (array_key_exists("tasks",$subproject)) {
            $subprojectData += ['tasks' => $subproject['tasks']];
        }

        $subprojectRequest = Request::create("", "", $subprojectData);

        //go to store subproject
        $this->subprojectService->store($subprojectRequest, $request);
    }


    /**
     * @param $collection
     * @return SubprojectTemplate
     */
    public function createIfNotExist($collection)
    {
        if ($collection->where('name', "-standaard deelproject-")->first()) {
            return $collection->where('name', "-standaard deelproject-")->first();
        } else {
            $request = ['name' => "-standaard deelproject-"];
            $request += ['hourly_rate' => 70];
            $request += ['budget' => 0];
            $request += ['billable' => 1];
            $request += ['productivity' => 1];
            //make object of array
            $templateRequest = (object)$request;

            return $this->subprojectTemplateService->store($templateRequest);
        }
    }

    /**
     * @return array
     */
    public function getCountProjects()
    {
        //get all projects
        $allProjects = $this->filterExcludedUsers(Project::withTrashed()->select('deleted_at', 'archived', 'calculated'))->get();

        //count all projects
        $countAll = count($allProjects);
        //count all active projects
        $countActive = count($allProjects->where('deleted_at', null)->where('archived', 0));
        //count all projects that need to be processed
        $countToBeProcessed = count($allProjects->where('deleted_at', null)->where('archived', 1)->where('calculated', 0));
        //count all projects that have been processed
        $countProcessed = count($allProjects->where('deleted_at', null)->where('archived', 1)->where('calculated', 1));
        //count all archived projects
        $countArchived = count($allProjects->where('deleted_at', null)->where('archived', 1));
        //count all deleted projects
        $countDeleted = count($allProjects->filter(function ($project) {
            return $project->deleted_at != null;
        }));

        return compact('countAll', 'countActive', 'countToBeProcessed', 'countProcessed', 'countDeleted', 'countArchived');

    }

    /**
     * @param $project
     * @return bool
     */
    public function recalculateProject($project)
    {

        // Check if everything was billed correctly
        $weightedAverageHourlyRate = $this->weightedAverageHourlyRate($project);
        $billableBudget = $project->Subprojects->where('billable', 1)->sum('budget');
        $budgets = (object)$this->getBudgets($project);
        $sumExpense = (object)$this->sumExpenses($project);

        if( $project->billed_amount < ($weightedAverageHourlyRate*($billableBudget+$budgets->projectHours['totalBillWithoutBudget']) + $sumExpense->total) ){
            \Session::flash('message', 'Herberekenen kan niet: De gefactureerde omzet is lager dan het berekend bedrag!');
            return false;
        }

        // start the actual recalculations

        //create collections
        $exceeds = collect();
        $billsInBudget = collect();
        $billsNoBudget = collect();
        $projectbudgets = $this->getBudgets($project);

        // billable hours in a budget
        $count = $projectbudgets['projectHours']['totalBillWithBudget'];

        // sum of budgets of billable subprojects
        $budget = $billableBudget;


        //loop trough subprojects to collect the hours
        foreach ($project->Subprojects as $subproject) {
            if (!empty($subproject->budget)) {
                foreach ($subproject->Tasks as $task) {
                    foreach ($task->Hours as $hour) {

                        // Budgetoverschrijdingen
                        if ($hour->exceed_subproject == 1) {
                            $exceeds->push($hour);
                        // Bewust niet facturabel met budget
                        } elseif ($hour->billable == 0 && $hour->exceed_subproject == 0) {
                            $billsInBudget->push($hour);
                        }
                    }
                }
            } else {
                $subproject->budget = 0;

                foreach ($subproject->Tasks as $task) {
                    foreach ($task->Hours as $hour) {
                        // Bewust niet facturabel zonder budget
                        if ($hour->billable == 0 && $hour->exceed_subproject == 0) {
                            $billsNoBudget->push($hour);
                        }
                    }
                }
            }
        }

        // Op volgorde zetten zodat de oudste uren eerst worden behandeld
        $exceeds = $exceeds->sortBy('date');
        $billsInBudget = $billsInBudget->sortBy('date');
        $billsNoBudget = $billsNoBudget->sortBy('date');

        // Eerst proberen we zoveel mogelijk budgetoverschrijdingen
        // facturabel in het evt. overgebleven budget te maken
        if ($count < $budget && count($exceeds) > 0) {
            foreach ($exceeds as $hour) {
                if ($count < $budget) {

                    // Als de hoeveelheid uren ervoor zorgen dat het budget overschreden wordt
                    // moet het uur opgedeeld worden
                    if (($count + $hour->value) > $budget) {
                        // het overschrijdende deel wordt als overschrijdend opgeslagen
                        $range = $budget - $count;
                        $this->hourService->split($hour, $range, 0, 1);

                        // Het resterende deel wordt facturabel
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();

                        $count += $range;
                    } else {

                        // Er is genoeg budget, maak het uur gewoon facturabel
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();
                        $count += $hour->value;
                    }

                }
            }
        }
        // Als er nog budget over is en er zijn bewust niet-facturabele uren met budget
        // dan proberen we deze ook facturabel te maken
        if ($count < $budget && count($billsInBudget) > 0) {
            foreach ($billsInBudget as $hour) {
                if ($count < $budget) {

                    // Als de hoeveelheid uren ervoor zorgen dat het budget overschreden wordt
                    // moet het uur opgedeeld worden
                    if (($count + $hour->value) > $budget) {
                        // het overschrijdende deel wordt als overschrijdend opgeslagen
                        $range = $budget - $count;
                        $this->hourService->split($hour, $range, 0, 0);

                        // Het resterende deel wordt facturabel
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();
                        $count += $range;
                    } else {

                        // Er is genoeg budget, maak het uur gewoon facturabel
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();
                        $count += $hour->value;
                    }
                }
            }
        }

        // Als er nog budget over is en er zijn bewust niet-facturabele uren zonder budget
        // dan proberen we deze ook facturabel te maken
        if ($count < $budget && count($billsNoBudget) > 0) {

            // we need to assign these hours to a new subproject with a
            // budget so they will be included into the main budget

            // TODO: Niet meer in een apart deelproject zetten maar gewoon flippen zoals hierboven
            $availableBudget = 0;
            foreach ($project->Subprojects as $subproject) {
                if (!empty($subproject->budget) && $subproject->billable == 1) {
                    $totalHours = $this->subprojectService->getBudget($subproject)['totalHours'];
                    if ($totalHours < $subproject->budget) {
                        $availableBudget += ($subproject->budget - $totalHours);
                        $subproject->budget = $totalHours;
                        $subproject->save();
                    }
                }
            }

            $newSubproject = new Subproject();
            $newSubproject->subproject_template_id = 24;
            $newSubproject->project_id = $project->id;
            $newSubproject->name = '(Herberekend)';
            $newSubproject->budget = $availableBudget;
            $newSubproject->billable = 1;
            $newSubproject->hourly_rate = 70;
            $newSubproject->save();

            $newTask = new Task();
            $newTask->subproject_id = $newSubproject->id;
            $newTask->task_template_id = 5;
            $newTask->save();

            foreach ($billsNoBudget as $hour) {
                if ($count < $budget) {
                    if (($count + $hour->value) > $budget) {
                        $range = $budget - $count;
                        $this->hourService->split($hour, $range, 0, 0);

                        $hour->task_id = $newTask->id;
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();
                        $count += $range;
                    } else {
                        $hour->task_id = $newTask->id;
                        $hour->exceed_subproject = 0;
                        $hour->billable = 1;
                        $hour->save();
                        $count += $hour->value;
                    }
                }
            }
        }


        // Als laatste moeten alle uren die nog niet gefactureerd zijn
        // de status gefactureerd krijgen door "billed_at" op de huidige datum te zetten
        foreach ($project->Subprojects as $subproject) {
            //loop trough tasks
            foreach ($subproject->Tasks as $task) {
                //loop trough hours
                foreach ($task->Hours as $hour) {
                    if ($hour->billable == 1) {
                        $hour->billed_at = Carbon::now();
                        $hour->save();
                    }
                }
            }
        }

        return true;

    }


    /**
     *
     * TODO: comments toevoegen
     *
     * @param $project
     * @param $value
     * @param null $actualRate
     */
    public function lockHours($project, $value, $actualRate = null)
    {
        //loop trough subproject
        foreach ($project->Subprojects as $subproject) {
            //loop trough tasks
            foreach ($subproject->Tasks as $task) {
                //loop trough hours
                foreach ($task->Hours as $hour) {
                    //update hour
                    $hour->locked_at = $value;
                    $hour->actual_hourly_rate = $actualRate;
                    $hour->save();
                }
            }
            //loop trough expenses
            foreach ($subproject->Expenses as $expense) {
                //update expense
                $expense->locked_at = $value;
                $expense->save();
            }
        }
    }


    /**
     * @param $project
     * @return string
     */
    public function findNotFilledSubprojects($project)
    {
        //create empty string
        $emptySubprojects = "";

        //loop trough subproject
        foreach ($project->Subprojects as $subproject) {
            $count = [];
            //if there is a budget
            if (!empty($subproject->budget)) {
                //loop trough tasks
                foreach ($subproject->Tasks as $task) {
                    $count[] = count($task->Hours);
                }
                if (empty(array_sum($count))) {
                    $emptySubprojects = $emptySubprojects . $subproject->name . ', ';
                }
            }
        }
        return $emptySubprojects;
    }


    /**
     * @param $project
     * @return int
     */
    public function allExpensesAreBilled($project)
    {
        //loop trough subproject
        foreach ($project->Subprojects as $subproject) {
            //if there are not billed expenses
            if (!empty(count($subproject->Expenses->where('billed_at', '0000-00-00 00:00:00')))) {
                return count($subproject->Expenses->where('billed_at', '0000-00-00 00:00:00'));
            }
        }
    }

    /**
     * @param $project
     * @return bool
     */
    public function ifHasHours($project)
    {
        //loop trough subproject
        foreach ($project->Subprojects as $subproject) {
            //if there are not billed expenses
            foreach ($subproject->Tasks as $task) {
                if (!empty(count($task->Hours))) {
                    return true;
                }
            }
        }
    }

    /**
     * @param $project
     * @return bool
     */
    public function ifHasExpenses($project)
    {
        //loop trough subproject
        foreach ($project->Subprojects as $subproject) {

            // Check if there are subprojects with expenses
            if(count($subproject->Expenses) > 0) {
                return true;
            }
        }
    }

    /**
     * @param $projects
     * @return mixed
     */
    public function filterExcludedUsers($projects)
    {
        $loggedInUser = Auth::user();
        return $projects->where(function ($query) use ($loggedInUser) {
            $query->whereNull('excluded_users')->orWhere('excluded_users', 'LIKE', '%' . $loggedInUser->id . '%');
        });
    }

    /**
     * @param $request
     * @return Project
     */
    public function checkIfExist(Request $request)
    {
        $project = Project::where('name', $request->name)->where('project_template_id',
            $request->project)->where('company_id', $request->company)->first();
        return $project;
    }

    /**
     * @param $id
     * @return Collection
     */
    public function getProjectSubprojectsByID($id)
    {
        $project = $this->getProjectByID($id);
        return !empty($project) ? $project->subProjects : null;
    }

    /**
     * @param $id
     * @return Project
     */
    public function getProjectByID($id)
    {
        return Project::where('id', $id)->first();
    }

    /**
     * @param $id
     * @return View
     */
    public function getProjectProgressBarByID($id)
    {
        $getProject = $this->getProjectByID($id);
        $budgets = (object)$this->getBudgets($getProject);

        return view('partials.generalElements.progressBar', [
            'totalHoursInBudget' => $budgets->projectHours['totalHoursInBudget'],
            'hoursNoBudget' => $budgets->projectHours['totalBillWithoutBudget'] + $budgets->projectHours['totalNotBillWithoutBudget'],
            'budget' => $budgets->projectHours['budget'],
            'hoursLeftInBudget' => $budgets->projectHours['hoursLeftInBudget'],
            'barWidth' => $budgets->projectHours['budget'] > 0 ? ((100 / $budgets->projectHours['budget']) * $budgets->projectHours['totalHoursInBudget']) : 100,
        ])->render();
    }

    /**
     * @param $id
     * @param $amount
     */
    public function storeProjectBilledAmount($id, $amount)
    {
        $getProject = $this->getProjectByID($id);
        $getProject->billed_amount = $amount;
        $getProject->save();
    }

    /**
     *
     * TODO: comments toevoegen
     * @param $project
     * @return float|int
     */
    public function weightedAverageHourlyRate($project)
    {
        $sumOfBudgetsTimesHourlyRates = 0;
        $totalOfBudgets = 0;
        $weightedAverageHourlyRate = 0;

        $totalValueOfHours = 0;
        $sumOfHoursTimesHourlyRates = 0;

        foreach ($project->Subprojects as $subproject) {
            if($subproject->hourly_rate > 0) {
                if ($subproject->budget > 0) {
                    if ($subproject->billable == 1) {
                        $totalOfBudgets += $subproject->budget;
                        $sumOfBudgetsTimesHourlyRates += ($subproject->budget * $subproject->hourly_rate);
                    }
                } else {
                    // nacalc uren
                    foreach ($subproject->Tasks as $task) {
                        foreach ($task->Hours as $hour) {
                            if ($hour->billable == 1) {
                                $totalValueOfHours += $hour->value;
                                $sumOfHoursTimesHourlyRates += ($hour->value * $subproject->hourly_rate);
                            }
                        }
                    }
                }
            }
        }

        $total = $totalOfBudgets + $totalValueOfHours;
        $sums = $sumOfBudgetsTimesHourlyRates + $sumOfHoursTimesHourlyRates;

        if ($total > 0) {
            $weightedAverageHourlyRate = ($sums / $total);
        }


        return $weightedAverageHourlyRate;
    }

    /**
     * @return mixed
     */
    public function getTravelProject()
    {
        return Project::where('name', 'LIKE', '%kilometer%')->orderBy('created_at', 'desc')->first();
    }
}