Merge branch 'add/impresion_etiquetas_envios' into 'main'

Add/impresion etiquetas envios

See merge request jjimenez/safekat!740
This commit is contained in:
2025-04-26 08:51:24 +00:00
7 changed files with 279 additions and 8 deletions

View File

@ -819,6 +819,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi
$routes->post('generateEnvio', 'LogisticaController::generarEnvio');
$routes->get('selectForNewEnvio', 'LogisticaController::findForNewEnvio');
$routes->get('selectDireccionForEnvio', 'LogisticaController::selectDireccionForEnvio');
$routes->post('imprimirEtiquetas', 'LogisticaController::imprimirEtiquetas');
});
/*

View File

@ -122,6 +122,65 @@ class LogisticaController extends BaseController
}
}
public function imprimirEtiquetas()
{
if ($this->request->isAJAX()) {
$envio_id = $this->request->getPost('envio_id');
$ids = $this->request->getPost('envio_lineas');
$cajas = $this->request->getPost('cajas');
$printer_id = $this->request->getPost('printer_id');
if($cajas == null || $cajas == 0){
return $this->response->setJSON([
'status' => false,
'message' => 'Cajas no válidas'
]);
}
$model = model('App\Models\Logistica\EnvioModel');
$envio = $model->select('envios.*, clientes.nombre as cliente')
->join('clientes', 'clientes.id = envios.cliente_id', 'left')
->where('envios.id', $envio_id)
->first();
if($envio == null){
return $this->response->setJSON([
'status' => false,
'message' => 'Envio no válido'
]);
}
$model = model('App\Models\Logistica\EnvioLineaModel');
$lineas = $model->select('envios_lineas.*, presupuestos.titulo as titulo, presupuestos.referencia_cliente as referencia_cliente')
->join('presupuestos', 'presupuestos.id = envios_lineas.presupuesto_id', 'left')
->whereIn('envios_lineas.id', $ids)->findAll();
if($lineas == null){
return $this->response->setJSON([
'status' => false,
'message' => 'Lineas no válidas'
]);
}
$modelImpresora = model('App\Models\Configuracion\ImpresoraEtiquetaModel');
$impresora = $modelImpresora->select('id, name')
->where('deleted_at', null)
->where('id', $printer_id)
->orderBy('name', 'asc')
->first();
if($impresora == null){
return $this->response->setJSON([
'status' => false,
'message' => 'Impresora no válida'
]);
}
$response = LogisticaService::generateEtiquetasTitulos($envio, $lineas, $impresora, $cajas);
return $this->response->setJSON($response);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function selectAddEnvioLinea()
{
@ -221,6 +280,14 @@ class LogisticaController extends BaseController
$envioEntity->proveedor_nombre = $proveedor->nombre;
}
$modelImpresora = model('App\Models\Configuracion\ImpresoraEtiquetaModel');
$impresoras = $modelImpresora->select('id, name')
->where('deleted_at', null)
->where('tipo', 1)
->orderBy('name', 'asc')
->findAll();
$envioEntity->impresoras = $impresoras;
$viewData = [
'currentModule' => static::$controllerSlug,
'boxTitle' => '<i class="ti ti-truck ti-xl"></i>' . ' ' . lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion,

View File

@ -30,6 +30,7 @@ return [
'no' => 'No',
'si' => 'Sí',
'todos' => 'Todos',
'impresoraEtiquetas' => 'Impresora de etiquetas',
'envio' => 'Envío',
'addLineasEnvio' => 'Añadir líneas al envío',

View File

@ -57,7 +57,7 @@ class ImpresoraEtiquetaService extends BaseService
return ["impresora" => $impresora, "content" => $th->getMessage(), "status" => $status];
}
}
protected function createEtiqueta(array $data_label = []): ?string
public function createEtiqueta(array $data_label = []): ?string
{
$xml = new DOMDocument('1.0', 'utf-8');
$labels = $xml->createElement("labels");
@ -76,7 +76,7 @@ class ImpresoraEtiquetaService extends BaseService
$xml->appendChild($labels);
return $xml->saveXML();
}
protected function sendToImpresoraEtiqueta(string $name, string $content, ImpresoraEtiquetaEntity $impresoraEtiqueta): bool
public function sendToImpresoraEtiqueta(string $name, string $content, ImpresoraEtiquetaEntity $impresoraEtiqueta): bool
{
$tmpFile = tmpfile();

View File

@ -332,7 +332,6 @@ class LogisticaService
}
public static function finalizarEnvio($envio_id, $finalizar_ot = false)
{
// hay que comprobar que para todas las lineas de envio de este envio
@ -419,4 +418,66 @@ class LogisticaService
}
return $data_return;
}
public static function generateEtiquetasTitulos($envio, $lineas, $printer, $cajas)
{
$data = [
"printer" => $printer->name,
"header" => [
"_FORMAT" => "E:PEDIDO.ZPL",
"_QUANTITY" => 1,
"_PRINBTERNAME" => $printer->name,
"_JOBNAME" => "LBL101"
],
];
foreach ($lineas as $linea) {
$data["labels"][] = [
"cliente" => $envio->cliente,
"titulo" => "[" . $linea->pedido_id . "] - " . $linea->titulo,
"cantidad" => $linea->unidades_envio,
"tirada" => $linea->unidades_total,
"cajas" => $cajas,
"ean" => null,
"nombre" => $envio->att,
"direccion" => $envio->direccion,
"notas" => "",
"refcliente" => $linea->refcliente,
"npedido" => $linea->pedido_id
];
}
$servicioImpresora = new ImpresoraEtiquetaService();
$xml = $servicioImpresora->createEtiqueta($data);
if($xml == null){
return [
'status' => false,
'message' => lang('Logistica.errors.noEtiquetas'),
];
}
$sk_environment = getenv('SK_ENVIRONMENT');
if($sk_environment == 'production'){
$status = $servicioImpresora->sendToImpresoraEtiqueta("ETIQUETA", $xml, $printer);
if ($status) {
return [
'status' => true,
'message' => lang('Logistica.success.imprimirEtiquetas'),
'data' => $xml
];
} else {
return [
'status' => false,
'message' => lang('Logistica.errors.noEtiquetas'),
];
}
}else{
return [
'status' => true,
'message' => lang('Logistica.success.imprimirEtiquetas'),
'data' => $xml
];
}
}
}

View File

@ -9,7 +9,9 @@
<div class="col-12">
<div class="card">
<div class="card-header">
<h4><?= $boxTitle ?> <?= ($envioEntity->finalizado == 0)?'':'<span class="badge text-bg-success fw-lg">FINALIZADO</span>' ?></h4>
<h4><?= $boxTitle ?>
<?= ($envioEntity->finalizado == 0) ? '' : '<span class="badge text-bg-success fw-lg">FINALIZADO</span>' ?>
</h4>
</div>
<div class="card-body">
@ -162,7 +164,7 @@
<div class="d-flex flex-row">
<p><?= lang('Logistica.buttonsActions') ?></p>
</div>
<div class="d-flex flex-row mb-3">
<div class="d-flex flex-row mb-3 align-items-end">
<div class="col-sm-2 px-3">
<button id="btnSelectAll" name="btnSelectAll" tabindex="1"
class="btn btn-primary w-100">
@ -194,6 +196,22 @@
</button>
</div>
<div class="col-sm-2 px-3 d-flex flex-column justify-content-end">
<div class="d-flex flex-column justify-content-end h-100">
<label for="impresoraEtiquetas" class="form-label">
<?= lang("Logistica.impresoraEtiquetas") ?>
</label>
<select id="impresoraEtiquetas" name="impresora_etiquetas" tabindex="1"
maxlength="50" class="form-control select2bs2" style="width: 100%;">
<?php foreach ($envioEntity->impresoras as $impresora): ?>
<option value="<?= $impresora->id ?>">
<?= $impresora->name ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<div class="row mb-3">
@ -288,9 +306,8 @@
<?= lang("Logistica.codigoSeguimiento") ?>
</label>
<input type="text" id="codigoSeguimiento" name="codigo_seguimiento" tabindex="1"
maxlength="100" class="form-control"
<?= ($envioEntity->finalizado == 0) ? "" : "readonly" ?>
value="<?= old('codigo_seguimiento', $envioEntity->codigo_seguimiento) ?>">
maxlength="100" class="form-control" <?= ($envioEntity->finalizado == 0) ? '' : 'readonly' ?>
value="<?= esc(old('codigo_seguimiento', $envioEntity->codigo_seguimiento)) ?>">
</div>
<div class="col-sm-3 px-3">
<label for="empresaMensajeria" class="form-label">

View File

@ -32,6 +32,8 @@ class EnvioEdit {
if (!$("#empresaMensajeriaInput").length) {
this.proveedor = new ClassSelect($("#empresaMensajeria"), '/compras/proveedores/getProveedores', "", true, { 'tipo_id': 2 });
}
this.impresoraEtiquetas = $("#impresoraEtiquetas");
}
init() {
@ -92,6 +94,63 @@ class EnvioEdit {
]
});
$('#btnImprimirEtiquetas').on('click', () => {
const table = this.table;
const selectedRows = table.rows({ page: 'current' }).nodes().filter((node) => {
const checkbox = $(node).find('.checkbox-linea-envio');
return checkbox.is(':checked');
}
);
const ids = selectedRows.map((node) => {
const rowData = table.row(node).data();
return rowData.id;
}).toArray();
if (ids.length <= 0) {
Swal.fire({
title: 'Atención!',
text: 'Debe seleccionar al menos una línea de envío para imprimir etiquetas.',
icon: 'info',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
return;
}
const idEnvio = $('#id').val();
let num_cajas = this.cajas.val();
if(ids.length != table.rows().count()){
// se preguntará el numero de cajas en un swal con un input para obtener el valor
Swal.fire({
title: 'Atención!',
text: 'No se ha seleccionado todas las líneas de envío. Ingrese el número de cajas a imprimir.',
icon: 'info',
input: 'text',
inputLabel: 'Número de cajas',
inputValue: num_cajas,
showCancelButton: true,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Imprimir etiquetas',
cancelButtonText: 'Cancelar',
customClass: {
confirmButton: 'btn btn-primary me-1',
cancelButton: 'btn btn-secondary'
},
buttonsStyling: false
}).then((result) => {
if (result.isConfirmed) {
num_cajas = result.value;
this._imprimirEtiquetas(idEnvio, ids, num_cajas);
}
});
}
else{
this._imprimirEtiquetas(idEnvio, ids, num_cajas);
}
});
this.cajas.on('change', (e) => {
const value = $(e.currentTarget).val();
if (value < 0) {
@ -429,6 +488,71 @@ class EnvioEdit {
this._getAlbaranes();
}
_imprimirEtiquetas(envio_id, ids, num_cajas) {
$.post('/logistica/imprimirEtiquetas', {
envio_id: envio_id,
envio_lineas: ids,
cajas: num_cajas,
printer_id: this.impresoraEtiquetas.val(),
}, function (response) {
if (response.status) {
Swal.fire({
title: 'Etiquetas generadas',
text: 'Las etiquetas se han generado correctamente.',
icon: 'success',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
}).then(() => {
if(response.data){
// show xml in a new tab
const blob = new Blob([response.data], { type: 'application/xml' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'etiquetas.xml';
a.click();
URL.revokeObjectURL(url);
a.remove();
}
});
}
else {
Swal.fire({
title: 'Error',
text: response.message,
icon: 'error',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
}
}
).fail(() => {
Swal.fire({
title: 'Error',
text: 'No se pudo generar las etiquetas.',
icon: 'error',
confirmButtonColor: '#3085d6',
confirmButtonText: 'Ok',
customClass: {
confirmButton: 'btn btn-primary me-1',
},
buttonsStyling: false
});
});
}
_checkDatosFinalizar() {
if (this.codigoSeguimiento.val().length <= 0 || this.proveedor.getVal() <= 0) {