From de25048671653d741318c1e07934fecd80f60b56 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Sat, 25 Jul 2026 18:54:23 +0000 Subject: [PATCH] Autosave: 20260725-185550 --- includes/drive_test_orders.php | 196 ++++++++++++++++++++++++++++ update_callcenter_test_tracking.php | 46 +++++++ 2 files changed, 242 insertions(+) diff --git a/includes/drive_test_orders.php b/includes/drive_test_orders.php index fb930bda..9ab0b3c4 100644 --- a/includes/drive_test_orders.php +++ b/includes/drive_test_orders.php @@ -32,6 +32,10 @@ function drive_test_available_stores(): array 'startRow' => 6804, 'enforce_db_start_row' => true, 'incremental_sync' => true, + 'status_sync_start_row' => 7207, + 'status_sync_column' => 'V', + 'advisor_sync_start_row' => 7207, + 'advisor_sync_column' => 'X', ], // Bandeja compartida de carritos recuperables: misma estructura, pero desde la fila 2000. 'tuani_recuperables' => [ @@ -131,6 +135,198 @@ function drive_test_get_store_config(string $storeKey): array return $stores[$storeKey] + ['key' => $storeKey]; } +function drive_test_status_sync_start_row(string $storeKey): ?int +{ + $storeConfig = drive_test_get_store_config($storeKey); + if (!array_key_exists('status_sync_start_row', $storeConfig)) { + return null; + } + + $startRow = (int) $storeConfig['status_sync_start_row']; + return $startRow > 0 ? $startRow : null; +} + +function drive_test_status_sync_start_date(string $storeKey): ?DateTimeImmutable +{ + $storeConfig = drive_test_get_store_config($storeKey); + $rawDate = trim((string) ($storeConfig['status_sync_start_date'] ?? '')); + if ($rawDate === '') { + return null; + } + + try { + return new DateTimeImmutable($rawDate); + } catch (Throwable $exception) { + return null; + } +} + +function drive_test_status_sync_column(string $storeKey): string +{ + $storeConfig = drive_test_get_store_config($storeKey); + $column = strtoupper(trim((string) ($storeConfig['status_sync_column'] ?? 'V'))); + + return preg_match('/^[A-Z]+$/', $column) ? $column : 'V'; +} + +function drive_test_advisor_sync_start_row(string $storeKey): ?int +{ + $storeConfig = drive_test_get_store_config($storeKey); + if (!array_key_exists('advisor_sync_start_row', $storeConfig)) { + return null; + } + + $startRow = (int) $storeConfig['advisor_sync_start_row']; + return $startRow > 0 ? $startRow : null; +} + +function drive_test_advisor_sync_column(string $storeKey): string +{ + $storeConfig = drive_test_get_store_config($storeKey); + $column = strtoupper(trim((string) ($storeConfig['advisor_sync_column'] ?? 'R'))); + + return preg_match('/^[A-Z]+$/', $column) ? $column : 'R'; +} + +function drive_test_status_sync_reference_datetime(array $sourceOrder): ?DateTimeImmutable +{ + $candidates = [ + trim((string) ($sourceOrder['first_seen_at'] ?? '')), + trim((string) ($sourceOrder['drive_imported_at'] ?? '')), + trim((string) ($sourceOrder['updated_at'] ?? '')), + ]; + + foreach ($candidates as $candidate) { + if ($candidate === '') { + continue; + } + + try { + return new DateTimeImmutable($candidate); + } catch (Throwable $exception) { + continue; + } + } + + return null; +} + +function drive_test_should_sync_status_to_sheet(array $sourceOrder): bool +{ + $storeKey = trim((string) ($sourceOrder['store_key'] ?? '')); + if ($storeKey === '') { + return false; + } + + $sourceRow = (int) ($sourceOrder['source_row'] ?? 0); + if ($sourceRow <= 0) { + return false; + } + + $cutoffRow = drive_test_status_sync_start_row($storeKey); + if ($cutoffRow !== null) { + return $sourceRow >= $cutoffRow; + } + + $cutoff = drive_test_status_sync_start_date($storeKey); + if ($cutoff === null) { + return false; + } + + $referenceDate = drive_test_status_sync_reference_datetime($sourceOrder); + if ($referenceDate === null) { + return false; + } + + return $referenceDate->format('Y-m-d') >= $cutoff->format('Y-m-d'); +} + +function drive_test_sync_status_to_sheet(array $sourceOrder, string $estado, ?string $advisorName = null): array +{ + $storeKey = trim((string) ($sourceOrder['store_key'] ?? '')); + if ($storeKey === '') { + return [ + 'success' => false, + 'skipped' => true, + 'reason' => 'missing_store_key', + ]; + } + + if (!drive_test_should_sync_status_to_sheet($sourceOrder)) { + return [ + 'success' => true, + 'skipped' => true, + 'reason' => 'before_cutoff', + ]; + } + + $sourceRow = (int) ($sourceOrder['source_row'] ?? 0); + if ($sourceRow <= 0) { + return [ + 'success' => false, + 'skipped' => true, + 'reason' => 'missing_source_row', + ]; + } + + $storeConfig = drive_test_get_store_config($storeKey); + $spreadsheetId = trim((string) ($storeConfig['spreadsheet_id'] ?? '')); + if ($spreadsheetId === '') { + throw new RuntimeException('Configuración de Drive para la tienda no válida.'); + } + + $credentialsPath = __DIR__ . '/../google_credentials.json'; + if (!file_exists($credentialsPath)) { + throw new RuntimeException('No se encontró el archivo de credenciales de Google.'); + } + + $statusColumn = drive_test_status_sync_column($storeKey); + $sheetGid = array_key_exists('sheet_gid', $storeConfig) ? ($storeConfig['sheet_gid'] === null ? null : (int) $storeConfig['sheet_gid']) : null; + + $client = new Google\Client(); + $client->setAuthConfig($credentialsPath); + $client->addScope(Google\Service\Sheets::SPREADSHEETS); + + $service = new Google\Service\Sheets($client); + $statusRange = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $statusColumn . $sourceRow); + $estadoNormalizado = cc_test_normalize_state(trim($estado)); + $updates = [ + new Google\Service\Sheets\ValueRange([ + 'range' => $statusRange, + 'values' => [[ $estadoNormalizado ]], + ]), + ]; + + $advisorName = drive_test_compact_text($advisorName); + $advisorRange = null; + $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); + $updates[] = new Google\Service\Sheets\ValueRange([ + 'range' => $advisorRange, + 'values' => [[ $advisorName ]], + ]); + } + + $body = new Google\Service\Sheets\BatchUpdateValuesRequest([ + 'data' => $updates, + 'valueInputOption' => 'RAW', + ]); + $service->spreadsheets_values->batchUpdate($spreadsheetId, $body); + + return [ + 'success' => true, + 'skipped' => false, + 'store_key' => $storeKey, + 'source_row' => $sourceRow, + 'range' => $statusRange, + 'advisor_range' => $advisorRange, + 'estado' => $estadoNormalizado, + 'advisor_name' => $advisorRange !== null ? $advisorName : null, + ]; +} + function drive_test_resolve_sheet_a1_range($service, string $spreadsheetId, ?int $sheetGid, string $rangeA1): string { if ($sheetGid === null) { diff --git a/update_callcenter_test_tracking.php b/update_callcenter_test_tracking.php index 98d92a2b..6c769fd0 100644 --- a/update_callcenter_test_tracking.php +++ b/update_callcenter_test_tracking.php @@ -2,6 +2,7 @@ session_start(); require_once 'db/config.php'; require_once 'includes/callcenter_test_helpers.php'; +require_once 'includes/drive_test_orders.php'; require_once 'includes/contraentrega_cobertura.php'; header('Content-Type: application/json; charset=utf-8'); @@ -65,6 +66,33 @@ function cc_test_normalize_optional_image_upload(string $key): ?array return $file; } +function cc_test_resolve_user_display_name(PDO $pdo, ?int $userId): string +{ + if ($userId === null || $userId <= 0) { + return ''; + } + + try { + $stmt = $pdo->prepare('SELECT nombre_asesor, username FROM users WHERE id = ? LIMIT 1'); + $stmt->execute([$userId]); + if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { + $nombreAsesor = trim((string) ($row['nombre_asesor'] ?? '')); + if ($nombreAsesor !== '') { + return $nombreAsesor; + } + + $username = trim((string) ($row['username'] ?? '')); + if ($username !== '') { + return $username; + } + } + } catch (Throwable $exception) { + // Use the fallback below if the user lookup fails. + } + + return 'Asesor #' . $userId; +} + function cc_test_store_tracking_evidence_image(array $file, string $prefix, string $sourceKey, int $userId): array { $tmpName = (string) ($file['tmp_name'] ?? ''); @@ -116,6 +144,7 @@ function cc_test_fetch_source_order(PDO $pdo, string $sourceKey): ?array 'SELECT source_key, store_key, + source_row, codigo, import_id, drive_imported_at, @@ -968,6 +997,7 @@ try { $userIdToSet = $isAdmin ? ($currentTracking ? ((int) ($currentTracking['user_id'] ?? 0) > 0 ? (int) $currentTracking['user_id'] : null) : null) : (int) $_SESSION['user_id']; + $advisorNameForDrive = cc_test_resolve_user_display_name($pdo, $userIdToSet); $proximaRaw = trim((string) ($_POST['proxima_llamada_at'] ?? '')); $proximaLlamada = null; @@ -1335,6 +1365,21 @@ try { $pdo->commit(); + $driveSyncResult = null; + if ($sourceOrderForAuth) { + try { + $driveSyncResult = drive_test_sync_status_to_sheet($sourceOrderForAuth, $estado, $advisorNameForDrive); + } catch (Throwable $driveException) { + error_log('update_callcenter_test_tracking.php drive sync: ' . $driveException->getMessage()); + $driveSyncResult = [ + 'success' => false, + 'skipped' => false, + 'reason' => 'sync_error', + 'error' => 'No se pudo sincronizar el estado con Drive.', + ]; + } + } + $message = 'Gestión actualizada correctamente.'; if ($moverAPromoFinal && $promoFinalEvidencePath !== null) { $message = 'Pedido movido a Promo Final correctamente.'; @@ -1367,6 +1412,7 @@ try { 'ruta_contraentrega_subido_at' => $rutaSubidoAt, 'pedido_rotulado_pedido_id' => $pedidoRotuladoId, 'pedido_rotulado_subido_at' => $pedidoRotuladoSubidoAt, + 'drive_sync' => $driveSyncResult, ]); } catch (Throwable $exception) { if (isset($pdo) && $pdo instanceof PDO && $pdo->inTransaction()) {