File: D:/HostingSpaces/MdnDirecteur/hours.komma.cloud/app/Komma/Subprojects/SubprojectService.php
<?php
namespace App\Komma\Subprojects;
use App\Komma\Messages\MessageController;
use App\Komma\Projects\Project;
use App\Komma\Settings\Subprojecttemplates\SubprojectTemplate;
use App\Komma\Tasks\TaskService;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Http\Request;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Pagination\Paginator;
class SubprojectService
{
protected $messageController;
protected $taskService;
public function __construct(MessageController $messageController, TaskService $taskService)
{
$this->messageController = $messageController;
$this->taskService = $taskService;
}
/**
* Get the sum of all the hours in the subproject and divide them in the relevant groups
*
* @param $subproject
* @return number
*/
public function getSumSubprojectHours($subProject)
{
$totalBillWithBudget = [];
$totalBillWithoutBudget = [];
$totalNotBillWithBudget = [];
$totalNotBillWithoutBudget = [];
$totalExceedsSubProject = [];
//loop trough each task of subproject
foreach ($subProject->Tasks as $task) {
$data = $this->getTaskHours($task, $subProject->budget);
//get task hours sum
$array[] = $data['billWithBudget'];
$arrayNotBil[] = $data['billWithoutBudget'];
$arrayNotBud[] = $data['notBillWithBudget'];
$arrayExceeds[] = $data['notBillWithoutBudget'];
$arrayBilled[] = $data['exceedsSubProject'];
//sum task hours
$totalBillWithBudget += [$task->TaskTemplate->name => array_sum($array)];
$totalBillWithoutBudget += [$task->TaskTemplate->name => array_sum($arrayNotBil)];
$totalNotBillWithBudget += [$task->TaskTemplate->name => array_sum($arrayNotBud)];
$totalNotBillWithoutBudget += [$task->TaskTemplate->name => array_sum($arrayExceeds)];
$totalExceedsSubProject += [$task->TaskTemplate->name => array_sum($arrayBilled)];
//clear array
$data = [];
$array = [];
$arrayNotBil = [];
$arrayNotBud = [];
$arrayExceeds = [];
$arrayBilled = [];
}
//sum and return all task hours
return compact('totalBillWithBudget', 'totalBillWithoutBudget', 'totalNotBillWithBudget', 'totalNotBillWithoutBudget', 'totalExceedsSubProject');
}
/**
* Get all the hours in the subproject and divide them in the relevant groups
*
* @param Subproject $subProject
* @return array
*/
public function getSubProjectHours(Subproject $subProject)
{
$billWithBudget = [];
$billWithoutBudget = [];
$notBillWithBudget = [];
$notBillWithoutBudget = [];
$exceedsSubProject = [];
$tasks = $subProject->Tasks;
$tasks->loadMissing('Hours');
//loop trough task of subproject
foreach ($tasks as $task) {
$data = $this->getTaskHours($task, $subProject->budget);
$billWithBudget[] = $data['billWithBudget'];
$billWithoutBudget[] = $data['billWithoutBudget'];
$notBillWithBudget[] = $data['notBillWithBudget'];
$notBillWithoutBudget[] = $data['notBillWithoutBudget'];
$exceedsSubProject[] = $data['exceedsSubProject'];
}
$totalBillWithBudget = array_sum($billWithBudget);
$totalBillWithoutBudget = array_sum($billWithoutBudget);
$totalNotBillWithBudget = array_sum($notBillWithBudget);
$totalNotBillWithoutBudget = array_sum($notBillWithoutBudget);
$totalExceedsSubproject = array_sum($exceedsSubProject);
return compact('totalBillWithBudget', 'totalBillWithoutBudget', 'totalNotBillWithBudget', 'totalNotBillWithoutBudget', 'totalExceedsSubproject');
}
private function getTaskHours($task, $budget){
$bWB = [];
$bWoB = [];
$nBWB = [];
$nBWoB = [];
$eS = [];
$hours = $task->Hours;
//loop though hours
foreach ($hours as $hour) {
if($hour->exceed_subproject == 0) {
if ($hour->billable == 1) {
if($budget > 0) {
$bWB[] = floatval($hour->value);
} else {
$bWoB[] = floatval($hour->value);
}
} else {
if($budget > 0) {
$nBWB[] = floatval($hour->value);
} else {
$nBWoB[] = floatval($hour->value);
}
}
} else {
$eS[] = floatval($hour->value);
}
}
$billWithBudget = array_sum($bWB);
$billWithoutBudget = array_sum($bWoB);
$notBillWithBudget = array_sum($nBWB);
$notBillWithoutBudget = array_sum($nBWoB);
$exceedsSubProject = array_sum($eS);
return compact('billWithBudget', 'billWithoutBudget', 'notBillWithBudget', 'notBillWithoutBudget', 'exceedsSubProject');
}
/**
* @param $request
*/
public function checkIfExist(Request $request)
{
//find project
$project = Project::find($request->project);
//if the chosen subproject exist
if (!empty($project->Subprojects->where('name', $request->name)->first())) {
//message
$this->messageController->exist("Deelproject", "project");
// Find redirect route
$redirectRoute = 'projecten';
//if ref exist
if ($request->filled('ref')) {
//get ref
$ref = $request->get('ref');
//replace - with / if - exist
$redirectRoute = str_replace('-', '/', $ref);
}
//return redirect route string
return $redirectRoute;
}
}
/**
* @param $request
* @return mixed
*/
public function storeSubproject(Request $request)
{
$subproject = $this->store($request);
//message + activity
$this->messageController->create("Nieuw deelproject", Subproject::find($subproject->id));
return $subproject;
}
/**
* @param $request
* @return mixed
*/
public function store(Request $request)
{
//store subproject
$subprojectTemplate = SubprojectTemplate::find($request->subproject);
$subproject = \DB::transaction(function () use ($request, $subprojectTemplate) {
//store new sub project
$subproject = new Subproject();
$subproject->subproject_template_id = $request->subproject;
$subproject->project_id = $request->project;
$subproject->name = $request->name;
$subproject->budget = !empty($request->budget) ? $request->budget : 0;
$subproject->billable = $request->billable;
$subproject->hourly_rate = $request->hourly_rate;
$subproject->save();
if($request->has('tasks')) {
$subproject->TaskTemplates()->sync($request->tasks);
} else {
//loop trough related task templates
foreach ($subprojectTemplate->TaskTemplates as $taskTemplate) {
//make $request array to store task
$taskRequest = ['subproject' => $subproject->id];
$taskRequest += ['task' => $taskTemplate->id];
//make object of array
$taskRequest = (object)$taskRequest;
//go to store task
$this->taskService->store($taskRequest);
}
}
return $subproject;
});
//return subproject
return $subproject;
}
/**
* @param $items
* @param $perPage
* @param null $page
* @return LengthAwarePaginator
*/
public function paginate($items, $perPage, $page = null)
{
$page = $page ?: (Paginator::resolveCurrentPath() ? 1 : 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, ['path' => Paginator::resolveCurrentPath()]);
}
/**
* @param Subproject $subproject
* @return array
*/
public function getBudget(Subproject $subproject)
{
//$values = (object)['totalHoursBil' => 0, 'totalHoursNotBil' => 0, 'totalHours' => 0, 'totalExceedHours' => 0];
$subproject->loadMissing('Tasks');
$values = (object)$this->getSubProjectHours($subproject);
$totalHours = $values->totalBillWithBudget+$values->totalBillWithoutBudget+$values->totalNotBillWithBudget+$values->totalNotBillWithoutBudget+$values->totalExceedsSubproject;
$totalHoursInBudget = $values->totalBillWithBudget+$values->totalNotBillWithBudget+$values->totalExceedsSubproject;
$actualRate = (object)$this->ActualHourlyRate($subproject->Project, $totalHours, $subproject->budget + $values->totalBillWithoutBudget);
$array = [
'totalBillWithBudget' => $values->totalBillWithBudget,
'totalBillWithoutBudget' => $values->totalBillWithoutBudget,
'totalNotBillWithBudget' => $values->totalNotBillWithBudget,
'totalNotBillWithoutBudget' => $values->totalNotBillWithoutBudget,
'totalExceedsSubproject' => $values->totalExceedsSubproject,
'totalHours' => $totalHours,
'totalHoursInBudget' => $totalHoursInBudget,
'actualRate' => $actualRate->actualRate,
'count' => $actualRate->i
];
return $array;
}
/**
* Calculate the actual hourly rate based on the budget and the written hours
*
* So projects that stay in budget, will have a positive ActualHourlyRate
* Example:
* $project->hourly_rate = €85
* $totalBudget = 10
* $totalHours = 5
* 85*10 = 850 / 5 = €170
*
* So projects that go over the budget, will have a negative ActualHourlyRate
* Example:
* $project->hourly_rate = €85
* $totalBudget = 5
* $totalHours = 10
* 85*10 = 425 / 10 = €42.50
*
* @param $subproject
* @param $totalHours
* @param $totalBudget
* @return float
*/
public function ActualHourlyRate($project, $totalHours, $totalBudget)
{
$i = 0;
//calculate actual hourly rate of subproject
if (empty($totalHours) || $project->hourly_rate == 0) {
$actualRate = 0;
} else {
$actualRate = ($project->hourly_rate * $totalBudget) / $totalHours;
$i = 1;
}
//return
return compact('actualRate', 'i');
}
/**
* API call urls for the hour write form
*/
public function getSubProjectWithTasksByID($id) {
$subproject = Subproject::with(['Tasks', 'TaskTemplates', 'SubprojectTemplate'])->where('id', $id)->first();
return !empty($subproject) ? $subproject : null;
}
public function getSubProjectByID($id) {
$subproject = Subproject::where('id', $id)->first();
return !empty($subproject) ? $subproject : null;
}
public function getProjectSubProgressBarByID($id){
$getSubProject = $this->getSubProjectByID($id);
$budgets = $this->getBudget($getSubProject);
return view('partials.generalElements.progressBar',[
'hoursNoBudget' => $budgets['totalBillWithoutBudget']+$budgets['totalNotBillWithoutBudget'],
'budget' => $getSubProject->budget,
'hoursLeftInBudget' => $getSubProject->budget - ($budgets['totalBillWithBudget']+$budgets['totalNotBillWithBudget']+$budgets['totalExceedsSubproject']),
'barWidth' => $getSubProject->budget > 0 ? (100 / $getSubProject->budget) * ($budgets['totalBillWithBudget']+$budgets['totalNotBillWithBudget']+$budgets['totalExceedsSubproject']) : 100,
]);
}
}