Skip to content

Commit

Permalink
feat: External services integration
Browse files Browse the repository at this point in the history
  • Loading branch information
rogeriolino committed Jan 14, 2025
1 parent cc11c04 commit 49f5169
Show file tree
Hide file tree
Showing 28 changed files with 1,868 additions and 1 deletion.
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
"pagerfanta/doctrine-orm-adapter": "*",
"pagerfanta/pagerfanta": "^4.6",
"symfony/framework-bundle": "7.1.*",
"symfony/form": "7.1.*"
"symfony/form": "7.1.*",
"symfony/security-core": "7.1.*",
"symfony/validator": "7.1.*",
"symfony/http-client": "7.1.*",
"symfony/security-bundle": "7.1.*"
},
"require-dev": {
"phpstan/phpstan": "^1.10",
Expand Down
38 changes: 38 additions & 0 deletions src/Clients/Dto/AgendamentoRemoto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients\Dto;

use DateTimeImmutable;

/**
* AgendamentoRemoto
*
* @author Rogerio Lino <[email protected]>
*/
class AgendamentoRemoto
{
public function __construct(
public readonly int|string|null $id = null,
public readonly ?string $nome = null,
public readonly ?string $situacao = null,
public readonly ?DateTimeImmutable $dataCancelamento = null,
public readonly ?DateTimeImmutable $dataConfirmacao = null,
public readonly ?string $documento = null,
public readonly ?string $data = null,
public readonly ?string $horaInicio = null,
public readonly ?string $email = null,
public readonly ?string $telefone = null
) {
}
}
32 changes: 32 additions & 0 deletions src/Clients/Dto/GetAgendamentosRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients\Dto;

use DateTimeImmutable;

/**
* GetAgendamentosRequest
*
* @author Rogerio Lino <[email protected]>
*/
class GetAgendamentosRequest
{
public function __construct(
public readonly string|int|null $servicoId = null,
public readonly string|int|null $unidadeId = null,
public readonly ?DateTimeImmutable $date = null,
public readonly int $page = 1
) {
}
}
28 changes: 28 additions & 0 deletions src/Clients/Dto/ServicoRemoto.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients\Dto;

/**
* ServicoRemoto
*
* @author Rogerio Lino <[email protected]>
*/
class ServicoRemoto
{
public function __construct(
public readonly int|string|null $id = null,
public readonly ?string $nome = null
) {
}
}
28 changes: 28 additions & 0 deletions src/Clients/Dto/UnidadeRemota.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients\Dto;

/**
* UnidadeRemota
*
* @author Rogerio Lino <[email protected]>
*/
class UnidadeRemota
{
public function __construct(
public readonly int|string|null $id = null,
public readonly ?string $nome = null
) {
}
}
38 changes: 38 additions & 0 deletions src/Clients/ExternalApiClientInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients;

use Novosga\SchedulingBundle\Clients\Dto\AgendamentoRemoto;
use Novosga\SchedulingBundle\Clients\Dto\ServicoRemoto;
use Novosga\SchedulingBundle\Clients\Dto\UnidadeRemota;
use Novosga\SchedulingBundle\Clients\Dto\GetAgendamentosRequest;

/**
* ExternalApiClientInterface
*
* @author Rogerio Lino <[email protected]>
*/
interface ExternalApiClientInterface
{
/** @return UnidadeRemota[] */
public function getUnidades(): array;

/** @return ServicoRemoto[] */
public function getServicos(): array;

/** @return AgendamentoRemoto[] */
public function getAgendamentos(GetAgendamentosRequest $request): array;

public function updateAgendamento(int|string $agendamentoId, string $situacao): bool;
}
50 changes: 50 additions & 0 deletions src/Clients/ExternalApiClientTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients;

use Symfony\Contracts\HttpClient\ResponseInterface;
use Throwable;

/**
* ExternalApiClientTrait
*
* @author Rogerio Lino <[email protected]>
*/
trait ExternalApiClientTrait
{
/**
* @param array<string,mixed> $query
* @param array<string,mixed> $body
*/
private function request(string $method, string $url, array $query = [], array $body = []): ?ResponseInterface
{
try {
$response = $this->client->request($method, $url, [
'headers' => [
'Authorization' => "Bearer {$this->apiToken}",
],
'query' => $query,
'body' => $body,
]);
//$statusCode = $response->getStatusCode();

return $response;
} catch (Throwable $ex) {
$this->logger->error('Error trying to access remote API: ' . $url);
$this->logger->error($ex->getMessage());
}

return null;
}
}
132 changes: 132 additions & 0 deletions src/Clients/MangatiAgendaApiClient.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Novo SGA project.
*
* (c) Rogerio Lino <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Novosga\SchedulingBundle\Clients;

use DateTime;
use Novosga\SchedulingBundle\Clients\Dto\AgendamentoRemoto;
use Novosga\SchedulingBundle\Clients\Dto\GetAgendamentosRequest;
use Novosga\SchedulingBundle\Clients\Dto\ServicoRemoto;
use Novosga\SchedulingBundle\Clients\Dto\UnidadeRemota;
use Psr\Log\LoggerInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;

/**
* MangatiAgendaApiClient
* Classe cliente da API do sistema Mangati Agenda
* {@link https://agenda.mangati.com/}
*
* @author Rogerio Lino <[email protected]>
*/
class MangatiAgendaApiClient implements ExternalApiClientInterface
{
use ExternalApiClientTrait;

/** @var array<string,string> */
private $statusDict;

public function __construct(
private readonly HttpClientInterface $client,
private readonly LoggerInterface $logger,
private readonly string $apiToken,
private string $apiUrl,
) {
if (!str_ends_with($this->apiUrl, '/')) {
$this->apiUrl .= '/';
}
$this->statusDict = [
'scheduled' => 'agendado',
'cancelled' => 'cancelado',
'completed' => 'confirmado',
'no_show' => 'nao_compareceu',
'deleted' => 'excluido',
];
}

/** @return UnidadeRemota[] */
public function getUnidades(): array
{
$unidades = [];
$response = $this->request('GET', "{$this->apiUrl}locations.json");

if ($response) {
$unidades = array_map(function ($row) {
return new UnidadeRemota(
id: $row['id'],
nome: $row['name'],
);
}, $response->toArray());
}

return $unidades;
}

/** @return ServicoRemoto[] */
public function getServicos(): array
{
$servicos = [];
$response = $this->request('GET', "{$this->apiUrl}resources.json");

if ($response) {
$servicos = array_map(function ($row) {
return new ServicoRemoto(
id: $row['id'],
nome: $row['name'],
);
}, $response->toArray());
}

return $servicos;
}

/** @return AgendamentoRemoto[] */
public function getAgendamentos(GetAgendamentosRequest $request): array
{
$date = $request->date;
if (!$date) {
$date = new DateTime();
}
$response = $this->request('GET', "{$this->apiUrl}appointments.json", [
'date' => $date->format('Y-m-d'),
'page' => $request->page,
'resource' => $request->servicoId,
'location' => $request->unidadeId,
]);

$agendamentos = array_map(function ($row) {
$status = $this->statusDict[$row['status']] ?? $row['status'];

return new AgendamentoRemoto(
id: $row['id'],
nome: $row['name'],
situacao: $status,
dataCancelamento: null,
dataConfirmacao: null,
documento: $row['documentId'] ?? '',
data: $row['date'],
horaInicio: $row['time'],
email: $row['email'] ?? '',
telefone: $row['phone'] ?? '',
);
}, $response->toArray());

return $agendamentos;
}

public function updateAgendamento(int|string $agendamentoId, string $situacao): bool
{
// TODO
$this->logger->info('updateAgendamento not implemented');
return false;
}
}
Loading

0 comments on commit 49f5169

Please sign in to comment.