diff --git a/ci4/app/Config/Routes.php b/ci4/app/Config/Routes.php index ec81df6c..2552a2be 100755 --- a/ci4/app/Config/Routes.php +++ b/ci4/app/Config/Routes.php @@ -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'); }); /* diff --git a/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php b/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php index 229a720b..81a9df16 100644 --- a/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php +++ b/ci4/app/Controllers/Logistica/EtiquetasTitulosController.php @@ -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 ''; } - ); - /*->edit( - "pedido", + ) + ->edit( + "ot", function ($row, $meta) { - return '' . $row->pedido . ''; + return '' . $row->ot . ''; + } + ) + ->edit( + "unidades", + function ($row, $meta) { + return ''; } ) ->edit( - "presupuesto", + "numero_caja", function ($row, $meta) { - return '' . $row->presupuesto . ''; + return ''; } - )->edit( - "unidadesEnvio", - function ($row, $meta) { - if($row->finalizado == 1 || $row->tipo_envio == 'ferro_prototipo'){ - return $row->unidadesEnvio; - } - return ''; + ) + ->add( + "action", + callback: function ($q) { + return ' +
+ '; } - );*/ + ); 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); + } + } } \ No newline at end of file diff --git a/ci4/app/Language/es/App.php b/ci4/app/Language/es/App.php index 417cb626..085766ef 100755 --- a/ci4/app/Language/es/App.php +++ b/ci4/app/Language/es/App.php @@ -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", diff --git a/ci4/app/Language/es/Logistica.php b/ci4/app/Language/es/Logistica.php index c3353c4a..b3fb360a 100755 --- a/ci4/app/Language/es/Logistica.php +++ b/ci4/app/Language/es/Logistica.php @@ -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', ], ]; \ No newline at end of file diff --git a/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php b/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php index 51be469a..aa2f0ff5 100644 --- a/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php +++ b/ci4/app/Models/Etiquetas/EtiquetasTitulosLineasModel.php @@ -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; } + } diff --git a/ci4/app/Models/Etiquetas/EtiquetasTitulosModel.php b/ci4/app/Models/Etiquetas/EtiquetasTitulosModel.php index f253051a..3ad4cec8 100644 --- a/ci4/app/Models/Etiquetas/EtiquetasTitulosModel.php +++ b/ci4/app/Models/Etiquetas/EtiquetasTitulosModel.php @@ -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') diff --git a/ci4/app/Services/EtiquetasTitulosService.php b/ci4/app/Services/EtiquetasTitulosService.php index 092afa6c..bb4aeb15 100644 --- a/ci4/app/Services/EtiquetasTitulosService.php +++ b/ci4/app/Services/EtiquetasTitulosService.php @@ -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'), + ]; + + } } \ No newline at end of file diff --git a/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php b/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php index fa3dabe5..9e4e10d1 100644 --- a/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php +++ b/ci4/app/Views/themes/vuexy/form/logistica/viewEtiquetasTitulosEdit.php @@ -166,9 +166,9 @@