From 7b24555be4cd6abcd7d12ae24e7aff00bc12a9b6 Mon Sep 17 00:00:00 2001 From: Narindra ezway Date: Thu, 27 Mar 2025 18:02:06 +0300 Subject: [PATCH] Add absence type constants and helper methods for absence type labels --- calendar/src/components/CalendarGrid.vue | 10 +- .../eventSources/eventSourceFunction.js | 18 ++ gestion/lib/Constants/AbsenceTypeConstant.php | 10 + .../Constants/VCalendarPropertyConstant.php | 13 + gestion/lib/Controller/PageController.php | 24 +- gestion/lib/Db/Bdd.php | 210 +++++++++++++++- gestion/lib/Helpers/DateHelpers.php | 67 +++++ gestion/lib/Helpers/FileExportHelpers.php | 14 ++ gestion/lib/Helpers/GeoHelpers.php | 17 ++ gestion/lib/Helpers/VCalendarHelpers.php | 17 +- .../Service/ExportThanatoStatisticService.php | 228 +++++++++++++++--- gestion/lib/Service/GeoService.php | 128 ++++++++++ 12 files changed, 683 insertions(+), 73 deletions(-) create mode 100644 gestion/lib/Constants/AbsenceTypeConstant.php create mode 100644 gestion/lib/Helpers/GeoHelpers.php create mode 100644 gestion/lib/Service/GeoService.php diff --git a/calendar/src/components/CalendarGrid.vue b/calendar/src/components/CalendarGrid.vue index bb24902..4be1546 100644 --- a/calendar/src/components/CalendarGrid.vue +++ b/calendar/src/components/CalendarGrid.vue @@ -139,7 +139,9 @@ export default { ...getFullCalendarLocale(), // Rendering dayHeaderDidMount, - eventDidMount, + eventDidMount : (info) => { + this.addAbsenceTypeEventClass(info); + }, noEventsDidMount, eventOrder: ['start', '-duration', 'allDay', eventOrder], forceEventDuration: false, @@ -303,6 +305,12 @@ export default { this.$store.dispatch('setInitialView', { initialView }) } }, 5000), + addAbsenceTypeEventClass(info){ + if (info.event.extendedProps.absenceTypeIsLeave) { + info.el.style.backgroundColor = info.event.backgroundColor; + info.el.style.color = info.event.textColor; + } + } }, } diff --git a/calendar/src/fullcalendar/eventSources/eventSourceFunction.js b/calendar/src/fullcalendar/eventSources/eventSourceFunction.js index 2d892da..56c0b17 100644 --- a/calendar/src/fullcalendar/eventSources/eventSourceFunction.js +++ b/calendar/src/fullcalendar/eventSources/eventSourceFunction.js @@ -143,6 +143,15 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez if (isPrivateEvent && !isOwenOfEvent ) { title = t('calendar', `Absent (${owenUser})`) } + let absenceTypeIsLeave = false; + let absenceTypeProperties = object._properties.get('ABSENCETYPE'); + if (absenceTypeProperties && absenceTypeProperties.length > 0) { + const absenceTypeValue = absenceTypeProperties[0]._value + if(absenceTypeValue == 'LEAVE'){ + absenceTypeIsLeave = true; + } + + } const fcEvent = { id: [calendarObject.id, object.id].join('###'), @@ -171,9 +180,16 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez isPrivate: isPrivateEvent, calendarObjectOwen : owenUser , calendarObjectIsOwen : isOwenOfEvent, + absenceTypeIsLeave : absenceTypeIsLeave }, } + if(absenceTypeIsLeave){ + fcEvent.backgroundColor = calendar.color + fcEvent.borderColor = calendar.color + fcEvent.textColor = generateTextColorForHex(calendar.color) + } + if (object.color) { const customColor = getHexForColorName(object.color) if (customColor) { @@ -183,6 +199,8 @@ export function eventSourceFunction(calendarObjects, calendar, start, end, timez } } + + fcEvents.push(fcEvent) } } diff --git a/gestion/lib/Constants/AbsenceTypeConstant.php b/gestion/lib/Constants/AbsenceTypeConstant.php new file mode 100644 index 0000000..171d422 --- /dev/null +++ b/gestion/lib/Constants/AbsenceTypeConstant.php @@ -0,0 +1,10 @@ + "CONGE", + AbsenceTypeConstant::REST => "REPOS", + AbsenceTypeConstant::DISEASE => "MALADIE" + ]; } \ No newline at end of file diff --git a/gestion/lib/Controller/PageController.php b/gestion/lib/Controller/PageController.php index 0093c30..55c08e9 100644 --- a/gestion/lib/Controller/PageController.php +++ b/gestion/lib/Controller/PageController.php @@ -2605,30 +2605,8 @@ class PageController extends Controller { } $month = $month ?? date('m'); $year = $year ?? date('Y'); - $exportData = $this->myDb->getExportThanatoStatisticData($thanatoIdsToExport,$month,$year); try{ - $current_config = json_decode($this->myDb->getConfiguration($this->idNextcloud)); - $clean_folder = html_entity_decode($current_config[0]->path).'/'; - $thanatoList = $this->myDb->getThanatoByIds($thanatoIdsToExport); - $thanatoFolders = $this->exportThanatoStatisticService->getThanatoStatisticFolders($thanatoList,$year); - $fileHeader = $this->exportThanatoStatisticService->getExportThanatoFileHeader(); - $fileContent = $this->exportThanatoStatisticService->populateExportDataIntoFileContent($exportData,$fileHeader); - $filename = $this->exportThanatoStatisticService->getFilename($thanatoList,$month,$year); - $filenames = []; - foreach($thanatoFolders as $thanatoFolder){ - $fullPath = $clean_folder.$thanatoFolder; - try { - $this->storage->newFolder($fullPath); - } - catch(\OCP\Files\NotPermittedException $e) { - - } - $fileNamePath = $fullPath."STAT-THANATOS-" . $filename . '.csv'; - $this->storage->newFile($fileNamePath); - $file = $this->storage->get($fileNamePath); - $file->putContent($fileContent); - $filenames[] = $fileNamePath; - } + $filenames = $this->exportThanatoStatisticService->exportThanatosListStatistic($thanatoIdsToExport,$month,$year,$this->idNextcloud); return $filenames; } catch(\OCP\Files\NotFoundException $e) { } diff --git a/gestion/lib/Db/Bdd.php b/gestion/lib/Db/Bdd.php index 680b396..113776d 100644 --- a/gestion/lib/Db/Bdd.php +++ b/gestion/lib/Db/Bdd.php @@ -9,6 +9,7 @@ use OCA\Gestion\Helpers\VCalendarHelpers; use OCP\IDBConnection; use OCP\IL10N; use \Datetime; +use OCA\Gestion\Constants\VCalendarPropertyConstant; use OCA\Gestion\Helpers\FileExportHelpers; class Bdd { @@ -2093,10 +2094,9 @@ class Bdd { $this->calculer_distance_trajet($ligne_trajet->id_trajet, $idNextcloud); } - public function getExportThanatoStatisticData(array $thanatoIds,$month,$year){ - $devisList = $this->getDevisListByThanatoIds($thanatoIds,$month,$year); - $devisListGroupedByDateAndThenByThanato = $this->getDevisListGroupedByDateAndThenByThanato($devisList); - return $devisListGroupedByDateAndThenByThanato; + public function getExportThanatoStatisticData($thanatoId,$month,$year){ + $devisList = $this->getThanatoDevisPerDateInAMonthYear($thanatoId,$month,$year); + return $devisList; } private function getDevisListByThanatoIds(array $thanatoIds,$month,$year){ @@ -2219,6 +2219,8 @@ class Bdd { $devisTimeValue = VCalendarHelpers::GetStartAndEndTimeFromVCalendarString($calendarData); $devis["startTime"] = $devisTimeValue["startTime"]; $devis["endTime"] = $devisTimeValue["endTime"]; + $devis["totalHours"] = $devisTimeValue["totalHours"]; + $devis["totalWorkedHours"] = $devisTimeValue["totalWorkedHours"]; return $devis; } @@ -3355,4 +3357,204 @@ class Bdd { return $message; } + public function getThanatoById($thanatoId){ + $sql = "SELECT id, nom, prenom,fk_user_uuid FROM ".$this->tableprefix."thanato WHERE id = ? LIMIT 1;"; + $thanato = $this->execSQLNoJsonReturn($sql,[$thanatoId]); + if(!empty($thanato)){ + return $thanato[0]; + } + return null; + } + + private function getCalendarByThanatoIdNextcloud($idNextCloud){ + $searchString = "%principals/users/$idNextCloud%"; + $sql = "SELECT * FROM ".self::DEFAULT_TABLE_PREFIX."calendars as calendar WHERE calendar.principaluri LIKE ? LIMIT 1;"; + $calendar = $this->execSQLNoJsonReturn($sql,[$searchString]); + if(!empty($calendar)){ + return $calendar[0]; + } + return null; + } + + private function getThanatoDevisListByDate($thanatoId,$date){ + $dateFormatted = $date->format('Y-m-d'); + $sql = "SELECT + devis.id, + devis.date, + devis.mentions, + devis.num as calendar_uuid, + devis.id_defunt as id_defunt, + devis.id_lieu as id_lieu, + devis.id_client as id_client, + devis.id_thanato as id_thanato, + thanato.nom as nom_thanato, + thanato.prenom as prenom_thanato, + defunt.nom as nom_defunt, + lieu.nom as nom_lieu, + lieu.latitude as lieu_latitude, + lieu.longitude as lieu_longitude, + client.nom as nom_client, + client.entreprise as client_entreprise, + client.adresse as client_adresse, + facture.num as facture_num + FROM ".$this->tableprefix."devis as devis + LEFT JOIN ".$this->tableprefix."thanato as thanato on devis.id_thanato = thanato.id + LEFT JOIN ".$this->tableprefix."lieu as lieu on devis.id_lieu = lieu.id + LEFT JOIN ".$this->tableprefix."defunt as defunt on devis.id_defunt = defunt.id + LEFT JOIN ".$this->tableprefix."client as client on devis.id_client = client.id + LEFT JOIN ".$this->tableprefix."facture as facture on devis.id = facture.id_devis + WHERE devis.date = ? AND + devis.id_thanato = ? AND + (devis.mentions = ? OR devis.mentions = ?) + ORDER BY devis.date ASC;"; + $devisList = $this->execSQLNoJsonReturn( + $sql, + [$dateFormatted,$thanatoId,DevisMentionConstant::FACTURED,DevisMentionConstant::FACTURED_FORMATTED]); + return $devisList; + } + + private function getThanatoLeaveByCalendarAndDate($calendarId,$date){ + $isLeaveConditionAsString = "ABSENCETYPE:"; + $datetimeFormatted = $date->format('Ymd'); + $dateCondition = "%DTSTART%".$datetimeFormatted."%"; + $conditions = []; + $params = [ $calendarId, $dateCondition ]; // First parameters for placeholders + + $absenceTypes = VCalendarPropertyConstant::ABSENCE_TYPES; + foreach ($absenceTypes as $type) { + $conditions[] = "calendarobject.calendardata LIKE ?"; + $params[] = "%$isLeaveConditionAsString$type%"; // Add corresponding values + } + + $sql = "SELECT * FROM ".self::DEFAULT_TABLE_PREFIX."calendarobjects as calendarobject WHERE + calendarobject.calendarid = ? AND + calendarobject.calendardata LIKE ? AND + calendarobject.deleted_at IS NULL AND + (" . implode(" OR ", $conditions) . ");"; + $leaves = $this->execSQLNoJsonReturn($sql,$params); + return $leaves; + } + + private function setDevisIsPublicHolidayOrNotText($devis){ + $isPublicHoliday = DateHelpers::isPublicHoliday($devis['date']); + $devis["dayType"] = DateHelpers::getPublicHolidayText($isPublicHoliday); + return $devis; + } + + public function getThanatoDevisPerDateInAMonthYear($thanatoId,$month,$year){ + $dateOfMonths = DateHelpers::getDatesOfMonth($year,$month); + $devisListPerThanatoPerDate = []; + $thanato = $this->getThanatoById($thanatoId); + $thanatoName = $thanato["nom"]; + $thanatoCalendar = $this->getCalendarByThanatoIdNextcloud($thanato["fk_user_uuid"] ?? $thanato["nom"]); + if($thanatoCalendar == null){ + return []; + } + $thanatoCalendarId = $thanatoCalendar["id"]; + foreach($dateOfMonths as $currentDate){ + $currentDateFormatted = $currentDate->format('Y-m-d'); + $isPublicHoliday = DateHelpers::isPublicHoliday($currentDateFormatted); + $devisList = $this->getThanatoDevisListByDate($thanatoId,$currentDate); + $thereIsNoDevisForCurrentDate = empty($devisList); + if($thereIsNoDevisForCurrentDate){ + $devisListPerThanatoPerDate[$currentDateFormatted]["hasDevis"] = false; + $thanatoLeavesThisDay = $this->getThanatoLeaveByCalendarAndDate($thanatoCalendarId,$currentDate); + if(empty($thanatoLeavesThisDay)){ + $devisListPerThanatoPerDate[$currentDateFormatted]["leaves"][] = [ + "onLeave" => false, + "startTime" => null, + "endTime" => null, + "thanatoName"=>$thanatoName, + "date" => $currentDateFormatted, + "totalHours" => 0, + "totalWorkedHours" => 8, + "isPublicHoliday" => $isPublicHoliday + ]; + } + else{ + foreach($thanatoLeavesThisDay as $currentLeave){ + $leaveTime = VCalendarHelpers::GetStartAndEndTimeFromVCalendarString($currentLeave['calendardata']); + $absenceType = VCalendarHelpers::GetValueFromKeyInVCalendarString(VCalendarPropertyConstant::ABSENCE_TYPE,$currentLeave['calendardata']); + $absenceTypeKey = null; + $absenceTypeLabel = null; + if($absenceType){ + $absenceTypeKey = $absenceType; + $absenceTypeLabel = FileExportHelpers::GetAbsenceTypeLabelFromKey($absenceType); + } + $devisListPerThanatoPerDate[$currentDateFormatted]["leaves"][] = [ + "onLeave" => true, + "startTime" => $leaveTime["startTime"], + "endTime" => $leaveTime["endTime"], + "thanatoName"=>$thanatoName, + "date" => $currentDateFormatted, + "totalHours" => $leaveTime["totalHours"], + "totalWorkedHours" => $leaveTime["totalWorkedHours"], + "isPublicHoliday" => $isPublicHoliday, + "absenceTypeKey" => $absenceTypeKey, + "absenceTypeLabel" => $absenceTypeLabel + ]; + } + } + } + else{ + foreach($devisList as $devis){ + $devis = $this->setDevisStartAndEndTime($devis); + $devis = $this->setDevisIsPublicHolidayOrNotText($devis); + $devis = $this->setDevisProduitsList($devis); + if (!isset($devisListPerThanatoPerDate[$currentDateFormatted])) { + $devisListPerThanatoPerDate[$currentDateFormatted] = [ + 'total_distance' => 0, + "devis" => [], + "devisId" => [], + "hasDevis" => true, + "leaves" => [] + ]; + } + $devisListPerThanatoPerDate[$currentDateFormatted]["devis"][] = $devis; + $devisListPerThanatoPerDate[$currentDateFormatted]["devisId"][] = $devis['id']; + } + $devisListPerThanatoPerDate[$currentDateFormatted]["leaves"] = []; + $thanatoLeavesThisDay = $this->getThanatoLeaveByCalendarAndDate($thanatoCalendarId,$currentDate); + foreach($thanatoLeavesThisDay as $currentLeave){ + $leaveTime = VCalendarHelpers::GetStartAndEndTimeFromVCalendarString($currentLeave['calendardata']); + $absenceType = VCalendarHelpers::GetValueFromKeyInVCalendarString(VCalendarPropertyConstant::ABSENCE_TYPE,$currentLeave['calendardata']); + $absenceTypeKey = null; + $absenceTypeLabel = null; + if($absenceType){ + $absenceTypeKey = $absenceType; + $absenceTypeLabel = FileExportHelpers::GetAbsenceTypeLabelFromKey($absenceType); + } + $devisListPerThanatoPerDate[$currentDateFormatted]["leaves"][] = [ + "onLeave" => true, + "startTime" => $leaveTime["startTime"], + "endTime" => $leaveTime["endTime"], + "thanatoName"=>$thanatoName, + "date" => $currentDateFormatted, + "totalHours" => $leaveTime["totalHours"], + "totalWorkedHours" => $leaveTime["totalWorkedHours"], + "isPublicHoliday" => $isPublicHoliday, + "absenceTypeKey" => $absenceTypeKey, + "absenceTypeLabel" => $absenceTypeLabel + ]; + } + } + } + return $devisListPerThanatoPerDate; + } + + public function getRouteLinesByDevisIdList(array $devisIdList){ + if(empty($devisIdList)){ + return []; + } + $sqlConditionsPlaceholder = implode(',', array_fill(0, count($devisIdList), '?')); + $sql = "SELECT ligne_trajet.id, ligne_trajet.rang, ligne_trajet.id_nextcloud, ligne_trajet.date, + ligne_trajet.user_id, ligne_trajet.commentaire, ligne_trajet.source, + lieu.id as lieu_id, lieu.nom as lieu, lieu.latitude as latitude, lieu.longitude as longitude + FROM (".$this->tableprefix."ligne_trajet as ligne_trajet + LEFT JOIN ".$this->tableprefix."lieu as lieu on ligne_trajet.id_lieu = lieu.id) + WHERE ligne_trajet.id_devis IN ($sqlConditionsPlaceholder) + ORDER BY ligne_trajet.date ASC, ligne_trajet.rang ASC;"; + return $this->execSQLNoJsonReturn($sql, $devisIdList); + } + } diff --git a/gestion/lib/Helpers/DateHelpers.php b/gestion/lib/Helpers/DateHelpers.php index 19961a7..6ded76d 100644 --- a/gestion/lib/Helpers/DateHelpers.php +++ b/gestion/lib/Helpers/DateHelpers.php @@ -64,4 +64,71 @@ class DateHelpers return $lastDay; } + public static function getDaysCountInAMonthAndYear($month,$year){ + return $month == 2 ? ($year % 4 ? 28 : ($year % 100 ? 29 : ($year % 400 ? 28 : 29))) : (($month - 1) % 7 % 2 ? 30 : 31); + } + + public static function getDatesOfMonth($year, $month) { + $dates = []; + $daysInMonth = self::getDaysCountInAMonthAndYear($month, $year); + + for ($day = 1; $day <= $daysInMonth; $day++) { + $dateString = sprintf("%04d-%02d-%02d", $year, $month, $day); + $dates[] = new DateTime($dateString); + } + + return $dates; + } + + public static function isPublicHoliday(string $dateString): bool + { + try { + $date = new DateTime($dateString); + $dayOfWeek = $date->format('N'); + return $dayOfWeek == 7; + } catch (Exception $e) { + return false; + } + } + + public static function getPublicHolidayText($isPublicHoliday){ + return $isPublicHoliday ? "Ferie" : "J"; + } + + public static function getHoursBetweenTwoDatetime($datetimeEnd,$datetimeStart){ + if($datetimeEnd == null || $datetimeStart == null){ + return 0; + } + $interval = $datetimeStart->diff($datetimeEnd); + $hours = $interval->h + ($interval->days * 24) + ($interval->i / 60); + return $hours; + } + + public static function GetWorkingHoursBetweenDatetimeEndAndDatetimeStart(Datetime|null $datetimeEnd,Datetime|null $datetimeStart){ + if($datetimeEnd == null || $datetimeStart == null){ + return 0; + } + $workingStartAM = new DateTime($datetimeStart->format('Y-m-d') . ' 08:00',$datetimeStart->getTimezone()); + $workingEndAM = new DateTime($datetimeStart->format('Y-m-d') . ' 12:00',$datetimeStart->getTimezone()); + $workingStartPM = new DateTime($datetimeStart->format('Y-m-d') . ' 13:00',$datetimeStart->getTimezone()); + $workingEndPM = new DateTime($datetimeStart->format('Y-m-d') . ' 17:00',$datetimeStart->getTimezone()); + $totalHours = 0; + if ($datetimeStart->format('N') < 7) { + $dayStartAM = max($datetimeStart, $workingStartAM); + $dayEndAM = min($datetimeEnd, $workingEndAM); + if ($dayStartAM < $dayEndAM) { + $totalHours += ($dayEndAM->getTimestamp() - $dayStartAM->getTimestamp()) / 3600; + } + $dayStartPM = max($datetimeStart, $workingStartPM); + $dayEndPM = min($datetimeEnd, $workingEndPM); + if ($dayStartPM < $dayEndPM) { + $totalHours += ($dayEndPM->getTimestamp() - $dayStartPM->getTimestamp()) / 3600; + } + } + else{ + $totalHours = ($datetimeEnd->getTimestamp() - $datetimeStart->getTimestamp()) / 3600; + } + return $totalHours; + } + } diff --git a/gestion/lib/Helpers/FileExportHelpers.php b/gestion/lib/Helpers/FileExportHelpers.php index 7a81732..d90d91a 100644 --- a/gestion/lib/Helpers/FileExportHelpers.php +++ b/gestion/lib/Helpers/FileExportHelpers.php @@ -2,6 +2,8 @@ namespace OCA\Gestion\Helpers; +use OCA\Gestion\Constants\VCalendarPropertyConstant; + class FileExportHelpers { @@ -37,4 +39,16 @@ class FileExportHelpers return $stringWithoutSpace; } + public static function GetAbsenceTypeLabelFromKey(string $key){ + $label = null; + $absenceTypes = VCalendarPropertyConstant::ABSENCE_TYPES_KEYS_VALUES; + foreach($absenceTypes as $absenceTypeKey => $absenceTypeLabel){ + if($absenceTypeKey == $key){ + $label = $absenceTypeLabel; + break; + } + } + return $label; + } + } diff --git a/gestion/lib/Helpers/GeoHelpers.php b/gestion/lib/Helpers/GeoHelpers.php new file mode 100644 index 0000000..290e020 --- /dev/null +++ b/gestion/lib/Helpers/GeoHelpers.php @@ -0,0 +1,17 @@ +format("H") . "h"; } $dateEnd = self::GetDateStartOrDateEndFromVCalendarString("DTEND", $vCalendarString); - if ($dateEnd != null) { + if($dateEnd != null){ $endTimeValue = $dateEnd->format("H") . "h"; } + $totalHours = DateHelpers::getHoursBetweenTwoDatetime($dateEnd,$dateStart); + $totalWorkedHours = DateHelpers::GetWorkingHoursBetweenDatetimeEndAndDatetimeStart($dateEnd,$dateStart); } return [ "startTime" => $startTimeValue, - "endTime" => $endTimeValue + "endTime" => $endTimeValue, + "totalHours" => $totalHours, + "totalWorkedHours" => $totalWorkedHours ]; } diff --git a/gestion/lib/Service/ExportThanatoStatisticService.php b/gestion/lib/Service/ExportThanatoStatisticService.php index 8e0a827..f3d33be 100644 --- a/gestion/lib/Service/ExportThanatoStatisticService.php +++ b/gestion/lib/Service/ExportThanatoStatisticService.php @@ -26,11 +26,13 @@ declare(strict_types=1); namespace OCA\Gestion\Service; -use OCA\Gestion\Constants\OrderTypeConstant; -use OCA\Gestion\Constants\ThanatoTypeConstant; +use OCA\Gestion\Constants\AbsenceTypeConstant; +use OCA\Gestion\Constants\BddConstant; use OCA\Gestion\Db\Bdd; +use OCA\Gestion\Helpers\DateHelpers; use OCA\Gestion\Helpers\FileExportHelpers; use Psr\Log\LoggerInterface; +use OCP\Files\IRootFolder; class ExportThanatoStatisticService { /** @var Bdd */ @@ -39,35 +41,70 @@ class ExportThanatoStatisticService { /** @var LoggerInterface */ private $logger; + /** @var IRootFolder */ + private $rootFolder; + + private $geoService; + public function __construct( Bdd $gestionBdd, - LoggerInterface $logger) { + LoggerInterface $logger, + IRootFolder $rootFolder, + GeoService $geoService) { + $this->geoService = $geoService; + $this->rootFolder = $rootFolder; $this->logger = $logger; $this->gestionBdd = $gestionBdd; } - public function getThanatoStatisticFolders($thanatoList,$year){ - $thanatoStatFolders = ['STATISTIQUES/THANATOS/']; - foreach($thanatoList as $thanato){ - if($thanato['fk_thanato_type_key'] == ThanatoTypeConstant::THANATO_TYPE_SUBCONTRACTOR){ - $thanatoStatFolders[] = 'STATISTIQUES/FOURNISSEURS/'.$year.'/'; - break; - } - } - return $thanatoStatFolders; - } - - public function getFilename(array $thanatoList,$month,$year){ + private function getFilename($thanatoName,$thanatoLastName,$month,$year){ $filename = "$year-$month-"; - foreach($thanatoList as $thanato){ - $filename .= $thanato['thanato_nom'] . '-' . $thanato['thanato_prenom'] . '--'; - } - $filename = rtrim($filename, '-'); + $filename .= $thanatoName . '-' . $thanatoLastName; $filename = str_replace(' ','-', $filename); $filename = str_replace(' ','-', $filename); return $filename; } + private function exportThanatoStatistic($thanatoId,$month,$year,$idNextcloud){ + $thanato = $this->gestionBdd->getThanatoById($thanatoId); + if($thanato == null){ + return null; + } + $exportData = $this->gestionBdd->getExportThanatoStatisticData($thanatoId,$month,$year); + if(empty($exportData)){ + return null; + } + $defaultConfig = json_decode($this->gestionBdd->getConfiguration(BddConstant::DEFAULT_ADMIN_APP_ID_NEXTCLOUD)); + $racineFolder = html_entity_decode($defaultConfig[0]->path).'/'; + $thanatoFolder = $racineFolder.'STATISTIQUES/THANATOS/'; + $fileHeader = $this->getExportThanatoFileHeader(); + $fileContent = $this->populateExportDataIntoFileContent($exportData,$fileHeader); + $storage = $this->rootFolder->getUserFolder($idNextcloud); + try{ + $storage->newFolder($thanatoFolder); + } + catch(\OCP\Files\NotPermittedException $e) { + + } + $filename = $this->getFilename($thanato["nom"],$thanato["prenom"],$month,$year); + $fileNamePath = $thanatoFolder."STAT-THANATO-" . $filename . '.csv'; + $storage->newFile($fileNamePath); + $file = $storage->get($fileNamePath); + $file->putContent($fileContent); + return $fileNamePath; + } + + public function exportThanatosListStatistic(array $thanatoIds,$month,$year,$idNextcloud){ + $filenames = []; + foreach($thanatoIds as $thanatoId){ + $filename = $this->exportThanatoStatistic($thanatoId,$month,$year,$idNextcloud); + if($filename != null){ + $filenames[] = $filename; + } + } + return $filenames; + } + public function getExportThanatoFileHeader(): string{ $fileHeader = 'FACTURE'.';'. @@ -77,34 +114,142 @@ class ExportThanatoStatisticService { 'HEURE DE FIN'.';'. 'SOINS'.';'. 'JOUR/FERIE'.';'. + 'CONGE'.';'. + 'REPOS'.';'. + 'MALADIE'.';'. 'NOM ET PRENOM'.';'. 'LIEU'.';'. 'POMPES FUNEBRES'.';'. 'ADRESSE'.';'. - 'BON DE COMMANDE'.';'. - 'TOTAL ACHAT'.';'. 'DISTANCE TOTALE KM'.';'. + 'HEURES TOTAL DE SOIN'.';'. + 'HEURES TOTAL DE CONGE'.';'. + 'HEURES TOTAL DE REPOS'.';'. + 'HEURES TOTAL DE MALADIE'.';'. + 'HEURES TOTAL DE TRAVAIL'.';'. + 'HEURES TOTAL DE PARCOURS ENTRE DEVIS'.';'. "\n"; return $fileHeader; } + private function populateNoDevisDataInADay(string $fileContent,$leave){ + $startTimeValue = ""; + $endTimeValue = ""; + $leaveValue = "Non"; + $diseaseValue = "Non"; + $restValue = "Non"; + if($leave["onLeave"]){ + $startTimeValue = $leave["startTime"]; + $endTimeValue = $leave["endTime"]; + if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE){ + $leaveValue = "Oui"; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){ + $diseaseValue = "Oui"; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){ + $restValue = "Oui"; + } + } + $fileContent = $fileContent. + ''.';'. + FileExportHelpers::FormatTextForExport($leave['thanatoName']).';'. + $leave['date'].';'. + $startTimeValue.';'. + $endTimeValue.';'. + ''.';'. + DateHelpers::getPublicHolidayText($leave['isPublicHoliday']).';'. + $leaveValue.';'. + $diseaseValue.';'. + $restValue.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'."\n"; + return $fileContent; + } + public function populateExportDataIntoFileContent(array $exportData,string $fileContent): string{ - foreach($exportData as $thanatoId => $devisPerThanato){ - foreach($devisPerThanato as $devisDate => $devisData){ - $distanceTotal = $this->gestionBdd->getDistanceTotalByDevisIdList($devisData["devisId"]); + foreach($exportData as $devisDate => $devisData){ + $totalDevisHours = 0; + $totalWorkedHours = 8; + $totalLeaveHours = 0; + $totalDiseaseHours = 0; + $totalRestHours = 0; + $totalDistance = 0; + $totalTravelingHoursBetweenDevisLocation = 0; + $hasDevisInTheCurrentDate = $devisData['hasDevis']; + if($hasDevisInTheCurrentDate === false){ + $leaves = $devisData["leaves"]; + foreach($leaves as $leave){ + $fileContent = $this->populateNoDevisDataInADay($fileContent,$leave); + if($leave["onLeave"]){ + $totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"]; + if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE){ + $totalLeaveHours += $totalLeaveHoursInsideWorkingHours; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){ + $totalRestHours += $totalLeaveHoursInsideWorkingHours; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){ + $totalDiseaseHours += $totalLeaveHoursInsideWorkingHours; + } + } + } + $totalWorkedHours -= $totalLeaveHours - $totalRestHours - $totalDiseaseHours; + } + else{ + $routeLines = $this->gestionBdd->getRouteLinesByDevisIdList($devisData["devisId"]); + $totalDistanceAndTotalTravelingHoursBetweenDevis = $this->geoService->getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines($routeLines); + $totalDistance = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalDistance"]; + $totalTravelingHoursBetweenDevisLocation = $totalDistanceAndTotalTravelingHoursBetweenDevis["totalTravelingHours"]; $devisList = $devisData["devis"]; + $leaves = $devisData["leaves"]; if(!empty($devisList)){ foreach($devisList as $devis){ $fileContent = $this->populateDevisDataIntoThanatoExportFileContent($fileContent,$devis); + $totalDevisHours += $devis["totalHours"]; } - $fileContent = $this->populateDistanceTotalIntoThanatoExportFileContent($fileContent,$distanceTotal); } + foreach($leaves as $leave){ + $fileContent = $this->populateNoDevisDataInADay($fileContent,$leave); + if($leave["onLeave"]){ + $totalLeaveHoursInsideWorkingHours = $leave["totalWorkedHours"]; + if($leave["absenceTypeKey"] == AbsenceTypeConstant::LEAVE){ + $totalLeaveHours += $totalLeaveHoursInsideWorkingHours; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::REST){ + $totalRestHours += $totalLeaveHoursInsideWorkingHours; + } + if($leave["absenceTypeKey"] == AbsenceTypeConstant::DISEASE){ + $totalDiseaseHours += $totalLeaveHoursInsideWorkingHours; + } + } + } + $totalWorkedHours -= $totalLeaveHours - $totalRestHours - $totalDiseaseHours; } + $fileContent = $this->populateLastRecapForTheLine( + $fileContent, + $totalDistance, + $totalDevisHours, + $totalWorkedHours, + $totalLeaveHours, + $totalTravelingHoursBetweenDevisLocation, + $totalDiseaseHours, + $totalRestHours + ); } return $fileContent; } - private function populateDistanceTotalIntoThanatoExportFileContent(string $fileContent,$distance){ + private function populateLastRecapForTheLine(string $fileContent,$distance,$totalDevisHours,$totalWorkedHours,$totalLeaveHours,$totalTravelingHours,$totalDiseaseHours = 0,$totalRestHours = 0){ $fileContent = $fileContent. ''.';'. ''.';'. @@ -119,7 +264,14 @@ class ExportThanatoStatisticService { ''.';'. ''.';'. ''.';'. - utf8_decode(html_entity_decode("$distance"))."\n"; + ''.';'. + "$distance"."KM".';'. + "$totalDevisHours"."H".';'. + "$totalLeaveHours"."H".';'. + "$totalRestHours"."H".';'. + "$totalDiseaseHours"."H".';'. + "$totalWorkedHours"."H".';'. + "$totalTravelingHours"."H"."\n"; return $fileContent; } @@ -135,15 +287,6 @@ class ExportThanatoStatisticService { private function populateDevisDataIntoThanatoExportFileContent(string $fileContent,array $devis){ $produitAsString = $this->getFormatDevisProduitsAsString($devis["produits"]); - $orderFullNumber = ""; - $totalOrderPrice = ""; - $isDevisDoneBySubContractor = $devis['fk_order_type_key'] == OrderTypeConstant::ORDER_TYPE_DEVIS && - $devis['order_id'] != null && $devis["fk_thanato_type_key"] == ThanatoTypeConstant::THANATO_TYPE_SUBCONTRACTOR; - - if($isDevisDoneBySubContractor){ - $orderFullNumber = $devis["order_full_number"]; - $totalOrderPrice = $devis["total_price"]; - } $fileContent = $fileContent. FileExportHelpers::FormatTextForExport($devis["facture_num"]).';'. FileExportHelpers::FormatTextForExport($devis['nom_thanato'] . ' ' . $devis['prenom_thanatho']).';'. @@ -152,12 +295,19 @@ class ExportThanatoStatisticService { FileExportHelpers::FormatTextForExport($devis["endTime"]).';'. FileExportHelpers::FormatTextForExport($produitAsString).';'. FileExportHelpers::FormatTextForExport($devis["dayType"]).';'. + FileExportHelpers::FormatTextForExport('Non').';'. + ''.';'. + ''.';'. FileExportHelpers::FormatTextForExport($devis["nom_defunt"]).';'. FileExportHelpers::FormatTextForExport($devis["nom_lieu"] ?? "").';'. FileExportHelpers::FormatTextForExport($devis["nom_client"] ?? "").';'. - FileExportHelpers::FormatTextForExport($devis["client_adresse"] ?? "").';'. - FileExportHelpers::FormatTextForExport($orderFullNumber).';'. - "$totalOrderPrice".';'. + FileExportHelpers::FormatTextForExport($devis["client_adresse"] ?? ""). + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. + ''.';'. ''.';'."\n"; return $fileContent; diff --git a/gestion/lib/Service/GeoService.php b/gestion/lib/Service/GeoService.php new file mode 100644 index 0000000..34acd1a --- /dev/null +++ b/gestion/lib/Service/GeoService.php @@ -0,0 +1,128 @@ + + * + * @author Anna Larch + * @author Richard Steinmetz + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE + * License as published by the Free Software Foundation; either + * version 3 of the License, or any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU AFFERO GENERAL PUBLIC LICENSE for more details. + * + * You should have received a copy of the GNU Affero General Public + * License along with this library. If not, see . + * + */ + +namespace OCA\Gestion\Service; + +use Exception; +use OCA\Gestion\Constants\GeoConstant; +use OCA\Gestion\Helpers\GeoHelpers; + +class GeoService { + + public function __construct() { + } + + /** + * Calcul la distance entre les deux points à vol d'oiseau + */ + private function getDistanceInKmBetweenTwoPoints($lat1, $lon1, $lat2, $lon2) { + $R = 6371; // Rayon moyen de la Terre en kilomètres + $dLat = deg2rad($lat2 - $lat1); + $dLon = deg2rad($lon2 - $lon1); + $a = sin($dLat/2) * sin($dLat/2) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * sin($dLon/2) * sin($dLon/2); + $c = 2 * atan2(sqrt($a), sqrt(1-$a)); + $d = $R * $c; + return round($d, 2); + } + + private function getTravelingHourBetweenTwoPoints(array $origin,array $destination,$mode = "driving"){ + $baseUrl = "https://api.geoapify.com/v1/routing"; + $originPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($origin["latitude"],$origin["longitude"]); + $destinationPoints = GeoHelpers::getPointsTextFromLatitudeAndLongitude($destination["latitude"],$destination["longitude"]); + + $fullUrl = $baseUrl."?waypoints=$originPoints|$destinationPoints&mode=$mode&apiKey=9e23d93e7f454c988344f9171bf867aa"; + $curl = curl_init(); + try { + curl_setopt_array($curl, array( + CURLOPT_URL => $fullUrl, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => '', + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 0, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => 'GET', + )); + + $response = curl_exec($curl); + + curl_close($curl); + + if ($response === false) { + return 0; + } else { + $timeInSecondes = json_decode($response)->features[0]->properties->time; + $travelTimeHours = $timeInSecondes / 3600; + $travelTimeHours = round($travelTimeHours, 2); + return $travelTimeHours; + } + } + catch(Exception $e){ + return 0; + } + } + + public function getTotalDistanceAndTotalTravelingHoursBetweenDevisLocationByRouteLines(array $routeLines){ + $distanceCumul = 0; + $totalTravelingHoursBetweenTwoDevisLocation = 0; + $lastPoint = NULL; + for ($i=0; $i < sizeof($routeLines); $i++) { + $currentDistance = 0; + if($routeLines[$i]['lieu_id'] != NULL){ + $lastPoint = $routeLines[$i]; + } + if($lastPoint['lieu_id'] != NULL && $routeLines[$i+1]['lieu_id'] != NULL){ + $currentDistance = $this->getDistanceInKmBetweenTwoPoints( + floatval(value: $lastPoint['latitude']), + floatval($lastPoint['longitude']), + floatval($routeLines[$i+1]['latitude']), + floatval($routeLines[$i+1]['longitude']) + ); + $targetIsBetweenTwoDevisLocation = $lastPoint['source'] != "siege" && $routeLines[$i+1]["source"] != "siege"; + if($targetIsBetweenTwoDevisLocation){ + $originPoints = [ + "latitude" => $lastPoint["latitude"], + "longitude" => $lastPoint["longitude"] + ]; + $destinationPoints = [ + "latitude" => $routeLines[$i+1]["latitude"], + "longitude" => $routeLines[$i+1]["longitude"] + ]; + $totalTravelingHoursBetweenTwoDevisLocation+= $this->getTravelingHourBetweenTwoPoints( + $originPoints, + $destinationPoints, + GeoConstant::DRIVING_MODE + ); + } + } + $distanceCumul += $currentDistance; + } + return [ + "totalDistance" => $distanceCumul, + "totalTravelingHours" => $totalTravelingHoursBetweenTwoDevisLocation + ]; + } +}