diff --git a/api/common/Controller/Cuentas.php b/api/common/Controller/Cuentas.php index b27fe66..3071c17 100644 --- a/api/common/Controller/Cuentas.php +++ b/api/common/Controller/Cuentas.php @@ -1,8 +1,10 @@ withJson($response, $output); } + protected function transaccionToArray(Service $service, Cuenta $cuenta, Transaccion $transaccion): array { + $arr = $transaccion->toArray(); + if ($cuenta->moneda()->codigo === 'CLP') { + if ($transaccion->debito()->moneda()->codigo !== 'CLP' or $transaccion->credito()->moneda()->codigo !== 'CLP') { + if ($transaccion->debito()->moneda()->codigo !== 'CLP') { + $c = $transaccion->debito(); + } else { + $c = $transaccion->credito(); + } + $service->get($transaccion->fecha(), $c->moneda()->id); + $arr['valor'] = $c->moneda()->cambiar($transaccion->fecha(), $transaccion->valor); + $arr['valorFormateado'] = $cuenta->moneda()->format($arr['valor']); + } + } + $arr['debito']['categoria'] = $transaccion->debito()->categoria()->toArray(); + $arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray(); + return $arr; + } public function transacciones(Request $request, Response $response, Factory $factory, Service $service, $cuenta_id, $limit = null, $start = 0): Response { $cuenta = $factory->find(Cuenta::class)->one($cuenta_id); $transacciones = null; @@ -116,7 +136,7 @@ class Cuentas { $transacciones = $cuenta->transacciones($limit, $start); if (count($transacciones) > 0) { foreach ($transacciones as &$transaccion) { - $arr = $transaccion->toArray(); + /*$arr = $transaccion->toArray(); if ($cuenta->moneda()->codigo === 'CLP') { if ($transaccion->debito()->moneda()->codigo !== 'CLP' or $transaccion->credito()->moneda()->codigo !== 'CLP') { if ($transaccion->debito()->moneda()->codigo !== 'CLP') { @@ -130,8 +150,8 @@ class Cuentas { } } $arr['debito']['categoria'] = $transaccion->debito()->categoria()->toArray(); - $arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray(); - $transaccion = $arr; + $arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray();*/ + $transaccion = $this->transaccionToArray($service, $cuenta, $transaccion); } } } @@ -142,6 +162,55 @@ class Cuentas { ]; return $this->withJson($response, $output); } + public function transaccionesMonth(Request $request, Response $response, Factory $factory, Service $service, $cuenta_id, $month): Response { + $cuenta = $factory->find(Cuenta::class)->one($cuenta_id); + $month = Carbon::parse($month); + $transacciones = null; + if ($cuenta !== null) { + $transacciones = $cuenta->transaccionesMonth($month); + if (count($transacciones) > 0) { + foreach ($transacciones as &$transaccion) { + /*$arr = $transaccion->toArray(); + if ($cuenta->moneda()->codigo === 'CLP') { + if ($transaccion->debito()->moneda()->codigo !== 'CLP' or $transaccion->credito()->moneda()->codigo !== 'CLP') { + if ($transaccion->debito()->moneda()->codigo !== 'CLP') { + $c = $transaccion->debito(); + } else { + $c = $transaccion->credito(); + } + $service->get($transaccion->fecha(), $c->moneda()->id); + $arr['valor'] = $c->moneda()->cambiar($transaccion->fecha(), $transaccion->valor); + $arr['valorFormateado'] = $cuenta->moneda()->format($arr['valor']); + } + } + $arr['debito']['categoria'] = $transaccion->debito()->categoria()->toArray(); + $arr['credito']['categoria'] = $transaccion->credito()->categoria()->toArray();*/ + $transaccion = $this->transaccionToArray($service, $cuenta, $transaccion); + } + } + } + $output = [ + 'input' => compact('cuenta_id', 'month'), + 'cuenta' => $cuenta?->toArray(), + 'transacciones' => $transacciones + ]; + return $this->withJson($response, $output); + } + public function transaccionesAcumulation(Request $request, Response $response, Factory $factory, $cuenta_id, $date): Response { + $cuenta = $factory->find(Cuenta::class)->one($cuenta_id); + $f = Carbon::parse($date); + $acum = 0; + if ($cuenta !== null) { + $acum = $cuenta->acumulacion($f); + } + $output = [ + 'input' => compact('cuenta_id', 'date'), + 'cuenta' => $cuenta?->toArray(), + 'format' => $cuenta->moneda()->toArray(), + 'acumulation' => $acum + ]; + return $this->withJson($response, $output); + } public function transaccionesAmount(Request $request, Response $response, Factory $factory, $cuenta_id): Response { $cuenta = $factory->find(Cuenta::class)->one($cuenta_id); $transacciones = 0; diff --git a/api/resources/routes/cuentas.php b/api/resources/routes/cuentas.php index c1df50c..76d6d03 100644 --- a/api/resources/routes/cuentas.php +++ b/api/resources/routes/cuentas.php @@ -9,6 +9,8 @@ $app->group('/cuenta/{cuenta_id}', function($app) { $app->get('/entradas', [Cuentas::class, 'entradas']); $app->group('/transacciones', function($app) { $app->get('/amount', [Cuentas::class, 'transaccionesAmount']); + $app->get('/month/{month}', [Cuentas::class, 'transaccionesMonth']); + $app->get('/acum/{date}', [Cuentas::class, 'transaccionesAcumulation']); $app->get('[/{limit:[0-9]+}[/{start:[0-9]+}]]', [Cuentas::class, 'transacciones']); }); $app->get('/categoria', [Cuentas::class, 'categoria']); diff --git a/api/src/Cuenta.php b/api/src/Cuenta.php index 3709a84..46f6d18 100644 --- a/api/src/Cuenta.php +++ b/api/src/Cuenta.php @@ -1,7 +1,9 @@ transacciones === null) { $transacciones = Model::factory(Transaccion::class) ->select('transacciones.*') ->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id') @@ -64,15 +65,52 @@ class Cuenta extends Model { $transacciones = $transacciones->limit($limit) ->offset($start); } - $this->transacciones = $transacciones->findMany(); - foreach ($this->transacciones as &$transaccion) { + $transacciones = $transacciones->findMany(); + foreach ($transacciones as &$transaccion) { $transaccion->setFactory($this->factory); - if ($transaccion->desde_id === $this->id) { + if ($transaccion->debito_id === $this->id) { $transaccion->valor = - $transaccion->valor; } } - } - return $this->transacciones; + return $transacciones; + } + public function transaccionesMonth(Carbon $month) { + $start = $month->copy()->startOfMonth(); + $end = $month->copy()->endOfMonth(); + + $transacciones = Model::factory(Transaccion::class) + ->select('transacciones.*') + ->join('cuentas', 'cuentas.id = transacciones.debito_id OR cuentas.id = transacciones.credito_id') + ->whereEqual('cuentas.id', $this->id) + ->whereRaw("transacciones.fecha BETWEEN '{$start->format('Y-m-d')}' AND '{$end->format('Y-m-d')}'") + ->orderByAsc('transacciones.fecha'); + $transacciones = $transacciones->findMany(); + + foreach ($transacciones as &$transaccion) { + $transaccion->setFactory($this->factory); + if ($transaccion->desde_id === $this->id) { + $transaccion->valor = - $transaccion->valor; + } + } + + return $transacciones; + } + public function acumulacion(Carbon $date) { + $abonos = Model::factory(Transaccion::class) + ->whereEqual('credito_id', $this->id) + ->whereLt('fecha', $date->format('Y-m-d')) + ->groupBy('credito_id') + ->sum('valor'); + $cargos = Model::factory(Transaccion::class) + ->whereEqual('debito_id', $this->id) + ->whereLt('fecha', $date->format('Y-m-d')) + ->groupBy('debito_id') + ->sum('valor'); + + if (in_array($this->tipo()->descripcion, ['activo', 'banco', 'perdida'])) { + return $abonos - $cargos; + } + return $cargos - $abonos; } protected $saldo; public function saldo(Service $service = null, $in_clp = false) { diff --git a/api/src/Moneda.php b/api/src/Moneda.php index 9b0fc81..9405f41 100644 --- a/api/src/Moneda.php +++ b/api/src/Moneda.php @@ -16,11 +16,11 @@ class Moneda extends Model { protected static $fields = ['denominacion', 'codigo']; public function format($valor) { - return implode('', [ + return trim(implode('', [ $this->prefijo, number_format($valor, $this->decimales, ',', '.'), $this->sufijo - ]); + ])); } public function cambio(\DateTime $fecha) { $cambio = $this->factory->find(TipoCambio::class) @@ -43,4 +43,14 @@ class Moneda extends Model { } return $cambio->transform($valor); } + + public function toArray(): array { + $arr = parent::toArray(); + $arr['format'] = [ + 'prefijo' => $this->prefijo, + 'sufijo' => $this->sufijo, + 'decimales' => $this->decimales + ]; + return $arr; + } } diff --git a/ui/common/Controller/Cuentas.php b/ui/common/Controller/Cuentas.php index 332096d..19913fc 100644 --- a/ui/common/Controller/Cuentas.php +++ b/ui/common/Controller/Cuentas.php @@ -10,7 +10,8 @@ class Cuentas { return $view->render($response, 'cuentas.list'); } public function show(Request $request, Response $response, View $view, $cuenta_id): Response { - return $view->render($response, 'cuentas.show', compact('cuenta_id')); + $max_transacciones = 100; + return $view->render($response, 'cuentas.show', compact('cuenta_id', 'max_transacciones')); } public function add(Request $request, Response $response, View $view): Response { return $view->render($response, 'cuentas.add'); diff --git a/ui/public/assets/scripts/cuentas.show.js b/ui/public/assets/scripts/cuentas.show.js index e913f36..5f863ce 100644 --- a/ui/public/assets/scripts/cuentas.show.js +++ b/ui/public/assets/scripts/cuentas.show.js @@ -1,5 +1,5 @@ class Transaccion { - constructor({id, debito_id, credito_id, fecha, glosa, detalle, valor, debito, credito, fechaFormateada, valorFormateado}) { + constructor({id, debito_id, credito_id, fecha, glosa, detalle, valor, debito, credito, fechaFormateada, valorFormateado, format}) { this.id = id this.debito_id = debito_id this.credito_id = credito_id @@ -13,6 +13,7 @@ class Transaccion { valor, formateado: valorFormateado } + this.format_array = format this.debito = debito this.credito = credito this.modal = null @@ -33,7 +34,7 @@ class Transaccion { } return !this.isDebito() } - draw({saldo, format}) { + draw({saldo, format, format_array, format_call}) { const fuente = (this.isDebito()) ? this.credito : this.debito return $('').append( $('').html(this.fecha.formateada) @@ -44,11 +45,11 @@ class Transaccion { ).append( $('').html(this.glosa + '
' + this.detalle) ).append( - $('').attr('class', 'right aligned').html((this.isIncrement()) ? '' : format.format(this.valor.valor)) + $('').attr('class', 'right aligned').html((this.isIncrement()) ? '' : format_call({value: this.valor.valor, format, format_array})) ).append( - $('').attr('class', 'right aligned').html((this.isIncrement()) ? format.format(this.valor.valor) : '') + $('').attr('class', 'right aligned').html((this.isIncrement()) ? format_call({value: this.valor.valor, format, format_array}) : '') ).append( - $('').attr('class', 'right aligned').html(format.format(saldo)) + $('').attr('class', 'right aligned').html(format_call({value: saldo, format_array, format})) ).append( $('').attr('class', 'right aligned').append( $('').attr('class', 'ui tiny circular icon button').append( @@ -90,11 +91,33 @@ class Transaccion { const transacciones = { id: '#transacciones', + mes: '#mes', + buttons: { + prev: '#prev_button', + left: '#left_button', + right: '#right_button', + next: '#next_button' + }, cuenta_id: 0, cuenta: null, transacciones: [], cuentas: [], + date: new Date(), saldo: 0, + acumulation: 0, + intl_format: null, + max: null, + format: ({format_array, format, value}) => { + let output = [] + if (format_array.prefijo !== '') { + output.push(format_array.prefijo) + } + output.push(format.format(Math.round(value * Math.pow(10, format_array.decimales)) / Math.pow(10, format_array.decimales))) + if (format_array.sufijo !== '') { + output.push(format_array.sufijo) + } + return output.join('') + }, get: function() { return { transacciones: () => { @@ -105,20 +128,15 @@ const transacciones = { return } this.cuenta = data.cuenta + this.intl_format = Intl.NumberFormat('es-CL') sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/categoria').then((resp) => { this.cuenta.categoria = resp.categoria }).then(() => { - this.saldo = this.cuenta.saldo + //this.saldo = this.cuenta.saldo $('#cuenta').html(this.cuenta.nombre + ' (' + this.cuenta.categoria.nombre + ')').append( $('').attr('class', 'square full icon').css('color', '#' + this.cuenta.tipo.color) ) - const amount = data.transacciones - const step = 50 - for (let i = 0; i < amount; i += step) { - promises.push( - sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/' + step + '/' + i) - ) - } + promises = this.get().transaccionesMes(this.date) if (promises.length > 0) { Promise.all(promises).then((data_arr) => { this.transacciones = [] @@ -137,7 +155,13 @@ const transacciones = { return (new Date(b.fecha)) - (new Date(a.fecha)) }) }).then(() => { - this.draw().table() + this.get().transaccionesAcumulacion(this.date).then((response) => { + this.acumulation = response.acumulation + this.saldo = response.acumulation + }).then(() => { + this.draw().table() + this.draw().acumulation() + }) }) } else { this.draw().table() @@ -145,6 +169,32 @@ const transacciones = { }) }) }, + transaccionesLimit: () => { + let promises = [] + const amount = data.transacciones + let step = 50 + let start = 0 + if (this.max !== null) { + step = Math.min(50, this.max) + start = Math.max(0, amount - this.max) + } + for (let i = start; i <= amount; i += step) { + promises.push( + sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/' + step + '/' + i) + ) + } + return promises + }, + transaccionesMes: (mes) => { + let promises = [] + promises.push( + sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/month/' + [mes.getFullYear(), mes.getMonth() + 1, '1'].join('-')) + ) + return promises + }, + transaccionesAcumulacion: (mes) => { + return sendGet(_urls.api + '/cuenta/' + this.cuenta_id + '/transacciones/acum/' + [mes.getFullYear(), mes.getMonth() + 1, '1'].join('-')) + }, cuentas: () => { return sendGet(_urls.api + '/cuentas').then((data) => { if (data.cuentas === null || data.cuentas.length === 0) { @@ -185,13 +235,36 @@ const transacciones = { ) }, table: () => { - const format = Intl.NumberFormat('es-CL', {style: 'currency', currency: this.cuenta.moneda.codigo}) const parent = $(this.id) parent.html('') $.each(this.transacciones, (i, el) => { - parent.append(el.draw({saldo: this.saldo, format: format})) this.saldo = this.saldo + parseInt(el.valor.valor) * ((el.isIncrement()) ? 1 : -1) + parent.append(el.draw({saldo: this.saldo, format: this.intl_format, format_array: this.cuenta.moneda.format, format_call: this.format})) }) + }, + acumulation: () => { + const parent = $(this.id) + parent.prepend( + $('').append( + $('').html('') + ).append( + $('').html('') + ).append( + $('').html('Acumulacion Anterior') + ).append( + $('').attr('class', 'right aligned').html('') + ).append( + $('').attr('class', 'right aligned').html('') + ).append( + $('').attr('class', 'right aligned').html(this.format({ + format_array: this.cuenta.moneda.format, + format: this.intl_format, + value: this.acumulation + })) + ).append( + $('').attr('class', 'right aligned').html('') + ) + ) } } }, @@ -248,6 +321,33 @@ const transacciones = { this.get().transacciones() }) }, + changeMonth: function(dif) { + let d = this.date + d.setMonth(this.date.getMonth() + dif) + this.date = d + this.checkButtons() + $(this.mes).calendar('set date', this.date) + }, + changeYear: function(dif) { + let d = this.date + d.setFullYear(this.date.getFullYear() + dif) + this.date = d + this.checkButtons() + $(this.mes).calendar('set date', this.date) + }, + checkButtons: function() { + let f = new Date() + if (this.date.getMonth() === f.getMonth() && this.date.getFullYear() === f.getFullYear()) { + $(this.buttons.right).addClass('disabled') + } else { + $(this.buttons.right).removeClass('disabled') + } + if (this.date.getFullYear() === f.getFullYear()) { + $(this.buttons.next).addClass('disabled') + } else { + $(this.buttons.next).removeClass('disabled') + } + }, refresh: function () { this.get().transacciones() }, @@ -283,11 +383,49 @@ const transacciones = { maxDate: new Date() }) this.get().cuentas() + }, + mes: () => { + const meses = ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Dicembre'] + $(this.mes).calendar({ + type: 'month', + initialDate: this.date, + maxDate: new Date(), + text: { + months: meses, + monthsShort: meses.map((item) => {item.slice(0, 3)}) + }, + formatter: { + date: function (date, settings) { + if (!date) return ''; + return meses[date.getMonth()] + ', ' + date.getFullYear() + } + }, + onChange: (date) => { + this.date = date + this.refresh() + } + }) + }, + buttons: () => { + $(this.buttons.right).click((e) => { + this.changeMonth(1) + }) + $(this.buttons.left).click((e) => { + this.changeMonth(-1) + }) + $(this.buttons.next).click(() => { + this.changeYear(1) + }) + $(this.buttons.prev).click(() => { + this.changeYear(-1) + }) } } }, setup: function() { this.build().modal() + this.build().mes() + this.build().buttons() $(this.id).parent().find('#refresh').click(() => { this.refresh() }) diff --git a/ui/resources/views/cuentas/show.blade.php b/ui/resources/views/cuentas/show.blade.php index f2614e5..632ff24 100644 --- a/ui/resources/views/cuentas/show.blade.php +++ b/ui/resources/views/cuentas/show.blade.php @@ -5,6 +5,26 @@ @endsection @section('cuentas_content') +
+
+
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
@@ -82,6 +102,7 @@ diff --git a/ui/setup/settings/03_web.php b/ui/setup/settings/03_web.php index 5e5d0d3..18dcb1a 100644 --- a/ui/setup/settings/03_web.php +++ b/ui/setup/settings/03_web.php @@ -22,5 +22,6 @@ return [ ]); $arr['api'] = $_ENV['API_URL'] ?? 'http://localhost:9001'; return (object) $arr; - } + }, + 'max_transacciones' => 100 ];