Editar movimientos
This commit is contained in:
@ -9,4 +9,5 @@ $app->group('/movimientos', function($app) {
|
|||||||
});
|
});
|
||||||
$app->group('/movimiento/{movimiento_id}', function($app) {
|
$app->group('/movimiento/{movimiento_id}', function($app) {
|
||||||
$app->post('/detalles[/]', [Movimientos::class, 'detalles']);
|
$app->post('/detalles[/]', [Movimientos::class, 'detalles']);
|
||||||
|
$app->delete('[/]', [Movimientos::class, 'remove']);
|
||||||
});
|
});
|
||||||
|
@ -50,7 +50,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="table_container">
|
<div id="table_container">
|
||||||
<table id="tabla_movimientos" class="ui table">
|
<table id="tabla_movimientos" class="ui compact table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Sigla</th>
|
<th>Sigla</th>
|
||||||
@ -71,72 +71,7 @@
|
|||||||
<tbody id="movimientos"></tbody>
|
<tbody id="movimientos"></tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui fluid modal" id="movimientos_modal">
|
@include('contabilidad.movimientos.edit_modal')
|
||||||
<div class="content">
|
|
||||||
<h3 class="header">
|
|
||||||
Editar Movimiento
|
|
||||||
</h3>
|
|
||||||
<div class="ui grid container" id="modal_info">
|
|
||||||
<div class="column sociedad"></div>
|
|
||||||
<div class="column banco"></div>
|
|
||||||
<div class="column cuenta"></div>
|
|
||||||
<div class="column fecha"></div>
|
|
||||||
<div class="column valor"></div>
|
|
||||||
<div class="column glosa"></div>
|
|
||||||
</div>
|
|
||||||
<div class="ui divider"></div>
|
|
||||||
<form class="ui form" id="movimientos_edit">
|
|
||||||
<input type="hidden" name="index"/>
|
|
||||||
<input type="hidden" name="id"/>
|
|
||||||
<div class="fields">
|
|
||||||
<div class="field">
|
|
||||||
<label for="centro_costo">Centro de Costo</label>
|
|
||||||
<div class="ui selection search dropdown" id="centro_costo">
|
|
||||||
<input type="hidden" name="centro_id"/>
|
|
||||||
<i class="dropdown icon"></i>
|
|
||||||
<div class="default text">Centro de Costo</div>
|
|
||||||
<div class="menu">
|
|
||||||
@foreach($centros as $centroCosto)
|
|
||||||
<div class="item" data-value="{{$centroCosto->id}}">{{$centroCosto->id}} - {{$centroCosto->descripcion}}</div>
|
|
||||||
@endforeach
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Categoría</label>
|
|
||||||
<input type="text" name="categoria" placeholder="Categoría" />
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Identificador</label>
|
|
||||||
<input type="text" name="identificador" placeholder="Identificador" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="fields">
|
|
||||||
<div class="field">
|
|
||||||
<label>RUT</label>
|
|
||||||
<div class="ui right labeled input">
|
|
||||||
<input type="text" name="rut" placeholder="RUT" />
|
|
||||||
<div class="ui basic label">-<span id="digito"></span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label>Nombre</label>
|
|
||||||
<input type="text" name="nombre" placeholder="Nombre" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="field">
|
|
||||||
<label for="detalle">Detalle</label>
|
|
||||||
<div class="ui input">
|
|
||||||
<textarea id="detalle" name="detalle"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<div class="ui red cancel button">Cancelar</div>
|
|
||||||
<div class="ui green approve success button">Guardar</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
@endsection
|
@endsection
|
||||||
|
|
||||||
@include('layout.body.scripts.datatables')
|
@include('layout.body.scripts.datatables')
|
||||||
@ -158,557 +93,29 @@
|
|||||||
</script>
|
</script>
|
||||||
@endpush
|
@endpush
|
||||||
@push('page_scripts')
|
@push('page_scripts')
|
||||||
|
@include('contabilidad.movimientos.scripts.event_handler')
|
||||||
|
@include('contabilidad.movimientos.scripts.loading_handler')
|
||||||
|
@include('contabilidad.movimientos.scripts.control_form')
|
||||||
|
@include('contabilidad.movimientos.scripts.movimientos_table')
|
||||||
|
@include('contabilidad.movimientos.scripts.edit_modal')
|
||||||
|
@include('contabilidad.movimientos.scripts.edit_form')
|
||||||
|
@include('contabilidad.movimientos.scripts.movimientos_handler')
|
||||||
|
@include('contabilidad.movimientos.scripts.results_handler')
|
||||||
<script>
|
<script>
|
||||||
class EventHandler {
|
|
||||||
props
|
|
||||||
constructor({movimientosHandler, modalHandler}) {
|
|
||||||
this.props = {
|
|
||||||
movimientosHandler,
|
|
||||||
modalHandler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get() {
|
|
||||||
return {
|
|
||||||
movimientos: submitEvent => {
|
|
||||||
submitEvent.preventDefault()
|
|
||||||
submitEvent.data.handler.props.movimientosHandler.get().movimientos({
|
|
||||||
sociedades_ruts: $(submitEvent.data.sociedades_id).dropdown('get values'),
|
|
||||||
mes: $(submitEvent.data.mes_id).calendar('get date')
|
|
||||||
}).then(() => {
|
|
||||||
app.handlers.table.draw().table(app.handlers.results.props.parsed)
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
edit() {
|
|
||||||
return {
|
|
||||||
movimiento: clickEvent => {
|
|
||||||
const id = $(clickEvent.currentTarget).data('id')
|
|
||||||
const index = $(clickEvent.currentTarget).data('index')
|
|
||||||
const movimiento = this.props.movimientosHandler.find().id(id)
|
|
||||||
clickEvent.data.handler.props.modalHandler.show({movimiento, index})
|
|
||||||
},
|
|
||||||
modal: submitEvent => {
|
|
||||||
submitEvent.preventDefault()
|
|
||||||
const form = submitEvent.currentTarget
|
|
||||||
const data = new FormData(form)
|
|
||||||
app.handlers.movimientos.edit().movimiento(data).then(() => {
|
|
||||||
app.handlers.table.draw().table(app.handlers.results.props.parsed)
|
|
||||||
})
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class LoadingHandler {
|
|
||||||
props
|
|
||||||
constructor(ids) {
|
|
||||||
this.props = {
|
|
||||||
...ids
|
|
||||||
}
|
|
||||||
}
|
|
||||||
show() {
|
|
||||||
$(this.props.id).addClass('loading')
|
|
||||||
}
|
|
||||||
hide() {
|
|
||||||
$(this.props.id).removeClass('loading')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class ControlForm {
|
|
||||||
props
|
|
||||||
constructor({ids,}) {
|
|
||||||
this.props = {
|
|
||||||
ids,
|
|
||||||
}
|
|
||||||
$(this.props.ids.sociedades).dropdown()
|
|
||||||
|
|
||||||
const cdo = structuredClone(calendar_date_options)
|
|
||||||
cdo['type'] = 'month'
|
|
||||||
cdo['maxDate'] = new Date()
|
|
||||||
$(this.props.ids.mes).calendar(cdo)
|
|
||||||
|
|
||||||
$(this.props.ids.form).on('submit', {
|
|
||||||
sociedades_id: this.props.ids.sociedades,
|
|
||||||
mes_id: this.props.ids.mes,
|
|
||||||
handler: app.handlers.events
|
|
||||||
}, app.handlers.events.get().movimientos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class MovimientosTable {
|
|
||||||
props
|
|
||||||
columns
|
|
||||||
constructor({ids, eventHandler}) {
|
|
||||||
this.props = {
|
|
||||||
ids,
|
|
||||||
eventHandler,
|
|
||||||
movimientos: [],
|
|
||||||
formatters: {
|
|
||||||
number: new Intl.NumberFormat('es-CL'),
|
|
||||||
date: new Intl.DateTimeFormat('es-CL', {
|
|
||||||
day: '2-digit',
|
|
||||||
month: '2-digit',
|
|
||||||
year: 'numeric'
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
this.columns = [
|
|
||||||
{title: 'Sigla', defs: {width: 'short', type: 'string'}, searchable: true, export: true}, //0
|
|
||||||
{title: 'Banco', defs: {width: 'long', type: 'string'}, searchable: true, export: true},
|
|
||||||
{title: 'Cuenta', defs: {width: 'short', type: 'string'}, searchable: true, export: true},
|
|
||||||
{title: 'Fecha', defs: {width: 'long', type: 'string'}, searchable: true, export: true},
|
|
||||||
{title: 'ISO Fecha', defs: {visible: false}},
|
|
||||||
{title: 'Mes', defs: {width: 'short', type: 'string'}, searchable: true}, //5
|
|
||||||
{title: 'Año', defs: {width: 'long', type: 'string'}, searchable: true},
|
|
||||||
{title: 'Valor', defs: {className: 'dt-right', width: 'long', type: 'num'}, export: true},
|
|
||||||
{title: 'ISO Valor', defs: {visible: false, type: 'num'}},
|
|
||||||
{title: 'Glosa', defs: {width: 'short', type: 'string'}, export: true},
|
|
||||||
{title: 'Centro de Costo', defs: {width: 'short', type: 'string'}, searchable: true, export: true}, //10
|
|
||||||
{title: 'Categoria', defs: {width: 'short', type: 'string'}},
|
|
||||||
{title: 'Detalle', defs: {width: 'long', type: 'string'}, export: true},
|
|
||||||
{title: 'RUT', defs: {width: 'short', type: 'string'}, export: true},
|
|
||||||
{title: 'Nombre', defs: {width: 'short', type: 'string'}, export: true},
|
|
||||||
{title: 'Identificador', defs: {width: 'short', type: 'string'}, export: true}, //15
|
|
||||||
{title: 'Editar', defs: {width: 'short', type: 'string'}},
|
|
||||||
]
|
|
||||||
const N = this.columns.filter(column => typeof column.defs.visible === 'undefined' || column.defs.visible).length
|
|
||||||
const nShort = this.columns.filter(column => column.defs.width === 'short').length
|
|
||||||
const nLong = this.columns.filter(column => column.defs.width === 'long').length
|
|
||||||
const short = `${(nShort / N).toFixed(2)}%`
|
|
||||||
const long = `${(nLong / N).toFixed(2)}%`
|
|
||||||
|
|
||||||
this.columns = this.columns.map(column => {
|
|
||||||
if (typeof column.defs.width === 'undefined') {
|
|
||||||
return column
|
|
||||||
}
|
|
||||||
switch (column.defs.width) {
|
|
||||||
case 'short':
|
|
||||||
column.defs.width = short
|
|
||||||
break
|
|
||||||
case 'long':
|
|
||||||
column.defs.width = long
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return column
|
|
||||||
})
|
|
||||||
|
|
||||||
const tr = $(this.props.ids.table).find('thead tr')
|
|
||||||
tr.empty()
|
|
||||||
this.columns.forEach(column => {
|
|
||||||
if (column.defs.className === 'dt-right') {
|
|
||||||
tr.append(`<th class="right aligned">${column.title}</th>`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
tr.append(`<th>${column.title}</th>`)
|
|
||||||
})
|
|
||||||
|
|
||||||
let dtD = structuredClone(datatables_defaults)
|
|
||||||
const groupedColumns = Object.groupBy(this.columns, ({defs}) => Object.entries(defs).map((field, value) => `${field}: ${value}`).join(' - '))
|
|
||||||
const columnDefs = Object.values(groupedColumns).map(group => {
|
|
||||||
return {
|
|
||||||
targets: group.map(({title}) => title).map(title => this.columns.map(column => column.title).indexOf(title)),
|
|
||||||
...group[0].defs
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const searchBuilderColumns = this.columns.filter(column => column.searchable)
|
|
||||||
.map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
|
|
||||||
const exportColumns = this.columns.filter(column => column.export)
|
|
||||||
.map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
|
|
||||||
const order = ['Sigla', 'Banco', 'ISO Fecha'].map(title => {
|
|
||||||
return [this.columns.map(column => column.title).indexOf(title), 'asc']
|
|
||||||
})
|
|
||||||
dtD = Object.assign(dtD, {
|
|
||||||
columnDefs,
|
|
||||||
order,
|
|
||||||
language: Object.assign(dtD.language, {
|
|
||||||
searchBuilder: {
|
|
||||||
add: 'Filtrar',
|
|
||||||
condition: 'Comparador',
|
|
||||||
clearAll: 'Resetear',
|
|
||||||
delete: 'Eliminar',
|
|
||||||
deleteTitle: 'Eliminar Titulo',
|
|
||||||
data: 'Columna',
|
|
||||||
left: 'Izquierda',
|
|
||||||
leftTitle: 'Titulo Izquierdo',
|
|
||||||
logicAnd: 'Y',
|
|
||||||
logicOr: 'O',
|
|
||||||
right: 'Derecha',
|
|
||||||
rightTitle: 'Titulo Derecho',
|
|
||||||
title: {
|
|
||||||
0: 'Filtros',
|
|
||||||
_: 'Filtros (%d)'
|
|
||||||
},
|
|
||||||
value: 'Opciones',
|
|
||||||
valueJoiner: 'y'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
layout: {
|
|
||||||
top1: {
|
|
||||||
searchBuilder: {
|
|
||||||
columns: searchBuilderColumns,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
top1End: {
|
|
||||||
buttons: [
|
|
||||||
{
|
|
||||||
extend: 'excelHtml5',
|
|
||||||
className: 'green',
|
|
||||||
text: 'Exportar a Excel <i class="file excel icon"></i>',
|
|
||||||
title: 'Movimientos Contables',
|
|
||||||
download: 'open',
|
|
||||||
exportOptions: {
|
|
||||||
columns: exportColumns,
|
|
||||||
format: {
|
|
||||||
body: (data, row, column, node) => {
|
|
||||||
if (column === this.columns.map(({title}) => title).indexOf('Fecha')) {
|
|
||||||
return data.split('-').reverse().join('-')
|
|
||||||
}
|
|
||||||
if (column === this.columns.map(({title}) => title).indexOf('Valor')) {
|
|
||||||
return data.replace(/\./g, '')
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
customize: xlsx => {
|
|
||||||
const sheet = xlsx.xl.worksheets['sheet1.xml']
|
|
||||||
const columns = Object.values($('row[r="2"] t', sheet).map((idx, column) => column.textContent))
|
|
||||||
const columnStylesMap = {
|
|
||||||
Valor: '63',
|
|
||||||
Fecha: '15'
|
|
||||||
}
|
|
||||||
Object.entries(columnStylesMap).forEach((column, style) => {
|
|
||||||
const columnIndex = String.fromCharCode('A'.charCodeAt(0) + columns.indexOf(column))
|
|
||||||
$(`c[r^="${columnIndex}"]`, sheet).attr('s', style)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data: this.props.movimientos,
|
|
||||||
})
|
|
||||||
this.props.table = new DataTable(this.props.ids.table, dtD)
|
|
||||||
}
|
|
||||||
draw() {
|
|
||||||
return {
|
|
||||||
table: (movimientos) => {
|
|
||||||
this.props.table.clear().rows.add(this.draw().movimientos(movimientos)).draw()
|
|
||||||
$(this.props.ids.buttons.edit).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.edit().movimiento)
|
|
||||||
},
|
|
||||||
movimientos: (movimientos) => {
|
|
||||||
const output = []
|
|
||||||
movimientos.forEach(movimiento => {
|
|
||||||
this.draw().movimiento({movimiento, output})
|
|
||||||
})
|
|
||||||
return output
|
|
||||||
},
|
|
||||||
movimiento: ({movimiento, output}) => {
|
|
||||||
const valor = movimiento.abono - movimiento.cargo
|
|
||||||
const fecha = movimiento.fecha
|
|
||||||
|
|
||||||
const data = {
|
|
||||||
Sigla: movimiento.cuenta.inmobiliaria.sigla,
|
|
||||||
Banco: movimiento.cuenta.banco.nombre,
|
|
||||||
Cuenta: movimiento.cuenta.cuenta,
|
|
||||||
Fecha: this.props.formatters.date.format(fecha),
|
|
||||||
'ISO Fecha': [fecha.getFullYear(), fecha.getMonth() + 1, fecha.getDate()].join('-'),
|
|
||||||
Mes: fecha.getMonth() + 1,
|
|
||||||
'Año': fecha.getFullYear(),
|
|
||||||
Valor: this.props.formatters.number.format(valor),
|
|
||||||
'ISO Valor': valor,
|
|
||||||
Glosa: movimiento.glosa,
|
|
||||||
'Centro de Costo': (movimiento.detalles) ? movimiento.detalles.centro_costo.id : '',
|
|
||||||
Categoria: (movimiento.detalles) ? movimiento.detalles.categoria : '',
|
|
||||||
Detalle: (movimiento.detalles) ? movimiento.detalles.detalle : '',
|
|
||||||
RUT: (movimiento.detalles && movimiento.detalles.digito) ? `${this.props.formatters.number.format(movimiento.detalles.rut)}-${movimiento.detalles.digito}` : '',
|
|
||||||
Nombre: (movimiento.detalles) ? movimiento.detalles.nombres : '',
|
|
||||||
Identificador: (movimiento.detalles) ? movimiento.detalles.identificador : '',
|
|
||||||
Editar: `<button class="ui icon button edit_button" data-id="${movimiento.id}" data-index="${movimiento.index}" data-type="movimiento"><i class="edit icon"></i></button>`,
|
|
||||||
}
|
|
||||||
const values = []
|
|
||||||
this.columns.forEach(column => {
|
|
||||||
values.push(data[column.title])
|
|
||||||
})
|
|
||||||
output.push(values)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class EditModal {
|
|
||||||
props
|
|
||||||
info
|
|
||||||
constructor({ids, editForm}) {
|
|
||||||
this.props = {
|
|
||||||
ids,
|
|
||||||
editForm,
|
|
||||||
movimientos: []
|
|
||||||
}
|
|
||||||
this.info = [
|
|
||||||
{
|
|
||||||
className: 'sociedad',
|
|
||||||
width: 'three wide',
|
|
||||||
value: movimiento => `<b>Sociedad</b>: ${movimiento.cuenta.inmobiliaria.sigla}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
className: 'banco',
|
|
||||||
width: 'three wide',
|
|
||||||
value: movimiento => `<b>Banco</b>: ${movimiento.cuenta.banco.nombre}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
className: 'cuenta',
|
|
||||||
width: 'three wide',
|
|
||||||
value: movimiento => `<b>Cuenta</b>: ${movimiento.cuenta.cuenta}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
className: 'fecha',
|
|
||||||
width: 'three wide',
|
|
||||||
value: movimiento => `<b>Fecha</b>: ${movimiento.fecha}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
className: 'valor',
|
|
||||||
width: 'three wide',
|
|
||||||
value: movimiento => `<b>Valor</b>: ${movimiento.abono - movimiento.cargo}`
|
|
||||||
},
|
|
||||||
{
|
|
||||||
className: 'glosa',
|
|
||||||
width: 'ten wide',
|
|
||||||
value: movimiento => `<b>Glosa</b>: ${movimiento.glosa}`
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const $info = $(this.props.ids.modal).find('#modal_info')
|
|
||||||
$info.empty()
|
|
||||||
this.info.forEach(field => {
|
|
||||||
$info.append(`<div class="${field.width} column ${field.className}"></div>`)
|
|
||||||
})
|
|
||||||
|
|
||||||
$(this.props.ids.modal).modal({
|
|
||||||
onApprove: $element => {
|
|
||||||
$(this.props.editForm.props.ids.form).submit()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
reset() {
|
|
||||||
this.info.forEach(info => {
|
|
||||||
$(this.props.ids.modal).find(`.${info.className}`).text('')
|
|
||||||
})
|
|
||||||
this.props.editForm.reset()
|
|
||||||
}
|
|
||||||
show({movimiento, index}) {
|
|
||||||
$(this.props.ids.modal).modal('show')
|
|
||||||
this.info.forEach(info => {
|
|
||||||
$(this.props.ids.modal).find(`.${info.className}`).html(info.value(movimiento))
|
|
||||||
})
|
|
||||||
this.props.editForm.show({modal: $(this.props.ids.modal), movimiento, index})
|
|
||||||
}
|
|
||||||
hide() {
|
|
||||||
$(this.props.ids.modal).modal('hide')
|
|
||||||
this.reset()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class EditForm {
|
|
||||||
props
|
|
||||||
fields
|
|
||||||
constructor({ids}) {
|
|
||||||
this.props = {
|
|
||||||
ids,
|
|
||||||
movimientos: []
|
|
||||||
}
|
|
||||||
this.fields = [
|
|
||||||
{
|
|
||||||
name: 'index',
|
|
||||||
value: index => index
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'id',
|
|
||||||
value: movimiento => movimiento.id
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'centro_costo',
|
|
||||||
name: 'centro_id',
|
|
||||||
type: 'dropdown',
|
|
||||||
value: movimiento => movimiento.detalles.centro_costo.id ?? '',
|
|
||||||
values: CentrosCostos.get().map(centroCosto => {
|
|
||||||
return {
|
|
||||||
value: centroCosto.id,
|
|
||||||
name: `${centroCosto.id} - ${centroCosto.descripcion}`,
|
|
||||||
text: `${centroCosto.id} - ${centroCosto.descripcion}`,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'rut',
|
|
||||||
type: 'text',
|
|
||||||
value: movimiento => movimiento.detalles.rut ?? ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'digito',
|
|
||||||
value: movimiento => movimiento.detalles.digito ?? ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'nombre',
|
|
||||||
type: 'text',
|
|
||||||
value: movimiento => movimiento.detalles.nombres ?? ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'categoria',
|
|
||||||
type: 'text',
|
|
||||||
value: movimiento => movimiento.detalles.categoria ?? ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'detalle',
|
|
||||||
type: 'text',
|
|
||||||
value: movimiento => movimiento.detalles.detalle ?? ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'identificador',
|
|
||||||
type: 'text',
|
|
||||||
value: movimiento => movimiento.detalles.identificador ?? ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
this.fields.filter(field => typeof field.values !== 'undefined').forEach(field => {
|
|
||||||
$(this.props.ids.form).find(`#${field.id}`).dropdown('change values', field.values)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
reset() {
|
|
||||||
$(this.props.ids.form).form('reset')
|
|
||||||
}
|
|
||||||
show({modal, movimiento, index}) {
|
|
||||||
modal.find(this.props.ids.data).show()
|
|
||||||
|
|
||||||
this.fields.forEach(field => {
|
|
||||||
if (typeof field.name !== 'undefined') {
|
|
||||||
switch (field.type) {
|
|
||||||
case 'dropdown':
|
|
||||||
modal.find(`#${field.id}`).dropdown('set selected', field.value(movimiento))
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
if (field.name === 'index') {
|
|
||||||
modal.find(`[name='${field.name}']`).val(index)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
modal.find(`[name='${field.name}']`).val(field.value(movimiento))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
modal.find(`#${field.id}`).text(field.value(movimiento))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
setup() {
|
|
||||||
$(this.props.ids.form).on('submit', {
|
|
||||||
form_id: this.props.ids.form,
|
|
||||||
}, app.handlers.events.edit().modal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class MovimientosHandler {
|
|
||||||
props
|
|
||||||
constructor({urls, loadingHandler, resultsHandler}) {
|
|
||||||
this.props = {
|
|
||||||
urls,
|
|
||||||
loadingHandler,
|
|
||||||
resultsHandler
|
|
||||||
}
|
|
||||||
}
|
|
||||||
get() {
|
|
||||||
return {
|
|
||||||
movimientos: ({sociedades_ruts, mes}) => {
|
|
||||||
this.props.loadingHandler.show()
|
|
||||||
const method = 'post'
|
|
||||||
const body = new FormData()
|
|
||||||
sociedades_ruts.forEach(sociedad_rut => {
|
|
||||||
body.append('sociedades_ruts[]', sociedad_rut)
|
|
||||||
})
|
|
||||||
body.set('mes', [mes.getFullYear(), mes.getMonth() + 1, mes.getDate()].join('-'))
|
|
||||||
return APIClient.fetch(this.props.urls.get, {method, body}).then(response => {
|
|
||||||
if (!response) {
|
|
||||||
throw new Error('No se pudo obtener los movimientos')
|
|
||||||
}
|
|
||||||
return response.json().then(json => {
|
|
||||||
this.movimientos = json.movimientos
|
|
||||||
this.props.resultsHandler.props.movimientos = json.movimientos
|
|
||||||
this.props.resultsHandler.parse().movimientos()
|
|
||||||
return json.movimientos
|
|
||||||
})
|
|
||||||
}).catch(error => {
|
|
||||||
console.error(error)
|
|
||||||
}).finally(() => {
|
|
||||||
this.props.loadingHandler.hide()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
edit() {
|
|
||||||
return {
|
|
||||||
movimiento: (data) => {
|
|
||||||
const method = 'post'
|
|
||||||
return APIClient.fetch(this.props.urls.edit, {method, body: data}).then(response => {
|
|
||||||
if (!response) {
|
|
||||||
throw new Error('No se pudo editar el movimiento')
|
|
||||||
}
|
|
||||||
return response.json().then(json => {
|
|
||||||
const movimiento = this.find().id(json.movimiento.id)
|
|
||||||
movimiento.detalles = json.movimiento.detalles
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
find() {
|
|
||||||
return {
|
|
||||||
id: id => {
|
|
||||||
return this.props.resultsHandler.props.movimientos.find(movimiento => movimiento.id === id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
class ResultsHandler {
|
|
||||||
props
|
|
||||||
constructor() {
|
|
||||||
this.props = {
|
|
||||||
movimientos: [],
|
|
||||||
timezone: ((new Date()).getTimezoneOffset()) / -60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
parse() {
|
|
||||||
return {
|
|
||||||
movimientos: () => {
|
|
||||||
const movimientos = this.props.movimientos
|
|
||||||
const data = []
|
|
||||||
movimientos.forEach((movimiento, index) => {
|
|
||||||
this.parse().movimiento({data, movimiento, index})
|
|
||||||
})
|
|
||||||
this.props.parsed = data
|
|
||||||
},
|
|
||||||
movimiento: ({data, movimiento, index}) => {
|
|
||||||
const fecha = new Date(movimiento.fecha + 'Z' + this.props.timezone)
|
|
||||||
data.push({
|
|
||||||
tipo: 'movimiento',
|
|
||||||
id: movimiento.id,
|
|
||||||
index,
|
|
||||||
cuenta: movimiento.cuenta,
|
|
||||||
fecha,
|
|
||||||
cargo: movimiento.cargo,
|
|
||||||
abono: movimiento.abono,
|
|
||||||
glosa: movimiento.glosa,
|
|
||||||
detalles: movimiento.detalles,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const app = {
|
const app = {
|
||||||
handlers: {},
|
handlers: {},
|
||||||
setup() {
|
setup() {
|
||||||
this.handlers.results = new ResultsHandler()
|
this.handlers.results = new ResultsHandler()
|
||||||
this.handlers.loading = new LoadingHandler({id: '#movimientos_form'})
|
this.handlers.loading = new LoadingHandler({id: '#movimientos_form'})
|
||||||
this.handlers.movimientos = new MovimientosHandler({urls: {
|
this.handlers.movimientos = new MovimientosHandler({
|
||||||
get: '{{$urls->api}}/contabilidad/movimientos/sociedad/mes',
|
urls: {
|
||||||
edit: '{{$urls->api}}/contabilidad/movimientos/edit'}, loadingHandler: this.handlers.loading, resultsHandler: this.handlers.results})
|
get: '{{$urls->api}}/contabilidad/movimientos/sociedad/mes',
|
||||||
|
edit: '{{$urls->api}}/contabilidad/movimientos/edit',
|
||||||
|
remove: '{{$urls->api}}/contabilidad/movimiento',
|
||||||
|
},
|
||||||
|
loadingHandler: this.handlers.loading,
|
||||||
|
resultsHandler: this.handlers.results
|
||||||
|
})
|
||||||
this.handlers.forms = {
|
this.handlers.forms = {
|
||||||
edit: new EditForm({ids: {modal: '#movimientos_modal', data: '#movimientos_data', form: '#movimientos_edit',}})
|
edit: new EditForm({ids: {modal: '#movimientos_modal', data: '#movimientos_data', form: '#movimientos_edit',}})
|
||||||
}
|
}
|
||||||
@ -716,7 +123,7 @@
|
|||||||
edit: new EditModal({ids: {modal: '#movimientos_modal'}, editForm: this.handlers.forms.edit})
|
edit: new EditModal({ids: {modal: '#movimientos_modal'}, editForm: this.handlers.forms.edit})
|
||||||
}
|
}
|
||||||
this.handlers.events = new EventHandler({movimientosHandler: this.handlers.movimientos, modalHandler: this.handlers.modals.edit})
|
this.handlers.events = new EventHandler({movimientosHandler: this.handlers.movimientos, modalHandler: this.handlers.modals.edit})
|
||||||
this.handlers.table = new MovimientosTable({ids: {table: '#tabla_movimientos', buttons: {edit: '.edit_button'}}, eventHandler: this.handlers.events})
|
this.handlers.table = new MovimientosTable({ids: {table: '#tabla_movimientos', buttons: {edit: '.edit_button', remove: '.remove_button'}}, eventHandler: this.handlers.events})
|
||||||
this.handlers.forms.control = new ControlForm({ids: {form: '#movimientos_form', sociedades: '#sociedades', mes: '#mes',},})
|
this.handlers.forms.control = new ControlForm({ids: {form: '#movimientos_form', sociedades: '#sociedades', mes: '#mes',},})
|
||||||
|
|
||||||
this.handlers.forms.edit.setup()
|
this.handlers.forms.edit.setup()
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
<div class="ui fluid modal" id="movimientos_modal">
|
||||||
|
<div class="content">
|
||||||
|
<h3 class="header">
|
||||||
|
Editar Movimiento
|
||||||
|
</h3>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div class="ui grid container" id="modal_info">
|
||||||
|
<div class="column sociedad"></div>
|
||||||
|
<div class="column banco"></div>
|
||||||
|
<div class="column cuenta"></div>
|
||||||
|
<div class="column fecha"></div>
|
||||||
|
<div class="column valor"></div>
|
||||||
|
<div class="column glosa"></div>
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<form class="ui form" id="movimientos_edit">
|
||||||
|
<input type="hidden" name="index"/>
|
||||||
|
<input type="hidden" name="id"/>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<label for="centro_costo">Centro de Costo</label>
|
||||||
|
<div class="ui selection search dropdown" id="centro_costo">
|
||||||
|
<input type="hidden" name="centro_id"/>
|
||||||
|
<i class="dropdown icon"></i>
|
||||||
|
<div class="default text">Centro de Costo</div>
|
||||||
|
<div class="menu">
|
||||||
|
@foreach($centros as $centroCosto)
|
||||||
|
<div class="item" data-value="{{$centroCosto->id}}">{{$centroCosto->id}} - {{$centroCosto->descripcion}}</div>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Categoría</label>
|
||||||
|
<input type="text" name="categoria" placeholder="Categoría" />
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Identificador</label>
|
||||||
|
<input type="text" name="identificador" placeholder="Identificador" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fields">
|
||||||
|
<div class="field">
|
||||||
|
<label>RUT</label>
|
||||||
|
<div class="ui right labeled input">
|
||||||
|
<input type="text" name="rut" placeholder="RUT" />
|
||||||
|
<div class="ui basic label">-<span id="digito"></span></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label>Nombre</label>
|
||||||
|
<input type="text" name="nombre" placeholder="Nombre" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="field">
|
||||||
|
<label for="detalle">Detalle</label>
|
||||||
|
<div class="ui input">
|
||||||
|
<textarea id="detalle" name="detalle"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<div class="ui red cancel button">Cancelar</div>
|
||||||
|
<div class="ui green approve success button">Guardar</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -0,0 +1,22 @@
|
|||||||
|
<script>
|
||||||
|
class ControlForm {
|
||||||
|
props
|
||||||
|
constructor({ids,}) {
|
||||||
|
this.props = {
|
||||||
|
ids,
|
||||||
|
}
|
||||||
|
$(this.props.ids.sociedades).dropdown()
|
||||||
|
|
||||||
|
const cdo = structuredClone(calendar_date_options)
|
||||||
|
cdo['type'] = 'month'
|
||||||
|
cdo['maxDate'] = new Date()
|
||||||
|
$(this.props.ids.mes).calendar(cdo)
|
||||||
|
|
||||||
|
$(this.props.ids.form).on('submit', {
|
||||||
|
sociedades_id: this.props.ids.sociedades,
|
||||||
|
mes_id: this.props.ids.mes,
|
||||||
|
handler: app.handlers.events
|
||||||
|
}, app.handlers.events.get().movimientos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,98 @@
|
|||||||
|
<script>
|
||||||
|
class EditForm {
|
||||||
|
props
|
||||||
|
fields
|
||||||
|
constructor({ids}) {
|
||||||
|
this.props = {
|
||||||
|
ids,
|
||||||
|
movimientos: []
|
||||||
|
}
|
||||||
|
this.fields = [
|
||||||
|
{
|
||||||
|
name: 'index',
|
||||||
|
value: index => index
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'id',
|
||||||
|
value: movimiento => movimiento.id
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'centro_costo',
|
||||||
|
name: 'centro_id',
|
||||||
|
type: 'dropdown',
|
||||||
|
value: movimiento => movimiento.detalles.centro_costo.id ?? '',
|
||||||
|
values: CentrosCostos.get().map(centroCosto => {
|
||||||
|
return {
|
||||||
|
value: centroCosto.id,
|
||||||
|
name: `${centroCosto.id} - ${centroCosto.descripcion}`,
|
||||||
|
text: `${centroCosto.id} - ${centroCosto.descripcion}`,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'rut',
|
||||||
|
type: 'text',
|
||||||
|
value: movimiento => movimiento.detalles.rut ?? ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'digito',
|
||||||
|
value: movimiento => movimiento.detalles.digito ?? ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'nombre',
|
||||||
|
type: 'text',
|
||||||
|
value: movimiento => movimiento.detalles.nombres ?? ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'categoria',
|
||||||
|
type: 'text',
|
||||||
|
value: movimiento => movimiento.detalles.categoria ?? ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'detalle',
|
||||||
|
type: 'text',
|
||||||
|
value: movimiento => movimiento.detalles.detalle ?? ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'identificador',
|
||||||
|
type: 'text',
|
||||||
|
value: movimiento => movimiento.detalles.identificador ?? ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
this.fields.filter(field => typeof field.values !== 'undefined').forEach(field => {
|
||||||
|
$(this.props.ids.form).find(`#${field.id}`).dropdown('change values', field.values)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
$(this.props.ids.form).form('reset')
|
||||||
|
}
|
||||||
|
show({modal, movimiento, index}) {
|
||||||
|
modal.find(this.props.ids.data).show()
|
||||||
|
|
||||||
|
this.fields.forEach(field => {
|
||||||
|
if (typeof field.name !== 'undefined') {
|
||||||
|
switch (field.type) {
|
||||||
|
case 'dropdown':
|
||||||
|
modal.find(`#${field.id}`).dropdown('set selected', field.value(movimiento))
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
if (field.name === 'index') {
|
||||||
|
modal.find(`[name='${field.name}']`).val(index)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modal.find(`[name='${field.name}']`).val(field.value(movimiento))
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
modal.find(`#${field.id}`).text(field.value(movimiento))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
setup() {
|
||||||
|
$(this.props.ids.form).on('submit', {
|
||||||
|
form_id: this.props.ids.form,
|
||||||
|
}, app.handlers.events.edit().modal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,74 @@
|
|||||||
|
<script>
|
||||||
|
class EditModal {
|
||||||
|
props
|
||||||
|
info
|
||||||
|
constructor({ids, editForm}) {
|
||||||
|
this.props = {
|
||||||
|
ids,
|
||||||
|
editForm,
|
||||||
|
movimientos: []
|
||||||
|
}
|
||||||
|
this.info = [
|
||||||
|
{
|
||||||
|
className: 'sociedad',
|
||||||
|
width: 'three wide',
|
||||||
|
value: movimiento => `<b>Sociedad</b>: ${movimiento.cuenta.inmobiliaria.sigla}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'banco',
|
||||||
|
width: 'three wide',
|
||||||
|
value: movimiento => `<b>Banco</b>: ${movimiento.cuenta.banco.nombre}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'cuenta',
|
||||||
|
width: 'three wide',
|
||||||
|
value: movimiento => `<b>Cuenta</b>: ${movimiento.cuenta.cuenta}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'fecha',
|
||||||
|
width: 'three wide',
|
||||||
|
value: movimiento => `<b>Fecha</b>: ${movimiento.fecha}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'valor',
|
||||||
|
width: 'three wide',
|
||||||
|
value: movimiento => `<b>Valor</b>: ${movimiento.abono - movimiento.cargo}`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: 'glosa',
|
||||||
|
width: 'ten wide',
|
||||||
|
value: movimiento => `<b>Glosa</b>: ${movimiento.glosa}`
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const $info = $(this.props.ids.modal).find('#modal_info')
|
||||||
|
$info.empty()
|
||||||
|
this.info.forEach(field => {
|
||||||
|
$info.append(`<div class="${field.width} column ${field.className}"></div>`)
|
||||||
|
})
|
||||||
|
|
||||||
|
$(this.props.ids.modal).modal({
|
||||||
|
onApprove: $element => {
|
||||||
|
$(this.props.editForm.props.ids.form).submit()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
this.info.forEach(info => {
|
||||||
|
$(this.props.ids.modal).find(`.${info.className}`).text('')
|
||||||
|
})
|
||||||
|
this.props.editForm.reset()
|
||||||
|
}
|
||||||
|
show({movimiento, index}) {
|
||||||
|
$(this.props.ids.modal).modal('show')
|
||||||
|
this.info.forEach(info => {
|
||||||
|
$(this.props.ids.modal).find(`.${info.className}`).html(info.value(movimiento))
|
||||||
|
})
|
||||||
|
this.props.editForm.show({modal: $(this.props.ids.modal), movimiento, index})
|
||||||
|
}
|
||||||
|
hide() {
|
||||||
|
$(this.props.ids.modal).modal('hide')
|
||||||
|
this.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,54 @@
|
|||||||
|
<script>
|
||||||
|
class EventHandler {
|
||||||
|
props
|
||||||
|
constructor({movimientosHandler, modalHandler}) {
|
||||||
|
this.props = {
|
||||||
|
movimientosHandler,
|
||||||
|
modalHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get() {
|
||||||
|
return {
|
||||||
|
movimientos: submitEvent => {
|
||||||
|
submitEvent.preventDefault()
|
||||||
|
submitEvent.data.handler.props.movimientosHandler.get().movimientos({
|
||||||
|
sociedades_ruts: $(submitEvent.data.sociedades_id).dropdown('get values'),
|
||||||
|
mes: $(submitEvent.data.mes_id).calendar('get date')
|
||||||
|
}).then(() => {
|
||||||
|
app.handlers.table.draw().table(app.handlers.results.props.parsed)
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edit() {
|
||||||
|
return {
|
||||||
|
movimiento: clickEvent => {
|
||||||
|
const id = $(clickEvent.currentTarget).data('id')
|
||||||
|
const index = $(clickEvent.currentTarget).data('index')
|
||||||
|
const movimiento = this.props.movimientosHandler.find().id(id)
|
||||||
|
clickEvent.data.handler.props.modalHandler.show({movimiento, index})
|
||||||
|
},
|
||||||
|
modal: submitEvent => {
|
||||||
|
submitEvent.preventDefault()
|
||||||
|
const form = submitEvent.currentTarget
|
||||||
|
const data = new FormData(form)
|
||||||
|
app.handlers.movimientos.edit().movimiento(data).then(() => {
|
||||||
|
app.handlers.table.draw().table(app.handlers.results.props.parsed)
|
||||||
|
})
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove() {
|
||||||
|
return {
|
||||||
|
movimiento: clickEvent => {
|
||||||
|
const id = $(clickEvent.currentTarget).data('id')
|
||||||
|
app.handlers.movimientos.remove().movimiento(id).then(() => {
|
||||||
|
app.handlers.table.draw().table(app.handlers.results.props.parsed)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,16 @@
|
|||||||
|
<script>
|
||||||
|
class LoadingHandler {
|
||||||
|
props
|
||||||
|
constructor(ids) {
|
||||||
|
this.props = {
|
||||||
|
...ids
|
||||||
|
}
|
||||||
|
}
|
||||||
|
show() {
|
||||||
|
$(this.props.id).addClass('loading')
|
||||||
|
}
|
||||||
|
hide() {
|
||||||
|
$(this.props.id).removeClass('loading')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,86 @@
|
|||||||
|
<script>
|
||||||
|
class MovimientosHandler {
|
||||||
|
props
|
||||||
|
constructor({urls, loadingHandler, resultsHandler}) {
|
||||||
|
this.props = {
|
||||||
|
urls,
|
||||||
|
loadingHandler,
|
||||||
|
resultsHandler
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get() {
|
||||||
|
return {
|
||||||
|
movimientos: ({sociedades_ruts, mes}) => {
|
||||||
|
this.props.loadingHandler.show()
|
||||||
|
const method = 'post'
|
||||||
|
const body = new FormData()
|
||||||
|
sociedades_ruts.forEach(sociedad_rut => {
|
||||||
|
body.append('sociedades_ruts[]', sociedad_rut)
|
||||||
|
})
|
||||||
|
body.set('mes', [mes.getFullYear(), mes.getMonth() + 1, mes.getDate()].join('-'))
|
||||||
|
return APIClient.fetch(this.props.urls.get, {method, body}).then(response => {
|
||||||
|
if (!response) {
|
||||||
|
throw new Error('No se pudo obtener los movimientos')
|
||||||
|
}
|
||||||
|
return response.json().then(json => {
|
||||||
|
this.movimientos = json.movimientos
|
||||||
|
this.props.resultsHandler.props.movimientos = json.movimientos
|
||||||
|
this.props.resultsHandler.parse().movimientos()
|
||||||
|
return json.movimientos
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
console.error(error)
|
||||||
|
}).finally(() => {
|
||||||
|
this.props.loadingHandler.hide()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
edit() {
|
||||||
|
return {
|
||||||
|
movimiento: (data) => {
|
||||||
|
data.set('digito', Rut.digitoVerificador(data.get('rut')))
|
||||||
|
const method = 'post'
|
||||||
|
return APIClient.fetch(this.props.urls.edit, {method, body: data}).then(response => {
|
||||||
|
if (!response) {
|
||||||
|
throw new Error('No se pudo editar el movimiento')
|
||||||
|
}
|
||||||
|
return response.json().then(json => {
|
||||||
|
this.props.resultsHandler.props.movimientos = this.props.resultsHandler.props.movimientos.map(movimiento => {
|
||||||
|
if (movimiento.id === json.movimiento.id) {
|
||||||
|
movimiento.detalles = json.movimiento.detalles
|
||||||
|
}
|
||||||
|
return movimiento
|
||||||
|
})
|
||||||
|
this.props.resultsHandler.parse().movimientos()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remove() {
|
||||||
|
return {
|
||||||
|
movimiento: id => {
|
||||||
|
const method = 'delete'
|
||||||
|
const url = this.props.urls.remove.replace(/\/$/, '') + '/' + id
|
||||||
|
return APIClient.fetch(url, {method}).then(response => {
|
||||||
|
if (!response) {
|
||||||
|
throw new Error('No se pudo eliminar el movimiento')
|
||||||
|
}
|
||||||
|
return response.json().then(json => {
|
||||||
|
this.props.resultsHandler.props.movimientos = this.props.resultsHandler.props.movimientos.filter(movimiento => movimiento.id !== id)
|
||||||
|
this.props.resultsHandler.parse().movimientos()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
find() {
|
||||||
|
return {
|
||||||
|
id: id => {
|
||||||
|
return this.props.resultsHandler.props.movimientos.find(movimiento => movimiento.id === id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,228 @@
|
|||||||
|
<script>
|
||||||
|
class MovimientosTable {
|
||||||
|
props
|
||||||
|
columns
|
||||||
|
constructor({ids, eventHandler}) {
|
||||||
|
this.props = {
|
||||||
|
ids,
|
||||||
|
eventHandler,
|
||||||
|
movimientos: [],
|
||||||
|
formatters: {
|
||||||
|
number: new Intl.NumberFormat('es-CL'),
|
||||||
|
date: new Intl.DateTimeFormat('es-CL', {
|
||||||
|
day: '2-digit',
|
||||||
|
month: '2-digit',
|
||||||
|
year: 'numeric'
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
this.columns = [
|
||||||
|
{title: 'Sigla', defs: {width: 'short', type: 'string'}, searchable: true, export: true}, //0
|
||||||
|
{title: 'Banco', defs: {width: 'long', type: 'string'}, searchable: true, export: true},
|
||||||
|
{title: 'Cuenta', defs: {width: 'short', type: 'string'}, searchable: true, export: true},
|
||||||
|
{title: 'Fecha', defs: {width: 'long', type: 'string'}, searchable: true, export: true},
|
||||||
|
{title: 'ISO Fecha', defs: {visible: false}},
|
||||||
|
{title: 'Mes', defs: {width: 'short', type: 'string'}, searchable: true}, //5
|
||||||
|
{title: 'Año', defs: {width: 'long', type: 'string'}, searchable: true},
|
||||||
|
{title: 'Valor', defs: {className: 'dt-right', width: 'long', type: 'num'}, export: true},
|
||||||
|
{title: 'ISO Valor', defs: {visible: false, type: 'num'}},
|
||||||
|
{title: 'Glosa', defs: {width: 'short', type: 'string'}, export: true},
|
||||||
|
{title: 'Centro de Costo', defs: {width: 'short', type: 'string'}, searchable: true, export: true}, //10
|
||||||
|
{title: 'Categoria', defs: {width: 'short', type: 'string'}},
|
||||||
|
{title: 'Detalle', defs: {width: 'long', type: 'string'}, export: true},
|
||||||
|
{title: 'RUT', defs: {width: 'short', type: 'string'}, export: true},
|
||||||
|
{title: 'Nombre', defs: {width: 'short', type: 'string'}, export: true},
|
||||||
|
{title: 'Identificador', defs: {width: 'short', type: 'string'}, export: true}, //15
|
||||||
|
{title: 'Editar', defs: {width: 'short', type: 'string'}},
|
||||||
|
]
|
||||||
|
const N = this.columns.filter(column => typeof column.defs.visible === 'undefined' || column.defs.visible).length
|
||||||
|
const nShort = this.columns.filter(column => column.defs.width === 'short').length
|
||||||
|
const nLong = this.columns.filter(column => column.defs.width === 'long').length
|
||||||
|
const short = `${(nShort / N).toFixed(2)}%`
|
||||||
|
const long = `${(nLong / N).toFixed(2)}%`
|
||||||
|
|
||||||
|
this.columns = this.columns.map(column => {
|
||||||
|
if (typeof column.defs.width === 'undefined') {
|
||||||
|
return column
|
||||||
|
}
|
||||||
|
switch (column.defs.width) {
|
||||||
|
case 'short':
|
||||||
|
column.defs.width = short
|
||||||
|
break
|
||||||
|
case 'long':
|
||||||
|
column.defs.width = long
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return column
|
||||||
|
})
|
||||||
|
|
||||||
|
const tr = $(this.props.ids.table).find('thead tr')
|
||||||
|
tr.empty()
|
||||||
|
this.columns.forEach(column => {
|
||||||
|
if (typeof column.defs.className === 'undefined') {
|
||||||
|
tr.append(`<th>${column.title}</th>`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (column.defs.className) {
|
||||||
|
case 'dt-right':
|
||||||
|
tr.append(`<th class="right aligned">${column.title}</th>`)
|
||||||
|
break
|
||||||
|
case 'dt-center':
|
||||||
|
tr.append(`<th class="center aligned">${column.title}</th>`)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
tr.append(`<th>${column.title}</th>`)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let dtD = structuredClone(datatables_defaults)
|
||||||
|
const groupedColumns = Object.groupBy(this.columns, ({defs}) => Object.entries(defs).map((field, value) => `${field}: ${value}`).join(' - '))
|
||||||
|
const columnDefs = Object.values(groupedColumns).map(group => {
|
||||||
|
return {
|
||||||
|
targets: group.map(({title}) => title).map(title => this.columns.map(column => column.title).indexOf(title)),
|
||||||
|
...group[0].defs
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const searchBuilderColumns = this.columns.filter(column => column.searchable)
|
||||||
|
.map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
|
||||||
|
const exportColumns = this.columns.filter(column => column.export)
|
||||||
|
.map(column => column.title).map(title => this.columns.map(column => column.title).indexOf(title))
|
||||||
|
const order = ['Sigla', 'Banco', 'ISO Fecha'].map(title => {
|
||||||
|
return [this.columns.map(column => column.title).indexOf(title), 'asc']
|
||||||
|
})
|
||||||
|
dtD = Object.assign(dtD, {
|
||||||
|
columnDefs,
|
||||||
|
order,
|
||||||
|
language: Object.assign(dtD.language, {
|
||||||
|
searchBuilder: {
|
||||||
|
add: 'Filtrar',
|
||||||
|
condition: 'Comparador',
|
||||||
|
clearAll: 'Resetear',
|
||||||
|
delete: 'Eliminar',
|
||||||
|
deleteTitle: 'Eliminar Titulo',
|
||||||
|
data: 'Columna',
|
||||||
|
left: 'Izquierda',
|
||||||
|
leftTitle: 'Titulo Izquierdo',
|
||||||
|
logicAnd: 'Y',
|
||||||
|
logicOr: 'O',
|
||||||
|
right: 'Derecha',
|
||||||
|
rightTitle: 'Titulo Derecho',
|
||||||
|
title: {
|
||||||
|
0: 'Filtros',
|
||||||
|
_: 'Filtros (%d)'
|
||||||
|
},
|
||||||
|
value: 'Opciones',
|
||||||
|
valueJoiner: 'y'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
layout: {
|
||||||
|
top1: {
|
||||||
|
searchBuilder: {
|
||||||
|
columns: searchBuilderColumns,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
top1End: {
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
extend: 'excelHtml5',
|
||||||
|
className: 'green',
|
||||||
|
text: 'Exportar a Excel <i class="file excel icon"></i>',
|
||||||
|
title: 'Movimientos Contables',
|
||||||
|
download: 'open',
|
||||||
|
exportOptions: {
|
||||||
|
columns: exportColumns,
|
||||||
|
format: {
|
||||||
|
body: (data, row, column, node) => {
|
||||||
|
if (column === this.columns.map(({title}) => title).indexOf('Fecha')) {
|
||||||
|
return data.split('-').reverse().join('-')
|
||||||
|
}
|
||||||
|
if (column === this.columns.map(({title}) => title).indexOf('Valor')) {
|
||||||
|
return data.replace(/\./g, '')
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
customize: xlsx => {
|
||||||
|
const sheet = xlsx.xl.worksheets['sheet1.xml']
|
||||||
|
const columns = Object.values($('row[r="2"] t', sheet).map((idx, column) => column.textContent))
|
||||||
|
const columnStylesMap = {
|
||||||
|
Valor: '63',
|
||||||
|
Fecha: '15'
|
||||||
|
}
|
||||||
|
Object.entries(columnStylesMap).forEach((column, style) => {
|
||||||
|
const columnIndex = String.fromCharCode('A'.charCodeAt(0) + columns.indexOf(column))
|
||||||
|
$(`c[r^="${columnIndex}"]`, sheet).attr('s', style)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: this.props.movimientos,
|
||||||
|
})
|
||||||
|
this.props.table = new DataTable(this.props.ids.table, dtD)
|
||||||
|
}
|
||||||
|
draw() {
|
||||||
|
return {
|
||||||
|
table: (movimientos) => {
|
||||||
|
this.props.table.clear().rows.add(this.draw().movimientos(movimientos)).draw()
|
||||||
|
$(this.props.ids.buttons.edit).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.edit().movimiento)
|
||||||
|
$(this.props.ids.buttons.remove).on('click', {handler: this.props.eventHandler}, this.props.eventHandler.remove().movimiento)
|
||||||
|
},
|
||||||
|
movimientos: (movimientos) => {
|
||||||
|
const output = []
|
||||||
|
movimientos.forEach(movimiento => {
|
||||||
|
this.draw().movimiento({movimiento, output})
|
||||||
|
})
|
||||||
|
return output
|
||||||
|
},
|
||||||
|
movimiento: ({movimiento, output}) => {
|
||||||
|
const valor = movimiento.abono - movimiento.cargo
|
||||||
|
const fecha = movimiento.fecha
|
||||||
|
|
||||||
|
const buttons = {
|
||||||
|
edit: {
|
||||||
|
icon: 'edit'
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
color: ' red',
|
||||||
|
icon: 'trash'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const buttonsHTML = Object.entries(buttons).map(([action, {color='', icon}]) => {
|
||||||
|
const className = this.props.ids.buttons[action].replace('.', '')
|
||||||
|
return `<button class="ui${color} icon button ${className}" data-id="${movimiento.id}" data-index="${movimiento.index}" data-type="movimiento"><i class="${icon} icon"></i></button>`
|
||||||
|
}).join('')
|
||||||
|
|
||||||
|
const data = {
|
||||||
|
Sigla: movimiento.cuenta.inmobiliaria.sigla,
|
||||||
|
Banco: movimiento.cuenta.banco.nombre,
|
||||||
|
Cuenta: movimiento.cuenta.cuenta,
|
||||||
|
Fecha: this.props.formatters.date.format(fecha),
|
||||||
|
'ISO Fecha': [fecha.getFullYear(), fecha.getMonth() + 1, fecha.getDate()].join('-'),
|
||||||
|
Mes: fecha.getMonth() + 1,
|
||||||
|
'Año': fecha.getFullYear(),
|
||||||
|
Valor: this.props.formatters.number.format(valor),
|
||||||
|
'ISO Valor': valor,
|
||||||
|
Glosa: movimiento.glosa,
|
||||||
|
'Centro de Costo': (movimiento.detalles) ? movimiento.detalles.centro_costo.id : '',
|
||||||
|
Categoria: (movimiento.detalles) ? movimiento.detalles.categoria : '',
|
||||||
|
Detalle: (movimiento.detalles) ? movimiento.detalles.detalle : '',
|
||||||
|
RUT: (movimiento.detalles && movimiento.detalles.digito) ? `${this.props.formatters.number.format(movimiento.detalles.rut)}-${movimiento.detalles.digito}` : '',
|
||||||
|
Nombre: (movimiento.detalles) ? movimiento.detalles.nombres : '',
|
||||||
|
Identificador: (movimiento.detalles) ? movimiento.detalles.identificador : '',
|
||||||
|
Editar: buttonsHTML,
|
||||||
|
}
|
||||||
|
const values = []
|
||||||
|
this.columns.forEach(column => {
|
||||||
|
values.push(data[column.title])
|
||||||
|
})
|
||||||
|
output.push(values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
class ResultsHandler {
|
||||||
|
props
|
||||||
|
constructor() {
|
||||||
|
this.props = {
|
||||||
|
movimientos: [],
|
||||||
|
timezone: ((new Date()).getTimezoneOffset()) / -60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parse() {
|
||||||
|
return {
|
||||||
|
movimientos: () => {
|
||||||
|
const movimientos = this.props.movimientos
|
||||||
|
const data = []
|
||||||
|
movimientos.forEach((movimiento, index) => {
|
||||||
|
this.parse().movimiento({data, movimiento, index})
|
||||||
|
})
|
||||||
|
this.props.parsed = data
|
||||||
|
},
|
||||||
|
movimiento: ({data, movimiento, index}) => {
|
||||||
|
const fecha = new Date(movimiento.fecha + 'Z' + this.props.timezone)
|
||||||
|
data.push({
|
||||||
|
tipo: 'movimiento',
|
||||||
|
id: movimiento.id,
|
||||||
|
index,
|
||||||
|
cuenta: movimiento.cuenta,
|
||||||
|
fecha,
|
||||||
|
cargo: movimiento.cargo,
|
||||||
|
abono: movimiento.abono,
|
||||||
|
glosa: movimiento.glosa,
|
||||||
|
detalles: movimiento.detalles,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -16,7 +16,8 @@ class Movimientos extends Ideal\Controller
|
|||||||
|
|
||||||
public function detalles(ServerRequestInterface $request, ResponseInterface $response,
|
public function detalles(ServerRequestInterface $request, ResponseInterface $response,
|
||||||
Service\Contabilidad\Movimiento $movimientoService,
|
Service\Contabilidad\Movimiento $movimientoService,
|
||||||
Repository\Contabilidad\CentroCosto $centroCostoRepository, int $movimiento_id): ResponseInterface
|
Repository\Contabilidad\CentroCosto $centroCostoRepository,
|
||||||
|
int $movimiento_id): ResponseInterface
|
||||||
{
|
{
|
||||||
$body = $request->getParsedBody();
|
$body = $request->getParsedBody();
|
||||||
$output = [
|
$output = [
|
||||||
@ -50,7 +51,8 @@ class Movimientos extends Ideal\Controller
|
|||||||
} catch (EmptyResult) {}
|
} catch (EmptyResult) {}
|
||||||
return $this->withJson($response, $output);
|
return $this->withJson($response, $output);
|
||||||
}
|
}
|
||||||
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, Service\Contabilidad\Movimiento $movimientoService): ResponseInterface
|
public function __invoke(ServerRequestInterface $request, ResponseInterface $response,
|
||||||
|
Service\Contabilidad\Movimiento $movimientoService): ResponseInterface
|
||||||
{
|
{
|
||||||
$output = [
|
$output = [
|
||||||
'movimientos' => []
|
'movimientos' => []
|
||||||
@ -92,6 +94,38 @@ class Movimientos extends Ideal\Controller
|
|||||||
}
|
}
|
||||||
return $this->withJson($response, $output);
|
return $this->withJson($response, $output);
|
||||||
}
|
}
|
||||||
|
public function edit(ServerRequestInterface $request, ResponseInterface $response,
|
||||||
|
Service\Contabilidad\Movimiento $movimientoService): ResponseInterface
|
||||||
|
{
|
||||||
|
$body = $request->getParsedBody();
|
||||||
|
$output = [
|
||||||
|
'input' => $body,
|
||||||
|
'status' => false,
|
||||||
|
'movimiento' => null
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$movimiento = $movimientoService->getById($body['id']);
|
||||||
|
$output['movimiento'] = $movimientoService->edit($movimiento, $body);
|
||||||
|
$output['status'] = true;
|
||||||
|
} catch (EmptyResult) {}
|
||||||
|
return $this->withJson($response, $output);
|
||||||
|
}
|
||||||
|
public function remove(ServerRequestInterface $request, ResponseInterface $response,
|
||||||
|
Service\Contabilidad\Movimiento $movimientoService, int $movimiento_id): ResponseInterface
|
||||||
|
{
|
||||||
|
$output = [
|
||||||
|
'movimiento_id' => $movimiento_id,
|
||||||
|
'movimiento' => null,
|
||||||
|
'status' => false
|
||||||
|
];
|
||||||
|
try {
|
||||||
|
$movimiento = $movimientoService->getById($movimiento_id);
|
||||||
|
$movimientoService->remove($movimiento);
|
||||||
|
$output['movimiento'] = $movimiento;
|
||||||
|
$output['status'] = true;
|
||||||
|
} catch (EmptyResult) {}
|
||||||
|
return $this->withJson($response, $output);
|
||||||
|
}
|
||||||
|
|
||||||
protected function movimientosToArray(array $movimientos): array
|
protected function movimientosToArray(array $movimientos): array
|
||||||
{
|
{
|
||||||
|
@ -45,6 +45,20 @@ class Detalle extends Ideal\Repository
|
|||||||
{
|
{
|
||||||
return $this->update($model, ['movimiento_id', 'centro_costo_id', 'rut', 'digito', 'nombres', 'categoria', 'detalle', 'identificador'], $new_data);
|
return $this->update($model, ['movimiento_id', 'centro_costo_id', 'rut', 'digito', 'nombres', 'categoria', 'detalle', 'identificador'], $new_data);
|
||||||
}
|
}
|
||||||
|
public function filterData(array $data): array
|
||||||
|
{
|
||||||
|
$map = [
|
||||||
|
'costo_id' => 'centro_costo_id',
|
||||||
|
'nombre' => 'nombres',
|
||||||
|
];
|
||||||
|
foreach ($map as $source => $dest) {
|
||||||
|
if (key_exists($source, $data)) {
|
||||||
|
$data[$dest] = $data[$source];
|
||||||
|
unset($data[$source]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
public function fetchByMovimiento(int $movimiento_id): Model\Contabilidad\Movimiento\Detalle
|
public function fetchByMovimiento(int $movimiento_id): Model\Contabilidad\Movimiento\Detalle
|
||||||
{
|
{
|
||||||
|
@ -62,6 +62,19 @@ class Movimiento extends Service
|
|||||||
}
|
}
|
||||||
return $movimiento;
|
return $movimiento;
|
||||||
}
|
}
|
||||||
|
public function edit(Model\Contabilidad\Movimiento $movimiento, array $data): Model\Contabilidad\Movimiento
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$detalles = $this->detalleRepository->fetchByMovimiento($movimiento->id);
|
||||||
|
$mappedData = $this->detalleRepository->filterData($data);
|
||||||
|
$this->detalleRepository->edit($detalles, $mappedData);
|
||||||
|
} catch (Implement\Exception\EmptyResult) {}
|
||||||
|
return $this->process($movimiento);
|
||||||
|
}
|
||||||
|
public function remove(Model\Contabilidad\Movimiento $movimiento): void
|
||||||
|
{
|
||||||
|
$this->movimientoRepository->remove($movimiento);
|
||||||
|
}
|
||||||
|
|
||||||
public function process(Model\Contabilidad\Movimiento $movimiento): Model\Contabilidad\Movimiento
|
public function process(Model\Contabilidad\Movimiento $movimiento): Model\Contabilidad\Movimiento
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user