|
69 | 69 | use ITILFollowup; |
70 | 70 | use ITILSolution; |
71 | 71 | use Location; |
| 72 | +use OlaLevel; |
72 | 73 | use Planning; |
73 | 74 | use PlanningEventCategory; |
74 | 75 | use PlanningExternalEvent; |
@@ -444,46 +445,137 @@ public static function getRawKnownSchemas(): array |
444 | 445 | 'readOnly' => true, |
445 | 446 | 'description' => 'Total SLA waiting duration in seconds', |
446 | 447 | ]; |
447 | | - /* |
448 | | - * @FIXME There can be multiple OLAs now, how should we handle this? |
449 | | - * - Should we provide the first element found in API v2.1.x? |
450 | | - * |
451 | | - $schemas[$itil_type]['properties']['ola_ttr'] = self::getDropdownTypeSchema(class: OLA::class, field: 'olas_id_ttr', full_schema: 'OLA') + ['x-version-introduced' => '2.1.0']; |
452 | | - $schemas[$itil_type]['properties']['ola_tto'] = self::getDropdownTypeSchema(class: OLA::class, field: 'olas_id_tto', full_schema: 'OLA') + ['x-version-introduced' => '2.1.0']; |
453 | | - $schemas[$itil_type]['properties']['ola_level_ttr'] = self::getDropdownTypeSchema(class: OlaLevel::class, field: 'olalevels_id_ttr', full_schema: 'OLALevel') + ['x-version-introduced' => '2.1.0']; |
| 448 | + |
| 449 | + // OLA fields: since OLAs are now stored in the items_ola junction table |
| 450 | + // (no more direct olas_id_ttr / olas_id_tto FK on the ticket), we use |
| 451 | + // x-mapper to read the first TTR / first TTO OLA for backward compatibility. |
| 452 | + // |
| 453 | + // A per-request static cache avoids repeated getById + getOlas*Data() calls |
| 454 | + // when multiple OLA fields are resolved for the same ticket during a list. |
| 455 | + $ola_data_cache = []; |
| 456 | + $get_ola_data = static function (int $ticket_id, int $ola_type) use (&$ola_data_cache): ?array { |
| 457 | + $cache_key = $ticket_id . '_' . $ola_type; |
| 458 | + if (!array_key_exists($cache_key, $ola_data_cache)) { |
| 459 | + $ticket = Ticket::getById($ticket_id); |
| 460 | + if (!$ticket instanceof Ticket) { |
| 461 | + $ola_data_cache[$cache_key] = null; |
| 462 | + } else { |
| 463 | + $olas = $ola_type === \SLM::TTR |
| 464 | + ? $ticket->getOlasTTRData() |
| 465 | + : $ticket->getOlasTTOData(); |
| 466 | + $ola_data_cache[$cache_key] = $olas !== [] ? $olas[0] : null; |
| 467 | + } |
| 468 | + } |
| 469 | + return $ola_data_cache[$cache_key]; |
| 470 | + }; |
| 471 | + |
| 472 | + $ola_dropdown_properties = [ |
| 473 | + 'type' => Doc\Schema::TYPE_OBJECT, |
| 474 | + 'nullable' => true, |
| 475 | + 'x-full-schema' => 'OLA', |
| 476 | + 'x-mapped-from' => 'id', |
| 477 | + 'properties' => [ |
| 478 | + 'id' => ['type' => Doc\Schema::TYPE_INTEGER, 'format' => Doc\Schema::FORMAT_INTEGER_INT64], |
| 479 | + 'name' => ['type' => Doc\Schema::TYPE_STRING, 'readOnly' => true], |
| 480 | + ], |
| 481 | + ]; |
| 482 | + $schemas[$itil_type]['properties']['ola_ttr'] = $ola_dropdown_properties + [ |
| 483 | + 'x-version-introduced' => '2.1.0', |
| 484 | + 'x-mapper' => static function ($v) use ($get_ola_data): array|string { |
| 485 | + $ola = $get_ola_data((int) $v, \SLM::TTR); |
| 486 | + return $ola !== null ? ['id' => $ola['olas_id'], 'name' => $ola['name']] : []; |
| 487 | + }, |
| 488 | + ]; |
| 489 | + $schemas[$itil_type]['properties']['ola_tto'] = $ola_dropdown_properties + [ |
| 490 | + 'x-version-introduced' => '2.1.0', |
| 491 | + 'x-mapper' => static function ($v) use ($get_ola_data): array|string { |
| 492 | + $ola = $get_ola_data((int) $v, \SLM::TTO); |
| 493 | + return $ola !== null ? ['id' => $ola['olas_id'], 'name' => $ola['name']] : []; |
| 494 | + }, |
| 495 | + ]; |
| 496 | + |
| 497 | + // OLA level for TTR (equivalent of sla_level_ttr) |
| 498 | + $schemas[$itil_type]['properties']['ola_level_ttr'] = [ |
| 499 | + 'x-version-introduced' => '2.1.0', |
| 500 | + 'type' => Doc\Schema::TYPE_OBJECT, |
| 501 | + 'nullable' => true, |
| 502 | + 'x-full-schema' => 'OLALevel', |
| 503 | + 'x-mapped-from' => 'id', |
| 504 | + 'properties' => [ |
| 505 | + 'id' => ['type' => Doc\Schema::TYPE_INTEGER, 'format' => Doc\Schema::FORMAT_INTEGER_INT64], |
| 506 | + 'name' => ['type' => Doc\Schema::TYPE_STRING, 'readOnly' => true], |
| 507 | + ], |
| 508 | + 'x-mapper' => static function ($v) use ($get_ola_data): ?array { |
| 509 | + $ola = $get_ola_data((int) $v, \SLM::TTR); |
| 510 | + if ($ola === null || empty($ola['level']) || !($ola['level'] instanceof OlaLevel)) { |
| 511 | + return null; |
| 512 | + } |
| 513 | + return ['id' => $ola['level']->getID(), 'name' => $ola['level']->getName()]; |
| 514 | + }, |
| 515 | + ]; |
| 516 | + |
| 517 | + // OLA waiting duration (sum of TTR + TTO waiting times; replaces old single ola_waiting_duration column) |
454 | 518 | $schemas[$itil_type]['properties']['ola_waiting_duration'] = [ |
455 | 519 | 'x-version-introduced' => '2.1.0', |
456 | 520 | 'type' => Doc\Schema::TYPE_INTEGER, |
457 | 521 | 'readOnly' => true, |
458 | 522 | 'description' => 'Total OLA waiting duration in seconds', |
| 523 | + 'x-mapped-from' => 'id', |
| 524 | + 'x-mapper' => static function ($v) use ($get_ola_data): int { |
| 525 | + $ttr = $get_ola_data((int) $v, \SLM::TTR); |
| 526 | + $tto = $get_ola_data((int) $v, \SLM::TTO); |
| 527 | + return (int) ($ttr['waiting_time'] ?? 0) + (int) ($tto['waiting_time'] ?? 0); |
| 528 | + }, |
459 | 529 | ]; |
| 530 | + |
| 531 | + // OLA begin dates (replacing ola_ttr_begin_date / ola_tto_begin_date columns) |
460 | 532 | $schemas[$itil_type]['properties']['ola_ttr_begin_date'] = [ |
461 | 533 | 'x-version-introduced' => '2.1.0', |
462 | 534 | 'type' => Doc\Schema::TYPE_STRING, |
463 | | - 'readOnly' => true, |
464 | 535 | 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME, |
| 536 | + 'readOnly' => true, |
| 537 | + 'x-mapped-from' => 'id', |
| 538 | + 'x-mapper' => static function ($v) use ($get_ola_data): ?string { |
| 539 | + $ola = $get_ola_data((int) $v, \SLM::TTR); |
| 540 | + return ($ola !== null && !empty($ola['start_time'])) ? $ola['start_time'] : null; |
| 541 | + }, |
465 | 542 | ]; |
466 | 543 | $schemas[$itil_type]['properties']['ola_tto_begin_date'] = [ |
467 | 544 | 'x-version-introduced' => '2.1.0', |
468 | 545 | 'type' => Doc\Schema::TYPE_STRING, |
469 | | - 'readOnly' => true, |
470 | 546 | 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME, |
| 547 | + 'readOnly' => true, |
| 548 | + 'x-mapped-from' => 'id', |
| 549 | + 'x-mapper' => static function ($v) use ($get_ola_data): ?string { |
| 550 | + $ola = $get_ola_data((int) $v, \SLM::TTO); |
| 551 | + return ($ola !== null && !empty($ola['start_time'])) ? $ola['start_time'] : null; |
| 552 | + }, |
471 | 553 | ]; |
| 554 | + |
| 555 | + // OLA due dates (replacing internal_time_to_resolve / internal_time_to_own columns) |
472 | 556 | $schemas[$itil_type]['properties']['internal_resolution_date'] = [ |
473 | 557 | 'x-version-introduced' => '2.1.0', |
474 | 558 | 'type' => Doc\Schema::TYPE_STRING, |
475 | 559 | 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME, |
476 | 560 | 'readOnly' => true, |
477 | | - 'x-field' => 'internal_time_to_resolve', |
| 561 | + 'x-mapped-from' => 'id', |
| 562 | + 'x-mapper' => static function ($v) use ($get_ola_data): ?string { |
| 563 | + $ola = $get_ola_data((int) $v, \SLM::TTR); |
| 564 | + return ($ola !== null && !empty($ola['due_time'])) ? $ola['due_time'] : null; |
| 565 | + }, |
478 | 566 | ]; |
479 | 567 | $schemas[$itil_type]['properties']['internal_take_into_account_date'] = [ |
480 | 568 | 'x-version-introduced' => '2.1.0', |
481 | 569 | 'type' => Doc\Schema::TYPE_STRING, |
482 | 570 | 'format' => Doc\Schema::FORMAT_STRING_DATE_TIME, |
483 | 571 | 'readOnly' => true, |
484 | | - 'x-field' => 'internal_time_to_own', |
| 572 | + 'x-mapped-from' => 'id', |
| 573 | + 'x-mapper' => static function ($v) use ($get_ola_data): ?string { |
| 574 | + $ola = $get_ola_data((int) $v, \SLM::TTO); |
| 575 | + return ($ola !== null && !empty($ola['due_time'])) ? $ola['due_time'] : null; |
| 576 | + }, |
485 | 577 | ]; |
486 | | - */ |
| 578 | + |
487 | 579 | } |
488 | 580 | if ($itil_type === Ticket::class || $itil_type === Change::class) { |
489 | 581 | $schemas[$itil_type]['properties']['global_validation'] = [ |
|
0 commit comments