Skip to content

Commit 846746f

Browse files
committed
is_late implementation & tests (wip)
1 parent 70690ce commit 846746f

6 files changed

Lines changed: 109 additions & 40 deletions

File tree

phpunit/functional/OLATest.php

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,33 @@
101101
* - ttr waiting time is incremented while the ticket status is WAITING : @see self::testOlaTTRWaitingTimeIsIncrementedWhileTicketStatusIsWaiting()
102102
* + @todo tests avec autres groupes
103103
*
104+
* - ticket is late if : (business logic extracted from CommonITILObject::generateSLAOLAComputation())
105+
* tto :
106+
* - ola due time is not null (0)
107+
* - and ticket status is not WAITING (1)
108+
* - and one of the following is true :
109+
* - takeintoaccountdate is not null & > due_time (2.1))
110+
* - takeintoaccountdate is null & target resolution delay (time elapsed since ticket creation without pauses) > time elapsed since ticket start start (2.2) // @todoseb need rewrite
111+
* - takeintoaccountdate is null & due time is passed (2.3)
112+
* - ttr :
113+
* - due time is not null
114+
* - ticket status is not WAITING
115+
* - ticket solved_date > due_time
116+
* - or solved_date is null & due_time is passed
117+
* // ---
118+
*
119+
* - tto : (takeintoaccountdate is replaced by end_time)
120+
* - end_time is defined and > due_time - @see self::testOlaTtoIsLateWhenEndTimeIsAfterDueTime()
121+
* - end_time is not defined & due_time is passed - @see self::testOlaTtoIsLateWhenDueTimeIsPassed()
122+
* - ticket status is not WAITING (1): @see self::testOlaTtoIsLateWhenTicketStatusIsNotWaiting() // @todoseb
123+
* and that's all.
124+
125+
* // ----
126+
* - is never late if ticket is solved or closed : @see self::testOlaTtoIsNotLateWhenTicketIsSolvedOrClosed()
127+
* - ttr : @todoseb implémenter tests manquants
128+
*
129+
* // @todoseb test si is_late change quand ticket devient waiting
130+
*
104131
* - when completion is done, the associated group is removed from ticket assignees : not implemented, seems not relevant atm
105132
*/
106133

@@ -811,6 +838,32 @@ public function testOlaTTRWaitingTimeIsIncrementedWhileTicketStatusIsWaiting()
811838
$this->assertEquals(20 * 60, $ola_data['waiting_time'], 'Waiting time should be incremented by 20 minutes after 20 min in WAITING status for an OLA TTR');
812839
}
813840

841+
public function testOlaTtoIsLateWhenEndTimeIsAfterDueTime(): void
842+
{
843+
// arrange
844+
$this->login();
845+
$ola = $this->createOLA(ola_type: SLM::TTR)['ola'];
846+
$now = $this->setCurrentTime('10:04:00', '2025-06-26');
847+
$ticket = $this->createTicket(['_la_update' => true, '_olas_id' => [$ola->getID()]]);
848+
849+
// act - check ola is not yet late
850+
$ola_data = $ticket->getOlasData()[0];
851+
assert($ola_data['is_late'] == 0, 'OLA should not be late when end time is not set');
852+
853+
// act : complete ola after due time - wait for ola to be late + assign the ola group to the ticket
854+
$later = clone($now);
855+
$later->add($this->getDefaultTtrDelayInterval());
856+
$later->add(new \DateInterval('PT1H')); // add 1 hour to ensure end time is after due time
857+
$this->setCurrentTime($later->format('Y-m-d H:i:s'));
858+
$this->updateItem($ticket::class, $ticket->getID(), ['_groups_id_assign' => $ola->fields['groups_id']]);
859+
$this->runOlaCron();
860+
861+
// assert - check ola is late
862+
$ola_data = $ticket->getOlasData()[0];
863+
dump($ola_data, $ola_data['is_late']);
864+
$this->assertEquals(1, $ola_data['is_late'], 'OLA should be late when end time is set');
865+
}
866+
814867
private function getDefaultTtoDelayInterval(): \DateInterval
815868
{
816869
[$amount, $unit] = self::OLA_TTO_DELAY;

phpunit/functional/SLMTest.php

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2966,14 +2966,4 @@ public function testCloneOLA()
29662966
$ola_compare
29672967
);
29682968
}
2969-
2970-
private function runSlaCron(): void
2971-
{
2972-
SlaLevel_Ticket::cronSlaTicket(getItemByTypeName(\CronTask::class, 'slaticket'));
2973-
}
2974-
2975-
private function runOlaCron(): void
2976-
{
2977-
OlaLevel_Ticket::cronOlaTicket(getItemByTypeName(\CronTask::class, 'slaticket')); // at the moment only slaticketcron exists
2978-
}
29792969
}

