diff --git a/download_ruta_contraentrega.php b/download_ruta_contraentrega.php index 4cf866e1..6467daa5 100644 --- a/download_ruta_contraentrega.php +++ b/download_ruta_contraentrega.php @@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) { } require_once 'db/config.php'; +require_once 'includes/callcenter_test_helpers.php'; require_once 'vendor/autoload.php'; use Shuchkin\SimpleXLSXGen; @@ -132,86 +133,18 @@ function extractProductNames(array $pedido): array return array_values(array_unique($names)); } -function extractProductDetailsWithQuantities(array $pedido): array +function extractProductDetailsWithQuantities(PDO $pdo, array $pedido): array { - $notas = (string)($pedido['notas'] ?? ''); - - // Prefer parsing from "Detalle de productos:" (it stores quantities as (xN)) - if (preg_match_all('/Detalle de productos:\\s*(.+)$/mi', $notas, $matches) && !empty($matches[1])) { - $lastLine = trim((string)end($matches[1])); - if ($lastLine !== '') { - $parts = preg_split('/\\s*,\\s*/u', $lastLine); - $out = []; - - if (is_array($parts)) { - foreach ($parts as $part) { - $part = trim((string)$part); - if ($part === '') { - continue; - } - - // Expected format: "Nombre de producto (x2)" - if (preg_match('/^(.*?)\\s*\\(x\\s*(\\d+)\\s*\\)\\s*$/iu', $part, $m)) { - $name = trim((string)$m[1]); - $qty = (int)$m[2]; - } else { - $name = $part; - $qty = 1; - } - - if ($name !== '') { - if ($qty <= 0) { - $qty = 1; - } - $out[] = ['name' => $name, 'qty' => $qty]; - } - } - } - - if (!empty($out)) { - return $out; - } - } - } - - // Fallback: use "producto" + "cantidad" (best-effort) - $productoStr = (string)($pedido['producto'] ?? ''); - $names = []; - foreach (preg_split('/\\s*,\\s*/u', $productoStr) as $n) { - $n = trim((string)$n); - if ($n !== '') { - $names[] = $n; - } - } - - if (empty($names)) { - return []; - } - - $cantidad_total = parseTotalQuantity($pedido['cantidad'] ?? 0); - - // Legacy possibility: "cantidad" can be like "1+2" - $cantidadField = $pedido['cantidad'] ?? ''; - $qtyParts = []; - if (is_string($cantidadField) && strpos(trim($cantidadField), '+') !== false) { - $qtyParts = array_map('trim', explode('+', $cantidadField)); - } + $rows = cc_test_resolve_pedido_product_rows($pdo, $pedido, 'ruta_contraentrega_pedido_id'); $out = []; - $countNames = count($names); - foreach ($names as $i => $name) { - if ($countNames === 1) { - $qty = $cantidad_total > 0 ? $cantidad_total : 1; - } elseif (!empty($qtyParts) && isset($qtyParts[$i]) && is_numeric($qtyParts[$i])) { - $qty = (int)$qtyParts[$i]; - if ($qty <= 0) { - $qty = 1; - } - } else { - $qty = 1; + foreach ($rows as $row) { + $name = trim((string)($row['nombre'] ?? '')); + $qty = (int)($row['cantidad'] ?? 0); + if ($name === '') { + continue; } - - $out[] = ['name' => $name, 'qty' => $qty]; + $out[] = ['name' => $name, 'qty' => $qty > 0 ? $qty : 1]; } return $out; @@ -365,7 +298,7 @@ $is_admin = in_array($user_role, ['Administrador', 'admin'], true); $cantidadOut = $cantidad_total; $precioOut = $unit_price_rounded; - $details = extractProductDetailsWithQuantities($pedido); + $details = extractProductDetailsWithQuantities($pdo, $pedido); $eanSegments = []; $qtySegments = []; diff --git a/gestiones_callcenter.php b/gestiones_callcenter.php index 815c1003..1bfe9df7 100644 --- a/gestiones_callcenter.php +++ b/gestiones_callcenter.php @@ -1486,6 +1486,7 @@ require_once 'layout_header.php'; color: var(--cc-assessor-accent-contrast, #212529); border-color: var(--cc-assessor-accent, #adb5bd) !important; font-weight: 600; + white-space: nowrap; } .cc-callcenter-color-trigger { @@ -1849,6 +1850,7 @@ require_once 'layout_header.php'; 0): ?>
+
@@ -1857,7 +1859,9 @@ require_once 'layout_header.php';
- Pendientes: + 0): ?> + Pendientes: +
Cupo restante ()
@@ -1903,6 +1907,7 @@ require_once 'layout_header.php'; Ver asesora sin actividad
+
@@ -1911,7 +1916,9 @@ require_once 'layout_header.php';
- Pendientes: + 0): ?> + Pendientes: +
Cupo restante ()
diff --git a/imprimir_rotulos_grandes.php b/imprimir_rotulos_grandes.php index 69b4013c..e84105df 100644 --- a/imprimir_rotulos_grandes.php +++ b/imprimir_rotulos_grandes.php @@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) { } require_once 'db/config.php'; +require_once 'includes/callcenter_test_helpers.php'; $pdo = db(); // Fetch all products to have their prefixes ready @@ -203,39 +204,21 @@ $label_generated_date = date('d/m'); trim($value) !== '')) : []; } +function cc_test_parse_quantity_value(mixed $value, int $default = 1): int +{ + if (is_int($value)) { + return $value > 0 ? $value : $default; + } + + if (is_float($value)) { + $quantity = (int) round($value); + return $quantity > 0 ? $quantity : $default; + } + + $value = trim((string) $value); + if ($value === '') { + return $default; + } + + if (strpos($value, '+') !== false) { + $sum = 0; + foreach (explode('+', $value) as $part) { + $part = trim($part); + if ($part === '') { + continue; + } + if (is_numeric($part)) { + $sum += (int) $part; + continue; + } + if (preg_match('/\d+/', $part, $match)) { + $sum += (int) $match[0]; + } + } + + return $sum > 0 ? $sum : $default; + } + + if (preg_match('/\d+/', $value, $match)) { + $quantity = (int) $match[0]; + return $quantity > 0 ? $quantity : $default; + } + + return $default; +} + +function cc_test_parse_product_detail_rows_from_text(string $text): array +{ + $text = trim($text); + if ($text === '') { + return []; + } + + if (!preg_match_all('/(?:Detalle de productos|Detalle confirmado):\s*(.+)$/mi', $text, $matches) || empty($matches[1])) { + return []; + } + + $lastLine = trim((string) end($matches[1])); + if ($lastLine === '') { + return []; + } + + $parts = preg_split('/\s*,\s*/u', $lastLine); + if (!is_array($parts)) { + return []; + } + + $rows = []; + foreach ($parts as $part) { + $part = trim((string) $part); + if ($part === '') { + continue; + } + + $name = $part; + $quantity = 1; + + if (preg_match('/^(.*?)\s*\(x\s*(\d+)\s*\)$/iu', $part, $match)) { + $name = trim((string) $match[1]); + $quantity = (int) $match[2]; + } + + $name = trim($name); + if ($name === '') { + continue; + } + + $rows[] = [ + 'nombre' => $name, + 'cantidad' => $quantity > 0 ? $quantity : 1, + ]; + } + + return $rows; +} + +function cc_test_product_rows_from_tracking(array $tracking): array +{ + $rows = []; + + $mainName = trim((string) ($tracking['confirmacion_producto'] ?? '')); + $mainQty = cc_test_parse_quantity_value($tracking['confirmacion_cantidad'] ?? '', 1); + if ($mainName !== '') { + $rows[] = [ + 'nombre' => $mainName, + 'cantidad' => $mainQty, + ]; + } + + $extraName = trim((string) ($tracking['confirmacion_producto_extra'] ?? '')); + $extraQty = cc_test_parse_quantity_value($tracking['confirmacion_cantidad_extra'] ?? '', 1); + if ($extraName !== '') { + $rows[] = [ + 'nombre' => $extraName, + 'cantidad' => $extraQty, + ]; + } + + return $rows; +} + +function cc_test_resolve_pedido_product_rows(PDO $pdo, array $pedido, ?string $trackingLinkColumn = null): array +{ + $pedidoId = (int) ($pedido['id'] ?? 0); + $allowedTrackingColumns = ['ruta_contraentrega_pedido_id', 'pedido_rotulado_pedido_id']; + + if ($pedidoId > 0 && $trackingLinkColumn !== null && in_array($trackingLinkColumn, $allowedTrackingColumns, true) && cc_test_table_exists($pdo, 'callcenter_test_tracking')) { + $sql = 'SELECT confirmacion_producto, confirmacion_cantidad, confirmacion_producto_extra, confirmacion_cantidad_extra FROM callcenter_test_tracking WHERE ' . $trackingLinkColumn . ' = ? ORDER BY id DESC LIMIT 1'; + $stmt = $pdo->prepare($sql); + $stmt->execute([$pedidoId]); + $tracking = $stmt->fetch(PDO::FETCH_ASSOC); + if (is_array($tracking)) { + $rows = cc_test_product_rows_from_tracking($tracking); + if (!empty($rows)) { + return $rows; + } + } + } + + $rows = cc_test_parse_product_detail_rows_from_text((string) ($pedido['notas'] ?? '')); + if (!empty($rows)) { + return $rows; + } + + $producto = trim((string) ($pedido['producto'] ?? '')); + if ($producto === '') { + return []; + } + + $names = array_values(array_filter(array_map('trim', preg_split('/\s*,\s*/u', $producto) ?: []), static fn ($value) => $value !== '')); + if (empty($names)) { + return []; + } + + $cantidadTotal = cc_test_parse_quantity_value($pedido['cantidad'] ?? 1, 1); + $cantidadField = $pedido['cantidad'] ?? ''; + $qtyParts = []; + if (is_string($cantidadField) && strpos(trim($cantidadField), '+') !== false) { + $qtyParts = array_values(array_map('trim', explode('+', trim($cantidadField)))); + } + + $rows = []; + $nameCount = count($names); + foreach ($names as $index => $name) { + if ($nameCount === 1) { + $quantity = $cantidadTotal; + } elseif (!empty($qtyParts) && isset($qtyParts[$index]) && is_numeric($qtyParts[$index])) { + $quantity = (int) $qtyParts[$index]; + } else { + $quantity = 1; + } + + $rows[] = [ + 'nombre' => $name, + 'cantidad' => $quantity > 0 ? $quantity : 1, + ]; + } + + return $rows; +} + function cc_test_row_background_style(string $estado): string { $color = match (cc_test_normalize_state($estado)) { diff --git a/pedido_form.php b/pedido_form.php index 1f986aee..d7c431dd 100644 --- a/pedido_form.php +++ b/pedido_form.php @@ -6,6 +6,7 @@ if (!isset($_SESSION['user_id'])) { } require_once 'db/config.php'; +require_once 'includes/callcenter_test_helpers.php'; $pdo = db(); $user_id = $_SESSION['user_id']; @@ -77,34 +78,9 @@ $stmt_products = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre AS $products = $stmt_products->fetchAll(); // Parse products for editing -$display_products = []; -if (!empty($pedido['id'])) { - // Try to parse from notas first as it has quantities - if (preg_match_all('/Detalle de productos: (.*)$/m', $pedido['notas'], $matches)) { - // Take the last match - $last_match = end($matches[1]); - $details = explode(', ', $last_match); - foreach ($details as $detail) { - if (preg_match('/(.*) \(x(\d+)\)/', $detail, $d_matches)) { - $display_products[] = [ - 'nombre' => trim($d_matches[1]), - 'cantidad' => (int)$d_matches[2] - ]; - } - } - } - - // Fallback if parsing failed or no details in notas - if (empty($display_products) && !empty($pedido['producto'])) { - $names = explode(', ', $pedido['producto']); - foreach ($names as $name) { - $display_products[] = [ - 'nombre' => trim($name), - 'cantidad' => count($names) == 1 ? $pedido['cantidad'] : 1 - ]; - } - } -} +$display_products = !empty($pedido['id']) + ? cc_test_resolve_pedido_product_rows($pdo, $pedido, 'pedido_rotulado_pedido_id') + : []; if (empty($display_products)) { $display_products[] = ['nombre' => '', 'cantidad' => 1]; diff --git a/pedidos_contraentrega.php b/pedidos_contraentrega.php index 0953b820..863c377d 100644 --- a/pedidos_contraentrega.php +++ b/pedidos_contraentrega.php @@ -7,6 +7,7 @@ if (!isset($_SESSION['user_id'])) { require_once 'db/config.php'; require_once 'includes/contraentrega_cobertura.php'; +require_once 'includes/callcenter_test_helpers.php'; require_once 'includes/tipo_paquete.php'; $pdo = db(); ensureTipoPaqueteEnumDefinition($pdo); @@ -79,34 +80,9 @@ $stmt_products = $pdo->query("SELECT id, nombre FROM products ORDER BY nombre AS $products = $stmt_products->fetchAll(); // Parse products for editing -$display_products = []; -if (!empty($pedido['id'])) { - // Try to parse from notas first as it has quantities - if (preg_match_all('/Detalle de productos: (.*)$/m', $pedido['notas'], $matches)) { - // Take the last match - $last_match = end($matches[1]); - $details = explode(', ', $last_match); - foreach ($details as $detail) { - if (preg_match('/(.*) \(x(\d+)\)/', $detail, $d_matches)) { - $display_products[] = [ - 'nombre' => trim($d_matches[1]), - 'cantidad' => (int)$d_matches[2] - ]; - } - } - } - - // Fallback if parsing failed or no details in notas - if (empty($display_products) && !empty($pedido['producto'])) { - $names = explode(', ', $pedido['producto']); - foreach ($names as $name) { - $display_products[] = [ - 'nombre' => trim($name), - 'cantidad' => count($names) == 1 ? $pedido['cantidad'] : 1 - ]; - } - } -} +$display_products = !empty($pedido['id']) + ? cc_test_resolve_pedido_product_rows($pdo, $pedido, 'ruta_contraentrega_pedido_id') + : []; if (empty($display_products)) { $display_products[] = ['nombre' => '', 'cantidad' => 1]; diff --git a/update_callcenter_test_tracking.php b/update_callcenter_test_tracking.php index 9012940f..dcd0b7bf 100644 --- a/update_callcenter_test_tracking.php +++ b/update_callcenter_test_tracking.php @@ -821,6 +821,7 @@ try { $stmtCurrent = $pdo->prepare('SELECT estado, numero_cuenta_enviado_at, numero_cuenta_sede_id, numero_cuenta_dni, user_id, assigned_at, promo_final_evidencia_path, promo_final_evidencia_subido_at, promo_final_evidencia_subido_por, cancelado_evidencia_path, cancelado_evidencia_subido_at, cancelado_evidencia_subido_por, eliminado_at, eliminado_por, ruta_contraentrega_pedido_id, pedido_rotulado_pedido_id FROM callcenter_test_tracking WHERE source_key = ? LIMIT 1'); $stmtCurrent->execute([$sourceKey]); $currentTracking = $stmtCurrent->fetch(PDO::FETCH_ASSOC) ?: null; + $tieneRutaContraentrega = isset($currentTracking['ruta_contraentrega_pedido_id']) && (int) $currentTracking['ruta_contraentrega_pedido_id'] > 0; $sourceOrderForAuth = cc_test_fetch_source_order($pdo, $sourceKey); $sourceStoreKeyForAuth = trim((string) ($sourceOrderForAuth['store_key'] ?? '')); @@ -1023,7 +1024,7 @@ try { } } - if ($subirALogistica && !in_array($estado, ['CONFIRMADO CONTRAENTREGA', 'CONFIRMADO ENVIO'], true)) { + if ($subirALogistica && !in_array($estado, ['CONFIRMADO CONTRAENTREGA', 'CONFIRMADO ENVIO'], true) && !$tieneRutaContraentrega) { throw new RuntimeException('Para subir el pedido, el estado debe ser CONFIRMADO CONTRAENTREGA o CONFIRMADO ENVIO.'); } @@ -1275,7 +1276,7 @@ try { throw new RuntimeException('No encontré el pedido base para enviarlo a logística.'); } - if ($estado === 'CONFIRMADO CONTRAENTREGA') { + if ($estado === 'CONFIRMADO CONTRAENTREGA' || $tieneRutaContraentrega) { $routePayload = cc_test_prepare_route_order_payload( $sourceOrder, $formData, @@ -1356,7 +1357,7 @@ try { if ($moverAPromoFinal && $promoFinalEvidencePath !== null) { $message = 'Pedido movido a Promo Final correctamente.'; } - if ($subirALogistica && $estado === 'CONFIRMADO CONTRAENTREGA' && $rutaPedidoId !== null) { + if ($subirALogistica && ($estado === 'CONFIRMADO CONTRAENTREGA' || $tieneRutaContraentrega) && $rutaPedidoId !== null) { $message = $rutaAction === 'updated' ? 'Pedido actualizado en Ruta Contraentrega #' . $rutaPedidoId . '.' : 'Pedido subido a Ruta Contraentrega #' . $rutaPedidoId . '.';