diff --git a/app/resources/routes/api/contabilidad/movimientos.php b/app/resources/routes/api/contabilidad/movimientos.php
new file mode 100644
index 0000000..545dd98
--- /dev/null
+++ b/app/resources/routes/api/contabilidad/movimientos.php
@@ -0,0 +1,6 @@
+group('/movimiento/{movimiento_id}', function($app) {
+ $app->post('/detalles', [Movimientos::class, 'detalles']);
+});
diff --git a/app/resources/views/contabilidad/cartolas/diaria.blade.php b/app/resources/views/contabilidad/cartolas/diaria.blade.php
index 9750f1e..316246b 100644
--- a/app/resources/views/contabilidad/cartolas/diaria.blade.php
+++ b/app/resources/views/contabilidad/cartolas/diaria.blade.php
@@ -52,6 +52,8 @@
Cargo |
Abono |
Saldo |
+ Centro de Costo |
+ Detalle |
Orden |
@@ -185,6 +187,46 @@
}
}
}
+ update() {
+ return {
+ centro: (idx, centro_id) => {
+ const id = this.movimientos[idx].id
+ const url = '{{$urls->api}}/contabilidad/movimiento/' + id + '/detalles'
+ const body = new FormData()
+ body.set('centro_id', centro_id)
+ return fetchAPI(url, {method: 'post', body}).then(response => {
+ if (!response) {
+ return
+ }
+ response.json().then(json => {
+ if (!json.status) {
+ return
+ }
+ const dropdown = $(".dropdown[data-idx='" + idx + "']")
+ dropdown.dropdown('set selected', json.centro.id, true)
+ })
+ })
+ },
+ detalle: (idx, detalle) => {
+ const id = this.movimientos[idx].id
+ const url = '{{$urls->api}}/contabilidad/movimiento/' + id + '/detalles'
+ const body = new FormData()
+ body.set('detalle', detalle)
+ return fetchAPI(url, {method: 'post', body}).then(response => {
+ if (!response) {
+ return
+ }
+ response.json().then(json => {
+ if (!json.status) {
+ return
+ }
+ const input = $("input[data-idx='" + idx + "']")
+ input.val(json.detalle)
+ })
+ })
+ }
+ }
+ }
draw() {
return {
form: ($form, inmobiliarias, first = false) => {
@@ -339,25 +381,73 @@
this.movimientos.forEach((row, idx) => {
$tbody.append(
$('
').append(
- $(' | ').html(this.inmobiliaria.razon)
+ '' + this.inmobiliaria.razon + ' | ' + "\n"
+ + '' + this.cuenta.descripcion + ' | ' + "\n"
+ + '' + dateFormatter.format(row.fecha) + ' | ' + "\n"
+ + '' + row.glosa + ' | ' + "\n"
+ + '' + (row.cargo === 0 ? '' : numberFormatter.format(row.cargo)) + ' | ' + "\n"
+ + '' + (row.abono === 0 ? '' : numberFormatter.format(row.abono)) + ' | ' + "\n"
+ + '' + (row.saldo === 0 ? '' : numberFormatter.format(row.saldo)) + ' | ' + "\n"
).append(
- $(' | ').html(this.cuenta.descripcion)
+ $(' | ').append(
+ this.draw().centroCosto(idx)
+ )
).append(
- $(' | ').html(dateFormatter.format(row.fecha))
- ).append(
- $(' | ').html(row.glosa)
- ).append(
- $(' | ').addClass('right aligned').html(row.cargo === 0 ? '' : numberFormatter.format(row.cargo))
- ).append(
- $(' | ').addClass('right aligned').html(row.abono === 0 ? '' : numberFormatter.format(row.abono))
- ).append(
- $(' | ').addClass('right aligned').html(row.saldo === 0 ? '' : numberFormatter.format(row.saldo))
+ $(' | ').append(
+ this.draw().detalle(idx)
+ )
).append(
$(' | ').html(idx + 1)
)
)
})
},
+ centroCosto: idx => {
+ const centros = JSON.parse('{!! json_encode($centrosCostos) !!}')
+ const menu = $('').addClass('menu')
+ centros.forEach(centro => {
+ menu.append(
+ ''
+ + centro.id + ' - ' + centro.descripcion
+ + '
'
+ )
+ })
+ const dropdown = $('').addClass('ui search selection dropdown').attr('data-idx', idx).html(
+ '' + "\n" +
+ '' + "\n" +
+ 'Centro de Costo
' + "\n"
+ ).append(menu)
+ dropdown.dropdown({
+ onChange: (value, text, $element) => {
+ const idx = $element.parent().parent().data('idx')
+ this.update().centro(idx, value)
+ }
+ })
+
+ if (this.movimientos[idx].centro !== '') {
+ const cid = centros.findIndex(centro => centro.descripcion === this.movimientos[idx].centro)
+ dropdown.dropdown('set selected', centros[cid].id, true)
+ }
+ return dropdown
+ },
+ detalle: idx => {
+ const detalle = document.createElement('input')
+ detalle.type = 'text'
+ detalle.name = 'detalle' + idx
+ detalle.placeholder = 'Detalle'
+ detalle.setAttribute('data-idx', idx)
+ const input = document.createElement('div')
+ input.className = 'ui input'
+ input.appendChild(detalle)
+ if (this.movimientos[idx].detalle !== '') {
+ detalle.value = this.movimientos[idx].detalle
+ }
+ detalle.addEventListener('blur', event => {
+ const idx = event.currentTarget.dataset['idx']
+ this.update().detalle(idx, event.currentTarget.value)
+ })
+ return $(input)
+ }
}
}
}
@@ -370,6 +460,8 @@
'cargo',
'abono',
'saldo',
+ 'centro',
+ 'detalle',
'orden'
];
@endphp
@@ -388,7 +480,7 @@
width: '{{round((1/(count($columns) + 3 - 1)) * 100,2)}}%'
},
{
- targets: [{{implode(',', array_keys(array_filter($columns, function($column) {return in_array($column, ['sociedad', 'cuenta', 'glosa']);})))}}],
+ targets: [{{implode(',', array_keys(array_filter($columns, function($column) {return in_array($column, ['sociedad', 'cuenta', 'glosa', 'centro', 'detalle']);})))}}],
width: '{{round((1/(count($columns) + 3 - 1)) * 2 * 100, 2)}}%'
},
{
@@ -506,12 +598,15 @@
const fecha = new Date(row.fecha)
fecha.setDate(fecha.getDate() + 1)
this.data.cartolas[cartolaIdx].movimientos[idx] = {
+ id: row.id,
fecha: fecha,
glosa: row.glosa,
documento: row.documento,
cargo: row.cargo,
abono: row.abono,
- saldo: row.saldo
+ saldo: row.saldo,
+ centro: row.detalles?.centro_costo.descripcion ?? '',
+ detalle: row.detalles?.detalle ?? ''
}
})
const ayer = new Date(this.data.cartolas[cartolaIdx].fecha.getTime())
@@ -629,41 +724,31 @@
movimiento: idx => {
$(this.ids.movimientos).append(
$('').addClass('fields').attr('data-movimiento', idx).append(
- $('').addClass('field').append(
- $('').html('Glosa')
- ).append(
- $('').attr('type', 'text').attr('name', 'glosa' + idx)
- )
- ).append(
- $('').addClass('field').append(
- $('').html('Cargo')
- ).append(
- $('').addClass('ui left labeled input').append(
- $('').addClass('ui basic label').html('$')
- ).append(
- $('').attr('type', 'text').attr('name', 'cargo' + idx)
- )
- )
- ).append(
- $('').addClass('field').append(
- $('').html('Abono')
- ).append(
- $('').addClass('ui left labeled input').append(
- $('').addClass('ui basic label').html('$')
- ).append(
- $('').attr('type', 'text').attr('name', 'abono' + idx)
- )
- )
- ).append(
- $('').addClass('field').append(
- $('').html('Saldo')
- ).append(
- $('').addClass('ui left labeled input').append(
- $('').addClass('ui basic label').html('$')
- ).append(
- $('').attr('type', 'text').attr('name', 'saldo' + idx)
- )
- )
+ '' + "\n"
+ + '' + "\n"
+ + '' + "\n"
+ + '
' + "\n" +
+ '' + "\n"
+ + '
' + "\n"
+ + '
' + "\n"
+ + '
' + "\n" +
+ '' + "\n"
+ + '
' + "\n"
+ + '
' + "\n"
+ + '
' + "\n" +
+ '' + "\n"
+ + '
' + "\n"
+ + '
' + "\n"
+ + '
'
).append(
$('').addClass('field').append(
$('').html('Eliminar')
diff --git a/app/setup/setups/services.php b/app/setup/setups/services.php
index aaec098..01dd83e 100644
--- a/app/setup/setups/services.php
+++ b/app/setup/setups/services.php
@@ -40,6 +40,7 @@ return [
$container->get(Incoviba\Repository\Inmobiliaria::class),
$container->get(Incoviba\Repository\Inmobiliaria\Cuenta::class),
$container->get(Incoviba\Repository\Movimiento::class),
+ $container->get(Incoviba\Service\Movimiento::class),
$container->get(Incoviba\Repository\Cartola::class)
))
->register('security', $container->get(Incoviba\Service\Cartola\Security::class))
diff --git a/app/src/Controller/API/Contabilidad/Movimientos.php b/app/src/Controller/API/Contabilidad/Movimientos.php
new file mode 100644
index 0000000..e792b86
--- /dev/null
+++ b/app/src/Controller/API/Contabilidad/Movimientos.php
@@ -0,0 +1,50 @@
+getParsedBody();
+ $output = [
+ 'movimiento_id' => $movimiento_id,
+ 'input' => $body,
+ 'status' => false,
+ 'movimiento' => null,
+ 'centro' => null,
+ 'detalle' => ''
+ ];
+ try {
+ $movimiento = $movimientoService->getById($movimiento_id);
+ $output['movimiento'] = $movimiento;
+ $data = [];
+ if (isset($body['centro_id'])) {
+ $centro = $centroCostoRepository->fetchById($body['centro_id']);
+ $data['centro_costo_id'] = $centro->id;
+ }
+ if (isset($body['detalle'])) {
+ $data['detalle'] = $body['detalle'];
+ }
+ $movimientoService->setDetalles($movimiento, $data);
+ if (isset($body['centro_id'])) {
+ $output['centro'] = $centro;
+ }
+ if (isset($body['detalle'])) {
+ $output['detalle'] = $body['detalle'];
+ }
+ } catch (EmptyResult) {}
+ return $this->withJson($response, $output);
+ }
+}
diff --git a/app/src/Controller/Contabilidad.php b/app/src/Controller/Contabilidad.php
index cf83532..4f9b618 100644
--- a/app/src/Controller/Contabilidad.php
+++ b/app/src/Controller/Contabilidad.php
@@ -18,7 +18,8 @@ class Contabilidad extends Controller
public function diaria(ServerRequestInterface $request, ResponseInterface $response, View $view,
Service\Redis $redisService,
- Repository\Inmobiliaria $inmobiliariaRepository): ResponseInterface
+ Repository\Inmobiliaria $inmobiliariaRepository,
+ Repository\CentroCosto $centroCostoRepository): ResponseInterface
{
$redisKey = 'inmobiliarias';
$inmobiliarias = [];
@@ -30,7 +31,8 @@ class Contabilidad extends Controller
$this->saveRedis($redisService, $redisKey, $inmobiliarias, 30 * 24 * 60 * 60);
} catch (EmptyResult) {}
}
- return $view->render($response, 'contabilidad.cartolas.diaria', compact('inmobiliarias'));
+ $centrosCostos = $centroCostoRepository->fetchAll();
+ return $view->render($response, 'contabilidad.cartolas.diaria', compact('inmobiliarias', 'centrosCostos'));
}
public function depositos(ServerRequestInterface $request, ResponseInterface $response, View $view,
Service\Redis $redisService,
diff --git a/app/src/Model/CentroCosto.php b/app/src/Model/CentroCosto.php
index 2e59fdb..fd4d5ef 100644
--- a/app/src/Model/CentroCosto.php
+++ b/app/src/Model/CentroCosto.php
@@ -13,7 +13,7 @@ class CentroCosto extends Ideal\Model
public function jsonSerialize(): mixed
{
- return array_map(parent::jsonSerialize(), [
+ return array_merge(parent::jsonSerialize(), [
'tipo_centro' => $this->tipoCentro,
'categoria' => $this->categoria,
'tipo_cuenta' => $this->tipoCuenta,
diff --git a/app/src/Model/Movimiento.php b/app/src/Model/Movimiento.php
index 6ca1a36..e89eb39 100644
--- a/app/src/Model/Movimiento.php
+++ b/app/src/Model/Movimiento.php
@@ -3,6 +3,7 @@ namespace Incoviba\Model;
use DateTimeInterface;
use Incoviba\Common\Ideal;
+use Incoviba\Model\Movimiento\Detalle;
class Movimiento extends Ideal\Model
{
@@ -14,6 +15,15 @@ class Movimiento extends Ideal\Model
public int $abono;
public int $saldo;
+ protected ?Detalle $detalles;
+ public function getDetalles(): ?Detalle
+ {
+ if (!isset($this->detalles)) {
+ $this->detalles = $this->runFactory('detalles');
+ }
+ return $this->detalles;
+ }
+
public function jsonSerialize(): mixed
{
return array_merge(parent::jsonSerialize(), [
@@ -23,7 +33,8 @@ class Movimiento extends Ideal\Model
'documento' => $this->documento,
'cargo' => $this->cargo,
'abono' => $this->abono,
- 'saldo' => $this->saldo
+ 'saldo' => $this->saldo,
+ 'detalles' => $this->getDetalles() ?? null
]);
}
}
diff --git a/app/src/Model/Movimiento/Detalle.php b/app/src/Model/Movimiento/Detalle.php
new file mode 100644
index 0000000..ec56449
--- /dev/null
+++ b/app/src/Model/Movimiento/Detalle.php
@@ -0,0 +1,21 @@
+ $this->movimiento->id,
+ 'centro_costo' => $this->centroCosto,
+ 'detalle' => $this->detalle
+ ];
+ }
+}
diff --git a/app/src/Repository/Movimiento/Detalle.php b/app/src/Repository/Movimiento/Detalle.php
new file mode 100644
index 0000000..cdeed75
--- /dev/null
+++ b/app/src/Repository/Movimiento/Detalle.php
@@ -0,0 +1,60 @@
+setTable('movimientos_detalles');
+ }
+
+ public function create(?array $data = null): Model\Movimiento\Detalle
+ {
+ $map = (new Implement\Repository\MapperParser(['detalle']))
+ ->register('movimiento_id', (new Implement\Repository\Mapper())
+ ->setProperty('movimiento')
+ ->setFunction(function(array $data) {
+ return $this->movimientoRepository->fetchById($data['movimiento_id']);
+ }))
+ ->register('centro_costo_id', (new Implement\Repository\Mapper())
+ ->setProperty('centroCosto')
+ ->setFunction(function(array $data) {
+ return $this->centroCostoRepository->fetchById($data['centro_costo_id']);
+ }));
+ return $this->parseData(new Model\Movimiento\Detalle(), $data, $map);
+ }
+ public function save(Define\Model $model): Model\Movimiento\Detalle
+ {
+ $this->saveNew(
+ ['movimiento_id', 'centro_costo_id', 'detalle'],
+ [$model->movimiento->id, $model->centroCosto->id, $model->detalle]
+ );
+ return $model;
+ }
+ public function edit(Define\Model $model, array $new_data): Model\Movimiento\Detalle
+ {
+ return $this->update($model, ['movimiento_id', 'centro_costo_id', 'detalle'], $new_data);
+ }
+
+ public function fetchByMovimiento(int $movimiento_id): Model\Movimiento\Detalle
+ {
+ $query = $this->connection->getQueryBuilder()
+ ->select()
+ ->from($this->getTable())
+ ->where('movimiento_id = ?');
+ return $this->fetchOne($query, [$movimiento_id]);
+ }
+
+ protected function getKey(): string
+ {
+ return 'movimiento_id';
+ }
+}
diff --git a/app/src/Service/Cartola.php b/app/src/Service/Cartola.php
index c566604..488feb8 100644
--- a/app/src/Service/Cartola.php
+++ b/app/src/Service/Cartola.php
@@ -21,6 +21,7 @@ class Cartola extends Service
protected Repository\Inmobiliaria $inmobiliariaRepository,
protected Repository\Inmobiliaria\Cuenta $cuentaRepository,
protected Repository\Movimiento $movimientoRepository,
+ protected Movimiento $movimientoService,
protected Repository\Cartola $cartolaRepository) {
parent::__construct($logger);
}
@@ -51,6 +52,7 @@ class Cartola extends Service
$movimientos = [];
foreach ($ms as $m) {
$movimiento = $this->buildMovimiento($cuenta, $m);
+ $movimiento = $this->movimientoService->process($movimiento);
if ($movimiento->fecha->getTimestamp() === $fecha->getTimestamp()) {
$movimientos []= $movimiento;
@@ -78,6 +80,7 @@ class Cartola extends Service
$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;
diff --git a/app/src/Service/Movimiento.php b/app/src/Service/Movimiento.php
new file mode 100644
index 0000000..5d9ad67
--- /dev/null
+++ b/app/src/Service/Movimiento.php
@@ -0,0 +1,43 @@
+process($this->movimientoRepository->fetchById($movimiento_id));
+ }
+ public function setDetalles(Model\Movimiento $movimiento, array $data): Model\Movimiento
+ {
+ try {
+ $detalles = $this->detalleRepository->fetchByMovimiento($movimiento->id);
+ $this->detalleRepository->edit($detalles, $data);
+ } catch (Implement\Exception\EmptyResult) {
+ $data['movimiento_id'] = $movimiento->id;
+ $detalles = $this->detalleRepository->create($data);
+ $this->detalleRepository->save($detalles);
+ }
+ return $movimiento;
+ }
+
+ public function process(Model\Movimiento $movimiento): Model\Movimiento
+ {
+ $movimiento->addFactory('detalles', (new Implement\Repository\Factory())->setCallable(function(int $movimiento_id) {
+ return $this->detalleRepository->fetchByMovimiento($movimiento_id);
+ })->setArgs(['movimiento_id' => $movimiento->id]));
+ return $movimiento;
+ }
+}