301 lines
13 KiB
PHP
301 lines
13 KiB
PHP
<?php
|
|
namespace Incoviba\Service\Contabilidad;
|
|
|
|
use DateTimeImmutable;
|
|
use DateTimeInterface;
|
|
use Incoviba\Common\Define\Cartola\Banco;
|
|
use Incoviba\Common\Define\Contabilidad\Exporter;
|
|
use Incoviba\Common\Ideal\Service;
|
|
use Incoviba\Common\Implement\Exception;
|
|
use Incoviba\Model;
|
|
use Incoviba\Repository;
|
|
use Psr\Http\Message\StreamFactoryInterface;
|
|
use Psr\Http\Message\UploadedFileInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
class Cartola extends Service
|
|
{
|
|
public function __construct(LoggerInterface $logger,
|
|
protected StreamFactoryInterface $streamFactory, protected Exporter $exporter,
|
|
protected Repository\Inmobiliaria $inmobiliariaRepository,
|
|
protected Repository\Inmobiliaria\Cuenta $cuentaRepository,
|
|
protected Repository\Contabilidad\Movimiento $movimientoRepository,
|
|
protected Movimiento $movimientoService,
|
|
protected Repository\Contabilidad\Cartola $cartolaRepository) {
|
|
parent::__construct($logger);
|
|
}
|
|
|
|
protected array $bancos;
|
|
public function register(string $name, Banco $banco): Cartola
|
|
{
|
|
$this->bancos[$name] = $banco;
|
|
return $this;
|
|
}
|
|
public function process(Model\Contabilidad\Banco $banco, UploadedFileInterface $file): array
|
|
{
|
|
return $this->bancos[strtolower($banco->nombre)]->process($file);
|
|
}
|
|
public function export(Model\Inmobiliaria $inmobiliaria, Model\Contabilidad\Banco $banco, DateTimeInterface $mes, array $movimientos): string
|
|
{
|
|
return $this->exporter->export($inmobiliaria, $banco, $mes, $movimientos);
|
|
}
|
|
public function diaria(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, UploadedFileInterface $file): array
|
|
{
|
|
$ms = $this->getMovimientosDiarios($cuenta->banco, $file);
|
|
|
|
$this->groupedMovimientos = [];
|
|
$movimientos = [];
|
|
foreach ($ms as $m) {
|
|
$movimiento = $this->buildMovimiento($cuenta, $m);
|
|
$movimiento = $this->movimientoService->process($movimiento);
|
|
$this->groupMovimientoByDay($movimiento);
|
|
if ($movimiento->fecha->getTimestamp() === $fecha->getTimestamp()) {
|
|
$movimientos []= $movimiento;
|
|
}
|
|
}
|
|
foreach ($this->groupedMovimientos as $timestamp => $movimientos) {
|
|
$cartolaData = [
|
|
'cargos' => 0,
|
|
'abonos' => 0,
|
|
'saldo' => last($movimientos)->saldo
|
|
];
|
|
foreach ($movimientos as $movimiento) {
|
|
$cartolaData['cargos'] += $movimiento->cargo;
|
|
$cartolaData['abonos'] += $movimiento->abono;
|
|
}
|
|
$this->buildCartola($cuenta, last($movimientos)->fecha, $cartolaData);
|
|
}
|
|
$cartola = $this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
|
|
return compact('cartola', 'movimientos');
|
|
}
|
|
public function diariaManual(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, array $data): array
|
|
{
|
|
$cartolaData = [
|
|
'cargos' => 0,
|
|
'abonos' => 0,
|
|
'saldos' => 0
|
|
];
|
|
$movimientos = [];
|
|
foreach ($data as $row) {
|
|
$dataMovimiento = $row;
|
|
$dataMovimiento['fecha'] = $fecha->format('Y-m-d');
|
|
$dataMovimiento['documento'] = '';
|
|
$movimiento = $this->buildMovimiento($cuenta, $dataMovimiento);
|
|
$movimiento = $this->movimientoService->process($movimiento);
|
|
|
|
$movimientos []= $movimiento;
|
|
$cartolaData['cargos'] += $movimiento->cargo;
|
|
$cartolaData['abonos'] += $movimiento->abono;
|
|
$cartolaData['saldo'] = $movimiento->saldo;
|
|
}
|
|
$cartola = $this->buildCartola($cuenta, $fecha, $cartolaData);
|
|
return compact('cartola', 'movimientos');
|
|
}
|
|
|
|
public function import(int $cuenta_id, UploadedFileInterface $file): array
|
|
{
|
|
$cuenta = $this->cuentaRepository->fetchById($cuenta_id);
|
|
$movimientos = $this->process($cuenta->banco, $file);
|
|
|
|
$inmobiliaria = $cuenta->inmobiliaria;
|
|
|
|
$addedMovimientos = [];
|
|
foreach ($movimientos as &$dataMovimiento) {
|
|
$dataMovimiento['cuenta_id'] = $cuenta->id;
|
|
if (array_key_exists('centro_costo', $dataMovimiento) and $dataMovimiento['centro_costo'] !== 0) {
|
|
$dataMovimiento['centro_costo_id'] = $dataMovimiento['centro_costo'];
|
|
}
|
|
$dataMovimiento['fecha'] = new DateTimeImmutable($dataMovimiento['fecha']);
|
|
if (array_key_exists('rut', $dataMovimiento)) {
|
|
$ruts = $this->parseRut($dataMovimiento['rut']);
|
|
if (key_exists('rut', $ruts)) {
|
|
$dataMovimiento['rut'] = $ruts['rut'];
|
|
$dataMovimiento['digito'] = $ruts['digito'];
|
|
} else {
|
|
$dataMovimiento['rut'] = $ruts[0]['rut'];
|
|
$dataMovimiento['digito'] = $ruts[0]['digito'];
|
|
}
|
|
}
|
|
try {
|
|
$movimiento = $this->movimientoRepository
|
|
->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo($dataMovimiento['cuenta_id'], $dataMovimiento['fecha'],
|
|
$dataMovimiento['glosa'], $dataMovimiento['cargo'] ?? 0,
|
|
$dataMovimiento['abono'] ?? 0, $dataMovimiento['saldo']);
|
|
} catch (Exception\EmptyResult) {
|
|
$movimiento = $this->movimientoService->add($dataMovimiento);
|
|
$dataMovimiento['nuevo'] = true;
|
|
}
|
|
$dataMovimiento['id'] = $movimiento->id;
|
|
$dataMovimiento['sociedad'] = $inmobiliaria;
|
|
$addedMovimientos []= $movimiento->id;
|
|
}
|
|
$fechas = array_unique(array_map(function($movimiento) {
|
|
return $movimiento['fecha']->format('Y-m-d');
|
|
}, $movimientos));
|
|
foreach ($fechas as $dia) {
|
|
try {
|
|
$this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, new DateTimeImmutable($dia));
|
|
continue;
|
|
} catch (Exception\EmptyResult) {}
|
|
$movs = array_filter($movimientos, function($movimiento) use ($dia) {
|
|
return $movimiento['fecha'] === $dia;
|
|
});
|
|
$cargos = array_sum(array_map(function($movimiento) {
|
|
return $movimiento['cargo'];
|
|
}, $movs));
|
|
$abonos = array_sum(array_map(function($movimiento) {
|
|
return $movimiento['abono'];
|
|
}, $movs));
|
|
$saldo = last($movs)['saldo'];
|
|
$cartolaData = [
|
|
'cargos' => $cargos,
|
|
'abonos' => $abonos,
|
|
'saldo' => $saldo
|
|
];
|
|
$this->buildCartola($cuenta, new DateTimeImmutable($dia), $cartolaData);
|
|
}
|
|
|
|
$startDate = new DateTimeImmutable(min($fechas));
|
|
$endDate = new DateTimeImmutable(max($fechas));
|
|
$movimientosFaltantes = $this->movimientoService->findMissing($cuenta, $addedMovimientos, $startDate, $endDate);
|
|
$movimientosObsoletos = [];
|
|
if (count($movimientosFaltantes) > 0) {
|
|
$movimientosObsoletos = array_map(function($movimiento) {
|
|
$arr = (array) $movimiento;
|
|
$arr['sociedad'] = $movimiento->cuenta->inmobiliaria;
|
|
$arr['obsoleto'] = true;
|
|
return $arr;
|
|
}, $movimientosFaltantes);
|
|
}
|
|
|
|
return array_map(function($movimiento) {
|
|
if (is_a($movimiento['fecha'], DateTimeInterface::class)) {
|
|
$movimiento['fecha'] = $movimiento['fecha']->format('Y-m-d');
|
|
}
|
|
return $movimiento;
|
|
}, array_merge($movimientos, $movimientosObsoletos));
|
|
}
|
|
public function check(): array
|
|
{
|
|
try {
|
|
$cuentas = $this->cuentaRepository->fetchAll();
|
|
$fechas = [];
|
|
foreach ($cuentas as $cuenta) {
|
|
$fechas[$cuenta->id] = $this->checkForCuenta($cuenta);
|
|
}
|
|
return $fechas;
|
|
} catch (Exception\EmptyResult) {
|
|
return [];
|
|
}
|
|
}
|
|
public function checkForCuenta(Model\Inmobiliaria\Cuenta $cuenta): array
|
|
{
|
|
$cartolas = $this->cartolaRepository->fetchByCuenta($cuenta->id);
|
|
$movimientos = $this->movimientoRepository->fetchByCuenta($cuenta->id);
|
|
$fechasMovimientos = array_unique(array_map(function(Model\Contabilidad\Movimiento $movimiento) {
|
|
return $movimiento->fecha->format('Y-m-d');
|
|
}, $movimientos));
|
|
$fechasCartolas = array_map(function(Model\Contabilidad\Cartola $cartola) {
|
|
return $cartola->fecha->format('Y-m-d');
|
|
}, $cartolas);
|
|
$fechas = array_diff($fechasMovimientos, $fechasCartolas);
|
|
return array_values($fechas);
|
|
}
|
|
public function update(array $cuentas): array
|
|
{
|
|
$cartolas = [];
|
|
foreach ($cuentas as $cuenta_id => $fechas) {
|
|
$cuenta = $this->cuentaRepository->fetchById($cuenta_id);
|
|
$cartolas[$cuenta_id] = $this->updateForCuenta($cuenta, $fechas);
|
|
}
|
|
return $cartolas;
|
|
}
|
|
public function updateForCuenta(Model\Inmobiliaria\Cuenta $cuenta, array $fechas): array
|
|
{
|
|
$cartolas = [];
|
|
foreach ($fechas as $fecha) {
|
|
$cartolas []= $this->updateForCuentaAndFecha($cuenta, new DateTimeImmutable($fecha));
|
|
}
|
|
return $cartolas;
|
|
}
|
|
public function updateForCuentaAndFecha(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha): Model\Contabilidad\Cartola
|
|
{
|
|
try {
|
|
return $this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
|
|
} catch (Exception\EmptyResult) {}
|
|
$movimientos = $this->movimientoRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
|
|
$cartolaData = [
|
|
'cargos' => array_sum(array_map(function(Model\Contabilidad\Movimiento $movimiento) {
|
|
return $movimiento->cargo;
|
|
}, $movimientos)),
|
|
'abonos' => array_sum(array_map(function(Model\Contabilidad\Movimiento $movimiento) {
|
|
return $movimiento->abono;
|
|
}, $movimientos)),
|
|
'saldo' => last($movimientos)->saldo
|
|
];
|
|
return $this->buildCartola($cuenta, $fecha, $cartolaData);
|
|
}
|
|
|
|
protected function getMovimientosDiarios(Model\Contabilidad\Banco $banco, UploadedFileInterface $file): array
|
|
{
|
|
$movimientos = $this->bancos[strtolower($banco->nombre)]->process($file);
|
|
return $this->bancos[strtolower($banco->nombre)]->processMovimientosDiarios($movimientos);
|
|
}
|
|
protected array $groupedMovimientos = [];
|
|
protected function groupMovimientoByDay(Model\Contabilidad\Movimiento $movimiento): Cartola
|
|
{
|
|
if (!isset($this->groupedMovimientos[$movimiento->fecha->getTimestamp()])) {
|
|
$this->groupedMovimientos[$movimiento->fecha->getTimestamp()] = [];
|
|
}
|
|
$this->groupedMovimientos[$movimiento->fecha->getTimestamp()] []= $movimiento;
|
|
return $this;
|
|
}
|
|
protected function buildCartola(Model\Inmobiliaria\Cuenta $cuenta, DateTimeInterface $fecha, array $data): Model\Contabilidad\Cartola
|
|
{
|
|
try {
|
|
return $this->cartolaRepository->fetchByCuentaAndFecha($cuenta->id, $fecha);
|
|
} catch (Exception\EmptyResult) {
|
|
$data['cuenta_id'] = $cuenta->id;
|
|
$data['fecha'] = $fecha->format('Y-m-d');
|
|
$cartola = $this->cartolaRepository->create($data);
|
|
return $this->cartolaRepository->save($cartola);
|
|
}
|
|
}
|
|
protected function buildMovimiento(Model\Inmobiliaria\Cuenta $cuenta, array $data): Model\Contabilidad\Movimiento
|
|
{
|
|
try {
|
|
return $this->movimientoRepository
|
|
->fetchByCuentaAndFechaAndGlosaAndCargoAndAbonoAndSaldo(
|
|
$cuenta->id,
|
|
new DateTimeImmutable($data['fecha']),
|
|
$data['glosa'],
|
|
$data['cargo'] ?? 0,
|
|
$data['abono'] ?? 0,
|
|
$data['saldo']
|
|
);
|
|
} catch (Exception\EmptyResult $exception) {
|
|
$data['cuenta_id'] = $cuenta->id;
|
|
$movimiento = $this->movimientoRepository->create($data);
|
|
try {
|
|
return $this->movimientoRepository->save($movimiento);
|
|
} catch (\PDOException $exception) {
|
|
$this->logger->critical(var_export($data,true));
|
|
throw $exception;
|
|
}
|
|
}
|
|
}
|
|
protected function parseRut(string $rut): array
|
|
{
|
|
if (str_contains($rut, '/')) {
|
|
$ruts = explode('/', $rut);
|
|
$output = [];
|
|
foreach ($ruts as $rut) {
|
|
$output []= $this->parseRut($rut);
|
|
}
|
|
return $output;
|
|
}
|
|
list($rut, $digito) = explode('-', $rut);
|
|
return ['rut' => trim(preg_replace('/\D+/', '', $rut)), 'digito' => trim($digito)];
|
|
}
|
|
}
|