-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ZMS-3460): create endpoint for free appointments grouped by office #797
Changes from 6 commits
999edd7
ec8569b
94a1a88
7d319ba
1105c6d
f93b834
0e22c1b
05e5192
e4b1108
f21f8a9
c49ae43
4bd2899
6f47aa1
38889db
5b47911
e1fd3bb
bc14ffe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace BO\Zmscitizenapi\Controllers\Availability; | ||
|
||
use BO\Zmscitizenapi\BaseController; | ||
use BO\Zmscitizenapi\Localization\ErrorMessages; | ||
use BO\Zmscitizenapi\Services\Availability\AvailableAppointmentsListService; | ||
use BO\Zmscitizenapi\Services\Core\ValidationService; | ||
use Psr\Http\Message\RequestInterface; | ||
use Psr\Http\Message\ResponseInterface; | ||
|
||
class AvailableAppointmentsListByOfficeController extends BaseController | ||
{ | ||
private AvailableAppointmentsListService $service; | ||
|
||
public function __construct() | ||
{ | ||
$this->service = new AvailableAppointmentsListService(); | ||
} | ||
|
||
public function readResponse(RequestInterface $request, ResponseInterface $response, array $args): ResponseInterface | ||
{ | ||
$requestErrors = ValidationService::validateServerGetRequest($request); | ||
if (!empty($requestErrors['errors'])) { | ||
return $this->createJsonResponse( | ||
$response, | ||
$requestErrors, | ||
ErrorMessages::get('invalidRequest', $this->language)['statusCode'] | ||
); | ||
} | ||
|
||
$result = $this->service->getAvailableAppointmentsListByOffice($request->getQueryParams()); | ||
|
||
return is_array($result) && isset($result['errors']) | ||
? $this->createJsonResponse( | ||
$response, | ||
$result, | ||
ErrorMessages::getHighestStatusCode($result['errors']) | ||
) | ||
: $this->createJsonResponse($response, $result->toArray(), 200); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,55 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<?php | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
declare(strict_types=1); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
namespace BO\Zmscitizenapi\Models; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use BO\Zmsentities\Schema\Entity; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use InvalidArgumentException; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
use JsonSerializable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
class ProcessFreeSlotsGroupByOffice extends Entity implements JsonSerializable | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public static $schema = 'citizenapi/processFreeSlots.json'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** @var array|null */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public array|null $appointmentTimestamps = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @param array $appointmentTimestamps | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function __construct(array $appointmentTimestamps = []) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$this->appointmentTimestamps = array_map('intval', $appointmentTimestamps); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$this->ensureValid(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validate the structure of $appointmentTimestamps Currently, the constructor maps Adjust the logic to handle nested arrays appropriately. For example: - $this->appointmentTimestamps = array_map('intval', $appointmentTimestamps);
+ foreach ($appointmentTimestamps as $officeId => $timestamps) {
+ $this->appointmentTimestamps[$officeId] = array_map('intval', $timestamps);
+ } This ensures that timestamps for each office are properly converted to integers. 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private function ensureValid(): void | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!$this->testValid()) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
throw new InvalidArgumentException('The provided data is invalid according to the schema.'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct the schema path in the The Update the schema path to reflect the appropriate JSON schema file: - public static $schema = 'citizenapi/processFreeSlots.json';
+ public static $schema = 'citizenapi/processFreeSlotsGroupByOffice.json'; This ensures that the 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Converts the model data back into an array for serialization. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* @return array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function toArray(): array | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'appointmentTimestamps' => $this->appointmentTimestamps, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* Implementation of JsonSerializable. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function jsonSerialize(): mixed | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->toArray(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -25,12 +25,14 @@ private function extractClientData(array $queryParams): object | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return (object) [ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'date' => isset($queryParams['date']) ? (string) $queryParams['date'] : null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'officeId' => isset($queryParams['officeId']) ? (int) $queryParams['officeId'] : null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'officeIds' => isset($queryParams['officeId']) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? array_map('trim', explode(',', (string) $queryParams['officeId'])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+29
to
+31
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Improve array mapping for office IDs. The current implementation splits and trims the office IDs but doesn't validate the values. Consider adding validation for numeric values and removing empty entries. 'officeIds' => isset($queryParams['officeId'])
- ? array_map('trim', explode(',', (string) $queryParams['officeId']))
+ ? array_filter(
+ array_map(function($id) {
+ $id = trim($id);
+ return is_numeric($id) ? (int)$id : null;
+ }, explode(',', (string) $queryParams['officeId'])),
+ function($id) { return $id !== null; }
+ )
: [], 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'serviceIds' => isset($queryParams['serviceId']) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? array_map('trim', explode(',', $queryParams['serviceId'])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? array_map('trim', explode(',', (string) $queryParams['serviceId'])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'serviceCounts' => isset($queryParams['serviceCount']) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? array_map('trim', explode(',', $queryParams['serviceCount'])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
? array_map('trim', explode(',', (string) $queryParams['serviceCount'])) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
: [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
@@ -39,19 +41,32 @@ private function validateClientData(object $data): array | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ValidationService::validateGetAvailableAppointments( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->date, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->officeId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->officeIds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->serviceIds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->serviceCounts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private function getAvailableAppointments(object $data): array|AvailableAppointments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
private function getAvailableAppointments(object $data, ?bool $groupByOffice = false): array|AvailableAppointments | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return ZmsApiFacadeService::getAvailableAppointments( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->date, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->officeId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->officeIds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->serviceIds, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->serviceCounts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$data->serviceCounts, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$groupByOffice | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
public function getAvailableAppointmentsListByOffice($queryParams) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$clientData = $this->extractClientData($queryParams); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
$errors = $this->validateClientData($clientData); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!empty($errors['errors'])) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $errors; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return $this->getAvailableAppointments($clientData, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add type hints and documentation for the new method. The new method should include proper type hints and documentation for better code quality and maintainability. +/**
+ * Get available appointments grouped by office
+ *
+ * @param array $queryParams The query parameters containing date, officeId, serviceId, and serviceCount
+ * @return array|AvailableAppointments Appointments grouped by office or validation errors
+ */
-public function getAvailableAppointmentsListByOffice($queryParams)
+public function getAvailableAppointmentsListByOffice(array $queryParams): array|AvailableAppointments 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verify the controller path in the route definition.
The route is using
AvailableAppointmentsListController
but based on the AI summary, there should be a newAvailableAppointmentsListByOfficeController
. This might cause runtime errors.Also, consider updating the Swagger documentation to include: