terminando a falta del listado añadir etiquetas

This commit is contained in:
2025-05-03 12:06:25 +02:00
parent 746955c3b1
commit 71e70bf551
14 changed files with 605 additions and 6 deletions

View File

@ -818,6 +818,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi
$routes->get('panel', 'LogisticaController::panel', ['as' => 'LogisticaPanel']);
$routes->get('envios', 'LogisticaController::gestionEnvios', ['as' => 'gestionEnvios']);
$routes->get('enviosFerros', 'LogisticaController::gestionEnviosFerros', ['as' => 'gestionEnviosFerros']);
$routes->get('etiquetasLogistica', 'LogisticaController::etiquetasLogistica', ['as' => 'etiquetasLogistica']);
$routes->get('datatableEnvios', 'LogisticaController::datatable_envios');
$routes->get('datatableLineasEnvios/(:num)', 'LogisticaController::datatable_enviosEdit/$1');
$routes->get('envio/(:num)', 'LogisticaController::editEnvio/$1');
@ -841,6 +842,13 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi
});
$routes->group('etiquetasTitulos', ['namespace' => 'App\Controllers\Logistica'], function ($routes) {
$routes->get('otList', 'EtiquetasTitulosController::findOTs');
$routes->get('addList', 'EtiquetasTitulosController::findAddresses');
$routes->post('newEtiquetaTitulos', 'EtiquetasTitulosController::addEtiqueta');
});
/*
* --------------------------------------------------------------------
* Translation

View File

@ -0,0 +1,112 @@
<?php
namespace App\Controllers\Logistica;
use App\Controllers\BaseController;
use App\Services\ImpresoraEtiquetaService;
use App\Services\EtiquetasTitulosService;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
use Hermawan\DataTables\DataTable;
class EtiquetasTitulosController extends BaseController
{
protected ImpresoraEtiquetaService $impresoraEtiquetaService;
protected string $locale;
protected array $viewData;
protected static $controllerSlug = 'logistica';
protected static $viewPath = 'themes/vuexy/form/logistica/';
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
$this->impresoraEtiquetaService = service('impresora_etiqueta');
$this->locale = session()->get('lang');
$this->viewData['pageTitle'] = lang('Logistica.logistica');
// Breadcrumbs
$this->viewData['breadcrumb'] = [
['title' => lang("App.menu_logistica"), 'route' => route_to("LogisticaPanel"), 'active' => false],
];
parent::initController($request, $response, $logger);
}
public function findOTs()
{
if ($this->request->isAJAX()) {
$query = EtiquetasTitulosService::getOtsWithTitulos();
if ($this->request->getGet("q")) {
$query->groupStart()
->orLike("ot.id", $this->request->getGet("q"))
->orLike("pr.titulo)", $this->request->getGet("q"))
->groupEnd();
}
$result = $query->orderBy("id", "DESC")->get()->getResultObject();
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function findAddresses()
{
if ($this->request->isAJAX()) {
$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"))
->groupEnd();
}
$result = $query->orderBy("pd.direccion", "ASC")->get()->getResultObject();
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function addEtiqueta()
{
if ($this->request->isAJAX()) {
$data = [];
$data['user_id'] = auth()->user()->id;
$data['ot_id'] = $this->request->getPost('ot_id') ?? null;
$data['direccion'] = $this->request->getPost('direccion') ?? null;
$data['unidades_caja'] = $this->request->getPost('unidades_caja') ?? null;
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')
];
}
$result = EtiquetasTitulosService::addEtiqueta($data);
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
}

View File

@ -85,6 +85,19 @@ class LogisticaController extends BaseController
return view(static::$viewPath . 'viewLogisticaSelectEnvios', $viewData);
}
public function etiquetasLogistica()
{
$viewData = [
'currentModule' => static::$controllerSlug,
'boxTitle' => lang('Logistica.etiquetasTitulos'),
'usingServerSideDataTable' => true,
];
$viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class
return view(static::$viewPath . 'viewImpresionEtiquetas', $viewData);
}
public function listAlbaranes(){
$viewData = [
'currentModule' => static::$controllerSlug,

View File

@ -0,0 +1,60 @@
<?php
namespace App\Database\Migrations;
use CodeIgniter\Database\Migration;
class CreateEtiquetasTitulos extends Migration
{
public function up()
{
// Tabla: etiquetas_titulos
$this->forge->addField([
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
'comentarios' => ['type' => 'TEXT', 'null' => true],
'direccion' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => false],
'att' => ['type' => 'VARCHAR', 'constraint' => 255, 'null' => false],
'cliente_id' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'updated_at' => ['type' => 'DATETIME', 'null' => true],
'deleted_at' => ['type' => 'DATETIME', 'null' => true],
'user_created_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
'user_updated_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
'user_deleted_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addForeignKey('user_created_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->addForeignKey('user_updated_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->addForeignKey('user_deleted_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->addForeignKey('cliente_id', 'clientes', 'id', 'SET NULL', 'CASCADE');
$this->forge->createTable('etiquetas_titulos');
// Tabla: etiquetas_titulos_lineas
$this->forge->addField([
'id' => ['type' => 'INT', 'unsigned' => true, 'auto_increment' => true],
'etiqueta_titulos_id' => ['type' => 'INT', 'unsigned' => true],
'ot_id' => ['type' => 'INT', 'unsigned' => true],
'unidades' => ['type' => 'INT', 'unsigned' => true],
'numero_caja' => ['type' => 'INT', 'unsigned' => true],
'created_at' => ['type' => 'DATETIME', 'null' => true],
'updated_at' => ['type' => 'DATETIME', 'null' => true],
'deleted_at' => ['type' => 'DATETIME', 'null' => true],
'user_created_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
'user_updated_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
'user_deleted_at' => ['type' => 'INT', 'unsigned' => true, 'null' => true],
]);
$this->forge->addKey('id', true);
$this->forge->addForeignKey('etiqueta_titulos_id', 'etiquetas_titulos', 'id', 'CASCADE', 'CASCADE');
$this->forge->addForeignKey('ot_id', 'ordenes_trabajo', 'id', 'CASCADE', 'CASCADE');
$this->forge->addForeignKey('user_created_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->addForeignKey('user_updated_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->addForeignKey('user_deleted_at', 'users', 'id', 'SET NULL', 'CASCADE');
$this->forge->createTable('etiquetas_titulos_lineas');
}
public function down()
{
$this->forge->dropTable('etiquetas_titulos_lineas', true);
$this->forge->dropTable('etiquetas_titulos', true);
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\Entities\Etiquetas;
use App\Models\Etiquetas\EtiquetasTitulosLineasModel;
use CodeIgniter\Entity\Entity;
class EtiquetaTitulo extends Entity
{
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
public function getLineas()
{
$model = new EtiquetasTitulosLineasModel();
return $model->where('etiqueta_titulos_id', $this->id)->findAll();
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace App\Entities\Etiquetas;
use CodeIgniter\Entity\Entity;
class EtiquetaTituloLinea extends Entity
{
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
}

View File

@ -65,12 +65,21 @@ return [
'finalizarEnvio' => 'Finalizar envío',
'finalizarEnvioYOTs' => 'Finalizar envío y OTS',
'id' => 'ID',
'numeroCajas' => 'Nº Cajas',
'listadoEtiquetas' => 'Listado de etiquetas',
'nuevaEtiqueta' => 'Nueva etiqueta',
'errors' => [
'noEnvio' => 'No se ha encontrado el envio',
'noEnvioLineas' => 'No se han encontrado líneas de envío',
'noDataToFind' => 'No se ha introducido ningún dato para buscar',
'notFound' => 'No se encuentra el pedido o ISBN, el pedido no está en producción o finalizado o no tiene envíos pendientes',
'noAddresses' => 'El pedido no tiene direcciones de envío',
'errorMissingData' => 'Faltan datos para crear la etiqueta',
'errorInsertarEtiqueta' => 'Error al insertar la etiqueta',
],
'success' => [
'finalizado' => 'El envío se ha finalizado correctamente',

View File

@ -0,0 +1,35 @@
<?php
namespace App\Models\Etiquetas;
use CodeIgniter\Model;
use App\Entities\Etiquetas\EtiquetaTituloLinea;
class EtiquetasTitulosLineasModel extends Model
{
protected $table = 'etiquetas_titulos_lineas';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = EtiquetaTituloLinea::class;
protected $useSoftDeletes = true;
protected $allowedFields = [
'etiqueta_titulos_id',
'ot_id',
'unidades',
'numero_caja',
'user_created_at',
'user_updated_at',
'user_deleted_at',
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
}

View File

@ -0,0 +1,35 @@
<?php
namespace App\Models\Etiquetas;
use CodeIgniter\Model;
use App\Entities\Etiquetas\EtiquetaTitulo;
class EtiquetasTitulosModel extends Model
{
protected $table = 'etiquetas_titulos';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = EtiquetaTitulo::class;
protected $useSoftDeletes = true;
protected $allowedFields = [
'comentarios',
'direccion',
'att',
'cliente_id',
'user_created_at',
'user_updated_at',
'user_deleted_at',
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
}

View File

@ -0,0 +1,107 @@
<?php
namespace App\Services;
use Config\Services;
class EtiquetasTitulosService
{
public static function getOtsWithTitulos()
{
$db = \Config\Database::connect();
// 3. Subconsulta principal
$builder = $db->table('ordenes_trabajo ot')
->select("
ot.id AS id,
CONCAT('[', ot.id, '] - ', pr.titulo) AS name")
->join('pedidos p', 'p.id = ot.pedido_id')
->join('pedidos_linea pl', 'p.id = pl.pedido_id')
->join('presupuestos pr', 'pr.id = pl.presupuesto_id')
->join('orden_trabajo_dates ot_dates', 'ot_dates.orden_trabajo_id = ot.id')
->whereIn('p.estado', ['finalizado', 'produccion'])
->where('ot_dates.embalaje_at IS NOT NULL');
return $builder;
}
public static function getDireccionesOT($ot_id){
$db = \Config\Database::connect();
// 3. Subconsulta principal
$builder = $db->table('presupuesto_direcciones pd')
->select("
pd.id AS id,
pd.direccion AS name")
->join('presupuestos pr', 'pr.id = pd.presupuesto_id')
->join('pedidos_linea pl', 'pr.id = pl.presupuesto_id')
->join('pedidos p', 'p.id = pl.pedido_id')
->join('ordenes_trabajo ot', 'ot.pedido_id = p.id')
->join('orden_trabajo_dates ot_dates', 'ot_dates.orden_trabajo_id = ot.id')
->whereIn('p.estado', ['finalizado', 'produccion'])
->where('ot_dates.embalaje_at IS NOT NULL')
->where('ot.id', $ot_id);
return $builder;
}
public static function addEtiqueta($data)
{
$db = \Config\Database::connect();
$builder = $db->table('presupuesto_direcciones pd');
$builder->select('pd.att, pd.direccion, pd.cantidad, pr.cliente_id');
$builder->join('presupuestos pr', 'pr.id = pd.presupuesto_id');
$builder->join('pedidos_linea pl', 'pr.id = pl.presupuesto_id');
$builder->join('pedidos p', 'p.id = pl.pedido_id');
$builder->join('ordenes_trabajo ot', 'ot.pedido_id = p.id');
$builder->where('ot.id', $data['ot_id']);
$builder->where('pd.direccion', $data['direccion']);
$result = $builder->get()->getRow();
$data['att'] = $result->att;
$data['direccion'] = $result->direccion;
$data['cantidad'] = $result->cantidad;
$data['cliente_id'] = $result->cliente_id;
$modelEtiquetasTitulos = model('App\Models\Etiquetas\EtiquetasTitulosModel');
$modelEtiquetasTitulos->insert([
'direccion' => $data['direccion'],
'att' => $data['att'],
'cliente_id' => $data['cliente_id'],
'user_created_at' => $data['user_id'],
]);
$etiquetaId = $modelEtiquetasTitulos->getInsertID();
if($etiquetaId == null){
return [
'status' => false,
'message' => lang('Logistica.errorInsertarEtiqueta'),
];
}
$cantidad_restante = intval($data['cantidad']);
$numero_caja = 1;
while($cantidad_restante > 0){
$modelEtiquetasTitulosLineas = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel');
$modelEtiquetasTitulosLineas->insert([
'etiqueta_titulos_id' => $etiquetaId,
'ot_id' => $data['ot_id'],
'unidades' => $cantidad_restante - intval($data['unidades_caja']) < 0 ? $cantidad_restante : intval($data['unidades_caja']),
'numero_caja' => $numero_caja,
'user_created_at' => $data['user_id'],
]);
$cantidad_restante -= $data['unidades_caja'];
$numero_caja++;
}
return [
'status' => true,
'etiqueta' => $etiquetaId,
];
}
}

View File

@ -78,6 +78,7 @@ class LogisticaService
return $builder;
}
public static function findForNewEnvio()
{
$db = \Config\Database::connect();
@ -576,11 +577,11 @@ class LogisticaService
$data = [
"printer" => $printer->name,
"header" => [
"_FORMAT" => "E:PEDIDO.ZPL",
"_QUANTITY" => 1,
"_PRINBTERNAME" => $printer->name,
"_JOBNAME" => "LBL101"
],
"_FORMAT" => "E:PEDIDO.ZPL",
"_QUANTITY" => 1,
"_PRINBTERNAME" => $printer->name,
"_JOBNAME" => "LBL101"
],
];
foreach ($lineas as $linea) {

View File

@ -0,0 +1,119 @@
<?= $this->include("themes/_commonPartialsBs/sweetalert") ?>
<?= $this->include('themes/_commonPartialsBs/datatables') ?>
<?= $this->include("themes/_commonPartialsBs/select2bs5") ?>
<?= $this->extend('themes/vuexy/main/defaultlayout') ?>
<?= $this->section('content'); ?>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4><?= $boxTitle ?></h4>
</div>
<div class="card-body">
<?= view("themes/_commonPartialsBs/_alertBoxes") ?>
<div class="card accordion-item active mb-5">
<h4 class="accordion-header px-4 py-3">
<?= lang("Logistica.nuevaEtiqueta") ?>
</h4>
<div id="accordionNuevaEtiquetaTip" class="accordion-collapse collapse show">
<div class="accordion-body px-4 py-3">
<div class="row">
<div class="mb-1 col-sm-6">
<label for="buscadorPedidos" class="form-label">
<?= lang("Logistica.buscadorPedidosTitle2") ?>
</label>
<select id="buscadorPedidos" name="buscador_pedidos" tabindex="1" maxlength="50"
class="form-control select2bs2">
</select>
</div>
</div>
<div class="row select-direcciones d-none">
<div class="col-sm-6 px-3">
<label for="selectDirecciones" class="form-label">
<?= lang("Logistica.selectDirecciones") ?>
</label>
<select id="selectDirecciones" name="select_direcciones" tabindex="1" maxlength="50"
class="form-control select2bs2" style="width: 100%;">
</select>
</div>
</div>
<div class="row add-etiqueta d-none">
<div class="col-sm-2 px-3">
<button id="btnAddEtiqueta" name="btn_add_etiqueta" tabindex="1"
class="btn btn-primary mt-4 w-100">
<?= lang("Logistica.add") ?>
<ti class="ti ti-circle-plus"></ti>
</button>
</div>
</div>
</div>
</div>
</div>
<div class="card accordion-item active">
<h4 class="accordion-header px-4 py-3">
<?= lang("Logistica.listadoEtiquetas") ?>
</h4>
<div id="accordionListadoEnviosTip" class="accordion-collapse collapse show">
<div class="accordion-body px-4 py-3">
<div class="row">
<table id="tableOfEnvios" class="table table-striped table-hover w-100">
<thead>
<tr>
<th><?= lang('Logistica.id') ?? 'ID Envío' ?></th>
<th><?= lang('Logistica.numeroOts') ?? 'Nº OTs' ?></th>
<th><?= lang('Logistica.numeroCajas') ?? 'Nº Cajas' ?></th>
<th><?= lang('Logistica.att') ?? 'Att' ?></th>
<th><?= lang('Logistica.direccion') ?? 'Dirección' ?></th>
<th><?= lang('Logistica.acciones') ?? 'Acciones' ?></th>
</tr>
<tr>
<th><input type="text" class="form-control envio-filter" name="id"></th>
<th><input type="text" class="form-control envio-filter-ots" name="ots"></th>
<th></th>
<th><input type="text" class="form-control envio-filter" name="att"></th>
<th><input type="text" class="form-control envio-filter" name="direccion"></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<div class="mt-3">
<button type="button" class="btn btn-secondary" id="btnBackToPanel"
onclick="window.location.href='<?= route_to('LogisticaPanel') ?>'">
<?= lang('Logistica.backToPanel') ?>
</button>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('css') ?>
<link rel="stylesheet" href="<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.css') ?>" />
<?= $this->endSection() ?>
<?= $this->section('additionalExternalJs') ?>
<script src="<?= site_url('themes/vuexy/vendor/libs/sweetalert2/sweetalert2.js') ?>"></script>
<script type="module" src="<?= site_url("assets/js/safekat/pages/logistica/impresionEtiquetas.js") ?>"></script>
<?= $this->endSection() ?>

View File

@ -21,7 +21,7 @@
<img src="<?= site_url("assets/img/logistica/envios_ferros.png") ?>" alt="Envío de Ferros/Prototipos">
<div><span><?= lang("Logistica.envioFerros"); ?></span></div>
</div>
<div class="item">
<div class="item" onclick="location.href='<?= route_to('etiquetasLogistica') ?>'">
<img src="<?= site_url("assets/img/logistica/impresionEtiquetas.jpg") ?>" alt="Etiquetas de títulos">
<div><span><?= lang("Logistica.etiquetasTitulos"); ?></span></div>
</div>

View File

@ -0,0 +1,73 @@
import ClassSelect from '../../components/select2.js';
$(() => {
const selectOts = new ClassSelect($('#buscadorPedidos'), '/etiquetasTitulos/otList', "", true);
selectOts.init();
const selectDirecciones = new ClassSelect($('#selectDirecciones'), '/etiquetasTitulos/addList', "", true, {
ot_id: () => selectOts.getVal()
});
selectDirecciones.init();
selectOts.item.on('select2:open', () => {
$('.select-direcciones').addClass('d-none');
$('.add-etiqueta').addClass('d-none');
})
selectOts.item.on('change', () => {
selectDirecciones.empty();
$('.add-etiqueta').addClass('d-none');
$('.select-direcciones').removeClass('d-none');
})
selectDirecciones.item.on('select2:open', () => {
$('.add-etiqueta').addClass('d-none');
})
selectDirecciones.item.on('change', () => {
$('.add-etiqueta').removeClass('d-none');
})
$('#btnAddEtiqueta').on('click', () => {
Swal.fire({
title: 'Unidades por caja',
text: 'Seleccione la cantidad de unidades por caja',
icon: 'info',
input: 'text',
inputLabel: 'Unidades/caja',
inputValue: 0,
showCancelButton: true,
confirmButtonColor: '#3085d6',
confirmButtonText: 'Aceptar',
cancelButtonText: 'Cancelar',
customClass: {
confirmButton: 'btn btn-primary me-1',
cancelButton: 'btn btn-secondary'
},
buttonsStyling: false
}).then((result) => {
if (result.isConfirmed) {
const unidades_caja = result.value;
const url = '/etiquetasTitulos/newEtiquetaTitulos';
const data = {
ot_id: selectOts.getVal(),
direccion: selectDirecciones.getText(),
unidades_caja: unidades_caja
};
$.post(
url,
data,
function (response) {
if (response.status) {
// OK
} else {
popErrorAlert('Error en la respuesta');
}
}
).fail(function (xhr, status, error) {
popErrorAlert(error);
});
}
});
})
})