mirror of
https://github.com/espocrm/espocrm.git
synced 2026-06-28 15:06:06 +00:00
394 lines
10 KiB
PHP
394 lines
10 KiB
PHP
<?php
|
|
/************************************************************************
|
|
* This file is part of EspoCRM.
|
|
*
|
|
* EspoCRM - Open Source CRM application.
|
|
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
|
* Website: https://www.espocrm.com
|
|
*
|
|
* EspoCRM is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* EspoCRM 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with EspoCRM. If not, see http://www.gnu.org/licenses/.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of this program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU General Public License version 3.
|
|
*
|
|
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
|
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
|
************************************************************************/
|
|
|
|
namespace Espo\Tools\WorkingTime;
|
|
|
|
use Espo\Tools\WorkingTime\Calendar\WorkingWeekday;
|
|
use Espo\Tools\WorkingTime\Calendar\WorkingDate;
|
|
use Espo\Tools\WorkingTime\Calendar\HavingRanges;
|
|
|
|
use Espo\Core\Field\DateTime;
|
|
use Espo\Core\Field\Date;
|
|
|
|
class Extractor
|
|
{
|
|
/**
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
public function extract(Calendar $calendar, DateTime $from, DateTime $to): array
|
|
{
|
|
$pointer = $from->withTimezone($calendar->getTimezone());
|
|
|
|
$fromDate = Date::fromDateTime($from->modify('-1 day')->getDateTime());
|
|
$toDate = Date::fromDateTime($from->modify('+1 day')->getDateTime());
|
|
|
|
$workingDates = $calendar->getWorkingDates($fromDate, $toDate);
|
|
$nonWorkingDates = $calendar->getNonWorkingDates($fromDate, $toDate);
|
|
$workingWeekdays = $calendar->getWorkingWeekdays();
|
|
|
|
$list = [];
|
|
|
|
$end = $to->withTimezone($calendar->getTimezone())->withTime(23, 59, 59);
|
|
|
|
while ($pointer->getTimestamp() < $end->getTimestamp()) {
|
|
$list = array_merge(
|
|
$list,
|
|
$this->extractIteration(
|
|
$pointer,
|
|
$workingDates,
|
|
$nonWorkingDates,
|
|
$workingWeekdays,
|
|
),
|
|
);
|
|
|
|
$pointer = $pointer->modify('+1 day');
|
|
}
|
|
|
|
return $this->trim($list, $from, $to, $calendar);
|
|
}
|
|
|
|
/**
|
|
* @param array{DateTime,DateTime}[] $list
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
private function trim(array $list, DateTime $from, DateTime $to, Calendar $calendar): array
|
|
{
|
|
$wasUnset = false;
|
|
|
|
foreach ($list as $i => $pair) {
|
|
if ($from->isLessThan($pair[0]) || $from->isEqualTo($pair[0])) {
|
|
break;
|
|
}
|
|
|
|
if ($from->isGreaterThan($pair[1]) || $from->isEqualTo($pair[1])) {
|
|
unset($list[$i]);
|
|
$wasUnset = true;
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($from->isLessThan($pair[1])) {
|
|
$list[$i][0] = $from->withTimezone($calendar->getTimezone());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ($wasUnset) {
|
|
$list = array_values($list);
|
|
|
|
$wasUnset = false;
|
|
}
|
|
|
|
for ($i = count($list) - 1; $i >= 0; $i--) {
|
|
$pair = $list[$i];
|
|
|
|
if ($to->isGreaterThan($pair[1]) || $to->isEqualTo($pair[1])) {
|
|
break;
|
|
}
|
|
|
|
if ($to->isLessThan($pair[0]) || $to->isEqualTo($pair[0])) {
|
|
unset($list[$i]);
|
|
$wasUnset = true;
|
|
|
|
continue;
|
|
}
|
|
|
|
if ($to->isGreaterThan($pair[0])) {
|
|
$list[$i][1] = $to->withTimezone($calendar->getTimezone());
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
if ($wasUnset) {
|
|
$list = array_values($list);
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
public function extractAllDay(Calendar $calendar, DateTime $from, DateTime $to): array
|
|
{
|
|
$pointer = $from
|
|
->withTimezone($calendar->getTimezone())
|
|
->withTime(0, 0, 0);
|
|
|
|
$fromDate = Date::fromDateTime($from->modify('-1 day')->getDateTime());
|
|
$toDate = Date::fromDateTime($from->modify('+1 day')->getDateTime());
|
|
|
|
$workingDates = $calendar->getWorkingDates($fromDate, $toDate);
|
|
$nonWorkingDates = $calendar->getNonWorkingDates($fromDate, $toDate);
|
|
$workingWeekdays = $calendar->getWorkingWeekdays();
|
|
|
|
$list = [];
|
|
|
|
$end = $to->withTimezone($calendar->getTimezone())->withTime(23, 59, 59);
|
|
|
|
while ($pointer->getTimestamp() < $end->getTimestamp()) {
|
|
$isWorkingDay = $this->isWorkingDay(
|
|
$pointer,
|
|
$workingDates,
|
|
$nonWorkingDates,
|
|
$workingWeekdays,
|
|
);
|
|
|
|
$nextPointer = $pointer->modify('+1 day');
|
|
|
|
if ($isWorkingDay) {
|
|
$list[] = [
|
|
$pointer,
|
|
$nextPointer
|
|
];
|
|
}
|
|
|
|
$pointer = $nextPointer;
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
|
|
/**
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
public function extractInversion(Calendar $calendar, DateTime $from, DateTime $to): array
|
|
{
|
|
$list = $this->extract($calendar, $from, $to);
|
|
|
|
$timezone = $calendar->getTimezone();
|
|
|
|
if ($list === []) {
|
|
return [
|
|
[
|
|
$from->withTimezone($timezone),
|
|
$to->withTimezone($timezone),
|
|
]
|
|
];
|
|
}
|
|
|
|
$listInverted = [];
|
|
|
|
$count = count($list);
|
|
|
|
$listInverted[] = [
|
|
$from->withTimezone($calendar->getTimezone()),
|
|
$list[0][0]
|
|
];
|
|
|
|
for ($i = 0; $i < $count - 1; $i++) {
|
|
$item1 = $list[$i];
|
|
$item2 = $list[$i + 1];
|
|
|
|
$listInverted[] = [
|
|
$item1[1],
|
|
$item2[0]
|
|
];
|
|
}
|
|
|
|
$listInverted[] = [
|
|
$list[$count - 1][1],
|
|
$to->withTimezone($timezone)
|
|
];
|
|
|
|
return $listInverted;
|
|
}
|
|
|
|
/**
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
public function extractAllDayInversion(Calendar $calendar, DateTime $from, DateTime $to): array
|
|
{
|
|
$list = $this->extractAllDay($calendar, $from, $to);
|
|
|
|
if ($list === []) {
|
|
return [[$from, $to]];
|
|
}
|
|
|
|
$count = count($list);
|
|
|
|
$listInverted = [];
|
|
|
|
$listInverted[] = [
|
|
$from,
|
|
$list[0][0]
|
|
];
|
|
|
|
for ($i = 0; $i < $count - 1; $i++) {
|
|
$item1 = $list[$i];
|
|
$item2 = $list[$i + 1];
|
|
|
|
$listInverted[] = [
|
|
$item1[1],
|
|
$item2[0]
|
|
];
|
|
}
|
|
|
|
$listInverted[] = [
|
|
$list[$count - 1][1],
|
|
$to
|
|
];
|
|
|
|
return $listInverted;
|
|
}
|
|
|
|
/**
|
|
* @param WorkingDate[] $workingDates
|
|
* @param WorkingDate[] $nonWorkingDates
|
|
* @param WorkingWeekday[] $workingWeekdays
|
|
*/
|
|
private function isWorkingDay(
|
|
DateTime $pointer,
|
|
array $workingDates,
|
|
array $nonWorkingDates,
|
|
array $workingWeekdays
|
|
): bool {
|
|
|
|
if ($this->findInDateList($pointer, $nonWorkingDates)) {
|
|
return false;
|
|
}
|
|
|
|
$day1 = $this->findInDateList($pointer, $workingDates);
|
|
|
|
if ($day1) {
|
|
return true;
|
|
}
|
|
|
|
$day2 = $this->findInWeekdayList($pointer, $workingWeekdays);
|
|
|
|
if ($day2) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* @param WorkingDate[] $workingDates
|
|
* @param WorkingDate[] $nonWorkingDates
|
|
* @param WorkingWeekday[] $workingWeekdays
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
private function extractIteration(
|
|
DateTime $pointer,
|
|
array $workingDates,
|
|
array $nonWorkingDates,
|
|
array $workingWeekdays
|
|
): array {
|
|
|
|
if ($this->findInDateList($pointer, $nonWorkingDates)) {
|
|
return [];
|
|
}
|
|
|
|
$day1 = $this->findInDateList($pointer, $workingDates);
|
|
|
|
if ($day1) {
|
|
return $this->extractFromDay($pointer, $day1);
|
|
}
|
|
|
|
$day2 = $this->findInWeekdayList($pointer, $workingWeekdays);
|
|
|
|
if ($day2) {
|
|
return $this->extractFromDay($pointer, $day2);
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @param DateTime $pointer
|
|
* @param WorkingDate[] $dateList
|
|
*/
|
|
private function findInDateList(DateTime $pointer, array $dateList): ?WorkingDate
|
|
{
|
|
$day = $pointer->getDay();
|
|
$month = $pointer->getMonth();
|
|
$year = $pointer->getYear();
|
|
|
|
foreach ($dateList as $item) {
|
|
$date = $item->getDate();
|
|
|
|
if (
|
|
$date->getDay() === $day &&
|
|
$date->getMonth() === $month &&
|
|
$date->getYear() === $year
|
|
) {
|
|
return $item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @param DateTime $pointer
|
|
* @param WorkingWeekday[] $dayList
|
|
*/
|
|
private function findInWeekdayList(DateTime $pointer, array $dayList): ?WorkingWeekday
|
|
{
|
|
$dow = $pointer->getDayOfWeek();
|
|
|
|
foreach ($dayList as $item) {
|
|
if ($item->getWeekday() === $dow) {
|
|
return $item;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* @return array{DateTime,DateTime}[]
|
|
*/
|
|
private function extractFromDay(DateTime $dateTime, HavingRanges $day): array
|
|
{
|
|
$pointer = $dateTime->getDateTime();
|
|
|
|
$list = [];
|
|
|
|
foreach ($day->getRanges() as $range) {
|
|
$start = $range->getStart();
|
|
$end = $range->getEnd();
|
|
|
|
$list[] = [
|
|
DateTime::fromDateTime(
|
|
$pointer->setTime($start->getHour(), $start->getMinute())
|
|
),
|
|
DateTime::fromDateTime(
|
|
$pointer->setTime($end->getHour(), $end->getMinute())
|
|
)
|
|
];
|
|
}
|
|
|
|
return $list;
|
|
}
|
|
}
|