diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index 2552a2be..062a4d08 100755 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -856,6 +856,9 @@ $routes->group('etiquetasTitulos', ['namespace' => 'App\Controllers\Logistica'], $routes->post('deleteLineas', 'EtiquetasTitulosController::deleteLineasEtiqueta'); $routes->post('updateLineas', 'EtiquetasTitulosController::updateLineasEtiqueta'); $routes->post('updateComentarios', 'EtiquetasTitulosController::updateComentarios'); + $routes->post('updateOrdenCajas', 'EtiquetasTitulosController::updateOrdenCajas'); + $routes->post('renumber', 'EtiquetasTitulosController::renumberCajas'); + $routes->post('imprimirEtiquetas', 'EtiquetasTitulosController::imprimirEtiquetas'); }); /* diff --git a/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php b/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php index 81a9df16..2026d8b8 100644 --- a/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php +++ b/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php @@ -42,7 +42,7 @@ class EtiquetasTitulosController extends BaseController if ($this->request->isAJAX()) { $query = EtiquetasTitulosService::getOtsWithTitulos(); - + if ($this->request->getGet("q")) { $query->groupStart() ->orLike("ot.id", $this->request->getGet("q")) @@ -66,7 +66,7 @@ class EtiquetasTitulosController extends BaseController $ot_id = $this->request->getGet("ot_id"); $query = EtiquetasTitulosService::getDireccionesOT($ot_id); - + if ($this->request->getGet("q")) { $query->groupStart() ->orLike("pd.direccion", $this->request->getGet("q")) @@ -92,11 +92,11 @@ class EtiquetasTitulosController extends BaseController $data['direccion'] = $this->request->getPost('direccion') ?? null; $data['unidades_caja'] = $this->request->getPost('unidades_caja') ?? null; - if( + if ( $this->request->getPost('ot_id') == null || $this->request->getPost('direccion') == null || $this->request->getPost('unidades_caja') == null - ){ + ) { return [ 'status' => false, 'message' => lang('Logistica.errorMissingData') @@ -125,12 +125,12 @@ class EtiquetasTitulosController extends BaseController $modelLineas = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); $ids = $modelLineas->where('etiqueta_titulos_id', $id)->findColumn('id'); - if($ids){ + if ($ids) { $modelLineas->delete($ids); } $model = model('App\Models\Etiquetas\EtiquetasTitulosModel'); $id = $model->where('id', $id)->findColumn('id'); - if($id){ + if ($id) { $model->delete($id); } $result = [ @@ -142,7 +142,7 @@ class EtiquetasTitulosController extends BaseController } else { return $this->failUnauthorized('Invalid request', 403); } - + } @@ -160,8 +160,8 @@ class EtiquetasTitulosController extends BaseController if (empty($etiquetaEntity)) { return redirect()->to(base_url('logistica/etiquetasLogistica'))->with('error', lang('Logistica.errors.noEnvio')); } - - + + $modelImpresora = model('App\Models\Configuracion\ImpresoraEtiquetaModel'); $impresoras = $modelImpresora->select('id, name') ->where('deleted_at', null) @@ -193,7 +193,7 @@ class EtiquetasTitulosController extends BaseController $q->groupEnd(); } - $result = DataTable::of($q) + $result = DataTable::of($q) ->add("action", callback: function ($q) { return '
@@ -202,7 +202,7 @@ class EtiquetasTitulosController extends BaseController
'; }); - + return $result->toJson(returnAsObject: true); } @@ -212,7 +212,7 @@ class EtiquetasTitulosController extends BaseController $id = $this->request->getGet('id') ?? null; $query = EtiquetasTitulosService::findOTsWithAddress($id); - + if ($this->request->getGet("q")) { $query->groupStart() ->orLike("name", $this->request->getGet("q")) @@ -229,9 +229,10 @@ class EtiquetasTitulosController extends BaseController } } - public function addLineasEtiqueta(){ + public function addLineasEtiqueta() + { - if($this->request->isAJAX()){ + if ($this->request->isAJAX()) { $etiqueta_id = $this->request->getPost('etiqueta_id') ?? null; $ot_id = $this->request->getPost('ot_id') ?? null; @@ -240,14 +241,14 @@ class EtiquetasTitulosController extends BaseController $result = EtiquetasTitulosService::addLineasEtiqueta($etiqueta_id, $ot_id, $unidades, $cajas); return $this->response->setJSON($result); - } - else { + } else { return $this->failUnauthorized('Invalid request', 403); } } - public function datatableLineasEtiquetas($id = null){ + public function datatableLineasEtiquetas($id = null) + { $model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); @@ -270,20 +271,22 @@ class EtiquetasTitulosController extends BaseController return '' . $row->ot . ''; } ) - ->edit( + ->edit( "unidades", function ($row, $meta) { - return ''; + return ''; } ) ->edit( "numero_caja", function ($row, $meta) { - return ''; + return ''; } ) + ->add("unidades_raw", fn($row) => $row->unidades) + ->add("pesoUnidad_raw", fn($row) => $row->pesoUnidad) ->add( "action", callback: function ($q) { @@ -311,10 +314,10 @@ class EtiquetasTitulosController extends BaseController } $model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); - for( $i = 0; $i < count($ids); $i++){ + for ($i = 0; $i < count($ids); $i++) { $model->delete($ids[$i]); } - + $result = [ 'status' => true, @@ -327,7 +330,8 @@ class EtiquetasTitulosController extends BaseController } } - public function updateLineasEtiqueta(){ + public function updateLineasEtiqueta() + { if ($this->request->isAJAX()) { $id = $this->request->getPost('id') ?? null; @@ -355,7 +359,8 @@ class EtiquetasTitulosController extends BaseController } } - public function updateComentarios(){ + public function updateComentarios() + { if ($this->request->isAJAX()) { $id = $this->request->getPost('id') ?? null; @@ -381,4 +386,82 @@ class EtiquetasTitulosController extends BaseController return $this->failUnauthorized('Invalid request', 403); } } + + public function updateOrdenCajas() + { + $rawInput = $this->request->getBody(); + $data = json_decode($rawInput, true); + $orden = $data['orden'] ?? []; + + if (!is_array($orden)) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'Datos inválidos' + ]); + } + + $model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); + + foreach ($orden as $item) { + if (isset($item['id'], $item['numero_caja'])) { + $model->update($item['id'], [ + 'numero_caja' => $item['numero_caja'], + 'updated_at' => date('Y-m-d H:i:s') // opcional + ]); + } + } + + return $this->response->setJSON([ + 'status' => true, + 'message' => 'Orden de cajas actualizado correctamente' + ]); + } + + public function renumberCajas() + { + $id = $this->request->getPost('id') ?? null; + + if ($id == null) { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.errorMissingData') + ]; + } + + $result = EtiquetasTitulosService::reordenarCajas($id); + + return $this->response->setJSON($result); + } + + public function imprimirEtiquetas() + { + $etiqueta_id = $this->request->getPost('etiqueta_id') ?? null; + $ids = $this->request->getPost('ids') ?? []; + $impresora_id = $this->request->getPost('impresora_id') ?? null; + + $modelImpresora = model('App\Models\Configuracion\ImpresoraEtiquetaModel'); + $impresora = $modelImpresora->select('id, name, ip, port, user, pass') + ->where('deleted_at', null) + ->where('id', $impresora_id) + ->orderBy('name', 'asc') + ->first(); + if ($impresora == null) { + return $this->response->setJSON([ + 'status' => false, + 'message' => 'Impresora no válida' + ]); + } + + if ($etiqueta_id == null || $ids == []) { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.errorMissingData') + ]; + } + + $result = EtiquetasTitulosService::imprimirEtiquetas($etiqueta_id, $ids, $impresora); + + return $this->response->setJSON($result); + } + } \ No newline at end of file diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index b3fb360a..0ef3e713 100755 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -78,7 +78,7 @@ return [ 'cliente' => 'Cliente', 'comentariosEtiqueta' => 'Comentarios etiqueta', 'addLineaEtiqueta' => 'Añadir líneas a la etiqueta', - + 'renumber' => 'Renumerar etiquetas', 'errors' => [ 'noEnvio' => 'No se ha encontrado el envio', @@ -88,6 +88,8 @@ return [ 'noAddresses' => 'El pedido no tiene direcciones de envío', 'errorMissingData' => 'Faltan datos para crear la etiqueta', 'errorInsertarEtiqueta' => 'Error al insertar la etiqueta', + 'noEtiqueta' => 'No se ha encontrado la etiqueta', + 'noEtiquetaLineas' => 'No se han encontrado líneas de etiqueta', ], 'success' => [ 'finalizado' => 'El envío se ha finalizado correctamente', @@ -97,6 +99,8 @@ return [ 'successDeleteLines' => 'Lineas de etiqueta eliminadas correctamente', 'successUpdateLine' => 'Linea de etiqueta actualizadas correctamente', 'comentariosUpdated' => 'Comentarios actualizados correctamente', + 'successReordenarCajas' => 'Cajas reordenadas correctamente', + 'imprimirEtiquetas' => 'Etiquetas impresas correctamente', ], ]; \ No newline at end of file diff --git a/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php b/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php index aa2f0ff5..a98b0ef1 100644 --- a/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php +++ b/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php @@ -79,10 +79,12 @@ class EtiquetasTitulosLineasModel extends Model $builder = $this->db->table('etiquetas_titulos_lineas etl') ->select(' + etl.id as id, etl.ot_id as ot, pr.titulo as titulo, etl.unidades as unidades, etl.numero_caja as numero_caja, + etl.numero_caja as numero_caja_raw, pd.cantidad as unidadesTotal, etl.id as id, etl.unidades as unidadesRaw, diff --git a/ci4/app/Services/EtiquetasTitulosService.php b/ci4/app/Services/EtiquetasTitulosService.php index bb4aeb15..55c6b53e 100644 --- a/ci4/app/Services/EtiquetasTitulosService.php +++ b/ci4/app/Services/EtiquetasTitulosService.php @@ -165,12 +165,12 @@ class EtiquetasTitulosService ->selectMax('numero_caja') ->where('etiqueta_titulos_id', $etiqueta_id) ->first(); - $next_caja = $next_caja->numero_caja ?? 0; + $next_caja = $next_caja->numero_caja ?? 0; $next_caja++; $user_id = auth()->user()->id; - while($unidades_restantes > 0){ + while ($unidades_restantes > 0) { $modelEtitquetaLinea->insert([ 'etiqueta_titulos_id' => $etiqueta_id, 'ot_id' => $ot_id, @@ -188,4 +188,177 @@ class EtiquetasTitulosService ]; } + + public static function reordenarCajas($etiqueta_id) + { + $model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); + + // 1. Obtener todas las líneas ordenadas por numero_caja e id + $lineas = $model + ->where('etiqueta_titulos_id', $etiqueta_id) + ->orderBy('numero_caja ASC') + ->orderBy('id ASC') + ->findAll(); + + // 2. Agrupar por caja + $grupos = []; + foreach ($lineas as $linea) { + $grupos[$linea->numero_caja][] = $linea; + } + + // 3. Reasignar números de caja de forma consecutiva + $nuevoNumeroCaja = 1; + foreach ($grupos as $grupo) { + foreach ($grupo as $linea) { + $model->update($linea->id, ['numero_caja' => $nuevoNumeroCaja]); + + } + $nuevoNumeroCaja++; + } + + return [ + 'status' => true, + 'message' => lang('Logistica.success.successReordenarCajas'), + ]; + } + + public static function imprimirEtiquetas($etiqueta_id = null, $ids = [], $printer = null){ + + $model = model('App\Models\Etiquetas\EtiquetasTitulosModel'); + $modelLineas = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel'); + + if ($etiqueta_id) { + $etiquetas = $model->where('id', $etiqueta_id)->first(); + $etiquetas_lineas = $modelLineas->whereIn('id', $ids)->orderBy('numero_caja', 'ASC')->findAll(); + } + + // buscar el maximo numero_cajas en el array de objetos etiquetas_lineas + $max_num_cajas = 0; + foreach ($etiquetas_lineas as $linea) { + if ($linea->numero_caja > $max_num_cajas) { + $max_num_cajas = $linea->numero_caja; + } + } + + // se obtienen los numero_caja diferentes en un array + $numero_cajas = []; + foreach ($etiquetas_lineas as $linea) { + if (!in_array($linea->numero_caja, $numero_cajas)) { + $numero_cajas[] = $linea->numero_caja; + } + } + + if (empty($etiquetas)) { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.noEtiqueta'), + ]; + } + if (empty($etiquetas_lineas)) { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.noEtiquetaLineas'), + ]; + } + + + $data = [ + "printer" => $printer->name, + "header" => [ + "_FORMAT" => "E:MULTI.ZPL", + "_QUANTITY" => 1, + "_PRINBTERNAME" => $printer->name, + "_JOBNAME" => "LBL101" + ], + 'direccion' => $etiquetas->direccion, + 'grupos' => [], + 'notas' => $etiquetas->comentarios, + 'nombre' => $etiquetas->att, + ]; + + + $index_etiqueta = 0; + foreach ($numero_cajas as $caja) { + + array_push($data['grupos'], [ + ]); + + $prefix = 1; + $lineas = array_filter($etiquetas_lineas, function ($linea) use ($caja) { + return $linea->numero_caja == $caja; + }); + + $lineaCounter = 0; + foreach($lineas as $linea){ + + + if($lineaCounter >= 5){ + $lineaCounter = 0; + $index_etiqueta++; + array_push($data['grupos'], []); + } + + $modelPresupuestos = model('App\Models\OrdenTrabajo\OrdenTrabajoModel'); + $datos_etiqueta = $modelPresupuestos->select(' + pr.titulo as titulo, + pr.isbn as isbn, + pr.referencia_cliente as referencia_cliente, + p.id as id_pedido, + ordenes_trabajo.total_tirada as total_tirada,') + ->join('pedidos p', 'p.id = ordenes_trabajo.pedido_id') + ->join('pedidos_linea pl', 'pl.pedido_id = p.id') + ->join('presupuestos pr', 'pr.id = pl.presupuesto_id') + ->where('ordenes_trabajo.id',$linea->ot_id)->first(); + + + + $data['grupos'][$index_etiqueta][] = [ + 'prefix' => $caja, + 'titulo' => mb_substr($datos_etiqueta->titulo, 0, 40), + 'cantidad' => $linea->unidades, + 'tirada' => $datos_etiqueta->total_tirada, + 'ean' => str_replace('-', '', $datos_etiqueta->isbn), + 'npedido' => $datos_etiqueta->id, + 'refcliente' => $datos_etiqueta->referencia_cliente, + ]; + + $lineaCounter++; + } + $index_etiqueta++; + } + + $servicioImpresora = new ImpresoraEtiquetaService(); + $xml = $servicioImpresora->createEtiquetaTitulos($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'), + ]; + } else { + return [ + 'status' => false, + 'message' => lang('Logistica.errors.noEtiquetas'), + ]; + } + + } else { + return [ + 'status' => true, + 'message' => lang('Logistica.success.imprimirEtiquetas'), + 'data' => $xml + ]; + } + + + } } \ No newline at end of file diff --git a/ci4/app/Services/ImpresoraEtiquetaService.php b/ci4/app/Services/ImpresoraEtiquetaService.php index 41be8605..9f884c09 100755 --- a/ci4/app/Services/ImpresoraEtiquetaService.php +++ b/ci4/app/Services/ImpresoraEtiquetaService.php @@ -24,9 +24,9 @@ class ImpresoraEtiquetaService extends BaseService "labels" => [ [ "cliente" => "Cliente Potencial", - "titulo" => "[1234] TEST OLIVEROS", + "titulo" => "[1234] TEST OLIVEROS", "cantidad" => 100, - "tirada" => 50, + "tirada" => 50, "cajas" => 1, "ean" => null, "nombre" => "___Nombre___", @@ -76,6 +76,66 @@ class ImpresoraEtiquetaService extends BaseService $xml->appendChild($labels); return $xml->saveXML(); } + + + public function createEtiquetaTitulos(array $data_label = []): ?string + { + $xml = new DOMDocument('1.0', 'utf-8'); + + // Crear nodo raíz "labels" + $labels = $xml->createElement("labels"); + + // Establecer atributos de "labels" desde "header" + foreach ($data_label["header"] as $key => $value) { + $labels->setAttribute($key, $value); + } + + // Recorrer grupos de etiquetas + foreach ($data_label["grupos"] as $grupo) { + $labelChild = $xml->createElement('label'); + + // Crear variables específicas del grupo + foreach ($grupo as $libro) { + $prefix = $libro['prefix']; + + $variables = [ + "titulo$prefix" => $libro['titulo'], + "tirada$prefix" => $libro['tirada'], + "ean$prefix" => $libro['ean'], + "npedido$prefix" => $libro['npedido'], + "refcliente$prefix" => $libro['refcliente'], + "textpedido$prefix" => 'Pedido', + "textcantidad$prefix" => 'Cantidad:', + "textref$prefix" => 'Ref:', + "textean$prefix" => 'ISBN', + ]; + + foreach ($variables as $varName => $varValue) { + $variableChild = $xml->createElement('variable'); + $variableChild->setAttribute("name", $varName); + $variableChild->appendChild($xml->createTextNode((string) $varValue)); + $labelChild->appendChild($variableChild); + } + } + + // Variables comunes del grupo + $nombreVariable = $xml->createElement('variable', htmlspecialchars($data_label['nombre'])); + $nombreVariable->setAttribute('name', 'nombre'); + $labelChild->appendChild($nombreVariable); + + $direccionVariable = $xml->createElement('variable', htmlspecialchars($data_label['direccion'])); + $direccionVariable->setAttribute('name', 'direccion'); + $labelChild->appendChild($direccionVariable); + + $labels->appendChild($labelChild); + } + + $xml->appendChild($labels); + return $xml->saveXML(); + } + + + public function sendToImpresoraEtiqueta(string $name, string $content, ImpresoraEtiquetaEntity $impresoraEtiqueta): bool { $tmpFile = tmpfile(); @@ -84,8 +144,8 @@ class ImpresoraEtiquetaService extends BaseService rewind($tmpFile); $tmpMetaData = stream_get_meta_data($tmpFile); - $conn = @ftp_connect($impresoraEtiqueta->ip,$impresoraEtiqueta->port); - if(!$conn){ + $conn = @ftp_connect($impresoraEtiqueta->ip, $impresoraEtiqueta->port); + if (!$conn) { throw new Exception('Error al establecer conexión FTP'); } $isLoginSuccess = @ftp_login($conn, $impresoraEtiqueta->user, $impresoraEtiqueta->pass); @@ -99,10 +159,10 @@ class ImpresoraEtiquetaService extends BaseService if (ftp_put($conn, $name, $tmpMetaData['uri'], FTP_ASCII) === FALSE) { $status = false; ftp_close($conn); - }else{ + } else { $status = true; } - + return $status; } } diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php b/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php index 9e4e10d1..c02a6c2c 100644 --- a/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php @@ -143,6 +143,21 @@ +
+ +
+
+ +
+