setFactory($factory); $this->setQueuer($queuer); } protected ModelFactory $factory; public function setFactory(ModelFactory $factory): Consolidar { $this->factory = $factory; return $this; } protected Queuer $queuer; public function setQueuer(Queuer $queuer): Consolidar { $this->queuer = $queuer; return $this; } protected $cuentas; public function getCuentas() { if ($this->cuentas === null) { $this->cuentas = $this->factory->find(Cuenta::class)->many(); } return $this->cuentas; } public function isConsolidado(): bool { $cuentas = $this->getCuentas(); if ($cuentas === null) { return true; } foreach ($cuentas as $cuenta) { $transacciones = $cuenta->hasTransacciones(); if (!$transacciones) { continue; } $pendientes = $cuenta->hasConsolidadosPending(); if ($pendientes) { return false; } } return true; } public function queue() { $this->queuer->queue('consolidar'); } public function consolidar() { ini_set('max_execution_time', 60*5); foreach ($this->getCuentas() as $cuenta) { if (!$cuenta->hasTransacciones()) { continue; } $first = $this->getFirst($cuenta); $last = $this->getLast($cuenta); for ($current = $first->copy()->startOfMonth(); $current < $last->copy()->addMonthWithoutOverflow()->endOfMonth(); $current = $current->copy()->addMonthWithoutOverflow()) { $this->consolidarCuenta($cuenta, $current); } } } public function consolidarCuenta(Cuenta $cuenta, Carbon $mes) { if (!$cuenta->hasTransacciones($mes)) { return; } $transacciones = $this->getTransacciones($cuenta, $mes); if (count($transacciones) == 0) { return; } array_walk($transacciones, function(&$item) use ($cuenta) { $item->valor = $item->transformar($cuenta->moneda()); }); $saldo = array_reduce($transacciones, function($sum, $item) { return $sum + $item->valor; }); if ($cuenta->tipo()->cargo()) { $saldo += -1; } $consolidado = $this->factory->find(Consolidado::class)->where([['cuenta_id', $cuenta->id], ['fecha', $mes->format('Y-m-1')]])->one(); if ($consolidado === null) { $data = [ 'cuenta_id' => $cuenta->id, 'fecha' => $mes->format('Y-m-1'), 'periodo' => 'P1M', 'saldo' => $saldo ]; $consolidado = $this->factory->create(Consolidado::class, $data); } $consolidado->saldo = $saldo; $consolidado->save(); } public function getFirst(Cuenta $cuenta): ?Carbon { $first = [ Model::factory(Transaccion::class) ->select('fecha') ->whereEqual('debito_id', $cuenta->id) ->orderByAsc('fecha') ->findOne(), Model::factory(Transaccion::class) ->select('fecha') ->whereEqual('credito_id', $cuenta->id) ->orderByAsc('fecha') ->findOne() ]; if (!$first[0]) { if (!$first[1]) { return null; } return $first[1]->fecha(); } if (!$first[1]) { return $first[0]->fecha(); } if ($first[0]->fecha() < $first[1]->fecha()) { return $first[0]->fecha(); } return $first[1]->fecha(); } public function getLast(Cuenta $cuenta): ?Carbon { $fechas = [ Model::factory(Transaccion::class) ->select('fecha') ->whereEqual('debito_id', $cuenta->id) ->orderByDesc('fecha') ->findOne(), Model::factory(Transaccion::class) ->select('fecha') ->whereEqual('credito_id', $cuenta->id) ->orderByDesc('fecha') ->findOne() ]; if (!$fechas[0]) { if (!$fechas[1]) { return null; } return $fechas[1]->fecha(); } if (!$fechas[1]) { return $fechas[0]->fecha(); } if ($fechas[0]->fecha() > $fechas[1]->fecha()) { return $fechas[0]->fecha(); } return $fechas[1]->fecha(); } public function getTransacciones(Cuenta $cuenta, Carbon $fecha) { $start = $fecha->copy()->startOfMonth(); $end = $fecha->copy()->endOfMonth(); $debitos = Model::factory(Transaccion::class) ->whereEqual('debito_id', $cuenta->id) ->whereRaw("fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'") ->findMany(); if ($debitos) { array_walk($debitos, function(&$item) { $item->valor *= -1; }); } $creditos = Model::factory(Transaccion::class) ->whereEqual('credito_id', $cuenta->id) ->whereRaw("fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'") ->findMany(); $transacciones = array_merge($debitos, $creditos); foreach ($transacciones as &$transaccion) { $transaccion->setFactory($this->factory); } return $transacciones; } }