From 04a725e51769b38e29ef1e13709f0d575de4a494 Mon Sep 17 00:00:00 2001 From: Juan Pablo Vial Date: Fri, 24 Oct 2025 18:35:52 -0300 Subject: [PATCH] Added new Money provider --- app/common/Define/Money/Provider.php | 1 + app/common/Ideal/Money/Provider.php | 13 ++++ app/setup/setups/services.php | 13 ++-- app/src/Service/Money.php | 34 ++++----- app/src/Service/Money/Findic.php | 106 ++++++++++++++++++++++++++ app/src/Service/Money/Ine.php | 12 ++- app/src/Service/Money/MiIndicador.php | 17 ++++- app/src/Service/Money/SII.php | 13 +++- 8 files changed, 178 insertions(+), 31 deletions(-) create mode 100644 app/common/Ideal/Money/Provider.php create mode 100644 app/src/Service/Money/Findic.php diff --git a/app/common/Define/Money/Provider.php b/app/common/Define/Money/Provider.php index 9a28da0..a246dd7 100644 --- a/app/common/Define/Money/Provider.php +++ b/app/common/Define/Money/Provider.php @@ -13,4 +13,5 @@ interface Provider * @throws EmptyResponse */ public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float; + public function supported(string $money_symbol): bool; } diff --git a/app/common/Ideal/Money/Provider.php b/app/common/Ideal/Money/Provider.php new file mode 100644 index 0000000..2337983 --- /dev/null +++ b/app/common/Ideal/Money/Provider.php @@ -0,0 +1,13 @@ +supportedMap), true); + } +} diff --git a/app/setup/setups/services.php b/app/setup/setups/services.php index e5cf4de..2dd889d 100644 --- a/app/setup/setups/services.php +++ b/app/setup/setups/services.php @@ -25,11 +25,14 @@ return [ $sii = new Incoviba\Service\Money\SII(new GuzzleHttp\Client([ 'base_uri' => 'https://www.sii.cl/valores_y_fechas/' ]), $container->get(Incoviba\Repository\UF::class)); - return (new Incoviba\Service\Money($container->get(Psr\Log\LoggerInterface::class))) - ->register('uf', $mindicador) - ->register('uf', $sii) - ->register('usd', $mindicador) - ->register('ipc', $ine); + $findic = new Incoviba\Service\Money\Findic(new GuzzleHttp\Client([ + 'base_uri' => 'https://findic.cl/api/' + ])); + return new Incoviba\Service\Money($container->get(Psr\Log\LoggerInterface::class)) + ->register($mindicador) + ->register($sii) + ->register($ine) + ->register($findic); }, Predis\ClientInterface::class => function(ContainerInterface $container) { $options = [ diff --git a/app/src/Service/Money.php b/app/src/Service/Money.php index 3405f3a..f28f1cd 100644 --- a/app/src/Service/Money.php +++ b/app/src/Service/Money.php @@ -8,32 +8,29 @@ use Incoviba\Common\Implement\Exception\EmptyResponse; class Money { - const UF = 'uf'; - const USD = 'usd'; - const IPC = 'ipc'; + const string UF = 'uf'; + const string USD = 'usd'; + const string IPC = 'ipc'; public function __construct(protected LoggerInterface $logger) {} - protected array $providers; - public function register(string $name, Provider $provider): Money + protected array $providers = []; + public function register(Provider $provider): Money { - if (isset($this->providers) and isset($this->providers[$name]) and in_array($provider, $this->providers[$name])) { + if (!in_array($provider, $this->providers)) { return $this; } - if (!isset($this->providers[$name])) { - $this->providers[$name] = []; - } - $this->providers[$name] []= $provider; + $this->providers []= $provider; return $this; } public function getProviders(string $name): array { - return $this->providers[$name]; + return array_values(array_filter($this->providers, fn($provider) => $provider->supported($name))); } - public function get(string $provider, DateTimeInterface $dateTime): float + public function get(string $name, DateTimeInterface $dateTime): float { - $providers = $this->getProviders($provider); + $providers = $this->getProviders($name); foreach ($providers as $provider) { try { return $provider->get(self::getSymbol($provider), $dateTime); @@ -45,7 +42,7 @@ class Money } public function getUF(?DateTimeInterface $dateTime = null): float { - $providers = $this->getProviders('uf'); + $providers = $this->getProviders(self::UF); foreach ($providers as $provider) { try { return $provider->get(self::UF, $dateTime); @@ -60,10 +57,13 @@ class Money if ($start >= $end) { return 0; } - $providers = $this->getProviders('ipc'); + $providers = $this->getProviders(self::IPC); foreach ($providers as $provider) { try { - return $provider->getVar($start, $end); + if (method_exists($provider, 'getVar')) { + return $provider->getVar($start, $end); + } + return $provider->get(self::IPC, $start); } catch (EmptyResponse $exception) { $this->logger->notice($exception); } @@ -72,7 +72,7 @@ class Money } public function getUSD(DateTimeInterface $dateTime): float { - $providers = $this->getProviders('usd'); + $providers = $this->getProviders(self::USD); foreach ($providers as $provider) { try { return $provider->get(self::USD, $dateTime); diff --git a/app/src/Service/Money/Findic.php b/app/src/Service/Money/Findic.php new file mode 100644 index 0000000..9a59c08 --- /dev/null +++ b/app/src/Service/Money/Findic.php @@ -0,0 +1,106 @@ +supported($money_symbol)) { + throw new EmptyResponse($money_symbol); + } + if ($dateTime === null) { + $dateTime = new DateTimeImmutable(); + } + return match (strtolower($money_symbol)) { + Money::UF, Money::USD => $this->getMonth(strtolower($money_symbol), $dateTime), + Money::IPC => $this->getSum(strtolower($money_symbol), $dateTime, + DateTimeImmutable::createFromFormat('Y-m-d', + $dateTime->modify('-1 year')->format('Y-11-01'))), + default => throw new EmptyResponse($money_symbol), + }; + } + + protected array $supportedMap = [ + Money::UF => 'uf', + Money::IPC => 'ipc', + Money::USD => 'dolar' + ]; + + /** + * @param string $request_uri + * @return float + * @throws EmptyResponse + */ + protected function sendRequest(string $request_uri): array + { + try { + $response = $this->client->get($request_uri); + } catch (ClientExceptionInterface $exception) { + throw new EmptyResponse($request_uri, $exception); + } + + if ((int) floor($response->getStatusCode() / 100) !== 2) { + throw new EmptyResponse($request_uri); + } + $body = $response->getBody(); + try { + $json = json_decode($body->getContents(), true, 512, JSON_THROW_ON_ERROR); + } catch (JsonException $exception) { + throw new EmptyResponse($request_uri, $exception); + } + + if (!array_key_exists('serie', $json) or count($json['serie']) === 0) { + throw new EmptyResponse($request_uri); + } + return $json['serie']; + } + + /** + * @param string $symbol + * @param DateTimeInterface $dateTime + * @return float + * @throws EmptyResponse + */ + protected function getMonth(string $symbol, DateTimeInterface $dateTime): float + { + $request_uri = "{$this->supportedMap[strtolower($symbol)]}/{$dateTime->format('d-m-Y')}"; + return (float) $this->sendRequest($request_uri)[0]['valor']; + } + + /** + * @param string $symbol + * @param DateTimeInterface $dateTime + * @param DateTimeInterface|null $fromDateTime + * @return float + * @throws EmptyResponse + */ + protected function getSum(string $symbol, DateTimeInterface $dateTime, ?DateTimeInterface $fromDateTime = null): float + { + $requestUri = "{$this->supportedMap[strtolower($symbol)]}/{$dateTime->format('Y')})"; + $json = $this->sendRequest($requestUri); + $values = array_filter($json['serie'], fn($month) => DateTimeImmutable::createFromFormat('Y-m-d', $month['fecha']) <= $dateTime); + $value = array_reduce($values, fn($value, $month) => $value + ((float) $month['valor']), 0.0); + + if ($fromDateTime === null) { + $fromDateTime = $dateTime->modify('-1 year'); + } + $requestUri = "{$this->supportedMap[strtolower($symbol)]}/{$fromDateTime->format('Y')})"; + $json = $this->sendRequest($requestUri); + $values = array_filter($json['serie'], fn($month) => DateTimeImmutable::createFromFormat('Y-m-d', $month['fecha']) > $dateTime); + return array_reduce($values, fn($value, $month) => $value + ((float) $month['valor']), $value); + } +} diff --git a/app/src/Service/Money/Ine.php b/app/src/Service/Money/Ine.php index a4d78cf..bd408a5 100644 --- a/app/src/Service/Money/Ine.php +++ b/app/src/Service/Money/Ine.php @@ -8,9 +8,10 @@ use DateInterval; use Psr\Http\Client\ClientInterface; use GuzzleHttp\Exception\GuzzleException; use Incoviba\Common\Implement\Exception\EmptyResponse; -use Incoviba\Common\Define\Money\Provider; +use Incoviba\Common\Ideal; +use Incoviba\Service\Money; -class Ine implements Provider +class Ine extends Ideal\Money\Provider { protected string $uri = 'https://api-calculadora.ine.cl/ServiciosCalculadoraVariacion'; public function __construct(protected ClientInterface $client) {} @@ -21,6 +22,9 @@ class Ine implements Provider */ public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float { + if (!$this->supported($money_symbol)) { + throw new EmptyResponse($money_symbol); + } if ($dateTime === null) { $dateTime = new DateTimeImmutable(); } @@ -29,6 +33,10 @@ class Ine implements Provider return $this->getVar($start, $end); } + protected array $supportedMap = [ + Money::IPC => 'ipc' + ]; + /** * @throws EmptyResponse */ diff --git a/app/src/Service/Money/MiIndicador.php b/app/src/Service/Money/MiIndicador.php index 302f978..d60d72c 100644 --- a/app/src/Service/Money/MiIndicador.php +++ b/app/src/Service/Money/MiIndicador.php @@ -4,10 +4,11 @@ namespace Incoviba\Service\Money; use DateTimeInterface; use Psr\Http\Client\ClientInterface; use GuzzleHttp\Exception\GuzzleException; -use Incoviba\Common\Define\Money\Provider; +use Incoviba\Common\Ideal; use Incoviba\Common\Implement\Exception\EmptyResponse; +use Incoviba\Service\Money; -class MiIndicador implements Provider +class MiIndicador extends Ideal\Money\Provider { public function __construct(protected ClientInterface $client) {} @@ -19,9 +20,12 @@ class MiIndicador implements Provider */ public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float { - $request_uri = "{$money_symbol}"; + if (!$this->supported($money_symbol)) { + throw new EmptyResponse($money_symbol); + } + $request_uri = "{$this->supportedMap[strtolower($money_symbol)]}"; if ($dateTime !== null) { - $request_uri = "{$money_symbol}/{$dateTime->format('d-m-Y')}"; + $request_uri = "{$request_uri}/{$dateTime->format('d-m-Y')}"; } try { $response = $this->client->get($request_uri); @@ -41,4 +45,9 @@ class MiIndicador implements Provider } return $json->serie[0]->valor; } + protected array $supportedMap = [ + Money::UF => 'uf', + Money::IPC => 'ipc', + Money::USD => 'dolar' + ]; } diff --git a/app/src/Service/Money/SII.php b/app/src/Service/Money/SII.php index 04a0460..b653252 100644 --- a/app/src/Service/Money/SII.php +++ b/app/src/Service/Money/SII.php @@ -9,24 +9,31 @@ use Psr\Http\Client\ClientInterface; use Dom\HTMLDocument; use GuzzleHttp\Exception\GuzzleException; use Incoviba\Common\Implement\Exception\EmptyResponse; -use Incoviba\Common\Define; +use Incoviba\Common\Ideal; use Incoviba\Repository; use Incoviba\Service; -class SII implements Define\Money\Provider +class SII extends Ideal\Money\Provider { public function __construct(protected ClientInterface $client, protected Repository\UF $ufRepository) {} public function get(string $money_symbol, ?DateTimeInterface $dateTime = null): float { - if ($money_symbol === Service\Money::UF) { + if (!$this->supported($money_symbol)) { + throw new EmptyResponse("{$money_symbol} not found in " . __CLASS__); + } + if (strtolower($money_symbol) === Service\Money::UF) { return $this->getUF($dateTime); } $class = __CLASS__; throw new EmptyResponse("{$money_symbol} not found in {$class}"); } + protected array $supportedMap = [ + Service\Money::UF => 'uf' + ]; + /** * @param DateTimeInterface|null $dateTime * @return float