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..b999723 --- /dev/null +++ b/app/common/Ideal/Money/Provider.php @@ -0,0 +1,16 @@ +supportedMap), true); + } +} diff --git a/app/resources/views/home.blade.php b/app/resources/views/home.blade.php index 33d01c4..b550843 100644 --- a/app/resources/views/home.blade.php +++ b/app/resources/views/home.blade.php @@ -2,7 +2,7 @@ @section('page_content')
-

Bienvenid@ {{$user->name}}

+

Bienvenid@ {{ $user->name }}

diff --git a/app/resources/views/ventas/facturacion/show.blade.php b/app/resources/views/ventas/facturacion/show.blade.php index b5e3f0d..63b08ba 100644 --- a/app/resources/views/ventas/facturacion/show.blade.php +++ b/app/resources/views/ventas/facturacion/show.blade.php @@ -44,6 +44,7 @@ facturas: () => { document.getElementById(this.ids.facturas).innerHTML = this.venta.draw().facturas(this.formatters) this.venta.watch().facturas() + $('[data-html]').popup() } } }, diff --git a/app/resources/views/ventas/facturacion/show/factura.blade.php b/app/resources/views/ventas/facturacion/show/factura.blade.php index 44547c3..ab909ba 100644 --- a/app/resources/views/ventas/facturacion/show/factura.blade.php +++ b/app/resources/views/ventas/facturacion/show/factura.blade.php @@ -220,9 +220,47 @@ }, resumen: ({no, classes, formatters}) => { const emptyTerreno = '
0
' + const calculoTerreno = [ + [ + `Base Terreno (${formatters.date.format(this.props.terreno.fecha)})`, + `\$${formatters.pesos.format(this.props.terreno.valor)}` + ], + [ + `IPC (${formatters.date.format(this.props.fecha)})`, + `${formatters.percent.format({{ $ipc }})}%` + ], + [ + 'Prorrateo', + `${formatters.percent.format(this.props.detalle.descuento * 100)}%` + ], + [ + 'Proporcion', + `${(this.props.proporcion * 100).toFixed(2).replace('.', ',')}%` + ], + [ + 'Terreno Aplicado', + `\$${formatters.pesos.format(this.props.detalle.terreno)}` + ] + ] + const tableClasses = [ + '', + " align='right'" + ] + const calculoTerrenoTable = [ + '' + ] + calculoTerreno.forEach(items => { + const row = [] + items.forEach((cell, idx) => { + row.push(`${cell}`) + }) + calculoTerrenoTable.push(`${row.join('')}`) + }) + calculoTerrenoTable.push('
') + const data = [ no, - 'Valor con Terreno: $' + formatters.pesos.format(this.props.detalle.base) + ' - Menos valor terreno: $' + ((this.props.detalle.terreno > 0) ? formatters.pesos.format(-this.props.detalle.terreno) : emptyTerreno) + '
' + + 'Valor con Terreno: $' + formatters.pesos.format(this.props.detalle.base) + ' - Menos valor terreno: $' + ((this.props.detalle.terreno > 0) ? formatters.pesos.format(-this.props.detalle.terreno) : emptyTerreno) + '
' + 'Base imponible (Neto): $' + formatters.pesos.format(this.props.detalle.neto) + '
' + 'IVA: $' + formatters.pesos.format(this.props.detalle.iva) + '
' + 'SUBTOTAL (Bruto): $' + formatters.pesos.format(this.props.detalle.bruto) + '
' + diff --git a/app/setup/setups/services.php b/app/setup/setups/services.php index e5cf4de..51df011 100644 --- a/app/setup/setups/services.php +++ b/app/setup/setups/services.php @@ -15,21 +15,24 @@ return [ ); }, Incoviba\Service\Money::class => function(ContainerInterface $container) { - $mindicador = new Incoviba\Service\Money\MiIndicador(new GuzzleHttp\Client([ + $mindicador = new Incoviba\Service\Money\MiIndicador($container->get(Psr\Log\LoggerInterface::class), new GuzzleHttp\Client([ 'base_uri' => 'https://mindicador.cl/api/', 'headers' => ['Accept' => 'application/json'] ])); - $ine = new Incoviba\Service\Money\Ine(new GuzzleHttp\Client([ + $ine = new Incoviba\Service\Money\Ine($container->get(Psr\Log\LoggerInterface::class), new GuzzleHttp\Client([ 'base_uri' => 'https://api-calculadora.ine.cl/ServiciosCalculadoraVariacion' ])); - $sii = new Incoviba\Service\Money\SII(new GuzzleHttp\Client([ + $sii = new Incoviba\Service\Money\SII($container->get(Psr\Log\LoggerInterface::class), 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($container->get(Psr\Log\LoggerInterface::class), new GuzzleHttp\Client([ + 'base_uri' => 'https://findic.cl/api/' + ])); + return new Incoviba\Service\Money($container->get(Psr\Log\LoggerInterface::class)) + ->register($findic) + ->register($sii) + ->register($ine) + ->register($mindicador); }, Predis\ClientInterface::class => function(ContainerInterface $container) { $options = [ @@ -46,7 +49,7 @@ return [ return new Predis\Client($options); }, Incoviba\Service\Contabilidad\Cartola::class => function(ContainerInterface $container) { - return (new Incoviba\Service\Contabilidad\Cartola( + return new Incoviba\Service\Contabilidad\Cartola( $container->get(Psr\Log\LoggerInterface::class), $container->get(Psr\Http\Message\StreamFactoryInterface::class), $container->get(Incoviba\Common\Define\Contabilidad\Exporter::class), @@ -55,7 +58,7 @@ return [ $container->get(Incoviba\Repository\Contabilidad\Movimiento::class), $container->get(Incoviba\Service\Contabilidad\Movimiento::class), $container->get(Incoviba\Repository\Contabilidad\Cartola::class) - )) + ) ->register('security', $container->get(Incoviba\Service\Contabilidad\Cartola\Security::class)) ->register('itau', $container->get(Incoviba\Service\Contabilidad\Cartola\Itau::class)) ->register('santander', $container->get(Incoviba\Service\Contabilidad\Cartola\Santander::class)) @@ -89,11 +92,10 @@ return [ $container->get('nubox')->get('url')); }, Incoviba\Service\Informe::class => function(ContainerInterface $container) { - return (new Incoviba\Service\Informe( + return new Incoviba\Service\Informe( $container->get(Psr\Log\LoggerInterface::class), $container->get('folders')->get('informes')) - ) - ->register('xlsx', Incoviba\Service\Informe\Excel::class); + ->register('xlsx', Incoviba\Service\Informe\Excel::class); }, Incoviba\Service\Contabilidad\Informe\Tesoreria\Output\Excel::class => function(ContainerInterface $container) { return new Incoviba\Service\Contabilidad\Informe\Tesoreria\Output\Excel( @@ -104,15 +106,15 @@ return [ ); }, Incoviba\Service\Contabilidad\Cartola\Santander::class => function(ContainerInterface $container) { - return (new Incoviba\Service\Contabilidad\Cartola\Santander( + return new Incoviba\Service\Contabilidad\Cartola\Santander( $container->get(Psr\Log\LoggerInterface::class), - )) + ) ->registerSub($container->get(Incoviba\Service\Contabilidad\Cartola\Santander\OfficeBanking::class)); }, Incoviba\Service\Contabilidad\Cartola\BCI::class => function(ContainerInterface $container) { - return (new Incoviba\Service\Contabilidad\Cartola\BCI( + return new Incoviba\Service\Contabilidad\Cartola\BCI( $container->get(Psr\Log\LoggerInterface::class), - )) + ) ->registerSub($container->get(Incoviba\Service\Contabilidad\Cartola\BCI\Mes::class)); }, 'TokuClient' => function(ContainerInterface $container) { diff --git a/app/src/Controller/API/Contabilidad/Cartolas.php b/app/src/Controller/API/Contabilidad/Cartolas.php index 88cfc33..b1d63bb 100644 --- a/app/src/Controller/API/Contabilidad/Cartolas.php +++ b/app/src/Controller/API/Contabilidad/Cartolas.php @@ -127,6 +127,9 @@ class Cartolas extends Controller $output['errors'] []= ['filename' => $file->getClientFilename(), 'error' => $errors[$file->getError()]]; continue; } + if (empty($body['cuenta_id'])) { + continue; + } try { $output['movimientos'] = array_merge($output['movimientos'], $cartolaService->import($body['cuenta_id'][$i], $file)); } catch (Read $exception) { diff --git a/app/src/Repository/Contabilidad/Movimiento/Detalle.php b/app/src/Repository/Contabilidad/Movimiento/Detalle.php index b70a059..b8fa540 100644 --- a/app/src/Repository/Contabilidad/Movimiento/Detalle.php +++ b/app/src/Repository/Contabilidad/Movimiento/Detalle.php @@ -28,6 +28,9 @@ class Detalle extends Ideal\Repository ->register('centro_costo_id', (new Implement\Repository\Mapper()) ->setProperty('centroCosto') ->setFunction(function(array $data) { + if (empty($data['centro_costo_id'])) { + return null; + } return $this->centroCostoRepository->fetchById($data['centro_costo_id']); }) ->setDefault(null)); diff --git a/app/src/Service/IPC.php b/app/src/Service/IPC.php index b8a51b2..8d1a546 100644 --- a/app/src/Service/IPC.php +++ b/app/src/Service/IPC.php @@ -5,11 +5,13 @@ use DateTimeInterface; use DateTimeImmutable; use DateInterval; use Incoviba\Common\Implement\Exception\EmptyRedis; +use Psr\Log\LoggerInterface; class IPC { protected string $redisKey = 'ipc'; - public function __construct(protected Redis $redisService, protected Money $moneyService) {} + public function __construct(protected LoggerInterface $logger, protected Redis $redisService, + protected Money $moneyService) {} public function get(DateTimeInterface $from, DateTimeInterface $to = new DateTimeImmutable()): float { @@ -33,7 +35,7 @@ class IPC ksort($ipcs); $this->redisService->set($this->redisKey, json_encode($ipcs), 60 * 60 * 24 * 30); } - return $ipcs[$dateKey]; + return $ipcs[$dateKey] * ($ipcs[$dateKey] > 1 ? 1/100 : 1); } public function readjust(float $base, DateTimeInterface $from, DateTimeInterface $to = new DateTimeImmutable()):float { diff --git a/app/src/Service/Money.php b/app/src/Service/Money.php index 3405f3a..ab01137 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, $end); } 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..2f5d1e3 --- /dev/null +++ b/app/src/Service/Money/Findic.php @@ -0,0 +1,112 @@ +supported($money_symbol)) { + throw new EmptyResponse($money_symbol); + } + if ($dateTime === null) { + $dateTime = new DateTimeImmutable(); + } + return match (strtolower($money_symbol)) { + Money::UF, Money::USD => $this->getDate(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 getDate(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 + { + $dateTime = $dateTime->modify('last day of this month'); + $requestUri = "{$this->supportedMap[strtolower($symbol)]}/{$dateTime->format('Y')}"; + $serie = $this->sendRequest($requestUri); + $values = array_filter($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'); + } else { + $fromDateTime = $fromDateTime->modify('last day of this month'); + } + $requestUri = "{$this->supportedMap[strtolower($symbol)]}/{$fromDateTime->format('Y')}"; + $serie = $this->sendRequest($requestUri); + $values = array_filter($serie, fn($month) => DateTimeImmutable::createFromFormat('Y-m-d', $month['fecha']) > $fromDateTime); + 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..8a4c449 100644 --- a/app/src/Service/Money/Ine.php +++ b/app/src/Service/Money/Ine.php @@ -6,14 +6,19 @@ use DateTimeInterface; use DateTimeImmutable; use DateInterval; use Psr\Http\Client\ClientInterface; +use Psr\Log\LoggerInterface; 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) {} + public function __construct(LoggerInterface $logger, protected ClientInterface $client) + { + parent::__construct($logger); + } /** * @throws EmptyResponse @@ -21,6 +26,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 +37,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..df353b9 100644 --- a/app/src/Service/Money/MiIndicador.php +++ b/app/src/Service/Money/MiIndicador.php @@ -3,13 +3,18 @@ namespace Incoviba\Service\Money; use DateTimeInterface; use Psr\Http\Client\ClientInterface; +use Psr\Log\LoggerInterface; 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) {} + public function __construct(LoggerInterface $logger, protected ClientInterface $client) + { + parent::__construct($logger); + } /** * @param string $money_symbol @@ -19,9 +24,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 +49,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..29d9fee 100644 --- a/app/src/Service/Money/SII.php +++ b/app/src/Service/Money/SII.php @@ -6,27 +6,38 @@ use DateTimeImmutable; use PDO; use PDOException; use Psr\Http\Client\ClientInterface; +use Psr\Log\LoggerInterface; 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 __construct(LoggerInterface $logger, protected ClientInterface $client, + protected Repository\UF $ufRepository) + { + parent::__construct($logger); + } 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