<?php
namespace App\Controller\Api;
use App\Entity\AccessRoles;
use App\Entity\Branches;
use App\Entity\ProjectBranches;
use App\Entity\ProjectOrders;
use App\Entity\Projects;
use App\Entity\ProjectStakeholders;
use App\Entity\TimesheetStatus;
use App\Entity\WorkerActivities;
use App\Entity\WorkerInProject;
use App\Entity\WorkerTimesheet;
use App\Entity\WorkerTimesheetHistories;
use App\Service\PdfOutputTimesheet;
use App\Service\RgbToHex;
use App\Service\TimesheetInterface\TimesheetHistoryInterface;
use App\Service\TimesheetInterface\TimesheetReaderInterface;
use App\Service\TimesheetInterface\TimesheetWriterInterface;
use App\Service\TimesheetSpecificMonthDays;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\Entity;
use IntlCalendar;
use Matrix\Exception;
use Monolog\DateTimeImmutable;
use phpDocumentor\Reflection\Project;
use phpDocumentor\Reflection\Types\This;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\HttpFoundation\InputBag;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Validator\Constraints\DateTime;
use Symfony\Contracts\Translation\TranslatorInterface;
use function PHPUnit\Framework\returnArgument;
use function Symfony\Component\DependencyInjection\Loader\Configurator\param;
/**
* @Route("/api/timesheet")
*/
class TimesheetController extends AISAbstractController {
/**
* @Route("/test", name="app_api_timesheet_test", methods={"POST"})
*/
public function test(): Response {
return $this->json([
'message' => 'Successfully'
]);
}
/**
* @Route("/status", name="app_api_timesheet_status", methods={"POST"})
*/
public function status(EntityManagerInterface $manager, SerializerInterface $serializer): Response {
$status = $manager->getRepository(TimesheetStatus::class)->findAll();
$status = json_decode($serializer->serialize($status, 'json', [
'groups' => [
]
]), true );
return $this->json([
'message' => 'Successfully',
'status' => $status
]);
}
/**
* @Route("/employee-list/{project_id}/{order_id}/{branch_id}", name="employee_list", methods={"POST"}, defaults={"project_id": null, "order_id": null, "branch_id": null})
* @ParamConverter("project", options={"mapping":{"project_id":"id"}})
* @ParamConverter("order", options={"mapping":{"order_id":"id"}})
* @ParamConverter("branch", options={"mapping":{"branch_id":"id"}})
*/
// public function employeeListOfJoinedProject(Projects $project, ProjectOrders $order, ProjectBranches $projectBranch, SerializerInterface $serializer, TranslatorInterface $translator, EntityManagerInterface $manager, Request $request, ?int $project_branch_id = null ): Response {
public function employeeList( ?Projects $project, ?ProjectOrders $order, ?Branches $branch, SerializerInterface $serializer, TimesheetSpecificMonthDays $timesheetSpecificMonthDays, TranslatorInterface $translator, EntityManagerInterface $manager, Request $request, int $project_id = null, int $order_id = null, int $branch_id = null ): Response {
$year = $request->request->get('year');
$month = $request->request->get('month');
$workers = [];
# dd($year, $month);
// dd($branch);
if( $project ){
$timesheetSpecificMonthDays->initWithDomain( $project, $order, $branch );
$project->getStakeholders()->map(function(/**@var $projectStakeholder ProjectStakeholders*/$projectStakeholder) use ($project, $branch, &$workers, $month, $year, $timesheetSpecificMonthDays ){
$sys = 1;
$dym = 'Branched';
if($sys === 1){
if($branch){
$workersInProjects = $projectStakeholder->getWorkerInProjects()->filter(function (/**@var WorkerInProject $workerInProject*/ $workerInProject) use ($branch) {
return $workerInProject->getAssignedProjectBranches()->exists(function ( $key, /**@var ProjectBranches $projectBranch*/ $projectBranch) use ($branch) {
return $projectBranch->getBranch()->getId() === $branch->getId();
});
});
}
else {
$workersInProjects = $projectStakeholder->getWorkerInProjects()->filter(function(/**@var WorkerInProject $workerInProject*/ $workerInProject ) use ($project){
return $workerInProject->getProject()->getProject()->getId() === $project->getId();
});
$dym = 'No-Branched';
}
# dump($projectStakeholder->getCustomer()->getCompany(), $workersInProjects->count(), $dym);
$workersInProjects->map(function(/**@var WorkerInProject $workerInProject*/ $workerInProject ) use (&$workers, $year, $month, $timesheetSpecificMonthDays){
$workerActivity = $workerInProject->getWorkerActivity();
/** @var $foundedTimeSheet WorkerTimesheet */
$foundedTimeSheet = $workerActivity->getWorkerTimesheets()->filter(function (/** @var $workerTimesheet WorkerTimesheet */ $workerTimesheet) use (&$workers, $year, $month, $timesheetSpecificMonthDays ) {
return $workerTimesheet->getYear() === intval($year);
})->first();
$specifiedTimesheet = [];
if($foundedTimeSheet){
/** @var $specifiedTimesheet WorkerTimesheet */
// $specifiedTimesheet = $foundedTimeSheet->getSpecificMonths($year, $month, $timesheetReader ); // Tüm kolonları bir dizi olarak al
$specifiedTimesheet = $timesheetSpecificMonthDays->getSpecificMonths( $year, $month, $foundedTimeSheet ); // Tüm kolonları bir dizi olarak al
}
$hasExit = $workerActivity->getExitAt() && $workerActivity->getExitAt() < new \DateTimeImmutable('now');
$workers[] = [
"id" => $workerActivity->getId(),
"is_kpi_responsible" => $workerActivity->isIsKpiResponsible(),
"status" => !$hasExit,
"exit_at" => $workerActivity->getExitAt(),
"entry_at" => $workerActivity->getEntryAt(),
"worker" => [
"name" => $workerActivity->getWorker()->getName(),
"surname" => $workerActivity->getWorker()->getSurname(),
],
"customer" => $workerActivity->getCustomer(),
"timesheet" => $specifiedTimesheet,
"timesheet_revisions" => $foundedTimeSheet ? $foundedTimeSheet->getWorkerTimesheetHistories(): [],
];
});
}
else {
$projectStakeholder->getWorkerInProjects()->map(function(/**@var $workerInProject WorkerInProject*/$workerInProject) use ($branch, &$workers, $month, $year, $timesheetSpecificMonthDays ){
if($branch){
$assigned = $workerInProject->getAssignedProjectBranches()->filter(function (/**@var $workerAssignedProjectBranches ProjectBranches*/ $workerAssignedProjectBranches) use ($branch, &$workers, $month, $year, $timesheetSpecificMonthDays ){
return $workerAssignedProjectBranches->getBranch()->getId() === $branch->getId();
})->first();
if( $assigned ){
$workerActivity = $workerInProject->getWorkerActivity();
/** @var $foundedTimeSheet WorkerTimesheet */
$foundedTimeSheet = $workerActivity->getWorkerTimesheets()->filter(function (/** @var $workerTimesheet WorkerTimesheet */ $workerTimesheet) use (&$workers, $year, $month, $timesheetSpecificMonthDays ) {
return $workerTimesheet->getYear() === intval($year);
})->first();
$specifiedTimesheet = [];
if($foundedTimeSheet){
/** @var $specifiedTimesheet WorkerTimesheet */
// $specifiedTimesheet = $foundedTimeSheet->getSpecificMonths($year, $month, $timesheetReader ); // Tüm kolonları bir dizi olarak al
$specifiedTimesheet = $timesheetSpecificMonthDays->getSpecificMonths( $year, $month, $foundedTimeSheet ); // Tüm kolonları bir dizi olarak al
}
$hasExit = $workerActivity->getExitAt() && $workerActivity->getExitAt() < new \DateTimeImmutable('now');
$workers[] = [
"id" => $workerActivity->getId(),
"is_kpi_responsible" => $workerActivity->isIsKpiResponsible(),
"status" => !$hasExit,
"exit_at" => $workerActivity->getExitAt(),
"entry_at" => $workerActivity->getEntryAt(),
"worker" => [
"id" => $workerActivity->getWorker()->getId(),
"name" => $workerActivity->getWorker()->getName(),
"surname" => $workerActivity->getWorker()->getSurname(),
],
"customer" => $workerActivity->getCustomer(),
"timesheet" => $specifiedTimesheet,
"timesheet_revisions" => $foundedTimeSheet ? $foundedTimeSheet->getWorkerTimesheetHistories(): [],
];
}
} else {
$workerActivity = $workerInProject->getWorkerActivity();
/** @var $foundedTimeSheet WorkerTimesheet */
$foundedTimeSheet = $workerActivity->getWorkerTimesheets()->filter(function (/** @var $workerTimesheet WorkerTimesheet */ $workerTimesheet) use (&$workers, $year, $month, $timesheetSpecificMonthDays ) {
return $workerTimesheet->getYear() === intval($year);
})->first();
$specifiedTimesheet = [];
if($foundedTimeSheet){
/** @var $specifiedTimesheet WorkerTimesheet */
// $specifiedTimesheet = $foundedTimeSheet->getSpecificMonths($year, $month, $timesheetReader ); // Tüm kolonları bir dizi olarak al
$specifiedTimesheet = $timesheetSpecificMonthDays->getSpecificMonths( $year, $month, $foundedTimeSheet ); // Tüm kolonları bir dizi olarak al
}
$hasExit = $workerActivity->getExitAt() && $workerActivity->getExitAt() < new \DateTimeImmutable('now');
$workers[] = [
"id" => $workerActivity->getId(),
"is_kpi_responsible" => $workerActivity->isIsKpiResponsible(),
"status" => !$hasExit,
"exit_at" => $workerActivity->getExitAt(),
"entry_at" => $workerActivity->getEntryAt(),
"worker" => [
"id" => $workerActivity->getWorker()->getId(),
"name" => $workerActivity->getWorker()->getName(),
"surname" => $workerActivity->getWorker()->getSurname(),
],
"customer" => $workerActivity->getCustomer(),
"timesheet" => $specifiedTimesheet,
"timesheet_revisions" => $foundedTimeSheet ? $foundedTimeSheet->getWorkerTimesheetHistories(): [],
];
}
});
}
});
}
else {
$timesheetSpecificMonthDays->initWithDomain( $project, $order, $branch );
// All employees in Timesheet
$workerActivities = new ArrayCollection($manager->getRepository(WorkerActivities::class)->findAll());
$workers = $workerActivities->map(function(/**@var $workerActivity WorkerActivities*/ $workerActivity) use (&$workers, $year, $month, $timesheetSpecificMonthDays, $serializer ){
/** @var $foundedTimeSheet WorkerTimesheet */
$foundedTimeSheet = $workerActivity->getWorkerTimesheets()->filter(function (/** @var $workerTimesheet WorkerTimesheet */ $workerTimesheet) use (&$workers, $year, $month, $timesheetSpecificMonthDays ) {
return $workerTimesheet->getYear() === intval($year);
})->first();
$specifiedTimesheet = [];
if($foundedTimeSheet){
/** @var $specifiedTimesheet WorkerTimesheet */
# $specifiedTimesheet = $foundedTimeSheet->getSpecificMonths($year, $month); // Tüm kolonları bir dizi olarak al
$specifiedTimesheet = $timesheetSpecificMonthDays->getSpecificMonths( $year, $month, $foundedTimeSheet ); // Tüm kolonları bir dizi olarak al
}
$hasExit = $workerActivity->getExitAt() && $workerActivity->getExitAt() < new \DateTimeImmutable('now');
return [
"id" => $workerActivity->getId(),
"is_kpi_responsible" => $workerActivity->isIsKpiResponsible(),
"status" => !$hasExit,
"exit_at" => $workerActivity->getExitAt(),
"entry_at" => $workerActivity->getEntryAt(),
"worker" => [
"id" => $workerActivity->getWorker()->getId(),
"name" => $workerActivity->getWorker()->getName(),
"surname" => $workerActivity->getWorker()->getSurname(),
],
"customer" => $workerActivity->getCustomer(),
"timesheet" => $specifiedTimesheet,
"timesheet_revisions" => $foundedTimeSheet ? $foundedTimeSheet->getWorkerTimesheetHistories(): [],
];
});
}
#dd(count($workers));
$serializedWorkers = json_decode($serializer->serialize($workers, 'json', [
'groups' => [
"worker.in.project.worker.activity",
"worker.in.project.worker.activity.base",
"worker.in.project.worker.activity.worker",
"worker.base",
"worker.in.project.worker.activity.customer",
"customer.base",
"timesheet.history",
"timesheet.history.base",
]
]));
return $this->json([
"message" => "Successfully",
"severity"=>"success",
"serializedWorkers"=>$serializedWorkers
], Response::HTTP_OK, []);
}
/**
* @Route("/pdf-output/{worker_activity_id}/{project_id}/{project_order_id}/{branch_id}", name="app_api_timesheet_pdf_output", methods={"POST"}, defaults={ "project_id"=null, "branch_id"=null, "project_order_id"=null })
* @ParamConverter("workerActivity", options={"mapping":{"worker_activity_id":"id"}})
* @ParamConverter("project", options={"mapping":{"project_id":"id"}})
* @ParamConverter("branch", options={"mapping":{"branch_id":"id"}})
* @ParamConverter("projectOrder", options={"mapping":{"project_order_id":"id"}})
* @param TimesheetReaderInterface $timesheetReader
* @param WorkerActivities $workerActivity
* @param PdfOutputTimesheet $pdfOutputTimesheet
* @param Projects|null $project
* @param Branches|null $branch
* @param ProjectOrders|null $projectOrder
* @param SerializerInterface $serializer
* @param TranslatorInterface $translator
* @param RgbToHex $rgbToHex
* @param Request $request
* @param EntityManagerInterface $manager
* @param int|null $project_order
* @return Response
*/
public function workerTimesheetPDF(TimesheetReaderInterface $timesheetReader, WorkerActivities $workerActivity, PdfOutputTimesheet $pdfOutputTimesheet, ?Projects $project, ?Branches $branch, ?ProjectOrders $projectOrder , SerializerInterface $serializer, TranslatorInterface $translator, RgbToHex $rgbToHex, Request $request, EntityManagerInterface $manager, int $project_order = null): Response
{
$params = $request->request;
$month = intval($params->get('month'));
$year = intval($params->get('year'));
/// TODO Should remove
$read_mode = $params->get('read_mode');
$absolutePdfInfoPathText = [];
if( $project ){
$absolutePdfInfoPathText[] = $project->getName();
}
if( $branch ){
$absolutePdfInfoPathText[] = $branch->getName();
}
if($projectOrder){
$absolutePdfInfoPathText[] = $projectOrder->getOrderNr();
}
if (!$year && !$month) {
return $this->json([
'message' => $translator->trans('Please select year & month first!'),
"severity" => "warning",
], Response::HTTP_UNAUTHORIZED ) ;
}
$foundedYear = $workerActivity->getWorkerTimesheets()->filter( function (/**@var WorkerTimesheet $workerTimesheet*/ $workerTimesheet ) use ( $year ){
return $year === $workerTimesheet->getYear();
})->first();
if( !$foundedYear ){
return $this->json([
'message' => 'B' . $translator->trans('Timesheet not found!!'),
"severity" => "warning",
], Response::HTTP_NO_CONTENT ) ;
}
$timesheetStatus = (new ArrayCollection($manager->getRepository(TimesheetStatus::class)->findAll() ?? []))->map( function(/**@var $item TimesheetStatus*/ $item ) use ($rgbToHex){
$item->setAbsenceColorHex($rgbToHex->convertWithArray($item->getAbsenceBrColor()));
return $item;
});
try{
/**
* Found day's of month
*/
$intlCalendar = IntlCalendar::createInstance(null, "@calendar=gregorian");
$intlCalendar->set(IntlCalendar::FIELD_MONTH, $month - 1); // Months in IntlCalendar are 0-based (0 to 11)
$intlCalendar->set(IntlCalendar::FIELD_YEAR, $year);
$numberOfDays = $intlCalendar->getActualMaximum(IntlCalendar::FIELD_DAY_OF_MONTH);
}
catch (\Exception $exception ){
return $this->json([
'message' => 'A' . $exception->getMessage(),
"severity" => "error"
], Response::HTTP_CONFLICT );
}
try{
$serializedTimesheet = json_decode($serializer->serialize($foundedYear, 'json', [
'groups' => [
'worker.manage.base.timesheet'
],
AbstractNormalizer::IGNORED_ATTRIBUTES => [
// 'worker_activity'
]
]), true );
} catch (\Exception $exception ){
return $this->json([
'message' => 'C' . $exception->getMessage(),
"severity" => "error"
], Response::HTTP_CONFLICT );
}
try{
// Dinamik olarak belirlenen "m" harfi sonrasındaki rakamı içeren bir filtre fonksiyonu
$pattern = '/^m' . $month . '\_d\d+?$/';
$activeColumns = array_filter( array_keys($serializedTimesheet), function($item) use ($pattern) {
return preg_match($pattern, $item);
});
$activeColumns = array_values($activeColumns);
foreach ($serializedTimesheet as $key => $item ) {
if( !in_array($key, $activeColumns) ){
unset($serializedTimesheet[$key]);
}
}
}
catch (\Exception $exception ){
return $this->json([
'message' => 'D' . $exception->getMessage(),
"severity" => "error"
], Response::HTTP_CONFLICT );
}
// Initial Values
$timesheetReader
->setTimesheetStatusCollection($timesheetStatus)
->setMonth($month);
try{
$finalDayTotalWithAllProjects = [];
$timesCollection = $workerActivity->getWorkerInProjects()->filter(function( /**@var $workerInProject WorkerInProject*/ $workerInProject) use ( $project, $branch, $projectOrder ){
if( !is_null($branch) ){
return $workerInProject->getProject()->getProject()->getId() === $project->getId()
&& $workerInProject->getAssignedProjectBranches()->filter(function(/**@var $assignedProjectBranches ProjectBranches*/ $assignedProjectBranches ) use ( $branch ){
return $assignedProjectBranches->getBranch()->getId() === $branch->getId();
})->first() && $workerInProject->getProject()->getProject()->getProjectOrders()->filter(function(/**@var $_projectOrder ProjectOrders*/ $_projectOrder ) use ( $projectOrder ){
return $_projectOrder->getId() === $projectOrder->getId();
})->first();
}
// TODO Eger Branch Secilmesse bile gösteriyor
if( !is_null($projectOrder)) {
return $workerInProject->getProject()->getProject()->getId() === $project->getId()
&& $workerInProject->getProject()->getProject()->getProjectOrders()->filter(function(/**@var $order ProjectOrders*/ $order) use ($projectOrder){
return $order->getId() === $projectOrder->getId();
})->first();
}
// if( !is_null($projectOrder) ){
// return $workerInProject->getProject()->getProject()->getId() === $project->getId()
// && $workerInProject->getAssignedProjectBranches()->filter(function(/**@var $assignedProjectBranches ProjectBranches*/ $assignedProjectBranches ) use ( $branch ){
// return $assignedProjectBranches->getBranch()->getId() === $branch->getId();
// })->first() && $workerInProject->getProject()->getProject()->getProjectOrders()->filter(function(/**@var $_projectOrder ProjectOrders*/ $_projectOrder ) use ( $projectOrder ){
// return $_projectOrder->getId() === $projectOrder->getId();
// })->first();
// }
// if( !is_null($branch)) {
// return $workerInProject->getProject()->getProject()->getId() === $project->getId()
// && $workerInProject->getAssignedProjectBranches()->filter(function(/**@var $assignedProjectBranches ProjectBranches*/ $assignedProjectBranches ) use ( $branch ){
// return $assignedProjectBranches->getBranch()->getId() === $branch->getId();
// })->first();
// }
if( !is_null($project) ){
return $workerInProject->getProject()->getProject()->getId() === $project->getId() ? $workerInProject : null;
}
return $workerInProject;
})
->map( function( /**@var $workerInProject WorkerInProject*/ $workerInProject) use ( $timesheetReader, &$finalDayTotalWithAllProjects, $serializedTimesheet, $workerActivity, $month, $timesheetStatus, $project, $branch, $projectOrder ){
// Update Stakeholder
if( $project ){
$timesheetReader->readerPathManager( $project, $branch, $projectOrder );
}
else {
$timesheetReader->readerPathManager( $workerInProject->getProject()->getProject(), $branch, $projectOrder );
}
$days = [];
foreach ($serializedTimesheet as $dayKey => $object) {
$timesheetReader
->setDayKey($dayKey)
->setData($object);
$days[$dayKey] = $timesheetReader->readTimeExtendRolesBasic();
// From All project same day add worked time
if( array_key_exists($timesheetReader::KEY_TIME_PROP, $days[$dayKey])){
if( $days[$dayKey][$timesheetReader::KEY_ABSENCE_SHORT_KEY_PROP] === ABSENCE_PRESENT ){
$finalDayTotalWithAllProjects[$dayKey][] = $days[$dayKey][$timesheetReader::KEY_TIME_PROP];
}
else {
// Absence Not Present Should Time add just one time
if( !array_key_exists( $dayKey, $finalDayTotalWithAllProjects ) ){
$finalDayTotalWithAllProjects[$dayKey][] = $days[$dayKey][$timesheetReader::KEY_TIME_PROP];
}
}
}
else {
if( !array_key_exists( $dayKey, $finalDayTotalWithAllProjects ) ){
$finalDayTotalWithAllProjects[$dayKey] = [];
}
}
}
$projectTime = [];
$projectCost = [];
$projectActiveCost = [];
$projectInactiveCost = [];
array_map( function($item) use ($timesheetReader, &$projectTime, &$projectCost, &$projectActiveCost, &$projectInactiveCost ){
if( array_key_exists( $timesheetReader::KEY_COST_TYPE , $item ) ){
if( $item[$timesheetReader::KEY_COST_TYPE] === $timesheetReader::KEY_COST_TYPE_ACTIVE ){
$projectActiveCost[] = $item[$timesheetReader::KEY_COST ];
$projectTime[] = $item[$timesheetReader::KEY_TIME_PROP ];
}
if( $item[$timesheetReader::KEY_COST_TYPE] === $timesheetReader::KEY_COST_TYPE_INACTIVE ){
$projectInactiveCost[] = $item[$timesheetReader::KEY_COST ];
}
$projectCost[] = $item[$timesheetReader::KEY_COST ];
}
}, array_values($days) );
return [
"name" => $workerInProject->getProject()->getProject()->getName(),
"days" => $days,
"projectTime" => array_sum($projectTime),
"projectCost" => array_sum($projectCost),
"projectActiveCost" => array_sum($projectActiveCost),
"projectInactiveCost" => array_sum($projectInactiveCost),
];
});
#dd();
#dd($timesCollection);
$costCollection = [];
$activeCostCollection = [];
$inActiveCostCollection = [];
$timesCollection->map(function ($project) use( &$costCollection, &$activeCostCollection, &$inActiveCostCollection ){
$costCollection[] = $project['projectCost'];
$activeCostCollection[] = $project['projectActiveCost'];
$inActiveCostCollection[] = $project['projectInactiveCost'];
});
$costs = [
// "costs" => array_sum($costCollection),
// For Inactive Costs need just one part
// Inactive Cost show only if not Project ( Stakeholder selected )
"inActiveCost" => $project ? "-" : $inActiveCostCollection[0], // array_sum($inActiveCostCollection),
"activeCost" => array_sum($activeCostCollection),
// Inactive Cost show only if not Project ( Stakeholder selected )
"costs" => array_sum(array_merge($activeCostCollection, [$project ? 0 : $inActiveCostCollection[0]])),
];
}
catch (\Exception $exception ){
return $this->json([
'message' => 'E' . $exception->getTraceAsString(),
"severity" => "error"
], Response::HTTP_CONFLICT );
}
$printedBy = $translator->trans('Anonymous');
try{
if(!is_null($this->getUser())){
$printedBy = $this->getUser()->getEmail();
}
} catch (\Exception $exception){}
#dd($timesCollection);
try{
// Reindex Collection
// Safe Mode As selected Project
$timesCollection = array_values($timesCollection->toArray());
#dd($timesCollection);
#dd($absolutePdfInfoPathText);
#if(true){
$output = null;
$pdfOutputTimesheet->setPrintedBy( $printedBy );
$output = $pdfOutputTimesheet->workerTimesheet(
$translator->trans('Timesheet') . ' ' . $workerActivity->getWorker()->getName() . ' ' . $workerActivity->getWorker()->getSurname(),
implode(" / ", $absolutePdfInfoPathText ),
$month,
$year,
$timesCollection,
$costs,
$timesheetStatus,
array_map(function ($item) {
return array_sum($item);
}, $finalDayTotalWithAllProjects),
'F'
);
#}
#dd(32);
}
catch (\Exception $exception ){
return $this->json([
'message' => 'F:' . $exception->getMessage(),
"severity" => "error"
], Response::HTTP_NOT_FOUND );
}
return $this->json([
'message' => $translator->trans('Timesheet created successfully!'),
"severity" => "success",
"output" => $output
]);
}
/**
* @Route("/add-time-v2/{project_id}/{project_order_id}/{branch_id}", name="worker_timesheet_add_time_v2", methods={"POST"}, defaults={"project_id": null, "branch_id": null, "project_order_id": null } )
* @ParamConverter("project", options={"mapping":{"project_id":"id"}})
* @ParamConverter("branch", options={"mapping":{"branch_id":"id"}})
* @ParamConverter("projectOrder", options={"mapping": {"project_order_id": "id"}})
* @throws \Exception
*/
public function timesheetAddTime_v2 ( ?Projects $project, ?Branches $branch, ?ProjectOrders $projectOrder, TimesheetReaderInterface $timesheetReader, TimesheetWriterInterface $timesheetWriter, TimesheetHistoryInterface $timesheetHistory, SerializerInterface $serializer, TranslatorInterface $translator, Request $request, EntityManagerInterface $manager, TimesheetSpecificMonthDays $timesheetSpecificMonthDays ): Response
{
// return $this->json([
// 'message' => $translator->trans('Out of service, Coming soon!'),
// "severity" => "info",
// "variant"=>"snackbar"
// ], Response::HTTP_NOT_ACCEPTABLE );
$params = $request->request;
#dd($params);
/* dump($params);
dump($project->getName());
dump($projectOrder->getOrderNr());
dump($branch->getName());*/
// CheckUp start...
if( $params->get('calendar_day_selected_action') === "P" ){
if( !$project->getProjectId() ){
return $this->json([
'message' => $translator->trans('ProjectID required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
if(!$projectOrder->getId()){
return $this->json([
'message' => $translator->trans('Project order required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
if(!$branch->getId()){
return $this->json([
'message' => $translator->trans('Project branch required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
}
if( !$this->getUser() ){
return $this->json([
'message' => $translator->trans('The operation must be performed by a user requiring authentication.!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
if( !$this->getUser()->getName() && !$this->getUser()->getSurname() ){
return $this->json([
'message' => $translator->trans('You cannot proceed with the transaction as your name or surname is not specified in your account.!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
/**@var $userRole AccessRoles */
$userRole =$this->getUser()->getUserAccessedRoles()->filter(function(/**@var $item AccessRoles*/$item){
return $item->getAccessType()->getName() === 'Timesheet';
})->first();
if( !$userRole ){
return $this->json([
'message' => $translator->trans('Access role required for this operation.'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
$timesheetStatusCollection = $manager->getRepository(TimesheetStatus::class)->findAll();
if( !count($timesheetStatusCollection) ){
return $this->json([
'message' => $translator->trans('This process cannot continue as no status has been found in the collection. Please manage the time tracking status before proceeding.'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
// Start Here...
$period = json_decode($params->get('period'), true);
$year = intval($period['year']['displayId']);
$month = intval($period['month']['displayId']);
$adder = $this->getUser() ? substr($this->getUser()->getName(), 0 ,1) . '. ' . $this->getUser()->getSurname() : "Anonymus";
// $writeMode = $params->get('write_mode');
$time = $params->get('time');
$route = $params->get('route');
$employees = json_decode($params->get('employee_days'), true);
$employeeIds = array_keys($employees);
$writeMode = $timesheetWriter::TIMESHEET_WRITE_TYPE_DAILY;
$response = [];
$workers = [];
$absenceChangeReason = json_decode($params->get('absenceChangeReason'), true);
$employeeCachedHistoryEntities = [];
/**@var $timesheetStatus TimesheetStatus */
$timesheetStatus = (new ArrayCollection($timesheetStatusCollection))->filter(function (/**@var $timesheetStatus TimesheetStatus */ $timesheetStatus) use ($time) {
// $time should be numeric(P) | S | H | HNP
return $timesheetStatus->getAbsenceShortKey() === (is_numeric($time) ? 'P' : $time);
})->first();
// Table for Update Costs
$projectOrderCosts = new OrderCostController( $timesheetReader, $manager );
// Loop Employees
$nestedEmployees = new ArrayCollection($manager->getRepository(WorkerActivities::class)->findBy(['id' => $employeeIds]));
# dd($nestedEmployees->count());
#dd($project->getId());
$timesheetSpecificMonthDays->initWithDomain( $project, $projectOrder, $branch );
$errors = [];
#dd($nestedEmployees);
$nestedEmployees->map(function( /**@var WorkerActivities $workerActivity*/ $workerActivity ) use (
$timesheetStatus,
$timesheetWriter,
$serializer,
$timesheetSpecificMonthDays,
$project,
$projectOrder,
$branch,
$userRole,
$writeMode,
$translator,
$employees,
$month,
$year,
$time,
$route,
$manager,
&$response,
&$workers,
// After added time orders table should be update for actually costs
$projectOrderCosts,
$params,
$timesheetHistory,
$absenceChangeReason,
&$employeeCachedHistoryEntities,
&$errors
) {
# dd($workerActivity);
if( !$workerActivity->getWorker()->getDailyWorkTime() ){
$response[] = [
'message' => $translator->trans('Please define Worker daily work time and price per hour!') . ' ' . $workerActivity->getWorker()->getFullName(),
"severity" => "info"
];
}
else {
/**
* Filter as year timesheet's
*@var $proceedYear WorkerTimesheet
*/
$proceedYear = $workerActivity->getWorkerTimesheets()->filter( function (/**@var $workerTimesheet WorkerTimesheet */ $workerTimesheet ) use( $year) {
return $workerTimesheet->getYear() === intval($year);
})->first();
// Create New
if( !$proceedYear ) {
$proceedYear = new WorkerTimesheet();
$proceedYear
// ->setWorker( $worker )
->setWorkerActivity( $workerActivity )
->setYear( $year );
}
// Update others
/**
* Example ...
* array:2 [
* 124 => array:2 [
* 0 => "m2_d4"
* 1 => "m2_d5"
* ]
* 138 => array:3 [
* 0 => "m2_d4"
* 1 => "m2_d6"
* 2 => "m2_d21"
* ]
* ]
*/
$pushedEmployeeDays = $employees[$workerActivity->getId()];
// Add This worker to Order as assign if already not assigned
if( $route === ABSENCE_PRESENT ){
$alreadyAssigned = $workerActivity->getAssignedOrders()->filter( fn(/**@var ProjectOrders $item*/ $item ) => $item->getId()
=== $projectOrder->getId());
if(!$alreadyAssigned->first()){
$workerActivity->addAssignedOrder($projectOrder);
}
}
#dd($alreadyAssigned->first());
foreach ($pushedEmployeeDays as $monthDay ) {
if( !$workerActivity->getWorker()->getDailyWorkTime() )
{
$response[] = [
'message' => $translator->trans('Please define Worker daily work time and price per hour!'),
"severity" => "info"
];
}
else {
// Get method name from prop name -> m2_d6 should be getM2D6 || setM2D6
$property = $monthDay;
$property = preg_replace('/_/', '', $property);
$getterMethod = 'get' . strtoupper($property);
$setterMethod = 'set' . strtoupper($property);
// Take Day
$dayData = $proceedYear->{$getterMethod}() ?? [];
$workerInProject = null;
if( $project ){
$workerInProject = $workerActivity->getWorkerInProjects()->filter(function (/**@var WorkerInProject $workerInProject*/ $workerInProject ) use ($project){
return $workerInProject->getProject()->getProject()->getId()
=== $project->getId();
})->first();
}
$manager->beginTransaction();
try{
$timesheetWriter
->setWorker($workerActivity->getWorker())
->setMonth($month)
->setUser( $this->getUser() )
->setManagerRole($userRole)
->setTimesheetStatus( $timesheetStatus )
// TODO ProjectStakeholder should replace with workerInProject project access over workerInProject
->writerPathManager( $workerInProject, $branch, $projectOrder )
->setData( $dayData );
if (is_numeric($time) )
{
// Time can addable if validate time
$upsertDayData = $timesheetWriter->addTime($time)->extendResultRolesBasic();
// $projectOrderCosts = new OrderCostController($timesheetReader, $manager );
// $projectOrder = $projectOrderCosts->updateProjectOrderSpentTimes($projectOrder, $manager);
// $manager->persist($projectOrder);
// // // 1. Persist Timesheets
// $manager->persist( $workerTimesheetForYear );
// // // 2. Summary Times and Costs
// // // Persist can run, while order ist defined here not like R,H...
// $projectOrder = $projectOrderCosts->updateProjectOrderSpentTimes($manager, $projectOrder, null);
// $manager->persist($projectOrder);
}
else {
#dd($projectOrder->getId(), $branch->getId());
// 1. Persist Order (Remove Times and Costs)
// Persist should run insider function for every order
// if($projectOrder){
// $manager->persist($projectOrder);
// }
if( $timesheetStatus->getAbsenceShortKey() === 'R' ){
// Other Status Will be change Automatically from null or Present
$upsertDayData = $timesheetWriter->reset()->extendResultRolesBasic();
}
else {
$upsertDayData = $timesheetWriter->updateStatus()->extendResultRolesBasic();
}
}
$proceedYear->{$setterMethod}( $upsertDayData );
$manager->persist( $proceedYear );
$manager->flush();
// ☝️ Burda yada employee loop disinda !!!
// Update Order Table for Cost of Project & Order
// 2. Persist Order (Remove Times and Costs)
if (is_numeric($time) ){
// Saat girilmis gerekli kontrolleri yapiyoruz
// Last Control
if( !$workerInProject->getProject()->getProject()->getProjectId() ){
return $this->json([
'message' => $translator->trans('ProjectID required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
if(!$projectOrder){
return $this->json([
'message' => $translator->trans('Project order required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
if(!$branch){
return $this->json([
'message' => $translator->trans('Project branch required!'),
"severity" => "error",
"variant"=>"snackbar"
], Response::HTTP_NOT_ACCEPTABLE );
}
// Sonra secilen Auftrag in butun saatlerini toplayip Auftragin ilgili kolonunu updateliyoruz
$projectOrder = $projectOrderCosts->updateProjectOrderSpentTimes( $manager, $projectOrder, null);
$manager->persist($projectOrder);
}
else {
// Saat yok bu bir R|H|HNP ... olabilir
// Kolon icindeki degeri alip O Gun icerisinde ki Auftrag lari alip,
// O auftraglari terar update ediyoruz yani o Auftragdaki saatler silinmis olacak sekilde son halini updateliyoruz...
$projectOrderCosts->updateProjectOrderSpentTimes( $manager, null, $dayData);
}
#dd($absenceChangeReason);
// History Manager // Ignore if is new
if($dayData){
if( $absenceChangeReason ){
$workerActivityLogs = $absenceChangeReason[$workerActivity->getId()];
$newDayLog = $workerActivityLogs[$monthDay];
/**
* 🛑 Sorunun Kaynağı:
* - Loop içinde employee’ye ait bir kayıt yoksa, `new WorkerTimesheetHistories()` çağırılıyor.
* - Ancak bu entity henüz persist edildiği için veritabanında görünmüyor.
* - Aynı employee için tekrar kontrol yapıldığında, veritabanında kayıt olmadığı için tekrar new ile yeni bir entity oluşturuluyor.
* - Bu da aynı kaydı iki kez persist etmeye ve duplicate hatasına yol açıyor.
*
* ✅ Çözüm: Geçici Bir Bellek Referansı Kullan
* - Persist edilmemiş entity’leri loop içinde saklamak için geçici bir bellek yapısı (örneğin bir dizi) kullanmalısın.
* - 👉 `$employeeCachedHistoryEntities[$workerActivity->getId()]`
*/
if( !array_key_exists($workerActivity->getId(), $employeeCachedHistoryEntities) ){
$historyInstance = $proceedYear->getWorkerTimesheetHistories();
if(is_null($historyInstance)){
$historyInstance = new WorkerTimesheetHistories();
$historyInstance
->setWorkerTimesheet($proceedYear)
->setCreatedAt(new \DateTimeImmutable('now'));
}
$employeeCachedHistoryEntities[$workerActivity->getId()] = $historyInstance;
}
#dd($employeeCachedHistoryEntities);
$timesheetHistory->setCachedEmployeeHistoryEntity($employeeCachedHistoryEntities[$workerActivity->getId()]);
$timesheetHistory->init( $proceedYear, $newDayLog, $monthDay, $route, $project, $projectOrder, $branch);
$timesheetHistory->upsert();
}
}
$manager->getConnection()->commit();
} catch (\Exception $exception){
$manager->getConnection()->rollBack();
$errors[] = [
$translator->trans('Please reset this day before adding time for it.')
];
// Orijinal hatayı tekrar fırlatırken, asıl hata mesajı ve stack trace'i koruyalım
// throw new \Exception(
// $exception->getMessage() . ' ' . $translator->trans('Please reset this day before adding time for it.') .
// "Hata Mesajı: " . ' ' . $exception->getMessage() . PHP_EOL .
// "Dosya: " . $exception->getFile() . PHP_EOL .
// "Satır: " . $exception->getLine() . PHP_EOL .
// "Stack Trace: " . $exception->getTraceAsString()
// );
}
}
}
if(!count($errors)){
$manager->flush();
$manager->refresh( $proceedYear );
// Simulate Fetched Timesheet from WorkerActivity
$specifiedTimesheet = $timesheetSpecificMonthDays->getSpecificMonths( $year, $month, $proceedYear ); // Tüm kolonları bir dizi olarak al
$workers[] = [
"id" => $workerActivity->getId(),
"worker" => [
"name" => $workerActivity->getWorker()->getName(),
"surname" => $workerActivity->getWorker()->getSurname(),
],
"customer" => $workerActivity->getCustomer(),
"timesheet" => $specifiedTimesheet,
"timesheet_revisions" => $proceedYear->getWorkerTimesheetHistories(),
];
}
}
});
#dd();
if(count($errors)){
return $this->json([
'message' => $translator->trans('Please reset this day before adding time for it.'),
"severity" => "error",
], Response::HTTP_NOT_ACCEPTABLE );
}
$serializedWorkers = json_decode($serializer->serialize($workers, 'json', [
'groups' => [
"worker.in.project.worker.activity",
"worker.in.project.worker.activity.base",
"worker.in.project.worker.activity.worker",
"worker.base",
"worker.in.project.worker.activity.customer",
"customer.base",
"timesheet.history",
"timesheet.history.base",
]
]));
return $this->json([
"message" => "Successfully",
"severity"=>"success",
"serializedWorkers"=>$serializedWorkers,
"response" => $response
], Response::HTTP_OK, []);
}
/**
* @Route("/employee-yearly-statistics/{worker_activity_id}", name="employee_yearly_statistics", methods={"POST"} )
* @ParamConverter("workerActivities", options={"mapping":{"worker_activity_id":"id"}})
* @throws \Exception
*/
public function employeeYearlyStatistics( WorkerActivities $workerActivities, Request $request, TranslatorInterface $translator): Response {
$params = $request->request;
$year = $params->get('year');
// this year until current month
$maxMonthIndex = 12;
$now = new \DateTimeImmutable('now');
if( intval($year) === intval($now->format('Y')) ){
$maxMonthIndex = intval($now->format('n'));
}
/**@var WorkerTimesheet $timesheet*/
$timesheet = $workerActivities->getWorkerTimesheets()->filter(function (/**@var WorkerTimesheet $workerTimesheet*/ $workerTimesheet) use ($year, $maxMonthIndex){
return $workerTimesheet->getYear() === intval($year);
})->first();
if($timesheet){
$timesheetClass = new \ReflectionClass(WorkerTimesheet::class);
$properties = $timesheetClass->getProperties(\ReflectionProperty::IS_PRIVATE);
$methods = $timesheetClass->getMethods(\ReflectionMethod::IS_PUBLIC);
// $filteredMethods = array_filter($methods, function ($method) {
// return preg_match('/^getM[1-12]\dD[1-31]\d$/', $method->getName());
// });
// Every Month
$filteredMethods = array_reduce($methods, function ($carry, $method) use ($maxMonthIndex) {
if (sscanf($method->getName(), "getM%dD%d", $month, $day) === 2) {
// if ($month >= 1 && $month <= 12 && $day >= 1 && $day <= 31) {
if ($month >= 1 && $month <= $maxMonthIndex && $day >= 1 && $day <= 31) {
$carry[$month][] = $method->getName();
// $carry[] = $method->getName();
}
}
return $carry;
}, []);
$P = $S = $H = $HNP = $chartDataset = [];
foreach ($filteredMethods as $monthIndex => $monthDays) {
$_P = $_S = $_H = $_HNP = [];
array_map( function($method) use ($timesheet, &$_P, &$_S, &$_H, &$_HNP, &$chartDataset){
$ts = $timesheet->{$method}();
if(!is_null($ts)){
if( array_key_exists('absenceShortKey', $ts)){
switch ($ts['absenceShortKey']){
case 'P':
$_P[] = array_sum(array_map(fn($prj) => array_sum(array_values($prj['orders_total'])), $ts['projects']));
break;
case 'S':
case 'H':
if($ts['absenceShortKey'] === 'S'){
$_S[] = $ts['info']['time'];
} else {
$_H[] = $ts['info']['time'];
}
break;
case 'HNP':
$_HNP[] = 0;
break;
}
}
}
}, $monthDays );
#dump($partActive);
$P[$monthIndex]['daily'] = $_P; // Presents Total
$P[$monthIndex]['total'] = array_sum($_P); // Presents Total
// $P[$monthIndex] = $_P; // Presents Total
$S[$monthIndex]['daily'] = $_S; // Sick Total
$S[$monthIndex]['total'] = array_sum($_S); // Sick Total
$H[$monthIndex]['daily'] = $_H; // Holiday Total
$H[$monthIndex]['total'] = array_sum($_H); // Holiday Total
$HNP[$monthIndex]['daily'] = $_HNP; // Holiday Not Payable Total
$HNP[$monthIndex]['total'] = array_sum($_HNP); // Holiday Not Payable Total
$chartDataset[] = [
'P' => array_sum($_P),
'S' => array_sum($_S),
'H' => array_sum($_H),
'HNP' => array_sum($_HNP),
'month' => $monthIndex,
'year' => $year
];
}
return $this->json([
"message" => "Successfully",
"severity" => "success",
"data" => [
"P" => $P,
"S" => $S,
"H" => $H,
"HNP" => $HNP,
],
"chartDataSet" => $chartDataset,
"founded" => true
], Response::HTTP_OK );
}
return $this->json([
"message" => $translator->trans('No timesheet found'),
"severity" => "warning",
"chartDataSet" => [],
"founded" => false
], Response::HTTP_OK );
}
}