diff --git a/call_center_pro.php b/call_center_pro.php index 687cfd99..b4b6778c 100644 --- a/call_center_pro.php +++ b/call_center_pro.php @@ -326,6 +326,12 @@ if (!isset($availableStores[$storeKey])) { } $storeConfig = $availableStores[$storeKey]; $storeLabel = (string) ($storeConfig['label'] ?? strtoupper($storeKey)); +$recoverablesStoreKey = trim((string) ($storeConfig['recoverables_store_key'] ?? '')); +$recoverablesStoreLabel = $recoverablesStoreKey !== '' && isset($availableStores[$recoverablesStoreKey]) ? (string) ($availableStores[$recoverablesStoreKey]['label'] ?? strtoupper($recoverablesStoreKey)) : ''; +$recoverablesMainStoreKey = trim((string) ($storeConfig['main_store_key'] ?? '')); +$recoverablesMainStoreLabel = $recoverablesMainStoreKey !== '' && isset($availableStores[$recoverablesMainStoreKey]) ? (string) ($availableStores[$recoverablesMainStoreKey]['label'] ?? strtoupper($recoverablesMainStoreKey)) : $storeLabel; +$recoverablesStoreLabelHtml = htmlspecialchars($storeLabel); +$recoverablesMainStoreLabelHtml = htmlspecialchars($recoverablesMainStoreLabel); $usesIncrementalSync = !empty($storeConfig['incremental_sync']); $storeNav = drive_test_store_navigation_state($availableStores, $storeKey); $storeNavGroups = $storeNav['groups']; @@ -335,7 +341,7 @@ $activeStoreGroupChildren = $storeNav['active_group_children'] ?? []; $parentStoreLabel = (string) ($storeNav['parent_label'] ?? ''); $isMainTuaniStore = cc_test_is_tuani_main_store_key($storeKey); -$isTuaniRecuperablesStore = $storeKey === 'tuani_recuperables'; +$isTuaniRecuperablesStore = cc_test_is_recoverables_store_key($storeKey); if ($isTuaniRecuperablesStore && trim((string) ($_GET['view'] ?? '')) === '') { $view = 'todos'; } @@ -347,17 +353,11 @@ $viewCardColumnClass = $isTuaniRecuperablesStore ? 'col-md-6 col-xl-2' : 'col-md $defaultView = cc_test_callcenter_pro_default_view_key($storeKey); $viewCards = $isTuaniRecuperablesStore ? [ - 'pendientes_hoy' => [ - 'label' => 'Carritos recuperables', - 'heading' => 'Carritos recuperables', - 'stat_key' => 'pendientes_hoy', - 'active_class' => 'bg-dark text-white', - ], - 'nuevos_hoy' => [ - 'label' => 'Nuevos hoy', - 'heading' => 'Nuevos hoy', - 'stat_key' => 'nuevos_hoy', - 'active_class' => 'bg-primary-subtle border border-primary', + 'todos' => [ + 'label' => 'Todos', + 'heading' => 'Todos los pedidos cargados', + 'stat_key' => 'total', + 'active_class' => 'bg-light border', ], 'confirmados' => [ 'label' => 'Confirmados', @@ -383,11 +383,11 @@ $viewCards = $isTuaniRecuperablesStore ? [ 'stat_key' => 'observados', 'active_class' => 'bg-warning-subtle border border-warning', ], - 'todos' => [ - 'label' => 'Todos', - 'heading' => 'Todos los pedidos cargados', - 'stat_key' => 'total', - 'active_class' => 'bg-light border', + 'pendientes_hoy' => [ + 'label' => $storeLabel, + 'heading' => $storeLabel, + 'stat_key' => 'pendientes_hoy', + 'active_class' => 'bg-dark text-white', ], ] : [ 'nuevos_hoy' => [ @@ -467,7 +467,7 @@ $_SESSION[cc_test_callcenter_store_session_key()] = cc_test_normalize_context_ke $_SESSION[cc_test_callcenter_view_session_key()] = cc_test_normalize_context_key($view); $viewStatesNote = $isTuaniRecuperablesStore - ? 'Estados disponibles: Carritos recuperables, Nuevos hoy, Seguimiento, Observados, Confirmados, Recuperados y Todos. La vista Nuevos hoy agrupa los pedidos más recientes agregados desde Drive. Esta bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en TUANI principal, se marca en gris como Pedido repetido en tienda solo en esta bandeja. Las vistas Carritos recuperables y Todos arrancan en la fila 2000, solo toman pedidos desde esa fila y se ordenan por el número #D más alto, lo que mantiene arriba el código más reciente, al más antiguo, en bloques de 200 pedidos.' + ? 'Estados disponibles: ' . $recoverablesStoreLabelHtml . ', Seguimiento, Observados, Confirmados, Recuperados y Todos. Esta bandeja abre por defecto en Todos. La bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en ' . $recoverablesMainStoreLabelHtml . ' principal, se marca en gris como Pedido repetido en tienda solo en esta bandeja. Las vistas ' . $recoverablesStoreLabelHtml . ' y Todos arrancan en la fila ' . (int) ($storeConfig['startRow'] ?? 0) . ', solo toman pedidos desde esa fila y se ordenan por el número #D más alto, lo que mantiene arriba el código más reciente, al más antiguo, en bloques de 200 pedidos.' : 'Estados disponibles: Por llamar, Devolver llamada, Observado, Se envió número de cuenta, Confirmado contraentrega, Confirmado envío, Cancelado y Repetido. Promo Final se habilita para mover el pedido desde el Día 4; la imagen de sustento se puede cargar desde el Día 3 para dejarlo listo antes del pase. Además, esta bandeja principal incluye reparto intercalado diario: en modo automático reparte pedidos sin asignar entre asesoras activas; en modo manual el supervisor los mueve pedido por pedido. También puedes usar la vista Últimos 4 días hábiles para concentrar el seguimiento reciente.'; $errorMessage = null; @@ -922,7 +922,7 @@ try { $aImport = cc_test_import_time($a); $bImport = cc_test_import_time($b); - if (cc_test_is_tuani_recoverables_store_key($storeKey) && in_array($view, ['pendientes_hoy', 'todos'], true)) { + if (cc_test_is_recoverables_store_key($storeKey) && in_array($view, ['pendientes_hoy', 'todos'], true)) { return cc_test_compare_recoverables_orders_desc($a, $b); } @@ -1042,7 +1042,7 @@ try { } if ($view === 'todos') { - if (cc_test_is_tuani_recoverables_store_key($storeKey)) { + if (cc_test_is_recoverables_store_key($storeKey)) { return cc_test_compare_recoverables_orders_desc($a, $b); } @@ -1179,14 +1179,14 @@ if (!empty($_GET['ajax_refresh'])) { } if ($isTuaniRecuperablesStore) { - $pageTitle = 'Carritos recuperables | Bandeja compartida'; - $pageDescription = 'Bandeja compartida para que cualquier asesora gestione carritos recuperables con vistas de seguimiento y observados desde Drive.'; + $pageTitle = $storeLabel . ' | Bandeja compartida'; + $pageDescription = 'Bandeja compartida para que cualquier asesora gestione ' . mb_strtolower($storeLabel) . ' con vistas de seguimiento y observados desde Drive.'; } else { $pageTitle = 'Pedidos Asignados | Bandeja de la asesora'; $pageDescription = 'Bandeja para que cada asesora gestione sus pedidos asignados con vistas de hoy, últimos 4 días hábiles, estados, historial y acciones.'; } -$callCenterSectionLabel = $isTuaniRecuperablesStore ? 'Carritos recuperables' : 'Pedidos Asignados'; +$callCenterSectionLabel = $isTuaniRecuperablesStore ? $storeLabel : 'Pedidos Asignados'; require_once 'layout_header.php'; ?> @@ -1399,7 +1399,7 @@ require_once 'layout_header.php'; Solo pedidos válidos: IDs #D... - Abrir Carritos recuperables (#D...) + Abrir (#D...)
@@ -1412,7 +1412,7 @@ require_once 'layout_header.php'; $group): ?> @@ -1422,9 +1422,9 @@ require_once 'layout_header.php';
Dentro de
- Pedidos + Pedidos $childConfig): ?> - + diff --git a/gestiones_callcenter.php b/gestiones_callcenter.php index 09a2f75c..c4c281df 100644 --- a/gestiones_callcenter.php +++ b/gestiones_callcenter.php @@ -223,6 +223,12 @@ if (!isset($availableStores[$storeKey])) { } $storeConfig = $availableStores[$storeKey]; $storeLabel = (string) ($storeConfig['label'] ?? strtoupper($storeKey)); +$recoverablesStoreKey = trim((string) ($storeConfig['recoverables_store_key'] ?? '')); +$recoverablesStoreLabel = $recoverablesStoreKey !== '' && isset($availableStores[$recoverablesStoreKey]) ? (string) ($availableStores[$recoverablesStoreKey]['label'] ?? strtoupper($recoverablesStoreKey)) : ''; +$recoverablesMainStoreKey = trim((string) ($storeConfig['main_store_key'] ?? '')); +$recoverablesMainStoreLabel = $recoverablesMainStoreKey !== '' && isset($availableStores[$recoverablesMainStoreKey]) ? (string) ($availableStores[$recoverablesMainStoreKey]['label'] ?? strtoupper($recoverablesMainStoreKey)) : $storeLabel; +$recoverablesStoreLabelHtml = htmlspecialchars($storeLabel); +$recoverablesMainStoreLabelHtml = htmlspecialchars($recoverablesMainStoreLabel); $usesIncrementalSync = !empty($storeConfig['incremental_sync']); $storeNav = drive_test_store_navigation_state($availableStores, $storeKey); $storeNavGroups = $storeNav['groups']; @@ -232,7 +238,7 @@ $activeStoreGroupChildren = $storeNav['active_group_children'] ?? []; $parentStoreLabel = (string) ($storeNav['parent_label'] ?? ''); $isMainTuaniStore = cc_test_is_tuani_main_store_key($storeKey); -$isTuaniRecuperablesStore = $storeKey === 'tuani_recuperables'; +$isTuaniRecuperablesStore = cc_test_is_recoverables_store_key($storeKey); if ($isTuaniRecuperablesStore && trim((string) ($_GET['view'] ?? '')) === '') { $view = 'todos'; } @@ -244,17 +250,11 @@ $viewCardColumnClass = $isTuaniRecuperablesStore ? 'col-md-6 col-xl-2' : 'col-md $callCenterDefaultView = ($isMainTuaniStore || $isTuaniRecuperablesStore) ? cc_test_callcenter_pro_default_view_key($storeKey) : $view; $viewCards = $isTuaniRecuperablesStore ? [ - 'pendientes_hoy' => [ - 'label' => 'Carritos recuperables', - 'heading' => 'Carritos recuperables', - 'stat_key' => 'pendientes_hoy', - 'active_class' => 'bg-dark text-white', - ], - 'nuevos_hoy' => [ - 'label' => 'Nuevos hoy', - 'heading' => 'Nuevos hoy', - 'stat_key' => 'nuevos_hoy', - 'active_class' => 'bg-primary-subtle border border-primary', + 'todos' => [ + 'label' => 'Todos', + 'heading' => 'Todos los pedidos cargados', + 'stat_key' => 'total', + 'active_class' => 'bg-light border', ], 'confirmados' => [ 'label' => 'Confirmados', @@ -280,11 +280,11 @@ $viewCards = $isTuaniRecuperablesStore ? [ 'stat_key' => 'observados', 'active_class' => 'bg-warning-subtle border border-warning', ], - 'todos' => [ - 'label' => 'Todos', - 'heading' => 'Todos los pedidos cargados', - 'stat_key' => 'total', - 'active_class' => 'bg-light border', + 'pendientes_hoy' => [ + 'label' => $storeLabel, + 'heading' => $storeLabel, + 'stat_key' => 'pendientes_hoy', + 'active_class' => 'bg-dark text-white', ], ] : [ 'pendientes_hoy' => [ @@ -358,7 +358,7 @@ $_SESSION[cc_test_callcenter_store_session_key()] = cc_test_normalize_context_ke $_SESSION[cc_test_callcenter_view_session_key()] = cc_test_normalize_context_key($view); $viewStatesNote = $isTuaniRecuperablesStore - ? 'Estados disponibles: Carritos recuperables, Nuevos hoy, Seguimiento, Observados, Confirmados, Recuperados y Todos. La vista Nuevos hoy agrupa los pedidos más recientes agregados desde Drive. Esta bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en TUANI principal, se marca en gris como Pedido repetido en tienda solo en esta bandeja. Las vistas Carritos recuperables y Todos arrancan en la fila 2000, solo toman pedidos desde esa fila y se ordenan por el número #D más alto, lo que mantiene arriba el código más reciente, al más antiguo, en bloques de 200 pedidos.' + ? 'Estados disponibles: ' . $recoverablesStoreLabelHtml . ', Seguimiento, Observados, Confirmados, Recuperados y Todos. Esta bandeja abre por defecto en Todos. La bandeja compartida está disponible para cualquier asesora y, cuando una asesora gestiona un carrito recuperable, el sistema lo asigna automáticamente a quien lo trabaja. Si el teléfono ya existe en ' . $recoverablesMainStoreLabelHtml . ' principal, se marca en gris como Pedido repetido en tienda solo en esta bandeja. Las vistas ' . $recoverablesStoreLabelHtml . ' y Todos arrancan en la fila ' . (int) ($storeConfig['startRow'] ?? 0) . ', solo toman pedidos desde esa fila y se ordenan por el número #D más alto, lo que mantiene arriba el código más reciente, al más antiguo, en bloques de 200 pedidos.' : 'Estados disponibles: Por llamar, Devolver llamada, Observado, Se envió número de cuenta, Confirmado contraentrega, Confirmado envío, Cancelado y Repetido. Promo Final se habilita para mover el pedido desde el Día 4; la imagen de sustento se puede cargar desde el Día 3 para dejarlo listo. En las vistas Todos y Últimos 4 días hábiles, la llamada y la gestión siguen disponibles desde el panel.'; $errorMessage = null; @@ -1149,7 +1149,7 @@ try { $aImport = cc_test_import_time($a); $bImport = cc_test_import_time($b); - if (cc_test_is_tuani_recoverables_store_key($storeKey) && in_array($view, ['pendientes_hoy', 'todos'], true)) { + if (cc_test_is_recoverables_store_key($storeKey) && in_array($view, ['pendientes_hoy', 'todos'], true)) { return cc_test_compare_recoverables_orders_desc($a, $b); } @@ -1227,7 +1227,7 @@ try { } if ($view === 'todos') { - if (cc_test_is_tuani_recoverables_store_key($storeKey)) { + if (cc_test_is_recoverables_store_key($storeKey)) { return cc_test_compare_recoverables_orders_desc($a, $b); } @@ -1310,14 +1310,14 @@ try { } if ($isTuaniRecuperablesStore) { - $pageTitle = 'Carritos recuperables | Base de Datos Pedidos'; - $pageDescription = 'Bandeja compartida para que cualquier asesora revise carritos recuperables con vistas de seguimiento y observados cargados desde Drive.'; + $pageTitle = $storeLabel . ' | Base de Datos Pedidos'; + $pageDescription = 'Bandeja compartida para que cualquier asesora revise ' . mb_strtolower($storeLabel) . ' con vistas de seguimiento y observados cargados desde Drive.'; } else { $pageTitle = 'Base de Datos Pedidos | Asignación'; $pageDescription = 'Bandejas de asignación y gestión de estados para el Call Center, cargadas desde Drive.'; } -$callCenterSectionLabel = $isTuaniRecuperablesStore ? 'Carritos recuperables' : 'Pedidos Asignados'; +$callCenterSectionLabel = $isTuaniRecuperablesStore ? $storeLabel : 'Pedidos Asignados'; require_once 'layout_header.php'; ?> @@ -1655,7 +1655,7 @@ require_once 'layout_header.php'; Solo pedidos válidos: IDs #D... - Abrir Carritos recuperables (#D...) + Abrir (#D...)
@@ -1666,7 +1666,7 @@ require_once 'layout_header.php'; $group): ?> @@ -1676,9 +1676,9 @@ require_once 'layout_header.php';
Dentro de
- Pedidos + Pedidos $childConfig): ?> - + diff --git a/includes/callcenter_test_helpers.php b/includes/callcenter_test_helpers.php index f39500b5..fb0f0f8c 100644 --- a/includes/callcenter_test_helpers.php +++ b/includes/callcenter_test_helpers.php @@ -253,7 +253,7 @@ function cc_test_default_assessor_keys(): array function cc_test_is_tuani_store_key(string $storeKey): bool { $storeKey = trim(mb_strtolower($storeKey)); - return in_array($storeKey, ['flower', 'otra_tienda', 'tuani_recuperables'], true); + return in_array($storeKey, ['flower', 'otra_tienda', 'flower_recuperables', 'tuani_recuperables'], true); } function cc_test_is_tuani_main_store_key(string $storeKey): bool @@ -262,10 +262,15 @@ function cc_test_is_tuani_main_store_key(string $storeKey): bool return in_array($storeKey, ['flower', 'otra_tienda'], true); } -function cc_test_is_tuani_recoverables_store_key(string $storeKey): bool +function cc_test_is_recoverables_store_key(string $storeKey): bool { $storeKey = trim(mb_strtolower($storeKey)); - return $storeKey === 'tuani_recuperables'; + return in_array($storeKey, ['flower_recuperables', 'tuani_recuperables'], true); +} + +function cc_test_is_tuani_recoverables_store_key(string $storeKey): bool +{ + return cc_test_is_recoverables_store_key($storeKey); } function cc_test_callcenter_pro_default_view_key(string $storeKey): string @@ -274,8 +279,8 @@ function cc_test_callcenter_pro_default_view_key(string $storeKey): string return 'ultimos_3_dias'; } - if (cc_test_is_tuani_recoverables_store_key($storeKey)) { - return 'nuevos_hoy'; + if (cc_test_is_recoverables_store_key($storeKey)) { + return 'todos'; } return 'pendientes_hoy'; @@ -358,14 +363,18 @@ if (!function_exists('cc_test_fetch_store_phone_index')) { } if (!function_exists('cc_test_mark_recoverables_duplicate_orders')) { - function cc_test_mark_recoverables_duplicate_orders(PDO $pdo, array $orders, string $storeKey, string $mainStoreKey = 'otra_tienda'): array + function cc_test_mark_recoverables_duplicate_orders(PDO $pdo, array $orders, string $storeKey, string $mainStoreKey = ''): array { $storeKey = trim(mb_strtolower($storeKey)); - if ($storeKey !== 'tuani_recuperables' || empty($orders)) { + if (!cc_test_is_recoverables_store_key($storeKey) || empty($orders)) { return $orders; } $mainStoreKey = trim(mb_strtolower($mainStoreKey)); + if ($mainStoreKey === '') { + $mainStoreKey = $storeKey === 'flower_recuperables' ? 'flower' : 'otra_tienda'; + } + if ($mainStoreKey === '') { return $orders; } @@ -1484,6 +1493,30 @@ function cc_test_followup_tracking_states(): array return ['POR LLAMAR', 'DEVOLVER LLAMADA', 'OBSERVADO', 'SE ENVIO NUMERO DE CUENTA']; } +function cc_test_recoverable_claimable_states(): array +{ + return cc_test_followup_tracking_states(); +} + +function cc_test_is_recoverable_claimable_state(string $estado): bool +{ + $estado = cc_test_normalize_state($estado); + if ($estado === '') { + return true; + } + + return in_array($estado, cc_test_recoverable_claimable_states(), true); +} + +function cc_test_can_claim_recoverable_order(?array $tracking): bool +{ + if ($tracking === null) { + return true; + } + + return cc_test_is_recoverable_claimable_state((string) ($tracking['estado'] ?? '')); +} + function cc_test_followup_parse_datetime(?string $value): ?DateTimeImmutable { $value = trim((string) $value); diff --git a/includes/drive_test_orders.php b/includes/drive_test_orders.php index 9433ca7b..8122a56e 100644 --- a/includes/drive_test_orders.php +++ b/includes/drive_test_orders.php @@ -26,6 +26,23 @@ function drive_test_available_stores(): array 'delivery_sync_start_row' => 8687, 'delivery_sync_column' => 'W', 'min_codigo_number' => 37431, + 'recoverables_store_key' => 'flower_recuperables', + 'enforce_db_start_row' => true, + 'incremental_sync' => true, + ], + // Nueva bandeja recuperable de Flower desde la pestaña compartida. + 'flower_recuperables' => [ + 'label' => 'Carritos recuperables Flower', + 'sheet_title' => 'easysell_abandoneds', + 'spreadsheet_id' => '1SSmQuR9quxeQbMKNMDkRe8-n1gU7WuEfsFaJ3WKFO-c', + 'startRow' => 1503, + 'status_sync_start_row' => 1503, + 'status_sync_column' => 'V', + 'advisor_sync_start_row' => 1503, + 'advisor_sync_column' => 'X', + 'delivery_sync_start_row' => 1503, + 'delivery_sync_column' => 'W', + 'main_store_key' => 'flower', 'enforce_db_start_row' => true, 'incremental_sync' => true, ], @@ -36,6 +53,7 @@ function drive_test_available_stores(): array 'spreadsheet_id' => '1QYKeBJIIqYm6yW6Ka-5gKdxhUHwXOAc0No7RjnimxTw', 'sheet_gid' => 1523126328, 'startRow' => 6804, + 'recoverables_store_key' => 'tuani_recuperables', 'enforce_db_start_row' => true, 'incremental_sync' => true, 'status_sync_start_row' => 7207, @@ -45,9 +63,9 @@ function drive_test_available_stores(): array 'delivery_sync_start_row' => 7291, 'delivery_sync_column' => 'W', ], - // Bandeja compartida de carritos recuperables/abandonados: misma estructura, pero desde la fila 2000. + // Bandeja compartida de carritos recuperables Tuani/abandonados: misma estructura, pero desde la fila 2000. 'tuani_recuperables' => [ - 'label' => 'Carritos recuperables', + 'label' => 'Carritos recuperables Tuani', 'sheet_title' => 'easysell_abandoneds', 'spreadsheet_id' => '1QYKeBJIIqYm6yW6Ka-5gKdxhUHwXOAc0No7RjnimxTw', 'sheet_gid' => 965530888, @@ -58,6 +76,7 @@ function drive_test_available_stores(): array 'advisor_sync_column' => 'X', 'delivery_sync_start_row' => 2000, 'delivery_sync_column' => 'W', + 'main_store_key' => 'otra_tienda', 'enforce_db_start_row' => true, 'incremental_sync' => true, ], @@ -348,6 +367,7 @@ function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?st } $storeConfig = drive_test_get_store_config($storeKey); + $sheetTitle = trim((string) ($storeConfig['sheet_title'] ?? '')); $spreadsheetId = trim((string) ($storeConfig['spreadsheet_id'] ?? '')); if ($spreadsheetId === '') { throw new RuntimeException('Configuración de Drive para la tienda no válida.'); @@ -366,7 +386,7 @@ function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?st $client->addScope(Google\Service\Sheets::SPREADSHEETS); $service = new Google\Service\Sheets($client); - $statusRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $statusColumn . $sourceRow); + $statusRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $statusColumn . $sourceRow, $sheetTitle); $estadoNormalizado = cc_test_normalize_state(trim($estado)); $deliveryDate = trim((string) $deliveryDate); @@ -389,7 +409,7 @@ function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?st $deliveryStartRow = drive_test_delivery_sync_start_row($storeKey); if ($deliveryStartRow !== null && $sourceRow >= $deliveryStartRow) { $deliveryColumn = drive_test_delivery_sync_column($storeKey); - $deliveryRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $deliveryColumn . $sourceRow); + $deliveryRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $deliveryColumn . $sourceRow, $sheetTitle); $updates[] = new Google\Service\Sheets\ValueRange([ 'range' => $deliveryRange, 'values' => [[ $deliveryLabel ]], @@ -400,7 +420,7 @@ function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?st $advisorStartRow = drive_test_advisor_sync_start_row($storeKey); if ($advisorName !== '' && $advisorStartRow !== null && $sourceRow >= $advisorStartRow) { $advisorColumn = drive_test_advisor_sync_column($storeKey); - $advisorRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $advisorColumn . $sourceRow); + $advisorRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $advisorColumn . $sourceRow, $sheetTitle); $updates[] = new Google\Service\Sheets\ValueRange([ 'range' => $advisorRange, 'values' => [[ $advisorName ]], @@ -428,9 +448,15 @@ function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?st ]; } -function drive_test_resolve_sheet_a1_range($service, string $spreadsheetId, ?int $sheetGid, string $rangeA1): string +function drive_test_resolve_sheet_a1_range($service, string $spreadsheetId, ?int $sheetGid, string $rangeA1, ?string $sheetTitle = null): string { + $sheetTitle = trim((string) $sheetTitle); if ($sheetGid === null) { + if ($sheetTitle !== '') { + $escapedTitle = str_replace("'", "''", $sheetTitle); + return "'{$escapedTitle}'!{$rangeA1}"; + } + return $rangeA1; } @@ -502,6 +528,7 @@ function drive_test_extract_codigo_number(?string $codigo): ?int function drive_test_fetch_orders(int $limit = 10, ?int $startRow = null, string $storeKey = 'flower'): array { $storeConfig = drive_test_get_store_config($storeKey); + $sheetTitle = trim((string) ($storeConfig['sheet_title'] ?? '')); if ($startRow === null || $startRow <= 0) { $startRow = (int) ($storeConfig['startRow'] ?? 0); } @@ -525,7 +552,7 @@ function drive_test_fetch_orders(int $limit = 10, ?int $startRow = null, string $service = new Google\Service\Sheets($client); - $range = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $rangeA1); + $range = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $rangeA1, $sheetTitle); $response = $service->spreadsheets_values->get($spreadsheetId, $range); $values = $response->getValues(); diff --git a/layout_header.php b/layout_header.php index 2d195657..8322fc7a 100644 --- a/layout_header.php +++ b/layout_header.php @@ -46,6 +46,9 @@ if (in_array($currentAssessorFilter, cc_test_callcenter_assessor_filter_clear_va } $currentCallCenterStore = cc_test_normalize_context_key($_GET['store'] ?? ($_SESSION[cc_test_callcenter_store_session_key()] ?? '')); $currentCallCenterView = cc_test_normalize_context_key($_GET['view'] ?? ($_SESSION[cc_test_callcenter_view_session_key()] ?? '')); +if (cc_test_is_tuani_recoverables_store_key($currentCallCenterStore) && $currentCallCenterView === 'nuevos_hoy') { + $currentCallCenterView = 'todos'; +} $shouldPersistAssessor = $currentAssessorFilter !== ''; $callCenterPersistentParams = []; if ($shouldPersistAssessor) { diff --git a/save_llamada.php b/save_llamada.php index 32a6c32a..ce53415b 100644 --- a/save_llamada.php +++ b/save_llamada.php @@ -50,8 +50,9 @@ try { $storeKey = ''; } - $isRecoverablesQueue = $storeKey === 'tuani_recuperables'; - $canClaimRecoverable = $isRecoverablesQueue && $trackingUserId === null; + $isRecoverablesQueue = cc_test_is_recoverables_store_key($storeKey); + $canClaimRecoverable = $isRecoverablesQueue && cc_test_can_claim_recoverable_order($tracking); + $needsRecoverableClaim = $canClaimRecoverable && ($tracking === null || $trackingUserId !== $asesor_id); if ($tracking === null) { if (!$canClaimRecoverable) { @@ -65,7 +66,7 @@ try { exit; } - if ($canClaimRecoverable) { + if ($needsRecoverableClaim) { cc_test_upsert_assignee($pdo, $pedido_id, $asesor_id); } } diff --git a/test_importar_drive.php b/test_importar_drive.php index 98584cd1..4e7f5a51 100644 --- a/test_importar_drive.php +++ b/test_importar_drive.php @@ -57,7 +57,7 @@ try { $service = new Google\Service\Sheets($client); - $range = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $rangeA1); + $range = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $rangeA1, $sheetTitle); $response = $service->spreadsheets_values->get($spreadsheetId, $range); $values = $response->getValues(); diff --git a/update_callcenter_test_tracking.php b/update_callcenter_test_tracking.php index 626a72c2..9012940f 100644 --- a/update_callcenter_test_tracking.php +++ b/update_callcenter_test_tracking.php @@ -824,7 +824,7 @@ try { $sourceOrderForAuth = cc_test_fetch_source_order($pdo, $sourceKey); $sourceStoreKeyForAuth = trim((string) ($sourceOrderForAuth['store_key'] ?? '')); - $isRecoverablesQueue = $sourceStoreKeyForAuth === 'tuani_recuperables'; + $isRecoverablesQueue = cc_test_is_recoverables_store_key($sourceStoreKeyForAuth); if (!array_key_exists('numero_cuenta_sede_id', $_POST)) { $numeroCuentaSedeIdCurrent = trim((string) ($currentTracking['numero_cuenta_sede_id'] ?? '')); @@ -851,12 +851,12 @@ try { $role = (string) ($_SESSION['user_role'] ?? ''); $isAdmin = in_array($role, ['Administrador', 'admin'], true); + $currentUserId = (int) ($_SESSION['user_id'] ?? 0); + $trackingUserId = $currentTracking ? (int) ($currentTracking['user_id'] ?? 0) : null; + // En carritos recuperables, los estados de seguimiento siguen siendo retomables por otra asesora. + // Solo los confirmados o cerrados quedan bloqueados para nuevas tomas. + $canClaimRecoverable = $isRecoverablesQueue && cc_test_can_claim_recoverable_order($currentTracking); if (!$isAdmin) { - $currentUserId = (int) ($_SESSION['user_id'] ?? 0); - $trackingUserId = $currentTracking ? (int) ($currentTracking['user_id'] ?? 0) : null; - // En la bandeja de carritos recuperables, cualquier pedido sin asignar - // debe poder ser tomado por la asesora, sin importar el estado inicial. - $canClaimRecoverable = $isRecoverablesQueue && $trackingUserId === null; if ($currentTracking === null) { if (!$canClaimRecoverable) { http_response_code(403); @@ -1101,6 +1101,10 @@ try { $pdo->beginTransaction(); + if (!$isAdmin && $canClaimRecoverable) { + cc_test_upsert_assignee($pdo, $sourceKey, $currentUserId); + } + $stmt = $pdo->prepare( 'INSERT INTO callcenter_test_tracking ( source_key,