phpunit/src/Glpi/SLMTrait.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
namespace Glpi\PHPUnit\Tests\Glpi;
3636

3737
use OLA;
38+
use OlaLevel_Ticket;
3839
use SLA;
40+
use SlaLevel_Ticket;
3941
use SLM;
4042

4143
trait SLMTrait
@@ -130,4 +132,15 @@ private function createSLM(array $data = [], ?\Calendar $calendar = null): SLM
130132
]
131133
);
132134
}
135+
136+
private function runSlaCron(): void
137+
{
138+
SlaLevel_Ticket::cronSlaTicket(getItemByTypeName(\CronTask::class, 'slaticket'));
139+
}
140+
141+
private function runOlaCron(): void
142+
{
143+
OlaLevel_Ticket::cronOlaTicket(getItemByTypeName(\CronTask::class, 'slaticket')); // at the moment only slaticketcron exists
144+
\Item_Ola::cron(getItemByTypeName(\CronTask::class, 'slaticket'));
145+
}
133146
}

src/Glpi/Dashboard/Provider.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,9 @@ public static function nbTicketsGeneric(
496496
}
497497

498498

499+
/**
500+
* Get the number of late tickets by SLA status and technician
501+
*/
499502
public static function nbTicketsByAgreementStatusAndTechnician(array $params = []): array
500503
{
501504
/** @var \DBmysql $DB */

src/Item_Ola.php

Lines changed: 40 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@
3333
* ---------------------------------------------------------------------
3434
*/
3535

36+
37+
use function \Safe\strtotime;
38+
3639
class Item_Ola extends CommonDBRelation
3740
{
3841
public static $itemtype_1 = 'itemtype'; // Only Ticket at the moment
@@ -41,6 +44,11 @@ class Item_Ola extends CommonDBRelation
4144
public static $itemtype_2 = OLA::class;
4245
public static $items_id_2 = 'olas_id';
4346

47+
public static function cron(CronTask $cronTask)
48+
{
49+
throw new \Exception('implement me');
50+
}
51+
4452
/**
4553
* Prepare the input for add
4654
*
@@ -69,7 +77,7 @@ public function prepareInputForAdd($input)
6977
}
7078

7179
/**
72-
* Compute the OLA for a ticket
80+
* Compute the OLA data for a ticket
7381
*
7482
* @param \Ticket $ticket
7583
* @param mixed $olas_id must exist in the database
@@ -85,7 +93,8 @@ public static function compute(Ticket $ticket, mixed $olas_id): void
8593
$ola = $item_ola->getOla();
8694
$ola->setTicketCalendar($calendars_id);
8795

88-
$item_ola_data['id'] = $item_ola->getID();
96+
$item_ola_data = $item_ola->fields;
97+
$item_ola_data['id'] = $item_ola->getID(); // for final CommonDBRelation::update
8998

9099
// - update start_time skipped
91100
// nothing to do for TTO : done at creation of item_ola
@@ -110,67 +119,53 @@ public static function compute(Ticket $ticket, mixed $olas_id): void
110119
)
111120
)
112121
) {
113-
$item_ola_data['waiting_time'] = $item_ola->fields['waiting_time'] + $ola->getActiveTimeBetween(
122+
$item_ola_data['waiting_time'] += $ola->getActiveTimeBetween(
114123
$ticket->fields['begin_waiting_date'] ?? 0,
115124
$_SESSION["glpi_currenttime"]
116125
);
117-
$item_ola->fields['waiting_time'] = $item_ola_data['waiting_time'];
118126
}
119127

120128
// - update due_time
121129
// update due_time (former internal_time_to_own, internal_time_to_resolve)
122130
$item_ola_data['due_time'] = $ola->computeDate(
123-
$item_ola->fields['start_time'],
124-
$item_ola->fields['waiting_time']
131+
$item_ola_data['start_time'],
132+
$item_ola_data['waiting_time']
125133
);
126134

127135
// - update end_time
128136
// for TTO, endtime is when the ticket is assigned to the dedicated group.
129137
if ($ola->fields['type'] === SLM::TTO) {
130-
if ($item_ola->fields['end_time'] == null
138+
if ($item_ola_data['end_time'] == null
131139
&&
132140
(
133141
$ticket->haveAGroup(CommonITILActor::ASSIGN, [$ola->fields['groups_id']])
134142
|| self::ticketHasAnAssigneeOfOlaGroup($ticket, $ola)
135143
)
136144
) {
137-
$item_ola->fields['end_time'] = Session::getCurrentTime();
138-
$item_ola_data['end_time'] = $item_ola->fields['end_time'];
145+
$item_ola_data['end_time'] = Session::getCurrentTime();
139146
}
140147
}
141148

142149
// For TTR, end_time is when the ticket is closed
143150
if ($ola->fields['type'] === SLM::TTR) {
144151
if ($ticket->isClosed() || $ticket->isSolved()) {
145-
$item_ola->fields['end_time'] = Session::getCurrentTime();
146152
$item_ola_data['end_time'] = $item_ola->fields['end_time'];
147153
}
148154
}
149155

150-
// - update is_late
151-
// just for POC, condition are a bit more complex
152-
$now = strtotime(Session::getCurrentTime());
153-
$due_time_timestamp = strtotime($item_ola->fields['due_time']);
154-
if( $now > $due_time_timestamp) {
155-
$item_ola->fields['is_late'] = 1;
156-
}
157-
else {
158-
$item_ola->fields['is_late'] = 0;
156+
// update current object
157+
foreach ($item_ola_data as $field => $value) {
158+
$item_ola->fields[$field] = $value;
159159
}
160160

161+
// - update is_late
162+
$item_ola_data['is_late'] = (int) $item_ola->isLate();
163+
161164
if (!(new Item_Ola())->update($item_ola_data)) {
162165
throw new \Exception('Failed to update item_ola');
163166
}
164167
// since dates may be changed, rebuild the levels todo
165168
$ticket->manageOlaLevel($item_ola->fields['olas_id']);
166-
//
167-
// $this->updates[] = "waiting_duration";
168-
// $this->fields["waiting_duration"] += $delay_time;
169-
//
170-
// // Reset begin_waiting_date
171-
// $this->updates[] = "begin_waiting_date";
172-
// $this->fields["begin_waiting_date"] = 'NULL';
173-
174169
}
175170

176171
public function getOla(): OLA
@@ -196,7 +191,7 @@ private static function ticketHasAnAssigneeOfOlaGroup(Ticket $ticket, OLA $ola):
196191

197192
/**
198193
* Get data from Item_Ola + linked OLA for a Ticket
199-
*
194+
* // @todoseb déplacer plus haut
200195
* @param \Ticket $ticket
201196
*
202197
* @return array<array{olas_id: int, items_olas_id: int, name: string, entities_id: int, is_recursive: bool, type: int, comment: string, number_time: int, use_ticket_calendar: bool, calendars_id: int, date_mod: string, definition_time: string, end_of_working_day: string, date_creation: string, slms_id: int, due_time: string, end_time: string, class: string, item: Ticket, nextaction: false|OlaLevel_Ticket|SlaLevel_Ticket, level: false|\LevelAgreementLevel, group_name: string}>
@@ -246,6 +241,23 @@ public function getDataFromOlasIdsForTicket(Ticket $ticket, array $olas_ids): ar
246241
return $this->sort($merged_data);
247242
}
248243

244+
/**
245+
* @todoseb implement me
246+
*/
247+
private function isLate(): bool
248+
{
249+
$now_timestamp = strtotime(Session::getCurrentTime());
250+
$due_time_timestamp = strtotime($this->fields['due_time']);
251+
$end_time_timestamp = is_null($this->fields['end_time']) ? null : strtotime($this->fields['end_time']);
252+
253+
// end_time is after due_time
254+
if(!is_null($end_time_timestamp) && $due_time_timestamp > $end_time_timestamp) {
255+
return true;
256+
}
257+
258+
return false;
259+
}
260+
249261
/**
250262
* @param array $ola_data fields from ola + possibly 'linkid' field representing items_olas_id
251263
* @param \Ticket $ticket
@@ -317,5 +329,4 @@ private function sort(array $merged_data): array
317329

318330
return $merged_data;
319331
}
320-
321332
}

src/LevelAgreement.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,6 @@ public function clearInvalidLevels(int $tickets_id): void
879879
{
880880
// CLear levels of others LA of the same type
881881
// e.g. if a new LA TTR was assigned, clear levels from others (= previous) LA TTR
882-
// @todoseb throw new \Exception('à reimplementer pour OLA ou à ne plus appeller carrément ?');
883882
$level_ticket_class = $this->getLevelTicketClass();
884883
$level_ticket = getItemForItemtype($level_ticket_class);
885884
$level_class = $this->getLevelClass();

0 commit comments

Comments
 (0)