<?php
namespace App\Controller\ProjectManagement;
use App\Entity\Vendor;
use App\Form\ProjectManagement\VendorType;
use App\Repository\DepartmentRepository;
use App\Repository\ProjectRepository;
use App\Repository\TimeSpentRepository;
use App\Repository\TaskRepository;
use App\Repository\UserRepository;
use App\Repository\VendorRepository;
use App\Service\CurrencyService;
use App\Entity\Client;
use App\Repository\ClientRepository;
use App\Form\ProjectManagement\ClientType;
use App\Repository\IndustryClassificationRepository;
use App\Repository\ProjectClassificationRepository;
use App\Service\GoogleDriveService;
use App\Service\ProjectService;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Contracts\Translation\TranslatorInterface;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Symfony\Component\HttpFoundation\RedirectResponse;
class ProjectManagementController extends AbstractController
{
/**
* @param ClientRepository $clientRepository
* @param ProjectRepository $projectRepository
* @param DepartmentRepository $departmentRepository
* @param TaskRepository $taskRepository
* @param Request $request
* @return Response
*/
#[Route(path: '/project-management', name: 'project_management')]
public function projectManagement(ProjectRepository $projectRepository, ClientRepository $clientRepository, TaskRepository $taskRepository, DepartmentRepository $departmentRepository, Request $request, IndustryClassificationRepository $industryClassificationRepository, ProjectClassificationRepository $projectClassificationRepository): Response
{
$user = $this->getUser();
$page = intval($request->query->get('page'));
$limit = intval($request->query->get('limit'));
if ($limit === 0) {
$limit = 20;
}
$keyword = $request->get('keyword');
$order = $request->get('order');
$orderBy = $request->get('orderBy');
$startDate = $request->get('startDate');
$endDate = $request->get('endDate');
$client = $request->get('client');
$project = $request->get('project');
$task = $request->get('task');
$status = $request->get('status');
$type = $request->get('type');
$department = $user->getDepartment()->getId();
$assignedUser = count(array_intersect(['ROLE_FINANCE', 'ROLE_HR', 'ROLE_MANAGEMENT'], $user->getRoles())) > 0 ? null : $user->getId();
$assignedDepartment = count(array_intersect(['ROLE_FINANCE', 'ROLE_HR', 'ROLE_MANAGEMENT'], $user->getRoles())) > 0 ? null : $user->getDepartment()->getId();
$clientsList = $clientRepository->findByPage($page, $limit, $keyword, $order, $orderBy, $department, $assignedUser);
$projectsList = $projectRepository->findByPage($page, $limit, $keyword, $order, $orderBy, $startDate, $endDate, $type, $client, $status, $project, $department, $assignedUser);
$departmentList = $departmentRepository->findAll();
$taskList = $taskRepository->findSummaryByPage($page, $limit, $keyword, $order, $orderBy, $user, $task, $assignedDepartment);
$totalProject = $projectRepository->getTotalProjectByEmployee($user);
$industryClassification = $industryClassificationRepository->findAll();
$projectClassification = $projectClassificationRepository->findAll();
return $this->render('private/project-management/project-management.html.twig', [
'user' => $user,
'totalProject' => $totalProject,
'clientList' => $clientsList,
'projectList' => $projectsList,
'departmentList' => $departmentList,
'taskList' => $taskList,
'industryClassification' => $industryClassification,
'projectClassification' => $projectClassification
]);
}
/**
* @param UserRepository $userRepository
* @param Request $request
* @throws \PhpOffice\PhpSpreadsheet\Exception
* @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
*/
#[Route(path: '/employee-task/export-summary', name: 'export_employee_task_summary')]
public function exportEmployeeSummary(UserRepository $userRepository, Request $request)
{
$page = intval($request->query->get('page') - 1);
if($page < 0) $page =0;
$limit = intval($request->query->get('limit'));
if ($limit === 0) $limit = 1000000;
$keyword = $request->get('keyword');
$order = $request->get('order');
$orderBy = $request->get('orderBy');
$waitForPage = $request->query->get('waitForPage');
$waitForPage === null ? $result['waitForPage'] = 'false' : $result['waitForPage'] = $waitForPage;
$office = $request->get('office');
$startDate = $request->get('startDate');
$endDate = $request->get('endDate');
$department = $request->get('department');
$employeeSummaryList = $userRepository->findEmployeeTaskSummaryByPage($page, $limit, $keyword, $order, $orderBy, $department, $office, $startDate, $endDate);
// dd($employeeSummaryList);
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Employee');
$sheet->setCellValue('B1', 'Department');
$sheet->setCellValue('C1', 'Total Project');
$sheet->setCellValue('D1', 'Total Hours');
$sheet->setCellValue('E1', 'COST');
$filename = 'Employees' . date('Y-m-d') . '.xlsx';
for($i =0; $i < sizeof($employeeSummaryList); $i++){
$row = $sheet->getHighestRow()+1;
$sheet->insertNewRowBefore($row);
$sheet->setCellValue('A'.$row, $employeeSummaryList[$i]['fullName']);
$sheet->setCellValue('B'.$row, $employeeSummaryList[$i]['department']);
$sheet->setCellValue('C'.$row, $employeeSummaryList[$i]['projects']);
$sheet->setCellValue('D'.$row, $employeeSummaryList[$i]['hours']);
$sheet->setCellValue('E'.$row, $employeeSummaryList[$i]['cost']);
}
$writer = new Xlsx($spreadsheet);
$writer->save($filename);
// Set the content-type:
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Length: ' . filesize($filename));
readfile($filename); // send file
unlink($filename); // delete file
exit;
}
/**
* @param UserRepository $userRepository
* @param Request $request
* @return Response
*/
#[Route(path: '/ajax/employee-task/summary', name: 'ajax_employee_task_summary')]
public function ajaxListEmployeeTaskSummary(UserRepository $userRepository, Request $request): Response
{
// Example params:
// ?office=1&startDate=2022-05-22&endDate=2022-05-26&department=1&keyword=&order=asc
$user = $this->getUser();
$page = intval($request->query->get('page') - 1);
if($page < 0) $page =0;
$limit = intval($request->query->get('limit'));
if ($limit === 0) $limit = 20;
$keyword = $request->get('keyword');
$order = $request->get('order');
$orderBy = $request->get('orderBy');
$waitForPage = $request->query->get('waitForPage');
$waitForPage === null ? $result['waitForPage'] = 'false' : $result['waitForPage'] = $waitForPage;
$office = $request->get('office');
$startDate = $request->get('startDate');
$endDate = $request->get('endDate');
$department = $request->get('department');
$employeeSummaryList = $userRepository->findEmployeeTaskSummaryByPage($user->assignedCompany(), $page, $limit, $keyword, $order, $orderBy, $department, $office, $startDate, $endDate);
$total = $userRepository->countEmployeeTaskSummary($user->assignedCompany(), $keyword, $department, $office, $startDate, $endDate);
$body = $this->renderView('private/project-management/employee/components/list-employee.html.twig', [
'employeeList' => $employeeSummaryList
]);
$result['content'] = [
'html' => $body,
'total' => $total
];
$result['status'] = 'OK';
return new JsonResponse($result);
}
/**
* @param Request $request
* @param ProjectRepository $projectRepository
* @param TimeSpentRepository $timeSpentRepository
* @param UserRepository $userRepository
* @param TranslatorInterface $translator
* @param Request $request
* @param UploadService $uploadService
* @param LogService $log
* @return Response
*/
#[Route(path: '/ajax/employee-task/time-record', name: 'ajax_project_employee_time_record')]
public function ajaxProjectEmployeeTimeRecord(Request $request, TimeSpentRepository $timeSpentRepository, ProjectRepository $projectRepository, UserRepository $userRepository, TranslatorInterface $translator): Response
{
$_id = intval($request->get('projectId'));
$project = $projectRepository->find($_id);
if (!$project) {
$result['status'] = 'OK';
return new JsonResponse($result);
};
$employeeTimeRecords = $timeSpentRepository->getEmployeeTimeRecord($_id);
$totalTasks = $timeSpentRepository->getTotalTasks($_id);
$totalHours = $timeSpentRepository->getTotalHours($_id);
$totalHoursAll = 0;
$totalCostAll = 0;
$departments = $timeSpentRepository->getDepartmentsForProject($_id, $project->getStartDate(), $project->getEndDate());
for ($i = 0; $i < sizeof($departments); $i++) {
$startDate = $project->getStartDate() ? $project->getStartDate()->format('Y-m-d') : $project->getCreatedAt()->format('Y-m-d');
$endDate = $project->getEndDate() ? $project->getEndDate()->format('Y-m-d') : null;
$employeeSummaryList = $userRepository->findTaskSummary($_id, $departments[$i]['id'], $startDate, $endDate);
$i2 = 0;
/*foreach($employeeSummaryList as $employee){
$projectMember = $project->getProjectMember($employee['id']);
$employeeSummaryList[$i2]['hourly'] = $projectMember->getUser()->getHourlyRateUsd();
$i2++;
}*/
$departments[$i]['employeeSummaryList'] = $employeeSummaryList;
$tmpHours = 0;
$tmpCost = 0;
for ($j = 0; $j < sizeof($employeeSummaryList); $j++) {
$tmpHours = $tmpHours + $employeeSummaryList[$j]['hours'];
$tmpCost = $tmpCost + $employeeSummaryList[$j]['cost'];
}
//$totalManpowerCost += $tmpCost;
$departments[$i]['totalCost'] = $tmpCost;
$departments[$i]['totalHours'] = $tmpHours;
}
if (count($departments) > 0){
foreach($departments as $department){
$totalHoursAll += $department['totalHours'];
$totalCostAll += $department['totalCost'];
}
}
$body = $this->renderView('private/project-management/employee/components/list-employee-time-record.html.twig', [
'timeRecordsByDepartments' => $departments
]);
$result['content'] = [
'html' => $body,
];
$result['status'] = 'OK';
return new JsonResponse($result);
}
/**
* @param TaskRepository $taskRepository
* @param Request $request
* @return Response
*/
#[Route(path: '/ajax/task/summary', name: 'ajax_task_summary')]
public function ajaxListTaskSummary(TaskRepository $taskRepository, Request $request): Response
{
// Example params:
// page=0&limit=25&keyword=&orderBy=task&order=asc&waitForPage=true&user=1&task=1
$page = intval($request->query->get('page'));
$limit = intval($request->query->get('limit')) ;
if ($limit === 0) $limit = 20;
$keyword = $request->get('keyword');
$order = $request->get('order');
$orderBy = $request->get('orderBy');
$waitForPage = $request->query->get('waitForPage');
$waitForPage === null ? $result['waitForPage'] = 'false' : $result['waitForPage'] = $waitForPage;
$user = $request->get('user');
$task = $request->get('task');
$timeSpentsList = $taskRepository->findSummaryByPage($page, $limit, $keyword, $order, $orderBy, $user, $task);
$body = $this->renderView('private/project-management/time-spent/list-time-spent.html.twig', [
'timeSpentList' => $timeSpentsList
]);
$result['content'] = [
'html' => $body,
'empty' => $timeSpentsList == null ? true : false
];
$result['status'] = 'OK';
return new JsonResponse($result);
}
#[Route(path: '/debug/currency', name: 'debug_currency')]
public function debugCurrency(CurrencyService $currencyHistoryService ) :Response{
// TODO remove this later when service in use already and this not needed
$date = '2022-06-01';
$to_ccy = 'SGD';
$from_ccy = 'USD';
$amount = '1025.44';
$converted = $currencyHistoryService->convertAtDate($date, $from_ccy, $to_ccy, $amount);
return new Response($converted);
}
#[Route(path: '/report/employee/{_target}', defaults: ['_target' => ''], name: 'report_employee_project')]
public function reportEmployeeProject(string $_target, Request $request, TaskRepository $taskRepository, GoogleDriveService $googleDriveService)
{
$baseurl = $request->getScheme() . '://' . $request->getHttpHost() . $request->getBasePath();
$start = $request->get('start');
$end = $request->get('end');
$keyword = $request->get('keyword');
$user = $this->getUser();
$userRoles = $user->getRoles();
$start = $request->get('start');
$end = $request->get('end');
$start = str_replace('/', '-', $start);
$start = date('Y-m-d', strtotime($start));
$startRange = date('d-M-Y', strtotime($start));
$end = str_replace('/', '-', $end);
$end = date('Y-m-d', strtotime($end));
$endRange = date('d-M-Y', strtotime($end));
$baseurl = $request->getScheme() . '://' . $request->getHttpHost() . $request->getBasePath();
$user = $this->getUser();
$userRoles = $user->getRoles();
$company = $user->assignedCompany();
$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue('A1', 'Today\'s Date');
$sheet->setCellValue('A2', 'From');
$sheet->setCellValue('A3', 'To');
$sheet->setCellValue('B1', date('d-M-Y'));
$sheet->setCellValue('B2', $startRange);
$sheet->setCellValue('B3', $endRange);
$sheet->setCellValue('A5', 'Employee Name');
$sheet->setCellValue('B5', 'Employee Status');
$sheet->setCellValue('C5', 'Project Type');
$sheet->setCellValue('D5', 'Client Name');
$sheet->setCellValue('E5', 'Project Name');
$sheet->setCellValue('F5', 'Project Status');
$sheet->setCellValue('G5', 'Project Start date');
$sheet->setCellValue('H5', 'Project End date');
$sheet->setCellValue('I5', 'Employee Hours');
$sheet->setCellValue('J5', 'Total Revenue');
$sheet->setCellValue('K5', 'Total Cost');
$sheet->setCellValue('L5', 'Total Profit');
$lastCol = 'L';
$sheet->getDefaultColumnDimension()->setWidth(25);
$sheet->getColumnDimension('E')->setWidth(42);
$sheet->getStyle("A1:B3")->getFont()->setBold(true);
$sheet->getStyle("A5:".$lastCol."5")->getFont()->setBold(true);
$sheet->getStyle("A5:".$lastCol."5")->getFont()->getColor()->setARGB(\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_WHITE);
$sheet->getStyle("A5:".$lastCol."5")->getFill()->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)->getStartColor()->setARGB('00000000');
$sheet->getStyle("A6:".$lastCol."6")->getFont()->setBold(false);
$sheet->getStyle("A6:".$lastCol."6")->getAlignment()->setWrapText(true);
$sheet->getStyle("A6:".$lastCol."6")->getAlignment()->setVertical(\PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_TOP);
$filename = "Employee_Report";
$filename .= $start ? "_" . urlencode($start) : "";
$filename .= $end ? "-" . urlencode($end) : "";
$filename .= $keyword ? "_" . urlencode($keyword) : "";
$filename .= ($start && $end) ? '.xlsx' : "_" . date('Y-m-d') . '.xlsx';
/*
$projects = $projectRepository->findByPage(0, 9999, $keyword, 'ASC', 'generatedId', $start, $end, '', 0, null, 0, null, null, null, false, 0, null, null, null);
$row = $sheet->getHighestRow();
foreach($projects as $project){
$projectMembers = $project[0]->getProjectMembers();
foreach($projectMembers as $member){
// if($project['type'] == 'CONFIRMED' || $project['type'] == 'LEAD'){
$memberName = $member->getUser()->getPersonalInfo()->getFullName();
$sheet->setCellValue('A' . $row, $memberName);
$sheet->setCellValue('B' . $row, $member->getUser()->getIsActive() ? 'Active' : 'Deactivated');
$sheet->setCellValue('C' . $row, $project['type']);
$sheet->setCellValue('D' . $row, $project['clientName']);
$sheet->setCellValue('E' . $row, $project['fullName']);
$sheet->setCellValue('F' . $row, $project[0]->actualStatus() ?: '-');
$sheet->setCellValue('G'. $row, $project['startDate'] ? $project['startDate']->format('Y-m-d') : '-');
$sheet->setCellValue('H'. $row, $project['endDate'] ? $project['endDate']->format('Y-m-d') : '-');
$sheet->setCellValue('I'. $row, $member->getUser()->getTotalHoursByProject($project['name']) ?: '-');
$sheet->setCellValue('J'. $row, $project[0]->getPlannedRevenueUsd() ?: '-');
$totalCost = $project['type'] == 'CONFIRMED' ? $project[0]->getProjectCost() : $project[0]->getProjectEstimatedCostUsd();
$totalProfit = $project['type'] == 'CONFIRMED' ? $project[0]->getProjectProfit1() : $project[0]->getEstimatedProfitUsd();
$sheet->setCellValue('K'. $row, $totalCost ?: '-');
$sheet->setCellValue('L'. $row, $totalProfit ?: '-');
$row++;
// }
}
}
$sheet->getStyle('I5:'.$lastCol.$sheet->getHighestRow())->getNumberFormat()->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED2);
*/
$tasks = $taskRepository->findByRangeGroupByPerson($start, $end);
$row = $sheet->getHighestRow();
foreach($tasks as $task){
$user = $task[0]->getUser();
$personalInfo = $user->getPersonalInfo();
$project = $task[0]->getProject();
$sheet->setCellValue('A' . $row, $personalInfo->getFullName());
$sheet->setCellValue('B' . $row, $user->getIsActive() ? 'Active' : 'Deactivated');
$sheet->setCellValue('C' . $row, $project->getType());
$sheet->setCellValue('D' . $row, $project->getClient()->getName());
$sheet->setCellValue('E' . $row, $project->fullName());
$sheet->setCellValue('F' . $row, $project->actualStatus() ?: '-');
$sheet->setCellValue('G'. $row, $project->getStartDate() ? $project->getStartDate()->format('Y-m-d') : '-');
$sheet->setCellValue('H'. $row, $project->getEndDate() ? $project->getEndDate()->format('Y-m-d') : '-');
$sheet->setCellValue('I'. $row, $task['hours'] ?: '-');
$sheet->setCellValue('J'. $row, $project->getPlannedRevenueUsd() ?: '-');
$totalCost = $project->getType() == 'CONFIRMED' ? $project->getProjectCost() : $project->getProjectEstimatedCostUsd();
$totalProfit = $project->getType() == 'CONFIRMED' ? $project->getProjectProfit1() : $project->getEstimatedProfitUsd();
$sheet->setCellValue('K'. $row, $totalCost ?: '-');
$sheet->setCellValue('L'. $row, $totalProfit ?: '-');
$row++;
}
// $sheet->getStyle('J5:'.$lastCol.$sheet->getHighestRow())->getNumberFormat()->setFormatCode(\PhpOffice\PhpSpreadsheet\Style\NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED2);
$sheet->getStyle('J5:'.$lastCol.$sheet->getHighestRow())->getNumberFormat()->setFormatCode('#,##0.00;(#,##0.00)');
$sheet->setAutoFilter('A5:'.$lastCol.$sheet->getHighestRow());
$writer = new Xlsx($spreadsheet);
$writer->save($filename);
if($_target == 'google'){
$gsheetURL = $googleDriveService->uploadToGoogleDrive($filename);
if($gsheetURL){
unlink($filename);
return new RedirectResponse($gsheetURL, 302);
}
}else{
$response = new Response();
$response->headers->set('Content-type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
$response->setContent(file_get_contents($filename));
$response->setStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_OK);
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', '0');
unlink($filename);
return $response;
exit;
}
}
}