mirror of
https://git.imnavajas.es/jjimenez/safekat.git
synced 2025-07-25 22:52:08 +00:00
Merge branch 'add/finalizar_envios_logistica' into 'main'
Add/finalizar envios logistica See merge request jjimenez/safekat!731
This commit is contained in:
@ -791,7 +791,7 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi
|
||||
|
||||
$routes->get('print/label/test', 'LogisticaController::print_test_label');
|
||||
$routes->get('panel', 'LogisticaController::panel', ['as' => 'LogisticaPanel']);
|
||||
$routes->get('selectEnvios/(:any)', 'LogisticaController::selectorEnvios/$1', ['as' => 'selectEnvios']);
|
||||
$routes->get('envios', 'LogisticaController::gestionEnvios', ['as' => 'gestionEnvios']);
|
||||
$routes->get('buscar/(:any)', 'LogisticaController::searchPedidoOrISBN/$1', ['as' => 'buscarPedidoOrISBN']);
|
||||
$routes->get('datatableEnvios', 'LogisticaController::datatable_envios');
|
||||
$routes->get('datatableLineasEnvios/(:num)', 'LogisticaController::datatable_enviosEdit/$1');
|
||||
@ -803,6 +803,10 @@ $routes->group('logistica', ['namespace' => 'App\Controllers\Logistica'], functi
|
||||
$routes->post('updateLineaEnvio', 'LogisticaController::updateLineaEnvio');
|
||||
$routes->post('updateComentariosEnvio', 'LogisticaController::saveComments');
|
||||
$routes->post('updateCajasEnvio', 'LogisticaController::updateCajasEnvio');
|
||||
$routes->post('updateCodigoSeguimiento', 'LogisticaController::updateCodigoSeguimiento');
|
||||
$routes->post('updateProveedorEnvio', 'LogisticaController::updateProveedorEnvio');
|
||||
$routes->post('finalizarEnvio', 'LogisticaController::finalizarEnvio');
|
||||
$routes->post('generateEnvio', 'LogisticaController::generarEnvio');
|
||||
});
|
||||
|
||||
/*
|
||||
|
||||
@ -19,6 +19,7 @@ $routes->group('compras', ['namespace' => 'App\Controllers\Compras'], function (
|
||||
$routes->get('delete/(:num)', 'Proveedores::delete/$1', ['as' => 'deleteProveedores']);
|
||||
$routes->post('allmenuitems', 'Proveedores::allItemsSelect', ['as' => 'select2ItemsOfProveedores']);
|
||||
$routes->post('menuitems', 'Proveedores::menuItems', ['as' => 'menuItemsOfProveedores']);
|
||||
$routes->get('getProveedores', 'Proveedores::getForSelect');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -383,4 +383,26 @@ class Proveedores extends \App\Controllers\BaseResourceController {
|
||||
}
|
||||
}
|
||||
|
||||
public function getForSelect(){
|
||||
|
||||
if ($this->request->isAJAX()) {
|
||||
$tipo_id = $this->request->getGet("tipo_id");
|
||||
$query = $this->model->builder()->select(
|
||||
[
|
||||
"id",
|
||||
"nombre as name"
|
||||
]
|
||||
)->where('tipo_id', $tipo_id)->where('deleted_at', null)->orderBy("nombre", "asc");
|
||||
if ($this->request->getGet("q")) {
|
||||
$query->groupStart()
|
||||
->orLike("lg_proveedores.nombre", $this->request->getGet("q"))
|
||||
->groupEnd();
|
||||
}
|
||||
|
||||
return $this->response->setJSON($query->get()->getResultObject());
|
||||
} else {
|
||||
return $this->failUnauthorized('Invalid request', 403);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -29,7 +29,7 @@ class LogisticaController extends BaseController
|
||||
|
||||
// Breadcrumbs
|
||||
$this->viewData['breadcrumb'] = [
|
||||
['title' => lang("App.menu_logistica"), 'route' => "javascript:void(0);", 'active' => false],
|
||||
['title' => lang("App.menu_logistica"), 'route' => route_to("LogisticaPanel"), 'active' => false],
|
||||
];
|
||||
|
||||
|
||||
@ -56,13 +56,12 @@ class LogisticaController extends BaseController
|
||||
return view(static::$viewPath . 'viewPanelLogistica', $viewData);
|
||||
}
|
||||
|
||||
public function selectorEnvios($tipoEnvio = null)
|
||||
public function gestionEnvios()
|
||||
{
|
||||
$viewData = [
|
||||
'currentModule' => static::$controllerSlug,
|
||||
'boxTitle' => lang('Logistica.envioSimpleMultiple'),
|
||||
'boxTitle' => lang('Logistica.gestionEnvios'),
|
||||
'usingServerSideDataTable' => true,
|
||||
'tipoEnvio' => $tipoEnvio,
|
||||
];
|
||||
|
||||
$viewData = array_merge($this->viewData, $viewData); // merge any possible values from the parent controller class
|
||||
@ -84,6 +83,20 @@ class LogisticaController extends BaseController
|
||||
return $this->response->setJSON($result);
|
||||
}
|
||||
|
||||
|
||||
public function generarEnvio()
|
||||
{
|
||||
if ($this->request->isAJAX()) {
|
||||
|
||||
$pedido_id = $this->request->getPost('pedido_id');
|
||||
$direccion = $this->request->getPost('direccion');
|
||||
$result = LogisticaService::generateEnvio($pedido_id, $direccion);
|
||||
return $this->response->setJSON($result);
|
||||
} else {
|
||||
return $this->failUnauthorized('Invalid request', 403);
|
||||
}
|
||||
}
|
||||
|
||||
public function selectAddEnvioLinea()
|
||||
{
|
||||
|
||||
@ -164,6 +177,16 @@ class LogisticaController extends BaseController
|
||||
return redirect()->to(base_url('logistica/selectEnvios/simple'))->with('error', lang('Logistica.errors.noEnvio'));
|
||||
}
|
||||
|
||||
$modelProveedor = model('App\Models\Compras\ProveedorModel');
|
||||
$proveedor = $modelProveedor->select('id, nombre')
|
||||
->where('deleted_at', null)
|
||||
->where('id', $envioEntity->proveedor_id)
|
||||
->orderBy('nombre', 'asc')
|
||||
->first();
|
||||
if(!empty($proveedor)){
|
||||
$envioEntity->proveedor_nombre = $proveedor->nombre;
|
||||
}
|
||||
|
||||
$viewData = [
|
||||
'currentModule' => static::$controllerSlug,
|
||||
'boxTitle' => '<i class="ti ti-truck ti-xl"></i>' . ' ' . lang('Logistica.envio') . ' [' . $envioEntity->id . ']: ' . $envioEntity->direccion,
|
||||
@ -193,6 +216,21 @@ class LogisticaController extends BaseController
|
||||
}
|
||||
}
|
||||
|
||||
public function finalizarEnvio()
|
||||
{
|
||||
if ($this->request->isAJAX()) {
|
||||
|
||||
$id = $this->request->getPost('id') ?? null;
|
||||
$finalizar_ots = $this->request->getPost('finalizar_ots') ?? false;
|
||||
|
||||
$result = LogisticaService::finalizarEnvio($id, $finalizar_ots);
|
||||
return $this->response->setJSON($result);
|
||||
} else {
|
||||
return $this->failUnauthorized('Invalid request', 403);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function datatable_enviosEdit($idEnvio)
|
||||
{
|
||||
$model = model('App\Models\Logistica\EnvioLineaModel');
|
||||
@ -217,23 +255,16 @@ class LogisticaController extends BaseController
|
||||
function ($row, $meta) {
|
||||
return '<a href="' . base_url('presupuestoadmin/edit/' . $row->presupuesto) . '" target="_blank">' . $row->presupuesto . '</a>';
|
||||
}
|
||||
)
|
||||
->edit(
|
||||
"cajas",
|
||||
function ($row, $meta) {
|
||||
return '<input type="number" class="form-control input-lineas input-cajas text-center"
|
||||
data-id="'. $row->id.'" data-name="cajas" value="' . $row->cajas . '">';
|
||||
}
|
||||
)->edit(
|
||||
"unidadesEnvio",
|
||||
function ($row, $meta) {
|
||||
if($row->finalizado == 1){
|
||||
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 . '">';
|
||||
}
|
||||
)
|
||||
->edit('cajasRaw', function ($row) {
|
||||
return is_null($row->cajas) ? '__SIN__ASIGNAR__' : $row->cajas;
|
||||
});
|
||||
);
|
||||
|
||||
return $result->toJson(returnAsObject: true);
|
||||
}
|
||||
@ -296,6 +327,52 @@ class LogisticaController extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateCodigoSeguimiento()
|
||||
{
|
||||
$id = $this->request->getPost('id');
|
||||
$fieldValue = $this->request->getPost('codigo_seguimiento');
|
||||
|
||||
if (!$id) {
|
||||
return $this->response->setJSON([
|
||||
'status' => false,
|
||||
'message' => 'Datos inválidos'
|
||||
]);
|
||||
}
|
||||
|
||||
$model = model('App\Models\Logistica\EnvioModel');
|
||||
$updated = $model->update($id, [
|
||||
"codigo_seguimiento" => $fieldValue==""? null: $fieldValue,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => $updated,
|
||||
'message' => $updated ? 'Actualizado' : 'Error al actualizar'
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateProveedorEnvio()
|
||||
{
|
||||
$id = $this->request->getPost('id');
|
||||
$fieldValue = $this->request->getPost('proveedor_id');
|
||||
|
||||
if (!$id) {
|
||||
return $this->response->setJSON([
|
||||
'status' => false,
|
||||
'message' => 'Datos inválidos'
|
||||
]);
|
||||
}
|
||||
|
||||
$model = model('App\Models\Logistica\EnvioModel');
|
||||
$updated = $model->update($id, [
|
||||
"proveedor_id" => $fieldValue==""? null: $fieldValue,
|
||||
]);
|
||||
|
||||
return $this->response->setJSON([
|
||||
'status' => $updated,
|
||||
'message' => $updated ? 'Actualizado' : 'Error al actualizar'
|
||||
]);
|
||||
}
|
||||
|
||||
public function saveComments()
|
||||
{
|
||||
$id = $this->request->getPost('id');
|
||||
|
||||
@ -2,13 +2,11 @@
|
||||
return [
|
||||
'logistica' => 'Logística',
|
||||
'panel' => 'Panel',
|
||||
'envioSimple' => 'Envío simple',
|
||||
'envioMultiple' => 'Envío múltiple',
|
||||
'envioConjunto' => 'Envío conjunto',
|
||||
'gestionEnvios' => 'Gestión de Envíos de pedidos',
|
||||
'etiquetasTitulos' => 'Etiquetas de títulos',
|
||||
'etiquetasEnvio' => 'Etiquetas de envío',
|
||||
'envioFerros' => 'Envío de ferros',
|
||||
'cerrarOTauto' => 'Cerrar OT automáticamente',
|
||||
'envioFerros' => 'Gestión de Envíos de ferros/prototipos',
|
||||
'albaranes' => 'Albaranes',
|
||||
'envioSimpleMultiple' => 'Envío simple/múltiple',
|
||||
'nuevoEnvio' => 'Nuevo envío',
|
||||
'buscadorPedidosTitle' => 'Código Pedido o ISBN',
|
||||
@ -58,11 +56,21 @@ return [
|
||||
'peso' => 'Peso (kg): ',
|
||||
'unidadesTotalesFooter' => 'Unidades:',
|
||||
|
||||
'codigoSeguimiento' => 'Código de seguimiento',
|
||||
'empresaMensajería' => 'Empresa de mensajería',
|
||||
'finalizarEnvio' => 'Finalizar envío',
|
||||
'finalizarEnvioYOTs' => 'Finalizar envío y OTS',
|
||||
|
||||
'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 aún no se ha finalizado o no tiene envíos pendientes',
|
||||
'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',
|
||||
],
|
||||
'success' => [
|
||||
'finalizado' => 'El envío se ha finalizado correctamente',
|
||||
'finalizadoOTs' => 'El envío se ha finalizado correctamente.\nSe han creado las OTs siguientes OTs: {ots}',
|
||||
],
|
||||
|
||||
];
|
||||
@ -40,19 +40,24 @@ class EnvioLineaModel extends Model
|
||||
t1.unidades_total as unidadesTotal,
|
||||
IFNULL((
|
||||
SELECT SUM(t_sub.unidades_envio)
|
||||
FROM " . $this->table . " t_sub
|
||||
FROM envios_lineas t_sub
|
||||
JOIN envios e ON e.id = t_sub.envio_id
|
||||
JOIN presupuesto_direcciones d ON d.presupuesto_id = t_sub.presupuesto_id
|
||||
WHERE e.finalizado = 1
|
||||
AND t_sub.pedido_id = t1.pedido_id
|
||||
AND e.direccion = d.direccion COLLATE utf8mb3_general_ci
|
||||
), 0) as unidadesEnviadas,
|
||||
AND e.direccion = t2.direccion COLLATE utf8mb3_general_ci
|
||||
AND (
|
||||
t_sub.envio_id <> t1.envio_id
|
||||
OR (t_sub.envio_id = t1.envio_id AND e.finalizado = 1)
|
||||
)
|
||||
), 0) AS unidadesEnviadas,
|
||||
IFNULL((
|
||||
SELECT ROUND(SUM(peso) / 1000, 1)
|
||||
FROM presupuesto_linea
|
||||
WHERE presupuesto_id = t3.id
|
||||
), 0) AS pesoUnidad"
|
||||
), 0) AS pesoUnidad,
|
||||
t2.finalizado as finalizado,"
|
||||
);
|
||||
$builder->join("envios t2", "t1.envio_id = t2.id", "left");
|
||||
$builder->join("presupuestos t3", "t1.presupuesto_id = t3.id", "left");
|
||||
|
||||
$builder->where("t1.envio_id", $envio_id);
|
||||
@ -60,5 +65,5 @@ class EnvioLineaModel extends Model
|
||||
return $builder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
use App\Services\ProductionService;
|
||||
|
||||
use Config\Services;
|
||||
|
||||
@ -9,6 +10,7 @@ class LogisticaService
|
||||
public static function findPedidoOrISBN($search)
|
||||
{
|
||||
$multienvio = false;
|
||||
$direcciones = [];
|
||||
|
||||
$modelPedido = model('App\Models\Pedidos\PedidoModel');
|
||||
|
||||
@ -31,13 +33,14 @@ class LogisticaService
|
||||
|
||||
$builder->groupStart()
|
||||
->where('pedidos.id', $search)
|
||||
->whereIn('pedidos.estado', ['finalizado'])
|
||||
->whereIn('pedidos.estado', ['finalizado', 'produccion'])
|
||||
->orWhere("REPLACE(presupuestos.isbn, '-', '')", $searchClean)
|
||||
->groupEnd();
|
||||
|
||||
$builder->groupBy('pedidos_linea.id');
|
||||
$builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < cantidad_linea', null, false);
|
||||
|
||||
|
||||
$result = $builder->get()->getResult();
|
||||
|
||||
if (empty($result)) {
|
||||
@ -59,6 +62,21 @@ class LogisticaService
|
||||
return $response;
|
||||
} else if ($numDirecciones > 1) {
|
||||
$multienvio = true;
|
||||
$dirs = $PresupuestoDireccionesModel->select('direccion')->where('presupuesto_id', $result[0]->presupuesto_id)
|
||||
->findAll();
|
||||
foreach ($dirs as $key => $direccion) {
|
||||
$modelEnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
|
||||
$unidades_en_direccion = $modelEnvioLineasModel->select('SUM(envios_lineas.unidades_envio) as unidades_enviadas,
|
||||
envios_lineas.unidades_total')
|
||||
->join('envios', 'envios.id = envios_lineas.envio_id')
|
||||
->where('pedido_id', $result[0]->pedido_id)
|
||||
->where('envios.direccion', $direccion->direccion)
|
||||
->where('envios.finalizado', 1)
|
||||
->groupBy('pedido_id')->get()->getResult();
|
||||
if (count($unidades_en_direccion) == 0 || $unidades_en_direccion[0]->unidades_enviadas < $unidades_en_direccion[0]->unidades_total) {
|
||||
array_push($direcciones, $direccion->direccion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$response = [
|
||||
@ -66,8 +84,18 @@ class LogisticaService
|
||||
'data' => $result[0],
|
||||
];
|
||||
|
||||
if ($multienvio) {
|
||||
$response_envio = [
|
||||
'status' => true,
|
||||
'multienvio' => true,
|
||||
'direcciones' => $direcciones,
|
||||
'pedido_id' => $result[0]->pedido_id,
|
||||
];
|
||||
return $response_envio;
|
||||
}
|
||||
|
||||
$response_envio = LogisticaService::generateEnvio($result[0]->pedido_id, $multienvio);
|
||||
|
||||
$response_envio = LogisticaService::generateEnvio($result[0]->pedido_id);
|
||||
if ($response_envio['status'] == false) {
|
||||
$response = [
|
||||
'status' => false,
|
||||
@ -83,84 +111,113 @@ class LogisticaService
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function findLineaEnvioPorEnvio(int $envio_id)
|
||||
{
|
||||
$db = \Config\Database::connect();
|
||||
$subCliente = $db->table('envios')
|
||||
->select('cliente_id')
|
||||
->where('id', $envio_id)
|
||||
->getCompiledSelect();
|
||||
|
||||
$builder = $db->table('envios e_main');
|
||||
// 1. Obtener dirección del envío actual
|
||||
$envio = $db->table('envios')->select('direccion')->where('id', $envio_id)->get()->getRow();
|
||||
if (!$envio) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$builder->select("
|
||||
CONCAT('[', p.id, '] - ', pr.titulo) AS name,
|
||||
pl.id AS id,
|
||||
pl.cantidad,
|
||||
(
|
||||
SELECT IFNULL(SUM(el.unidades_envio), 0)
|
||||
FROM envios_lineas el
|
||||
JOIN envios e ON e.id = el.envio_id
|
||||
WHERE el.pedido_id = p.id
|
||||
AND e.direccion = e_main.direccion
|
||||
AND pr.cliente_id = ($subCliente)
|
||||
) AS unidades_enviadas,
|
||||
(
|
||||
pl.cantidad - (
|
||||
SELECT IFNULL(SUM(el2.unidades_envio), 0)
|
||||
FROM envios_lineas el2
|
||||
JOIN envios e2 ON e2.id = el2.envio_id
|
||||
WHERE el2.pedido_id = p.id
|
||||
AND e2.direccion = e_main.direccion
|
||||
AND pr.cliente_id = ($subCliente)
|
||||
)
|
||||
) AS unidades_pendientes
|
||||
");
|
||||
$direccionNormalizada = str_replace(' ', '', strtolower(trim($envio->direccion)));
|
||||
$direccionSQL = $db->escape($direccionNormalizada);
|
||||
|
||||
$builder->join('pedidos_linea pl', '1=1'); // para incluir líneas sin envío aún
|
||||
$builder->join('pedidos p', 'p.id = pl.pedido_id');
|
||||
$builder->join('presupuestos pr', 'pr.id = pl.presupuesto_id');
|
||||
$builder->where('e_main.id', $envio_id);
|
||||
$builder->where('p.estado', 'finalizado');
|
||||
$builder->where("pr.cliente_id = ($subCliente)", null, false);
|
||||
// 2. Obtener los presupuesto_id asociados a esa dirección
|
||||
$presupuestosConEsaDireccion = $db->table('presupuesto_direcciones')
|
||||
->select('presupuesto_id')
|
||||
->where("REPLACE(LOWER(TRIM(direccion)), ' ', '') = $direccionSQL", null, false)
|
||||
->get()
|
||||
->getResultArray();
|
||||
|
||||
$builder->having('unidades_pendientes >', 0);
|
||||
$presupuestoIds = array_column($presupuestosConEsaDireccion, 'presupuesto_id');
|
||||
if (empty($presupuestoIds)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// 3. Subconsulta principal con unidades pendientes
|
||||
$subBuilder = $db->table('pedidos_linea pl')
|
||||
->select("
|
||||
pl.id AS id,
|
||||
CONCAT('[', p.id, '] - ', pr.titulo) AS name,
|
||||
(
|
||||
SELECT IFNULL(SUM(el.unidades_envio), 0)
|
||||
FROM envios_lineas el
|
||||
JOIN envios e ON e.id = el.envio_id
|
||||
WHERE el.pedido_id = p.id
|
||||
AND el.presupuesto_id = pr.id
|
||||
AND REPLACE(LOWER(TRIM(e.direccion)), ' ', '') = $direccionSQL
|
||||
AND (e.finalizado = 1 OR e.id = $envio_id)
|
||||
) AS unidades_enviadas,
|
||||
pd.cantidad AS cantidad
|
||||
")
|
||||
->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')
|
||||
->whereIn('pr.id', $presupuestoIds)
|
||||
->whereIn('p.estado', ['finalizado', 'produccion'])
|
||||
->where("REPLACE(LOWER(TRIM(pd.direccion)), ' ', '') = $direccionSQL", null, false)
|
||||
->groupBy('pl.id');
|
||||
|
||||
// 4. Envolver y filtrar por unidades pendientes reales
|
||||
$builder = $db->table("({$subBuilder->getCompiledSelect(false)}) AS sub");
|
||||
$builder->select('id, name');
|
||||
$builder->where('cantidad > unidades_enviadas');
|
||||
$builder->orderBy('name', 'ASC');
|
||||
|
||||
return $builder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static function addLineaEnvio($envio_id = null, $pedido_id = null, $direccion = null)
|
||||
{
|
||||
$modelPedido = model('App\Models\Pedidos\PedidoModel');
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
$builder = $modelPedido->builder();
|
||||
$direccionNormalizada = strtolower(trim($direccion));
|
||||
|
||||
$builder->select("
|
||||
pedidos.id as pedido_id,
|
||||
pedidos_linea.id as linea_id,
|
||||
pedidos_linea.cantidad as total_unidades,
|
||||
(
|
||||
SELECT IFNULL(SUM(el.unidades_envio), 0)
|
||||
FROM envios_lineas el
|
||||
JOIN envios e ON e.id = el.envio_id
|
||||
WHERE el.pedido_id = pedidos.id
|
||||
AND e.finalizado = 1
|
||||
AND TRIM(e.direccion) = '" . addslashes(trim($direccion)) . "'
|
||||
) as unidades_enviadas,
|
||||
pedidos_linea.cantidad - IFNULL(SUM(envios_lineas.unidades_envio), 0) as unidades_envio,
|
||||
presupuestos.id as presupuesto_id
|
||||
");
|
||||
|
||||
$builder->join('pedidos_linea', 'pedidos_linea.pedido_id = pedidos.id', 'left');
|
||||
$builder->join('presupuestos', 'presupuestos.id = pedidos_linea.presupuesto_id', 'left');
|
||||
$builder->join('envios_lineas', 'envios_lineas.pedido_id = pedidos_linea.pedido_id', 'left');
|
||||
|
||||
$builder->groupBy('pedidos_linea.id');
|
||||
$builder->having('IFNULL(SUM(envios_lineas.unidades_envio), 0) < pedidos_linea.cantidad', null, false);
|
||||
$builder->where('pedidos.estado', 'finalizado');
|
||||
$builder->where('pedidos.id', $pedido_id);
|
||||
// 1. Obtener presupuesto_id y cantidad desde presupuesto_direcciones
|
||||
$builder = $db->table('pedidos_linea pl')
|
||||
->select("
|
||||
p.id AS pedido_id,
|
||||
pl.id AS linea_id,
|
||||
pr.id AS presupuesto_id,
|
||||
pd.cantidad AS total_unidades,
|
||||
|
||||
(
|
||||
SELECT IFNULL(SUM(el.unidades_envio), 0)
|
||||
FROM envios_lineas el
|
||||
JOIN envios e ON e.id = el.envio_id
|
||||
WHERE el.pedido_id = p.id
|
||||
AND el.presupuesto_id = pr.id
|
||||
AND TRIM(LOWER(e.direccion)) = '$direccionNormalizada'
|
||||
AND (e.finalizado = 1 OR e.id = $envio_id)
|
||||
) AS unidades_enviadas,
|
||||
|
||||
(
|
||||
pd.cantidad - (
|
||||
SELECT IFNULL(SUM(el2.unidades_envio), 0)
|
||||
FROM envios_lineas el2
|
||||
JOIN envios e2 ON e2.id = el2.envio_id
|
||||
WHERE el2.pedido_id = p.id
|
||||
AND el2.presupuesto_id = pr.id
|
||||
AND TRIM(LOWER(e2.direccion)) = '$direccionNormalizada'
|
||||
AND (e2.finalizado = 1 OR e2.id = $envio_id)
|
||||
)
|
||||
) AS unidades_envio
|
||||
")
|
||||
->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')
|
||||
->where('p.id', $pedido_id)
|
||||
->whereIn('p.estado', ['finalizado', 'produccion'])
|
||||
->where("TRIM(LOWER(pd.direccion)) = '$direccionNormalizada'", null, false)
|
||||
->groupBy('pl.id');
|
||||
|
||||
$result = $builder->get()->getResultObject();
|
||||
|
||||
@ -169,119 +226,216 @@ class LogisticaService
|
||||
'status' => false,
|
||||
'message' => lang('Logistica.errors.notFound'),
|
||||
];
|
||||
} else {
|
||||
}
|
||||
|
||||
$r = $result[0];
|
||||
|
||||
// 2. Insertar solo si hay unidades a enviar
|
||||
if ($r->unidades_envio > 0) {
|
||||
$EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
|
||||
$EnvioLineasModel->save([
|
||||
'envio_id' => $envio_id,
|
||||
'pedido_id' => $result[0]->pedido_id,
|
||||
'unidades_envio' => $result[0]->unidades_envio,
|
||||
'unidades_total' => $result[0]->total_unidades,
|
||||
'pedido_id' => $r->pedido_id,
|
||||
'presupuesto_id' => $r->presupuesto_id,
|
||||
'unidades_envio' => $r->unidades_envio,
|
||||
'unidades_total' => $r->total_unidades,
|
||||
'cajas' => null,
|
||||
'unidades_cajas' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
'presupuesto_id' => $result[0]->presupuesto_id,
|
||||
]);
|
||||
}
|
||||
|
||||
return [
|
||||
'status' => true,
|
||||
'data' => [
|
||||
'unidades_envio' => $result[0]->unidades_envio,
|
||||
'unidades_enviadas' => $result[0]->unidades_enviadas,
|
||||
'total_unidades' => $result[0]->total_unidades,
|
||||
'unidades_envio' => $r->unidades_envio,
|
||||
'unidades_enviadas' => $r->unidades_enviadas,
|
||||
'total_unidades' => $r->total_unidades,
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static function generateEnvio($pedido_id, $multienvio = false)
|
||||
public static function generateEnvio($pedido_id, $direccion = null)
|
||||
{
|
||||
|
||||
$presupuestoDireccionesModel = model('App\Models\Presupuestos\PresupuestoDireccionesModel');
|
||||
$direccionNormalizada = strtolower(trim($direccion));
|
||||
|
||||
if (!$multienvio) {
|
||||
// solo hay una dirección, se obtiene de los albaranes
|
||||
// Consulta con cálculo exacto de unidades pendientes por dirección
|
||||
$datosEnvio = $presupuestoDireccionesModel
|
||||
->select("
|
||||
presupuestos.id as presupuesto_id,
|
||||
presupuesto_direcciones.att,
|
||||
presupuesto_direcciones.direccion,
|
||||
presupuesto_direcciones.provincia as ciudad,
|
||||
presupuesto_direcciones.cp,
|
||||
presupuesto_direcciones.telefono,
|
||||
presupuesto_direcciones.email,
|
||||
presupuesto_direcciones.pais_id,
|
||||
presupuesto_direcciones.cantidad as cantidad_total,
|
||||
presupuestos.cliente_id as cliente_id,
|
||||
|
||||
$datosEnvio = $presupuestoDireccionesModel
|
||||
->select('
|
||||
presupuestos.id as presupuesto_id,
|
||||
presupuesto_direcciones.att,
|
||||
presupuesto_direcciones.direccion,
|
||||
presupuesto_direcciones.provincia as ciudad,
|
||||
presupuesto_direcciones.cp,
|
||||
presupuesto_direcciones.telefono,
|
||||
presupuesto_direcciones.email,
|
||||
presupuesto_direcciones.pais_id,
|
||||
presupuesto_direcciones.cantidad - IFNULL(SUM(envios_lineas.unidades_envio), 0) as cantidad,
|
||||
presupuesto_direcciones.cantidad as cantidad_total,
|
||||
presupuestos.cliente_id as cliente_id
|
||||
')
|
||||
->join('pedidos_linea', 'pedidos_linea.presupuesto_id = presupuesto_direcciones.presupuesto_id')
|
||||
->join('pedidos', 'pedidos.id = pedidos_linea.pedido_id')
|
||||
->join('presupuestos', 'pedidos_linea.presupuesto_id = presupuestos.id')
|
||||
->join('envios_lineas', 'envios_lineas.pedido_id = pedidos.id', 'left')
|
||||
->join('envios', 'envios.id = envios_lineas.envio_id', 'left')
|
||||
->where('pedidos.id', $pedido_id)
|
||||
->groupBy('presupuesto_direcciones.id') // Necesario por el uso de SUM
|
||||
->first();
|
||||
(
|
||||
presupuesto_direcciones.cantidad - IFNULL((
|
||||
SELECT SUM(el.unidades_envio)
|
||||
FROM envios_lineas el
|
||||
JOIN envios e ON e.id = el.envio_id
|
||||
WHERE el.pedido_id = pedidos.id
|
||||
AND el.presupuesto_id = presupuestos.id
|
||||
AND TRIM(LOWER(e.direccion)) = '$direccionNormalizada'
|
||||
AND e.finalizado = 1
|
||||
), 0)
|
||||
) as cantidad
|
||||
")
|
||||
->join('pedidos_linea', 'pedidos_linea.presupuesto_id = presupuesto_direcciones.presupuesto_id')
|
||||
->join('pedidos', 'pedidos.id = pedidos_linea.pedido_id')
|
||||
->join('presupuestos', 'pedidos_linea.presupuesto_id = presupuestos.id')
|
||||
->where('pedidos.id', $pedido_id)
|
||||
->where("TRIM(LOWER(presupuesto_direcciones.direccion)) = '$direccionNormalizada'", null, false)
|
||||
->groupBy('presupuesto_direcciones.id')
|
||||
->first();
|
||||
|
||||
|
||||
// se genera un nuevo envio con estos datos
|
||||
$EnvioModel = model('App\Models\Logistica\EnvioModel');
|
||||
$EnvioModel->set('cliente_id', $datosEnvio->cliente_id);
|
||||
$EnvioModel->set('att', $datosEnvio->att);
|
||||
$EnvioModel->set('direccion', $datosEnvio->direccion);
|
||||
$EnvioModel->set('ciudad', $datosEnvio->ciudad);
|
||||
$EnvioModel->set('cp', $datosEnvio->cp);
|
||||
$EnvioModel->set('telefono', $datosEnvio->telefono);
|
||||
$EnvioModel->set('email', $datosEnvio->email);
|
||||
$EnvioModel->set('pais_id', $datosEnvio->pais_id);
|
||||
$EnvioModel->set('cantidad', $datosEnvio->cantidad);
|
||||
$EnvioModel->set('cajas', 1);
|
||||
$EnvioModel->set('multienvio', $multienvio ? 1 : 0);
|
||||
$EnvioModel->set('created_at', date('Y-m-d H:i:s'));
|
||||
$EnvioModel->set('updated_at', date('Y-m-d H:i:s'));
|
||||
$EnvioModel->insert();
|
||||
$idEnvio = $EnvioModel->insertID();
|
||||
|
||||
// se genera la linea de envio
|
||||
$EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
|
||||
$EnvioLineasModel->save([
|
||||
'envio_id' => $idEnvio,
|
||||
'pedido_id' => $pedido_id,
|
||||
'unidades_envio' => $datosEnvio->cantidad,
|
||||
'unidades_total' => $datosEnvio->cantidad_total,
|
||||
'cajas' => 1,
|
||||
'unidades_cajas' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
'presupuesto_id' => (int) $datosEnvio->presupuesto_id
|
||||
]);
|
||||
|
||||
|
||||
|
||||
return [
|
||||
'status' => true,
|
||||
'data' => [
|
||||
'id_envio' => $idEnvio,
|
||||
'multienvio' => false,
|
||||
],
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
if (empty($datosEnvio)) {
|
||||
// Validación si no hay datos o no quedan unidades
|
||||
if (empty($datosEnvio) || $datosEnvio->cantidad <= 0) {
|
||||
return [
|
||||
'status' => false,
|
||||
'message' => lang('Logistica.errors.noAddresses'),
|
||||
'message' => lang('Logistica.errors.noAddresses') . ' o no hay unidades pendientes.',
|
||||
];
|
||||
}
|
||||
|
||||
// Crear envío
|
||||
$EnvioModel = model('App\Models\Logistica\EnvioModel');
|
||||
$EnvioModel->set([
|
||||
'cliente_id' => $datosEnvio->cliente_id,
|
||||
'att' => $datosEnvio->att,
|
||||
'direccion' => $datosEnvio->direccion,
|
||||
'ciudad' => $datosEnvio->ciudad,
|
||||
'cp' => $datosEnvio->cp,
|
||||
'telefono' => $datosEnvio->telefono,
|
||||
'email' => $datosEnvio->email,
|
||||
'pais_id' => $datosEnvio->pais_id,
|
||||
'cantidad' => $datosEnvio->cantidad,
|
||||
'cajas' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
$EnvioModel->insert();
|
||||
$idEnvio = $EnvioModel->insertID();
|
||||
|
||||
// Crear línea de envío
|
||||
$EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
|
||||
$EnvioLineasModel->save([
|
||||
'envio_id' => $idEnvio,
|
||||
'pedido_id' => $pedido_id,
|
||||
'unidades_envio' => $datosEnvio->cantidad,
|
||||
'unidades_total' => $datosEnvio->cantidad_total,
|
||||
'cajas' => 1,
|
||||
'unidades_cajas' => 1,
|
||||
'created_at' => date('Y-m-d H:i:s'),
|
||||
'updated_at' => date('Y-m-d H:i:s'),
|
||||
'created_by' => auth()->user()->id,
|
||||
'updated_by' => auth()->user()->id,
|
||||
'presupuesto_id' => (int) $datosEnvio->presupuesto_id
|
||||
]);
|
||||
|
||||
return [
|
||||
'status' => true,
|
||||
'data' => [
|
||||
'id_envio' => $idEnvio,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static function finalizarEnvio($envio_id, $finalizar_ot = false)
|
||||
{
|
||||
// hay que comprobar que para todas las lineas de envio de este envio
|
||||
// se ha enviado toda la cantidad teniendo en cuenta otros envios
|
||||
$EnvioModel = model('App\Models\Logistica\EnvioModel');
|
||||
$EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
|
||||
|
||||
$ots = [];
|
||||
|
||||
$envio = $EnvioModel->find($envio_id);
|
||||
if (empty($envio)) {
|
||||
return [
|
||||
'status' => false,
|
||||
'message' => lang('Logistica.errors.noEnvio'),
|
||||
];
|
||||
}
|
||||
$lineasEnvio = $EnvioLineasModel->where('envio_id', $envio_id)
|
||||
->findAll();
|
||||
if (empty($lineasEnvio)) {
|
||||
return [
|
||||
'status' => false,
|
||||
'message' => lang('Logistica.errors.noEnvioLineas'),
|
||||
];
|
||||
}
|
||||
|
||||
foreach ($lineasEnvio as $linea) {
|
||||
|
||||
$pedido = model('App\Models\Pedidos\PedidoModel')->find($linea->pedido_id);
|
||||
if (empty($pedido)) {
|
||||
return [
|
||||
'status' => false,
|
||||
'message' => lang('Logistica.errors.notFound'),
|
||||
];
|
||||
}
|
||||
$cantidad_enviada = $EnvioLineasModel->select('SUM(envios_lineas.unidades_envio) as unidades_enviadas')
|
||||
->where('envios_lineas.pedido_id', $linea->pedido_id)
|
||||
->where('envios_lineas.envio_id !=', $envio_id)
|
||||
->where('envios.finalizado', 1)
|
||||
->join('envios', 'envios.id = envios_lineas.envio_id')
|
||||
->get()->getResult();
|
||||
|
||||
if (
|
||||
count($cantidad_enviada) == 0 ||
|
||||
empty($cantidad_enviada[0]->unidades_enviadas) ||
|
||||
$cantidad_enviada[0]->unidades_enviadas == null
|
||||
) {
|
||||
$cantidad_enviada = 0;
|
||||
} else {
|
||||
$cantidad_enviada = $cantidad_enviada[0]->unidades_enviadas;
|
||||
}
|
||||
|
||||
if ($cantidad_enviada + $linea->unidades_envio == $pedido->total_tirada) {
|
||||
$otModel = model('App\Models\OrdenTrabajo\OrdenTrabajoModel');
|
||||
$ot = $otModel->where('pedido_id', $linea->pedido_id)
|
||||
->first();
|
||||
$ps = (new ProductionService())->init($ot->id);
|
||||
$ps->updateOrdenTrabajoDate([
|
||||
"name" => "envio_at",
|
||||
"envio_at" => date('Y-m-d H:i:s')
|
||||
]);
|
||||
if ($finalizar_ot) {
|
||||
$ps->updateOrdenTrabajo(
|
||||
[
|
||||
"estado" => 'F'
|
||||
]
|
||||
);
|
||||
array_push($ots, $ot->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$EnvioModel->update($envio_id, ['finalizado' => 1]);
|
||||
|
||||
$data_return = [
|
||||
'status' => true,
|
||||
'message' => lang('Logistica.success.finalizado'),
|
||||
];
|
||||
|
||||
if ($finalizar_ot) {
|
||||
$data_return['message'] = lang('Logistica.success.finalizadoOTs', [
|
||||
'ots' => implode(', ', $ots)
|
||||
]);
|
||||
$data_return['ots'] = $ots;
|
||||
}
|
||||
return $data_return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ class PresupuestoService extends BaseService
|
||||
$maquina->velocidad
|
||||
);
|
||||
$tiempo = round($tiempo, 2);
|
||||
[$precio_hora, $margen_precio_hora] = $clientePreciosModel->get_precio_hora($cliente_id, $config, $tiempo);
|
||||
[$precio_hora, $margen_precio_hora] = $clientePreciosModel->get_precio_hora($cliente_id, $config, round($tiempo, 2));
|
||||
|
||||
|
||||
if (is_null($precio_hora)) {
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4><?= $boxTitle ?></h4>
|
||||
<h4><?= $boxTitle ?> <?= ($envioEntity->finalizado == 0)?'':'<span class="badge text-bg-success fw-lg">FINALIZADO</span>' ?></h4>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
@ -112,41 +112,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion accordion-bordered">
|
||||
<div class="card accordion-item active mb-5">
|
||||
<h4 class="accordion-header px-4 py-3">
|
||||
<?= lang("Logistica.addLineasEnvio") ?>
|
||||
</h4>
|
||||
<?php if ($envioEntity->finalizado == 0): ?>
|
||||
<div class="accordion accordion-bordered">
|
||||
<div class="card accordion-item active mb-5">
|
||||
<h4 class="accordion-header px-4 py-3">
|
||||
<?= lang("Logistica.addLineasEnvio") ?>
|
||||
</h4>
|
||||
|
||||
<div id="accordionaddLineasEnvioTip" class="accordion-collapse collapse show">
|
||||
<div id="accordionaddLineasEnvioTip" class="accordion-collapse collapse show">
|
||||
|
||||
<div class="d-flex flex-row mb-3">
|
||||
<div class="col-sm-12 px-3">
|
||||
<p><?= lang('Logistica.addLineasText') ?></p>
|
||||
<div class="d-flex flex-row mb-3">
|
||||
<div class="col-sm-12 px-3">
|
||||
<p><?= lang('Logistica.addLineasText') ?></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-row mb-3">
|
||||
<div class="col-sm-6 px-3">
|
||||
<label for="buscadorPedidos" class="form-label">
|
||||
<?= lang("Logistica.buscadorPedidosTitle2") ?>
|
||||
</label>
|
||||
<select id="buscadorPedidos" name="buscador_pedidos" tabindex="1" maxlength="50"
|
||||
class="form-control select2bs2" style="width: 100%;">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-2 px-3">
|
||||
<button id="btnAddLinea" name="btnBuscar" 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 class="d-flex flex-row mb-3">
|
||||
<div class="col-sm-6 px-3">
|
||||
<label for="buscadorPedidos" class="form-label">
|
||||
<?= lang("Logistica.buscadorPedidosTitle2") ?>
|
||||
</label>
|
||||
<select id="buscadorPedidos" name="buscador_pedidos" tabindex="1" maxlength="50"
|
||||
class="form-control select2bs2" style="width: 100%;">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-2 px-3">
|
||||
<button id="btnAddLinea" name="btnBuscar" 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>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<div class="accordion accordion-bordered">
|
||||
@ -168,13 +170,15 @@
|
||||
<i class="ti ti-select"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-2 px-3">
|
||||
<button id="btnEliminarLineas" name="btnEliminarLineas" tabindex="1"
|
||||
class="btn btn-danger w-100">
|
||||
<?= lang("Logistica.eliminar") ?>
|
||||
<i class="ti ti-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php if ($envioEntity->finalizado == 0): ?>
|
||||
<div class="col-sm-2 px-3">
|
||||
<button id="btnEliminarLineas" name="btnEliminarLineas" tabindex="1"
|
||||
class="btn btn-danger w-100">
|
||||
<?= lang("Logistica.eliminar") ?>
|
||||
<i class="ti ti-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="col-sm-2 px-3">
|
||||
<button id="btnGenerarAlbaran" name="btnGenerarAlbaran" tabindex="1"
|
||||
class="btn btn-success w-100">
|
||||
@ -244,35 +248,90 @@
|
||||
<input type="number" id="cajas" name="cajas" tabindex="1" maxlength="50"
|
||||
class="form-control" value="<?= old('cajas', $envioEntity->cajas) ?>">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion accordion-bordered mt-3" id="accordioAlbaranes">
|
||||
<div class="accordion accordion-bordered mt-3 mb-5" id="accordioAlbaranes">
|
||||
|
||||
<div class="card accordion-item active">
|
||||
<h2 class="accordion-header" id="headingAlbaranes">
|
||||
<button type="button" class="accordion-button" data-bs-toggle="collapse"
|
||||
data-bs-target="#accordionAlbaranesTip" aria-expanded="false"
|
||||
aria-controls="accordionAlbaranesTip">
|
||||
<h3><?= lang("Pedidos.albaranes") ?></h3>
|
||||
</button>
|
||||
</h2>
|
||||
<div class="card accordion-item active">
|
||||
<h2 class="accordion-header" id="headingAlbaranes">
|
||||
<button type="button" class="accordion-button" data-bs-toggle="collapse"
|
||||
data-bs-target="#accordionAlbaranesTip" aria-expanded="false"
|
||||
aria-controls="accordionAlbaranesTip">
|
||||
<h3><?= lang("Pedidos.albaranes") ?></h3>
|
||||
</button>
|
||||
</h2>
|
||||
|
||||
<div id="accordionAlbaranesTip" class="accordion-collapse collapse show"
|
||||
data-bs-parent="#accordioAlbaranes">
|
||||
<div id="contenedorAlbaranes" class="accordion-body">
|
||||
<div id="accordionAlbaranesTip" class="accordion-collapse collapse show"
|
||||
data-bs-parent="#accordioAlbaranes">
|
||||
<div id="contenedorAlbaranes" class="accordion-body">
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="accordion accordion-bordered">
|
||||
<div class="card accordion-item active mb-5">
|
||||
<h4 class="accordion-header px-4 py-3">
|
||||
<?= lang("Logistica.acciones") ?>
|
||||
</h4>
|
||||
|
||||
<div class="d-flex flex-row mb-3">
|
||||
<div class="col-sm-3 px-3">
|
||||
<label for="codigoSeguimiento" class="form-label">
|
||||
<?= 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) ?>">
|
||||
</div>
|
||||
<div class="col-sm-3 px-3">
|
||||
<label for="empresaMensajeria" class="form-label">
|
||||
<?= lang("Logistica.empresaMensajería") ?>
|
||||
</label>
|
||||
<?php if ($envioEntity->finalizado == 0): ?>
|
||||
<select id="empresaMensajeria" name="empresa_mensajeria" tabindex="1" maxlength="50"
|
||||
class="form-control select2bs2" style="width: 100%;">
|
||||
<?php if ($envioEntity->proveedor_id): ?>
|
||||
<option value="<?= $envioEntity->proveedor_id ?>" "selected">
|
||||
<?= $envioEntity->proveedor_nombre ?>
|
||||
</option>
|
||||
<?php endif; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<input type="text" id="empresaMensajeriaInput" name="empresa_mensajeria_input"
|
||||
tabindex="1" maxlength="100" class="form-control" readonly
|
||||
value="<?= old('empresa_mensajeria', $envioEntity->proveedor_nombre) ?>">
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php if ($envioEntity->finalizado == 0): ?>
|
||||
<div class="col-sm-3 px-3">
|
||||
<button id="finalizarEnvio" name="finalizar_envio" tabindex="1"
|
||||
class="btn btn-primary mt-4 w-100 btn-finalizar">
|
||||
<?= lang("Logistica.finalizarEnvio") ?>
|
||||
<ti class="ti ti-check"></ti>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-sm-3 px-3">
|
||||
<button id="finalizarEnvioYOTs" name="finalizar_envio_ots" tabindex="1"
|
||||
class="btn btn-primary mt-4 w-100 btn-finalizar">
|
||||
<?= lang("Logistica.finalizarEnvioYOTs") ?>
|
||||
<ti class="ti ti-checks"></ti>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -12,48 +12,24 @@
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
||||
<div class="row mb-3">
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 "
|
||||
onclick="window.location.href='<?= route_to('selectEnvios', 'simple') ?>'"
|
||||
>
|
||||
<?= lang('Logistica.envioSimple') ?>
|
||||
</button>
|
||||
<div class="grid">
|
||||
<div class="item" onclick="location.href='<?= route_to('gestionEnvios') ?>'">
|
||||
<img src="<?= site_url("assets/img/logistica/envios.jpg") ?>" alt="Envíos">
|
||||
<div><span><?= lang("Logistica.gestionEnvios"); ?></span></div>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.envioMultiple') ?>
|
||||
</button>
|
||||
<div class="item">
|
||||
<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="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.envioConjunto') ?>
|
||||
</button>
|
||||
<div class="item">
|
||||
<img src="<?= site_url("assets/img/logistica/impresionEtiquetas.jpg") ?>" alt="Etiquetas de títulos">
|
||||
<div><span><?= lang("Logistica.etiquetasTitulos"); ?></span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.etiquetasTitulos') ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.etiquetasEnvio') ?>
|
||||
</button>
|
||||
</div>
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.envioFerros') ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4">
|
||||
<button type="button" style="height: 80px;" class="btn btn-primary w-100 " >
|
||||
<?= lang('Logistica.cerrarOTauto') ?>
|
||||
</button>
|
||||
<div class="item">
|
||||
<img src="<?= site_url("assets/img/logistica/albaranes.png") ?>" alt="Albaranes">
|
||||
<div><span><?= lang("Logistica.albaranes"); ?></span></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -63,6 +39,7 @@
|
||||
<?= $this->endSection(); ?>
|
||||
|
||||
<?= $this->section('css') ?>
|
||||
<link rel="stylesheet" href="<?= site_url('themes/vuexy/css/logisticaPanel.css') ?>">
|
||||
<?= $this->endSection() ?>
|
||||
|
||||
|
||||
|
||||
BIN
httpdocs/assets/img/logistica/albaranes.png
Normal file
BIN
httpdocs/assets/img/logistica/albaranes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 MiB |
BIN
httpdocs/assets/img/logistica/envios.jpg
Normal file
BIN
httpdocs/assets/img/logistica/envios.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 507 KiB |
BIN
httpdocs/assets/img/logistica/envios_ferros.png
Normal file
BIN
httpdocs/assets/img/logistica/envios_ferros.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 727 KiB |
BIN
httpdocs/assets/img/logistica/impresionEtiquetas.jpg
Normal file
BIN
httpdocs/assets/img/logistica/impresionEtiquetas.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@ -1,33 +1,36 @@
|
||||
import Ajax from '../../components/ajax.js';
|
||||
|
||||
$(()=>{
|
||||
$(() => {
|
||||
|
||||
$('#buscadorPedidos').on('keydown', function(e) {
|
||||
$('#buscadorPedidos').on('keydown', function (e) {
|
||||
if (e.key === 'Enter' || e.keyCode === 13) {
|
||||
e.preventDefault(); // Evita el submit si está dentro de un form
|
||||
let search = $(this).val().trim();
|
||||
new Ajax(
|
||||
'/logistica/buscar/'+search,
|
||||
'/logistica/buscar/' + search,
|
||||
{},
|
||||
{},
|
||||
function(response) {
|
||||
if(!response.status){
|
||||
function (response) {
|
||||
if (!response.status) {
|
||||
popErrorAlert(response.message);
|
||||
}
|
||||
if(response.data){
|
||||
if (response.multienvio) {
|
||||
mostrarSwalDirecciones(response);
|
||||
}
|
||||
else if (response.data) {
|
||||
|
||||
window.open(`${window.location.origin}/logistica/envio/${response.data.id_envio}`);
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
function(xhr, status, error) {
|
||||
if(status == 'error' && typeof(error)== 'string')
|
||||
function (xhr, status, error) {
|
||||
if (status == 'error' && typeof (error) == 'string')
|
||||
popErrorAlert(error);
|
||||
else
|
||||
popErrorAlert(error.responseJSON.message);
|
||||
}
|
||||
).get();
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@ -55,7 +58,7 @@ $(()=>{
|
||||
{ "data": "cp" },
|
||||
{ "data": "email" },
|
||||
{ "data": "telefono" },
|
||||
{
|
||||
{
|
||||
"data": "finalizado",
|
||||
"className": "text-center",
|
||||
},
|
||||
@ -78,5 +81,52 @@ $(()=>{
|
||||
$(document).on('click', '.btn-edit', function (e) {
|
||||
window.location.href = '/logistica/envio/' + $(this).attr('data-id');
|
||||
});
|
||||
|
||||
|
||||
function mostrarSwalDirecciones(response) {
|
||||
// Crear el select como HTML
|
||||
let options = response.direcciones.map((dir, index) =>
|
||||
`<option value="${index}">${dir}</option>`
|
||||
).join("");
|
||||
|
||||
Swal.fire({
|
||||
title: 'Múltiples direcciones',
|
||||
html: `
|
||||
<p>El pedido tiene múltiples direcciones. Debe seleccionar una dirección:</p>
|
||||
<select id="swal-select-direccion" class="form-select" style="width: 100%; margin-top: 1rem;">
|
||||
${options}
|
||||
</select>
|
||||
`,
|
||||
confirmButtonText: 'Aceptar',
|
||||
cancelButtonText: 'Cancelar',
|
||||
customClass: {
|
||||
confirmButton: 'swal2-confirm btn btn-primary',
|
||||
cancelButton: 'swal2-cancel btn btn-secondary' // Estilo gris
|
||||
},
|
||||
preConfirm: () => {
|
||||
const select = document.getElementById('swal-select-direccion');
|
||||
if (!select.value) {
|
||||
Swal.showValidationMessage('Debe seleccionar una dirección');
|
||||
return false;
|
||||
}
|
||||
return response.direcciones[select.value]; // Devuelve la dirección seleccionada
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
const direccionSeleccionada = result.value;
|
||||
$.post('/logistica/generateEnvio', {
|
||||
pedido_id: response.pedido_id,
|
||||
direccion: direccionSeleccionada
|
||||
}, function (response) {
|
||||
if (response.status) {
|
||||
window.open(`${window.location.origin}/logistica/envio/${response.data.id_envio}`);
|
||||
} else {
|
||||
popErrorAlert(response.message);
|
||||
}
|
||||
}).fail(function (xhr, status, error) {
|
||||
popErrorAlert(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
@ -28,9 +28,18 @@ class EnvioEdit {
|
||||
this.btnGenerarAlbaran = $("#btnGenerarAlbaran");
|
||||
this.btnbtnSelectAll = $("#btnSelectAll");
|
||||
this.cajas = $("#cajas");
|
||||
this.codigoSeguimiento = $("#codigoSeguimiento");
|
||||
if (!$("#empresaMensajeriaInput").length) {
|
||||
this.proveedor = new ClassSelect($("#empresaMensajeria"), '/compras/proveedores/getProveedores', "", true, { 'tipo_id': 2 });
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
|
||||
if (!$("#empresaMensajeriaInput").length) {
|
||||
this.proveedor.init();
|
||||
}
|
||||
|
||||
this.table = $('#tableLineasEnvio').DataTable({
|
||||
processing: true,
|
||||
serverSide: true,
|
||||
@ -53,14 +62,14 @@ class EnvioEdit {
|
||||
footerCallback: function (row, data, start, end, display) {
|
||||
let totalUnidades = 0;
|
||||
let totalPeso = 0;
|
||||
|
||||
|
||||
data.forEach(row => {
|
||||
const unidades = parseFloat(row.unidadesEnvioRaw) || 0;
|
||||
const pesoUnidad = parseFloat(row.pesoUnidad) || 0;
|
||||
totalUnidades += unidades;
|
||||
totalPeso += unidades * pesoUnidad;
|
||||
});
|
||||
|
||||
|
||||
// Mostrar en spans personalizados del <tfoot>
|
||||
$('#footer-unidades-envio').text(totalUnidades);
|
||||
$('#footer-peso').text(totalPeso.toFixed(2));
|
||||
@ -117,7 +126,7 @@ class EnvioEdit {
|
||||
buttonsStyling: false
|
||||
});
|
||||
$(e.currentTarget).val(0);
|
||||
}
|
||||
}
|
||||
}).fail(() => {
|
||||
Swal.fire({
|
||||
title: 'Error',
|
||||
@ -205,12 +214,240 @@ class EnvioEdit {
|
||||
const checkboxes = this.table.$('input[type="checkbox"]');
|
||||
const allChecked = checkboxes.length === checkboxes.filter(':checked').length;
|
||||
checkboxes.prop('checked', !allChecked);
|
||||
});
|
||||
|
||||
this.codigoSeguimiento.on('change', (e) => {
|
||||
const value = $(e.currentTarget).val();
|
||||
|
||||
$.post('/logistica/updateCodigoSeguimiento', {
|
||||
id: $('#id').val(),
|
||||
codigo_seguimiento: value
|
||||
}, function (response) {
|
||||
if (!response.status) {
|
||||
Swal.fire({
|
||||
title: 'Error',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
$(e.currentTarget).val(value.substring(0, 100));
|
||||
}
|
||||
}).fail(() => {
|
||||
Swal.fire({
|
||||
title: 'Error',
|
||||
text: 'No se pudo actualizar el código de seguimiento.',
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
$(e.currentTarget).val(value.substring(0, 100));
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
if (!$("#empresaMensajeriaInput").length) {
|
||||
this.proveedor.onChange((e) => {
|
||||
|
||||
const value = this.proveedor.getVal();
|
||||
$.post('/logistica/updateProveedorEnvio', {
|
||||
id: $('#id').val(),
|
||||
proveedor_id: value
|
||||
}, function (response) {
|
||||
if (!response.status) {
|
||||
Swal.fire({
|
||||
title: 'Error',
|
||||
text: response.message,
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
this.proveedor.setVal(0);
|
||||
}
|
||||
}).fail(() => {
|
||||
Swal.fire({
|
||||
title: 'Error',
|
||||
text: 'No se pudo actualizar el proveedor.',
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
this.proveedor.setVal(0);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
$('#finalizarEnvio').on('click', (e) => {
|
||||
|
||||
if (!this._checkDatosFinalizar())
|
||||
return;
|
||||
|
||||
Swal.fire({
|
||||
title: 'Finalizar envío',
|
||||
text: '¿Está seguro de que desea finalizar el envío?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí',
|
||||
cancelButtonText: 'Cancelar',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-danger me-1',
|
||||
cancelButton: 'btn btn-secondary'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.post('/logistica/finalizarEnvio', {
|
||||
id: $('#id').val()
|
||||
}, function (response) {
|
||||
if (response.status) {
|
||||
Swal.fire({
|
||||
text: response.message,
|
||||
icon: 'success',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
} 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 finalizar el envío.',
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('#finalizarEnvioYOTs').on('click', (e) => {
|
||||
|
||||
if (!this._checkDatosFinalizar())
|
||||
return;
|
||||
|
||||
Swal.fire({
|
||||
title: 'Finalizar envío y las OTs',
|
||||
text: '¿Está seguro de que desea finalizar el envío y las OTs de las líneas de envío?',
|
||||
icon: 'warning',
|
||||
showCancelButton: true,
|
||||
confirmButtonText: 'Sí',
|
||||
cancelButtonText: 'Cancelar',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-danger me-1',
|
||||
cancelButton: 'btn btn-secondary'
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
$.post('/logistica/finalizarEnvio', {
|
||||
id: $('#id').val(),
|
||||
finalizar_ots: true
|
||||
}, function (response) {
|
||||
if (response.status) {
|
||||
|
||||
Swal.fire({
|
||||
text: response.message,
|
||||
icon: 'success',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
}).then(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
} 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 finalizar el envío.',
|
||||
icon: 'error',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._getAlbaranes();
|
||||
}
|
||||
|
||||
_checkDatosFinalizar() {
|
||||
|
||||
if (this.codigoSeguimiento.val().length <= 0 || this.proveedor.getVal() <= 0) {
|
||||
Swal.fire({
|
||||
title: 'Atención!',
|
||||
text: 'Debe seleccionar un proveedor y un código de seguimiento antes de finalizar el envío.',
|
||||
icon: 'info',
|
||||
confirmButtonColor: '#3085d6',
|
||||
confirmButtonText: 'Ok',
|
||||
customClass: {
|
||||
confirmButton: 'btn btn-primary me-1',
|
||||
},
|
||||
buttonsStyling: false
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
_getAlbaranes() {
|
||||
$.get('/albaranes/albaranesEnvio', {
|
||||
envio_id: $('#id').val(),
|
||||
|
||||
26
httpdocs/themes/vuexy/css/logisticaPanel.css
Normal file
26
httpdocs/themes/vuexy/css/logisticaPanel.css
Normal file
@ -0,0 +1,26 @@
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.item {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.item img {
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.item p {
|
||||
margin-top: 10px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
@media (max-width: 700px) {
|
||||
.grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user