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();
}
}