Files
safekat/ci4/app/Services/LogisticaService.php

479 lines
18 KiB
PHP

<?php
namespace App\Services;
use App\Services\ProductionService;
use Config\Services;
class LogisticaService
{
public static function findLineaEnvioPorEnvio(int $envio_id)
{
$db = \Config\Database::connect();
// 1. Dirección del envío actual
$envio = $db->table('envios')->select('direccion')->where('id', $envio_id)->get()->getRow();
if (!$envio) {
return $db->table('(SELECT NULL AS id, NULL AS name) AS empty')->where('1 = 0');
}
$direccionNormalizada = str_replace(' ', '', strtolower(trim($envio->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) 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,
(
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')
->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'])
->where('ot_dates.embalaje_at IS NOT NULL')
->where("NOT EXISTS (
SELECT 1
FROM envios_lineas el
WHERE el.envio_id = $envio_id
AND el.pedido_id = p.id
AND el.presupuesto_id = pr.id
GROUP BY el.pedido_id, el.presupuesto_id
HAVING SUM(el.unidades_envio) >= pd.cantidad
)", null, false)
->groupBy('pl.id');
// 4. Envolver y filtrar por unidades pendientes
$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 findForNewEnvio()
{
$db = \Config\Database::connect();
// 3. Subconsulta principal
$subBuilder = $db->table('pedidos_linea pl')
->select("
ot.id AS id,
CONCAT('[', ot.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 e.finalizado = 1
) 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')
->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')
->groupBy('pl.id');
// 4. Envolver y filtrar por unidades pendientes
$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 findDireccionesNewEnvio($pedido_id, $searchVal = "")
{
$direcciones = [];
$counter = 1;
$PresupuestoDireccionesModel = model('App\Models\Presupuestos\PresupuestoDireccionesModel');
$dirs = $PresupuestoDireccionesModel->select('direccion')
->join('presupuestos pr', 'pr.id=presupuesto_direcciones.presupuesto_id')
->join('pedidos_linea pl', 'pl.presupuesto_id = pr.id')
->join('pedidos p', 'pl.pedido_id=p.id')
->where('p.id', $pedido_id);
if ($searchVal != "") {
$dirs = $dirs->groupStart()
->Like("id", $searchVal)
->groupEnd();
}
$dirs = $dirs->orderBy('direccion', 'asc')->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', $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,
(object) [
"id" => $counter,
'name' => $direccion->direccion
]
);
$counter++;
}
}
return $direcciones;
}
public static function addLineaEnvio($envio_id = null, $pedido_id = null, $direccion = null)
{
$db = \Config\Database::connect();
$direccionNormalizada = strtolower(trim($direccion));
// 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();
if (empty($result)) {
return [
'status' => false,
'message' => lang('Logistica.errors.notFound'),
];
}
$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' => $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,
]);
}
return [
'status' => true,
'data' => [
'unidades_envio' => $r->unidades_envio,
'unidades_enviadas' => $r->unidades_enviadas,
'total_unidades' => $r->total_unidades,
]
];
}
public static function generateEnvio($pedido_id, $direccion = null)
{
$presupuestoDireccionesModel = model('App\Models\Presupuestos\PresupuestoDireccionesModel');
$direccionNormalizada = strtolower(trim($direccion));
$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,
(
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 e.direccion LIKE " . $presupuestoDireccionesModel->db->escape("%$direccion%") . "
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)
->like('presupuesto_direcciones.direccion', $direccion)
->groupBy('presupuesto_direcciones.id')
->first();
// Validación si no hay datos o no quedan unidades
if (empty($datosEnvio) || $datosEnvio->cantidad <= 0) {
return [
'status' => false,
'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 imprimirEtiquetas($envio_id, $ids)
{
$array = [
"printer" => "LABPRINT-1",
"header" => [
"_FORMAT" => "E:PEDIDO.ZPL",
"_QUANTITY" => 1,
"_PRINBTERNAME" => "Printer 1",
"_JOBNAME" => "LBL101"
],
"labels" => [
/* Ejemplo etiqueta
[
"cliente" => "Cliente Potencial",
"titulo" => "[1234] TEST OLIVEROS",
"cantidad" => 100,
"tirada" => 50,
"cajas" => 1,
"ean" => null,
"nombre" => "___Nombre___",
"direccion" => "C/ test n10, Madrid, 12345, España",
"notas" => "Nota....",
"refcliente" => "Refclient:1234",
"npedido" => "1234"
]
*/
]
];
$EnvioModel = model('App\Models\Logistica\EnvioModel');
$EnvioLineasModel = model('App\Models\Logistica\EnvioLineaModel');
$envios = $EnvioModel->whereIn('id', $ids)->findAll();
if (empty($envios)) {
return [
'status' => false,
'message' => lang('Logistica.errors.noEnvio'),
];
}
foreach ($envios as $envio) {
$lineasEnvio = $EnvioLineasModel->where('envio_id', $envio->id)->findAll();
if (empty($lineasEnvio)) {
return [
'status' => false,
'message' => lang('Logistica.errors.noEnvioLineas'),
];
}
}
return [
'status' => true,
'data' => $envios,
];
}
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;
}
}