mirror of
https://git.imnavajas.es/jjimenez/safekat.git
synced 2025-07-25 22:52:08 +00:00
Primera version del importador RAMA
This commit is contained in:
@ -18,6 +18,7 @@ $routes->group('importador', ['namespace' => 'App\Controllers\Importadores'], fu
|
|||||||
* AJAX
|
* AJAX
|
||||||
*========================**/
|
*========================**/
|
||||||
$routes->post('validar-fila', 'ImportadorCatalogo::validarFila');
|
$routes->post('validar-fila', 'ImportadorCatalogo::validarFila');
|
||||||
|
$routes->post('importar-fila', 'ImportadorCatalogo::importarFila');
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,8 +4,7 @@ namespace App\Controllers\Importadores;
|
|||||||
use App\Controllers\BaseResourceController;
|
use App\Controllers\BaseResourceController;
|
||||||
use App\Entities\Catalogo\CatalogoLibroEntity;
|
use App\Entities\Catalogo\CatalogoLibroEntity;
|
||||||
use App\Models\Catalogo\CatalogoLibroModel;
|
use App\Models\Catalogo\CatalogoLibroModel;
|
||||||
use App\Models\Clientes\ClienteModel;
|
use App\Controllers\Presupuestos\Presupuestocliente;
|
||||||
use Hermawan\DataTables\DataTable;
|
|
||||||
|
|
||||||
class ImportadorCatalogo extends BaseResourceController
|
class ImportadorCatalogo extends BaseResourceController
|
||||||
{
|
{
|
||||||
@ -57,134 +56,6 @@ class ImportadorCatalogo extends BaseResourceController
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function add()
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($this->request->getPost()):
|
|
||||||
|
|
||||||
$postData = $this->request->getPost();
|
|
||||||
|
|
||||||
$sanitizedData = $this->sanitized($postData, true);
|
|
||||||
|
|
||||||
$sanitizedData['user_created_id'] = auth()->user()->id;
|
|
||||||
unset($sanitizedData['isk']);
|
|
||||||
|
|
||||||
$noException = true;
|
|
||||||
if ($successfulResult = $this->canValidate()):
|
|
||||||
|
|
||||||
if ($this->canValidate()):
|
|
||||||
try {
|
|
||||||
$successfulResult = $this->model->skipValidation(true)->save($sanitizedData);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$noException = false;
|
|
||||||
$this->dealWithException($e);
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
$this->viewData['errorMessage'] = lang('Basic.global.formErr1', [lang('Basic.global.record')]);
|
|
||||||
$this->session->setFlashdata('formErrors', $this->model->errors());
|
|
||||||
endif;
|
|
||||||
|
|
||||||
$thenRedirect = true; // Change this to false if you want your user to stay on the form after submission
|
|
||||||
endif;
|
|
||||||
|
|
||||||
if ($noException && $successfulResult):
|
|
||||||
|
|
||||||
$id = $this->model->db->insertID();
|
|
||||||
|
|
||||||
$message = lang('Basic.global.saveSuccess', [lang('Basic.global.record')]) . '.';
|
|
||||||
|
|
||||||
if ($thenRedirect):
|
|
||||||
if (!empty($this->indexRoute)):
|
|
||||||
return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
|
|
||||||
else:
|
|
||||||
return $this->redirect2listView('sweet-success', $message);
|
|
||||||
endif;
|
|
||||||
else:
|
|
||||||
$this->session->setFlashData('sweet-success', $message);
|
|
||||||
endif;
|
|
||||||
|
|
||||||
endif; // $noException && $successfulResult
|
|
||||||
|
|
||||||
endif; // ($requestMethod === 'post')
|
|
||||||
|
|
||||||
$this->viewData['catalogoLibrosEntity'] = isset($sanitizedData) ? new CatalogoLibroEntity($sanitizedData) : new CatalogoLibroEntity();
|
|
||||||
$this->viewData['formAction'] = route_to('catalogoLibrosAdd');
|
|
||||||
$this->viewData['boxTitle'] = lang('Basic.global.addNew') . ' ' . lang('Catalogo.moduleTitle') . ' ' . lang('Basic.global.addNewSuffix');
|
|
||||||
|
|
||||||
return $this->displayForm(__METHOD__);
|
|
||||||
} // end function add()
|
|
||||||
|
|
||||||
public function edit($requestedId = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
if ($requestedId == null):
|
|
||||||
return $this->redirect2listView();
|
|
||||||
endif;
|
|
||||||
$id = filter_var($requestedId, FILTER_SANITIZE_URL);
|
|
||||||
$catalogoLibrosEntity = $this->model->find($id);
|
|
||||||
|
|
||||||
if ($catalogoLibrosEntity == false):
|
|
||||||
$message = lang('Basic.global.notFoundWithIdErr', [mb_strtolower(lang('Catalogo.pais')), $id]);
|
|
||||||
return $this->redirect2listView('sweet-error', $message);
|
|
||||||
endif;
|
|
||||||
|
|
||||||
if ($this->request->getPost()):
|
|
||||||
|
|
||||||
$postData = $this->request->getPost();
|
|
||||||
$sanitizedData = $this->sanitized($postData, true);
|
|
||||||
unset($sanitizedData['isk']);
|
|
||||||
$sanitizedData['user_update_id'] = auth()->user()->id;
|
|
||||||
|
|
||||||
$noException = true;
|
|
||||||
|
|
||||||
if ($successfulResult = $this->canValidate()): // if ($successfulResult = $this->validate($this->formValidationRules) ) :
|
|
||||||
|
|
||||||
|
|
||||||
if ($this->canValidate()):
|
|
||||||
try {
|
|
||||||
$successfulResult = $this->model->skipValidation(true)->update($id, $sanitizedData);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
$noException = false;
|
|
||||||
$this->dealWithException($e);
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
$this->viewData['warningMessage'] = lang('Basic.global.formErr1', [mb_strtolower(lang('Catalogo.catalogo'))]);
|
|
||||||
$this->session->setFlashdata('formErrors', $this->model->errors());
|
|
||||||
|
|
||||||
endif;
|
|
||||||
|
|
||||||
$catalogoLibrosEntity->fill($sanitizedData);
|
|
||||||
$thenRedirect = false;
|
|
||||||
endif;
|
|
||||||
|
|
||||||
if ($noException && $successfulResult):
|
|
||||||
$id = $catalogoLibrosEntity->id ?? $id;
|
|
||||||
$message = lang('Basic.global.updateSuccess', [lang('Basic.global.record')]) . '.';
|
|
||||||
|
|
||||||
if ($thenRedirect):
|
|
||||||
if (!empty($this->indexRoute)):
|
|
||||||
return redirect()->to(route_to($this->indexRoute))->with('sweet-success', $message);
|
|
||||||
else:
|
|
||||||
return $this->redirect2listView('sweet-success', $message);
|
|
||||||
endif;
|
|
||||||
else:
|
|
||||||
$this->session->setFlashData('sweet-success', $message);
|
|
||||||
endif;
|
|
||||||
|
|
||||||
endif; // $noException && $successfulResult
|
|
||||||
endif; // ($requestMethod === 'post')
|
|
||||||
|
|
||||||
|
|
||||||
$this->viewData['catalogoLibrosEntity'] = $catalogoLibrosEntity;
|
|
||||||
$this->viewData['formAction'] = route_to('catalogoLibrosEdit', $id);
|
|
||||||
$this->viewData['boxTitle'] = lang('Basic.global.edit2') . ' ' . lang('Catalogo.moduleTitle') . ' ' . lang('Basic.global.edit3');
|
|
||||||
|
|
||||||
|
|
||||||
return $this->displayForm(__METHOD__, $id);
|
|
||||||
} // end function edit(...)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function validarFila()
|
public function validarFila()
|
||||||
{
|
{
|
||||||
$json = $this->request->getJSON();
|
$json = $this->request->getJSON();
|
||||||
@ -234,4 +105,244 @@ class ImportadorCatalogo extends BaseResourceController
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function importarFila()
|
||||||
|
{
|
||||||
|
$json = $this->request->getJSON();
|
||||||
|
|
||||||
|
if (!$json || !isset($json->fila[0])) {
|
||||||
|
return $this->response->setJSON([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Datos inválidos.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mapear cada columna a una variable
|
||||||
|
$isbn = isset($json->fila[0]) ? trim($json->fila[0]) : null;
|
||||||
|
$refCliente = isset($json->fila[1]) ? trim($json->fila[1]) : null;
|
||||||
|
//$descripcion = isset($json->fila[2]) ? trim($json->fila[2]) : null;
|
||||||
|
$tirada = isset($json->fila[3]) ? (float) $json->fila[3] : null;
|
||||||
|
//$precio_compra = isset($json->fila[4]) ? (float) $json->fila[4] : null;
|
||||||
|
|
||||||
|
if (empty($isbn)) {
|
||||||
|
return $this->response->setJSON([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Input vacío o no proporcionado.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$catalogoModel = new CatalogoLibroModel();
|
||||||
|
|
||||||
|
// 1. Buscar por ISBN exacto
|
||||||
|
$libro = $catalogoModel->where('isbn', $isbn)->first();
|
||||||
|
|
||||||
|
// 2. Si no, buscar por EAN sin guiones
|
||||||
|
if (!$libro) {
|
||||||
|
$eanLimpio = str_replace('-', '', $isbn);
|
||||||
|
|
||||||
|
$libro = $catalogoModel->where('REPLACE(ean, "-", "")', $eanLimpio)->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$libro) {
|
||||||
|
return $this->response->setJSON([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'No se encontró el libro en el catálogo.'
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aquí ya tenemos el libro correcto.
|
||||||
|
// Ahora se prepara la "inserción" o el "registro" a importar
|
||||||
|
// Variables intermedias
|
||||||
|
$colorPaginas = (int) ($libro->color_paginas ?? 0);
|
||||||
|
$negroPaginas = (int) ($libro->negro_paginas ?? 0);
|
||||||
|
$papelInteriorDiferente = ($colorPaginas > 0 && $negroPaginas > 0) ? 1 : 0;
|
||||||
|
|
||||||
|
// --- Interior (lo que cambiamos ahora)
|
||||||
|
if ($papelInteriorDiferente) {
|
||||||
|
// Mixto: páginas en negro + color
|
||||||
|
$interior = [
|
||||||
|
'papelInterior' => [
|
||||||
|
'negro' => $libro->negro_papel_id,
|
||||||
|
'color' => $libro->color_papel_id,
|
||||||
|
],
|
||||||
|
'gramajeInterior' => [
|
||||||
|
'negro' => $libro->negro_gramaje,
|
||||||
|
'color' => $libro->color_gramaje,
|
||||||
|
]
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// SOLO un tipo: negro O color
|
||||||
|
$colorPaginas = (int)($libro->color_paginas ?? 0);
|
||||||
|
$negroPaginas = (int)($libro->negro_paginas ?? 0);
|
||||||
|
|
||||||
|
if ($colorPaginas > 0 && $negroPaginas == 0) {
|
||||||
|
// Libro completamente en color
|
||||||
|
$interior = [
|
||||||
|
'papelInterior' => $libro->color_papel_id,
|
||||||
|
'gramajeInterior' => $libro->color_gramaje,
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// Libro completamente en blanco y negro
|
||||||
|
$interior = [
|
||||||
|
'papelInterior' => $libro->negro_papel_id,
|
||||||
|
'gramajeInterior' => $libro->negro_gramaje,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sobrecubierta
|
||||||
|
$sobrecubierta = [];
|
||||||
|
if (!is_null($libro->sobrecubierta_paginas)) {
|
||||||
|
$sobrecubierta['papel'] = $libro->sobrecubierta_papel_id;
|
||||||
|
$sobrecubierta['gramaje'] = $libro->sobrecubierta_gramaje;
|
||||||
|
$sobrecubierta['solapas'] = $libro->sobrecubierta_solapas;
|
||||||
|
$sobrecubierta['acabado'] = $libro->sobrecubierta_acabado_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$dataToImport = [
|
||||||
|
'selectedTirada' => $tirada,
|
||||||
|
'datosCabecera' => [
|
||||||
|
'titulo' => $libro->titulo,
|
||||||
|
'autor' => $libro->autor,
|
||||||
|
'isbn' => $isbn,
|
||||||
|
'coleccion' => $libro->coleccion,
|
||||||
|
'referenciaCliente' => $refCliente
|
||||||
|
],
|
||||||
|
'tirada' => array_values(array_filter([
|
||||||
|
$tirada,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
])),
|
||||||
|
'tamanio' => [
|
||||||
|
'ancho' => $libro->ancho,
|
||||||
|
'alto' => $libro->alto
|
||||||
|
],
|
||||||
|
'tipo' => "",
|
||||||
|
'tipo_presupuesto_id' => $libro->encuadernacion_id,
|
||||||
|
'clienteId' => 251,
|
||||||
|
'isColor' => (in_array(strtolower($libro->tipo_impresion), ['color', 'colorhq']) ? 1 : 0),
|
||||||
|
'isHq' => (in_array(strtolower($libro->tipo_impresion), ['negrohq', 'colorhq']) ? 1 : 0),
|
||||||
|
'paginas' => $libro->paginas,
|
||||||
|
'paginasColor' => $colorPaginas,
|
||||||
|
'papelInteriorDiferente' => $papelInteriorDiferente,
|
||||||
|
'paginasCuadernillo' => 32,
|
||||||
|
|
||||||
|
'interior' => $interior,
|
||||||
|
|
||||||
|
'cubierta' => [
|
||||||
|
'papelCubierta' => $libro->cubierta_papel_id,
|
||||||
|
'gramajeCubierta' => $libro->cubierta_gramaje,
|
||||||
|
'solapas' => $libro->cubierta_ancho_solapas,
|
||||||
|
'acabado' => $libro->cubierta_acabado_id,
|
||||||
|
'cabezada' => 'WHI',
|
||||||
|
'lomoRedondo' => 0
|
||||||
|
],
|
||||||
|
|
||||||
|
'guardas' => [],
|
||||||
|
'sobrecubierta' => $sobrecubierta,
|
||||||
|
'faja' => [],
|
||||||
|
|
||||||
|
'entrega_taller' => 1,
|
||||||
|
];
|
||||||
|
|
||||||
|
/*return $this->response->setJSON([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Libro encontrado y preparado para importar.',
|
||||||
|
'data' => $dataToImport
|
||||||
|
]);*/
|
||||||
|
|
||||||
|
|
||||||
|
// Procedemos a intentar guardar el presupuesto
|
||||||
|
// Instancia de presupuesto cliente
|
||||||
|
$presupuestocliente = new Presupuestocliente();
|
||||||
|
try {
|
||||||
|
$response = $presupuestocliente->guardar($dataToImport);
|
||||||
|
|
||||||
|
// DEBUG LINE
|
||||||
|
//return $this->respond($response);
|
||||||
|
|
||||||
|
if (!isset($response['sk_id'])) {
|
||||||
|
return $this->respond([
|
||||||
|
'status' => 400,
|
||||||
|
'error' => 'Missing sk_id',
|
||||||
|
'message' => 'El identificador sk_id es requerido pero no se recibió.'
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'status' => 200,
|
||||||
|
'error' => null,
|
||||||
|
'data' => [
|
||||||
|
'sk_id' => $response['sk_id'],
|
||||||
|
'sk_url' => $response['sk_url'] ?? null
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->respond($response);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
return $this->respond([
|
||||||
|
'status' => 500,
|
||||||
|
'error' => 'Server error',
|
||||||
|
'message' => 'Error inesperado durante el procesado',
|
||||||
|
'debug' => $e->getMessage()
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function guardar()
|
||||||
|
{
|
||||||
|
helper(['form']);
|
||||||
|
|
||||||
|
// Access the entire POST data
|
||||||
|
$post_data = $this->request->getJSON(true);
|
||||||
|
|
||||||
|
//return $this->respond(var_dump($post_data));
|
||||||
|
|
||||||
|
// Instancia de presupuesto cliente
|
||||||
|
$presupuestocliente = new Presupuestocliente();
|
||||||
|
try {
|
||||||
|
$response = $presupuestocliente->guardar($post_data);
|
||||||
|
|
||||||
|
// DEBUG LINE
|
||||||
|
//return $this->respond($response);
|
||||||
|
|
||||||
|
if (!isset($response['sk_id'])) {
|
||||||
|
return $this->respond([
|
||||||
|
'status' => 400,
|
||||||
|
'error' => 'Missing sk_id',
|
||||||
|
'message' => 'El identificador sk_id es requerido pero no se recibió.'
|
||||||
|
], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = [
|
||||||
|
'status' => 200,
|
||||||
|
'error' => null,
|
||||||
|
'data' => [
|
||||||
|
'sk_id' => $response['sk_id'],
|
||||||
|
'sk_url' => $response['sk_url'] ?? null
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->respond($response);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
return $this->respond([
|
||||||
|
'status' => 500,
|
||||||
|
'error' => 'Server error',
|
||||||
|
'message' => 'Error inesperado durante el procesado'
|
||||||
|
]);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,40 +35,33 @@
|
|||||||
|
|
||||||
<div class="col-md-12 mb-3">
|
<div class="col-md-12 mb-3">
|
||||||
|
|
||||||
<div class="table-responsive">
|
<table id="excelTable" class="table table-striped table-hover" style="width: 100%;">
|
||||||
<table id="excelTable" class="table table-striped table-hover" style="width: 100%;">
|
<thead>
|
||||||
<thead>
|
<tr>
|
||||||
<tr>
|
<th><input type="checkbox" id="selectAll"></th> <!-- Checkbox general -->
|
||||||
<th>
|
<th><?= lang('Importador.input') ?></th>
|
||||||
<input type="checkbox" id="select-all" class="form-check-input">
|
<th><?= lang('Importador.idlinea') ?></th>
|
||||||
</th>
|
<th><?= lang('Importador.descripcion') ?></th>
|
||||||
<th><?= lang('Importador.input') ?></th>
|
<th><?= lang('Importador.cnt_pedida') ?></th>
|
||||||
<th><?= lang('Importador.idlinea') ?></th>
|
<th><?= lang('Importador.precio_compra') ?></th>
|
||||||
<th><?= lang('Importador.descripcion') ?></th>
|
<th>Notas</th> <!-- Comentarios -->
|
||||||
<th><?= lang('Importador.cnt_pedida') ?></th>
|
<th><?= lang('Basic.global.Action') ?></th>
|
||||||
<th><?= lang('Importador.precio_compra') ?></th>
|
<!-- Acciones (importar/eliminar) -->
|
||||||
<th class="text-nowrap" style="min-width: 120px;">
|
</tr>
|
||||||
<?= lang('Basic.global.Action') ?></th>
|
<tr> <!-- Segunda fila para filtros -->
|
||||||
</tr>
|
<th></th> <!-- No filtro en checkbox -->
|
||||||
<tr>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th><input type="text" class="form-control form-control-sm"
|
<th></th>
|
||||||
placeholder="Filtrar..." /></th>
|
<th></th>
|
||||||
<th><input type="text" class="form-control form-control-sm"
|
<th></th>
|
||||||
placeholder="Filtrar..." /></th>
|
<th></th> <!-- No filtro en notas -->
|
||||||
<th><input type="text" class="form-control form-control-sm"
|
<th></th> <!-- No filtro en acciones -->
|
||||||
placeholder="Filtrar..." /></th>
|
</tr>
|
||||||
<th><input type="text" class="form-control form-control-sm"
|
</thead>
|
||||||
placeholder="Filtrar..." /></th>
|
<tbody></tbody>
|
||||||
<th><input type="text" class="form-control form-control-sm"
|
</table>
|
||||||
placeholder="Filtrar..." /></th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,18 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
order: [[1, 'asc']]
|
order: [[1, 'asc']]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Crear filtros por columna en el segundo <tr>
|
||||||
|
$('#excelTable thead tr:eq(1) th').each(function (i) {
|
||||||
|
if (![0, 6, 7].includes(i)) { // No poner input en Checkbox, Notas ni Acciones
|
||||||
|
$(this).html('<input type="text" class="form-control form-control-sm" placeholder="Filtrar..." />');
|
||||||
|
$('input', this).on('keyup change', function () {
|
||||||
|
if (dataTable.column(i).search() !== this.value) {
|
||||||
|
dataTable.column(i).search(this.value).draw();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.getElementById('excelFile').addEventListener('change', function (e) {
|
document.getElementById('excelFile').addEventListener('change', function (e) {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
@ -64,38 +76,39 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
const rowData = TABLE_COLUMNS.map(col => data[i][headerMap[col]] ?? '');
|
const rowData = TABLE_COLUMNS.map(col => data[i][headerMap[col]] ?? '');
|
||||||
|
|
||||||
// Llamar backend para validar la fila
|
// Llamar backend para validar la fila
|
||||||
const isValid = await validarFila(rowData);
|
const result = await validarFila(rowData);
|
||||||
|
|
||||||
let checkboxHtml = '';
|
let checkboxHtml = '';
|
||||||
let actionBtnsHtml = '';
|
let actionBtnsHtml = '';
|
||||||
|
let notaHtml = '';
|
||||||
|
|
||||||
if (isValid) {
|
if (result.apto) {
|
||||||
checkboxHtml = `<input type="checkbox" class="select-row form-check-input" checked>`;
|
checkboxHtml = `<input type="checkbox" class="select-row form-check-input" checked>`;
|
||||||
|
notaHtml = '';
|
||||||
actionBtnsHtml = `
|
actionBtnsHtml = `
|
||||||
<div class="d-flex flex-column align-items-start">
|
<div class="d-flex flex-column align-items-start">
|
||||||
<button type="button" class="btn btn-outline-success btn-sm mb-1 importRow">
|
<button type="button" class="btn btn-outline-success btn-sm mb-1 importRow">
|
||||||
<i class="fas fa-file-import me-1"></i> Importar
|
<i class="fas fa-file-import me-1"></i> Importar
|
||||||
</button>
|
</button>
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
||||||
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
} else {
|
} else {
|
||||||
checkboxHtml = `<input type="checkbox" class="select-row form-check-input" disabled>`;
|
checkboxHtml = `<input type="checkbox" class="select-row form-check-input" disabled>`;
|
||||||
|
notaHtml = `<span class="badge bg-danger">${result.reason}</span>`;
|
||||||
actionBtnsHtml = `
|
actionBtnsHtml = `
|
||||||
<div class="d-flex flex-column align-items-start">
|
<div class="d-flex flex-column align-items-start">
|
||||||
<span class="badge rounded-pill bg-danger mb-2">No Apto</span>
|
<span class="badge rounded-pill bg-danger mb-2">No Apto</span>
|
||||||
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
<button type="button" class="btn btn-outline-danger btn-sm deleteRow">
|
||||||
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
<i class="fas fa-trash-alt me-1"></i> Eliminar
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.push([checkboxHtml, ...rowData, actionBtnsHtml]);
|
rows.push([checkboxHtml, ...rowData, notaHtml, actionBtnsHtml]);
|
||||||
}
|
}
|
||||||
|
|
||||||
dataTable.clear().rows.add(rows).draw();
|
dataTable.clear().rows.add(rows).draw();
|
||||||
@ -114,11 +127,10 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
body: JSON.stringify({ fila: rowData })
|
body: JSON.stringify({ fila: rowData })
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await response.json();
|
return await response.json();
|
||||||
return result.apto === true;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error validando fila', error);
|
console.error('Error validando fila', error);
|
||||||
return false;
|
return { apto: false, reason: 'Error conexión' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,25 +139,92 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
dataTable.row($(this).parents('tr')).remove().draw();
|
dataTable.row($(this).parents('tr')).remove().draw();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#excelTable tbody').off('click', '.importRow').on('click', '.importRow', function () {
|
$('#excelTable tbody').off('click', '.importRow').on('click', '.importRow', async function () {
|
||||||
const rowData = dataTable.row($(this).parents('tr')).data();
|
const $row = $(this).closest('tr');
|
||||||
console.log('Importar esta fila:', rowData);
|
const rowData = dataTable.row($row).data();
|
||||||
// Aquí podrías enviar sólo esta fila al servidor si quieres importar individualmente
|
if (!rowData) return;
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('importBtn').addEventListener('click', function () {
|
const fila = rowData.slice(1, 6); // solo datos de negocio
|
||||||
const selectedRows = [];
|
|
||||||
|
|
||||||
dataTable.rows().every(function () {
|
try {
|
||||||
const data = this.data();
|
const response = await fetch('/importador/catalogo/importar-fila', {
|
||||||
const checkboxHtml = $(data[0]).find('input.select-row');
|
method: 'POST',
|
||||||
if (checkboxHtml.length > 0 && checkboxHtml.is(':checked') && !checkboxHtml.is(':disabled')) {
|
headers: {
|
||||||
selectedRows.push(data.slice(1, -1)); // sin checkbox ni botones
|
'Content-Type': 'application/json',
|
||||||
|
'X-CSRF-TOKEN': '<?= csrf_hash() ?>'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ fila: fila })
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && result.status === 200) {
|
||||||
|
const skUrl = result.data?.sk_url ?? null;
|
||||||
|
|
||||||
|
// Actualizar campo "Notas" con el enlace
|
||||||
|
if (skUrl) {
|
||||||
|
const notasHtml = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-secondary">Ver presupuesto</a>`;
|
||||||
|
// La columna de notas es la posición 6 (índice 6)
|
||||||
|
rowData[6] = notasHtml;
|
||||||
|
dataTable.row($row).data(rowData).draw(false); // Redibujar la fila SIN perder scroll ni filtros
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Importado correctamente',
|
||||||
|
html: skUrl
|
||||||
|
? `La fila se importó exitosamente.<br><br><a href="${skUrl}" target="_blank" class="btn btn-primary mt-2">Ver presupuesto</a>`
|
||||||
|
: 'La fila se importó exitosamente.',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'Aceptar',
|
||||||
|
buttonsStyling: true,
|
||||||
|
customClass: { confirmButton: 'btn btn-success' }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: result.message ?? 'Hubo un error al importar esta fila.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'Aceptar',
|
||||||
|
buttonsStyling: true,
|
||||||
|
customClass: { confirmButton: 'btn btn-danger' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error en la llamada a importar-fila:', error);
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Error',
|
||||||
|
text: 'Error de comunicación con el servidor.',
|
||||||
|
icon: 'error',
|
||||||
|
confirmButtonText: 'Aceptar',
|
||||||
|
buttonsStyling: true,
|
||||||
|
customClass: { confirmButton: 'btn btn-danger' }
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (selectedRows.length === 0) {
|
|
||||||
|
// Select All funcional
|
||||||
|
$('#selectAll').off('change').on('change', function () {
|
||||||
|
const checked = $(this).is(':checked');
|
||||||
|
$('#excelTable tbody input.select-row:enabled').prop('checked', checked);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Importacion */
|
||||||
|
document.getElementById('importBtn').addEventListener('click', function () {
|
||||||
|
const filasAptas = [];
|
||||||
|
|
||||||
|
dataTable.rows().every(function () {
|
||||||
|
const rowNode = this.node();
|
||||||
|
const checkbox = $(rowNode).find('input.select-row');
|
||||||
|
|
||||||
|
if (checkbox.length > 0 && checkbox.is(':checked') && !checkbox.is(':disabled')) {
|
||||||
|
const rowData = this.data();
|
||||||
|
filasAptas.push({ fila: rowData.slice(1, 6), rowNode: rowNode, rowData: rowData });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filasAptas.length === 0) {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
title: 'Atención',
|
title: 'Atención',
|
||||||
text: 'No hay filas aptas seleccionadas para importar.',
|
text: 'No hay filas aptas seleccionadas para importar.',
|
||||||
@ -157,35 +236,66 @@ document.addEventListener('DOMContentLoaded', function () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch('/importar', {
|
Swal.fire({
|
||||||
method: 'POST',
|
title: '¿Confirmar importación?',
|
||||||
headers: {
|
text: `Se van a importar ${filasAptas.length} filas.`,
|
||||||
'Content-Type': 'application/json',
|
icon: 'warning',
|
||||||
'X-CSRF-TOKEN': '<?= csrf_hash() ?>'
|
showCancelButton: true,
|
||||||
},
|
confirmButtonText: 'Sí, importar',
|
||||||
body: JSON.stringify({ data: selectedRows })
|
cancelButtonText: 'Cancelar',
|
||||||
}).then(res => res.json())
|
reverseButtons: true,
|
||||||
.then(response => {
|
buttonsStyling: true,
|
||||||
Swal.fire({
|
customClass: {
|
||||||
title: 'Importación exitosa',
|
confirmButton: 'btn btn-primary',
|
||||||
text: response.message,
|
cancelButton: 'btn btn-secondary'
|
||||||
icon: 'success',
|
}
|
||||||
confirmButtonText: 'Aceptar',
|
}).then(async (result) => {
|
||||||
buttonsStyling: true,
|
if (!result.isConfirmed) return;
|
||||||
customClass: { confirmButton: 'btn btn-success' }
|
|
||||||
});
|
for (const fila of filasAptas) {
|
||||||
})
|
try {
|
||||||
.catch(error => {
|
const response = await fetch('/importador/catalogo/importar-fila', {
|
||||||
console.error(error);
|
method: 'POST',
|
||||||
Swal.fire({
|
headers: {
|
||||||
title: 'Error',
|
'Content-Type': 'application/json',
|
||||||
text: 'Error importando datos.',
|
'X-CSRF-TOKEN': '<?= csrf_hash() ?>'
|
||||||
icon: 'error',
|
},
|
||||||
confirmButtonText: 'Aceptar',
|
body: JSON.stringify({ fila: fila.fila })
|
||||||
buttonsStyling: true,
|
});
|
||||||
customClass: { confirmButton: 'btn btn-danger' }
|
|
||||||
});
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (response.ok && result.status === 200) {
|
||||||
|
const skUrl = result.data?.sk_url ?? null;
|
||||||
|
|
||||||
|
if (skUrl) {
|
||||||
|
fila.rowData[6] = `<a href="${skUrl}" target="_blank" class="btn btn-sm btn-primary">Ver presupuesto</a>`;
|
||||||
|
} else {
|
||||||
|
fila.rowData[6] = `<span class="badge bg-success">Importado</span>`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fila.rowData[6] = `<span class="badge bg-danger">${result.message ?? 'Error desconocido'}</span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataTable.row(fila.rowNode).data(fila.rowData).draw(false);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error importando fila:', error);
|
||||||
|
fila.rowData[6] = `<span class="badge bg-danger">Error de comunicación</span>`;
|
||||||
|
dataTable.row(fila.rowNode).data(fila.rowData).draw(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Importación finalizada',
|
||||||
|
text: 'Se han procesado todas las filas seleccionadas.',
|
||||||
|
icon: 'success',
|
||||||
|
confirmButtonText: 'Aceptar',
|
||||||
|
buttonsStyling: true,
|
||||||
|
customClass: { confirmButton: 'btn btn-success' }
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user