falta ordenar por cajas

This commit is contained in:
2025-05-04 13:05:37 +02:00
parent 3f90665c39
commit 39639d9ff8
10 changed files with 519 additions and 60 deletions

View File

@ -851,6 +851,11 @@ $routes->group('etiquetasTitulos', ['namespace' => 'App\Controllers\Logistica'],
$routes->post('delete', 'EtiquetasTitulosController::deleteEtiqueta');
$routes->get('edit/(:num)', 'EtiquetasTitulosController::edit/$1');
$routes->get('datatableLineas/(:num)', 'EtiquetasTitulosController::datatableLineasEtiquetas/$1');
$routes->get('findOts', 'EtiquetasTitulosController::findOtsWithAddress');
$routes->post('addLineas', 'EtiquetasTitulosController::addLineasEtiqueta');
$routes->post('deleteLineas', 'EtiquetasTitulosController::deleteLineasEtiqueta');
$routes->post('updateLineas', 'EtiquetasTitulosController::updateLineasEtiqueta');
$routes->post('updateComentarios', 'EtiquetasTitulosController::updateComentarios');
});
/*

View File

@ -206,6 +206,47 @@ class EtiquetasTitulosController extends BaseController
return $result->toJson(returnAsObject: true);
}
public function findOtsWithAddress()
{
if ($this->request->isAJAX()) {
$id = $this->request->getGet('id') ?? null;
$query = EtiquetasTitulosService::findOTsWithAddress($id);
if ($this->request->getGet("q")) {
$query->groupStart()
->orLike("name", $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 addLineasEtiqueta(){
if($this->request->isAJAX()){
$etiqueta_id = $this->request->getPost('etiqueta_id') ?? null;
$ot_id = $this->request->getPost('ot_id') ?? null;
$unidades = $this->request->getPost('unidades') ?? null;
$cajas = $this->request->getPost('cajas') ?? null;
$result = EtiquetasTitulosService::addLineasEtiqueta($etiqueta_id, $ot_id, $unidades, $cajas);
return $this->response->setJSON($result);
}
else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function datatableLineasEtiquetas($id = null){
$model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel');
@ -222,29 +263,122 @@ class EtiquetasTitulosController extends BaseController
callback: function ($q) {
return '<input type="checkbox" class="form-check-input checkbox-linea-envio" name="row_selected[]" value="' . $q->id . '">';
}
);
/*->edit(
"pedido",
)
->edit(
"ot",
function ($row, $meta) {
return '<a href="' . base_url('pedidos/edit/' . $row->pedido) . '" target="_blank">' . $row->pedido . '</a>';
return '<a href="' . base_url('produccion/ordentrabajo/edit/' . $row->ot) . '" target="_blank">' . $row->ot . '</a>';
}
)
->edit(
"unidades",
function ($row, $meta) {
return '<input type="number" class="form-control input-lineas input-unidades text-center"
data-id="'. $row->id.'" data-name="unidades" value="' . $row->unidades . '">';
}
)
->edit(
"presupuesto",
"numero_caja",
function ($row, $meta) {
return '<a href="' . base_url('presupuestoadmin/edit/' . $row->presupuesto) . '" target="_blank">' . $row->presupuesto . '</a>';
return '<input type="number" class="form-control input-lineas input-cajas text-center"
data-id="'. $row->id.'" data-name="numero_caja" value="' . $row->numero_caja . '">';
}
)->edit(
"unidadesEnvio",
function ($row, $meta) {
if($row->finalizado == 1 || $row->tipo_envio == 'ferro_prototipo'){
return $row->unidadesEnvio;
}
return '<input type="number" class="form-control input-lineas input-unidades text-center"
data-id="'. $row->id.'" data-name="unidades_envio" value="' . $row->unidadesEnvio . '">';
)
->add(
"action",
callback: function ($q) {
return '
<div class="btn-group btn-group-sm">
<a href="javascript:void(0);"><i class="ti ti-trash ti-sm btn-delete" data-id="' . $q->id . '"></i></a>
</div>
';
}
);*/
);
return $result->toJson(returnAsObject: true);
}
public function deleteLineasEtiqueta()
{
if ($this->request->isAJAX()) {
$ids = $this->request->getPost('ids') ?? [];
if ($ids == [] || $ids == null) {
return [
'status' => false,
'message' => lang('Logistica.errors.errorMissingData')
];
}
$model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel');
for( $i = 0; $i < count($ids); $i++){
$model->delete($ids[$i]);
}
$result = [
'status' => true,
'message' => lang('Logistica.success.successDeleteLines'),
];
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function updateLineasEtiqueta(){
if ($this->request->isAJAX()) {
$id = $this->request->getPost('id') ?? null;
$name = $this->request->getPost('name') ?? null;
$value = $this->request->getPost('value') ?? null;
if ($id == null || $name == null || $value == null) {
return [
'status' => false,
'message' => lang('Logistica.errors.errorMissingData')
];
}
$model = model('App\Models\Etiquetas\EtiquetasTitulosLineasModel');
$model->update($id, [$name => $value]);
$result = [
'status' => true,
'message' => lang('Logistica.success.successUpdateLine'),
];
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
public function updateComentarios(){
if ($this->request->isAJAX()) {
$id = $this->request->getPost('id') ?? null;
$comentarios = $this->request->getPost('comentarios') ?? null;
if ($id == null || $comentarios == null) {
return [
'status' => false,
'message' => lang('Logistica.errors.errorMissingData')
];
}
$model = model('App\Models\Etiquetas\EtiquetasTitulosModel');
$model->update($id, ['comentarios' => $comentarios]);
$result = [
'status' => true,
'message' => lang('Logistica.success.comentariosUpdated'),
];
return $this->response->setJSON($result);
} else {
return $this->failUnauthorized('Invalid request', 403);
}
}
}

View File

@ -753,7 +753,7 @@ return [
"menu_informes" => "Informes",
"menu_pedidos" => "Pedidos",
"menu_pedidos_validacion" => "Validación",
"menu_pedidos_validacion" => "Aprobación",
"menu_pedidos_activos" => "Producción",
"menu_pedidos_finalizados" => "Finalizados",
"menu_pedidos_cancelados" => "Cancelados",

View File

@ -93,6 +93,10 @@ return [
'finalizado' => 'El envío se ha finalizado correctamente',
'finalizadoOTs' => 'El envío se ha finalizado correctamente.\nSe han creado las OTs siguientes OTs: {ots}',
'successDeleteEtiqueta' => 'Etiqueta eliminada correctamente',
'successInsertLines' => 'Lineas de etiqueta insertadas correctamente',
'successDeleteLines' => 'Lineas de etiqueta eliminadas correctamente',
'successUpdateLine' => 'Linea de etiqueta actualizadas correctamente',
'comentariosUpdated' => 'Comentarios actualizados correctamente',
],
];

View File

@ -7,14 +7,14 @@ use App\Entities\Etiquetas\EtiquetaTituloLinea;
class EtiquetasTitulosLineasModel extends Model
{
protected $table = 'etiquetas_titulos_lineas';
protected $primaryKey = 'id';
protected $table = 'etiquetas_titulos_lineas';
protected $primaryKey = 'id';
protected $useAutoIncrement = true;
protected $returnType = EtiquetaTituloLinea::class;
protected $useSoftDeletes = true;
protected $returnType = EtiquetaTituloLinea::class;
protected $useSoftDeletes = true;
protected $allowedFields = [
protected $allowedFields = [
'etiqueta_titulos_id',
'ot_id',
'unidades',
@ -24,16 +24,17 @@ class EtiquetasTitulosLineasModel extends Model
'user_deleted_at',
];
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $useTimestamps = true;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $validationRules = [];
protected $validationRules = [];
protected $validationMessages = [];
protected $skipValidation = false;
protected $skipValidation = false;
protected $beforeDelete = ['addUserDeleted'];
protected $beforeUpdate = ['addUserUpdated'];
protected function addUserDeleted(array $data)
{
@ -46,36 +47,60 @@ class EtiquetasTitulosLineasModel extends Model
if (!empty($data['id'])) {
$builder = $this->builder();
$builder->whereIn($this->primaryKey, (array) $data['id'])
->update(['user_deleted_at' => $userId]);
->update(['user_deleted_at' => $userId]);
}
return $data;
}
public function getDatatableQuery($etiqueta_id, $direccion = null){
protected function addUserUpdated(array $data)
{
$userId = auth()->user()->id;
if (!isset($data['data'])) {
$data['data'] = [];
}
if (!empty($data['id'])) {
$builder = $this->builder();
$builder->whereIn($this->primaryKey, (array) $data['id'])
->update(['user_updated_at' => $userId]);
}
return $data;
}
public function getDatatableQuery($etiqueta_id, $direccion = null)
{
$direccionNormalizada = str_replace(' ', '', strtolower(trim($direccion)));
$direccionSQL = $this->db->escape($direccionNormalizada);
// Subconsulta: suma de pesos por presupuesto
$subPeso = $this->db->table('presupuesto_linea')
->select('presupuesto_id, ROUND(SUM(peso)/1000, 2) as pesoUnidad')
->groupBy('presupuesto_id');
$builder = $this->db->table('etiquetas_titulos_lineas etl')
->select('etl.ot_id as ot, pr.titulo as titulo, etl.unidades as unidades, etl.numero_caja as numero_caja,
pd.cantidad as unidadesTotal, etl.id as id, etl.unidades as unidadesRaw,
(SELECT ROUND(SUM(peso)/1000, 2)
FROM presupuesto_linea
WHERE presupuesto_id = pr.id) AS pesoUnidad')
->select('
etl.ot_id as ot,
pr.titulo as titulo,
etl.unidades as unidades,
etl.numero_caja as numero_caja,
pd.cantidad as unidadesTotal,
etl.id as id,
etl.unidades as unidadesRaw,
peso_sub.pesoUnidad
')
->join('etiquetas_titulos et', 'et.id = etl.etiqueta_titulos_id')
->join('ordenes_trabajo ot', 'ot.id = etl.ot_id')
->join('pedidos p', 'p.id = ot.pedido_id')
->join('pedidos_linea pl', 'pl.pedido_id = p.id')
->join('presupuestos pr', 'pr.id = pl.presupuesto_id')
->join('presupuesto_linea plinea', 'pr.id = plinea.presupuesto_id')
->join("({$subPeso->getCompiledSelect()}) as peso_sub", 'peso_sub.presupuesto_id = pr.id', 'left')
->join('presupuesto_direcciones pd', 'pd.presupuesto_id = pr.id')
->where('etl.deleted_at IS NULL')
->where('et.id', $etiqueta_id)
->where("REPLACE(LOWER(TRIM(pd.direccion)), ' ', '') = $direccionSQL", null, false)
->groupBy('etl.numero_caja');
->where("REPLACE(LOWER(TRIM(pd.direccion)), ' ', '') = '{$direccionNormalizada}'", null, false)
->orderBy('etl.numero_caja');
return $builder;
}
}

View File

@ -35,6 +35,7 @@ class EtiquetasTitulosModel extends Model
protected $beforeDelete = ['addUserDeleted'];
protected $beforeUpdate = ['addUserUpdated'];
protected function addUserDeleted(array $data)
{
@ -52,6 +53,22 @@ class EtiquetasTitulosModel extends Model
return $data;
}
protected function addUserUpdated(array $data)
{
$userId = auth()->user()->id;
if (!isset($data['data'])) {
$data['data'] = [];
}
if (!empty($data['id'])) {
$builder = $this->builder();
$builder->whereIn($this->primaryKey, (array) $data['id'])
->update(['user_updated_at' => $userId]);
}
return $data;
}
public function getEtiquetasTitulos()
{
return $this->db->table('etiquetas_titulos et')

View File

@ -21,13 +21,13 @@ class EtiquetasTitulosService
->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');
->whereIn('p.estado', ['finalizado', 'produccion']);
return $builder;
}
public static function getDireccionesOT($ot_id){
public static function getDireccionesOT($ot_id)
{
$db = \Config\Database::connect();
@ -42,7 +42,6 @@ class EtiquetasTitulosService
->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;
@ -51,7 +50,7 @@ class EtiquetasTitulosService
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');
@ -75,8 +74,8 @@ class EtiquetasTitulosService
'user_created_at' => $data['user_id'],
]);
$etiquetaId = $modelEtiquetasTitulos->getInsertID();
if($etiquetaId == null){
if ($etiquetaId == null) {
return [
'status' => false,
'message' => lang('Logistica.errorInsertarEtiqueta'),
@ -85,23 +84,108 @@ class EtiquetasTitulosService
$cantidad_restante = intval($data['cantidad']);
$numero_caja = 1;
while($cantidad_restante > 0){
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,
'numero_caja' => $numero_caja,
'user_created_at' => $data['user_id'],
]);
$cantidad_restante -= $data['unidades_caja'];
$numero_caja++;
}
return [
'status' => true,
'etiqueta' => $etiquetaId,
];
}
public static function findOTsWithAddress(int $etiqueta_id)
{
$db = \Config\Database::connect();
// 1. Dirección del envío actual
$etiqueta = $db->table('etiquetas_titulos')->select('direccion')->where('id', $etiqueta_id)->get()->getRow();
if (!$etiqueta) {
return $db->table('(SELECT NULL AS id, NULL AS name, NULL as unidades) AS empty')->where('1 = 0');
}
$direccionNormalizada = str_replace(' ', '', strtolower(trim($etiqueta->direccion)));
$direccionSQL = $db->escape($direccionNormalizada);
// 2. Obtener presupuestos con esa dirección
$presupuestosConEsaDireccion = $db->table('presupuesto_direcciones')
->select('presupuesto_id')
->where("REPLACE(LOWER(TRIM(direccion)), ' ', '') = $direccionSQL", null, false)
->get()
->getResultArray();
$presupuestoIds = array_column($presupuestosConEsaDireccion, 'presupuesto_id');
if (empty($presupuestoIds)) {
return $db->table('(SELECT NULL AS id, NULL AS name, NULL as unidades) AS empty')->where('1 = 0');
}
// 3. Subconsulta principal
$subBuilder = $db->table('pedidos_linea pl')
->select("
ot.id AS id,
CONCAT('[', ot.id, '] - ', pr.titulo) AS name,
pd.cantidad AS description
")
->join('pedidos p', 'p.id = pl.pedido_id')
->join('presupuestos pr', 'pr.id = pl.presupuesto_id')
->join('presupuesto_direcciones pd', 'pd.presupuesto_id = pr.id')
->join('ordenes_trabajo ot', 'ot.pedido_id = p.id')
->join('orden_trabajo_dates ot_dates', 'ot_dates.orden_trabajo_id = ot.id')
->whereIn('pr.id', $presupuestoIds)
->whereIn('p.estado', ['finalizado', 'produccion'])
->groupBy('pl.id');
// 4. Envolver y filtrar por unidades pendientes
$builder = $db->table("({$subBuilder->getCompiledSelect(false)}) AS sub");
$builder->select('id, name, description');
return $builder;
}
public static function addLineasEtiqueta($etiqueta_id, $ot_id, $unidades, $cajas)
{
$unidades_caja = intdiv($unidades, $cajas);
$unidades_caja = $unidades_caja == 0 ? $unidades : $unidades_caja;
$unidades_restantes = $unidades;
$modelEtitquetaLinea = model('\App\Models\Etiquetas\EtiquetasTitulosLineasModel');
$next_caja = $modelEtitquetaLinea
->selectMax('numero_caja')
->where('etiqueta_titulos_id', $etiqueta_id)
->first();
$next_caja = $next_caja->numero_caja ?? 0;
$next_caja++;
$user_id = auth()->user()->id;
while($unidades_restantes > 0){
$modelEtitquetaLinea->insert([
'etiqueta_titulos_id' => $etiqueta_id,
'ot_id' => $ot_id,
'unidades' => $unidades_restantes - $unidades_caja < 0 ? $unidades_restantes : intval($unidades_caja),
'numero_caja' => $next_caja,
'user_created_at' => $user_id,
]);
$unidades_restantes -= $unidades_caja;
$next_caja++;
}
return [
'status' => true,
'message' => lang('Logistica.success.successInsertLines'),
];
}
}

View File

@ -166,9 +166,9 @@
<thead>
<tr>
<th></th>
<th><?= lang("Logistica.otId") ?></th>
<th><?= lang("Logistica.titulo") ?></th>
<th><?= lang("Logistica.num_caja") ?></th>
<th style="max-width: 10%;"><?= lang("Logistica.otId") ?></th>
<th style="max-width: 70%;"><?= lang("Logistica.titulo") ?></th>
<th style="max-width: 10%;"><?= lang("Logistica.num_caja") ?></th>
<th class="text-center" style="width: 10%;">
<?= lang("Logistica.unidadesEnCaja") ?>
</th>
@ -178,13 +178,14 @@
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<th colspan="9">
<th colspan="10">
<div class="text-end">
<?= lang("Logistica.unidadesTotalesFooter") ?>
<span id="footer-unidades-envio"></span>
@ -192,7 +193,7 @@
</th>
</tr>
<tr>
<th colspan="9">
<th colspan="10">
<div class="text-end">
<?= lang("Logistica.peso") ?>
<span id="footer-peso"></span>