[ 'label' => 'Flower', 'spreadsheet_id' => '1SSmQuR9quxeQbMKNMDkRe8-n1gU7WuEfsFaJ3WKFO-c', 'sheet_gid' => null, 'startRow' => 7796, // Pedido #37431 'min_codigo_number' => 37431, 'enforce_db_start_row' => true, 'incremental_sync' => true, ], // Segunda tienda (nuevo link que pasaste). 'otra_tienda' => [ 'label' => 'TUANI', 'spreadsheet_id' => '1QYKeBJIIqYm6yW6Ka-5gKdxhUHwXOAc0No7RjnimxTw', 'sheet_gid' => 1523126328, 'startRow' => 6804, 'enforce_db_start_row' => true, 'incremental_sync' => true, ], ]; } function drive_test_get_store_config(string $storeKey): array { $storeKey = trim(mb_strtolower($storeKey)); $stores = drive_test_available_stores(); if (!isset($stores[$storeKey])) { return $stores['flower']; } return $stores[$storeKey] + ['key' => $storeKey]; } function drive_test_resolve_sheet_a1_range($service, string $spreadsheetId, ?int $sheetGid, string $rangeA1): string { if ($sheetGid === null) { return $rangeA1; } static $cache = []; $cacheKey = $spreadsheetId . '|' . (string) $sheetGid . '|' . $rangeA1; if (isset($cache[$cacheKey])) { return $cache[$cacheKey]; } try { $meta = $service->spreadsheets->get($spreadsheetId, ['fields' => 'sheets(properties(sheetId,title))']); foreach (($meta->getSheets() ?? []) as $sheet) { $props = $sheet->getProperties(); if (!$props) { continue; } if ((int) $props->getSheetId() === (int) $sheetGid) { $title = trim((string) ($props->getTitle() ?? '')); if ($title !== '') { // Sheet names with spaces/special chars must be quoted. $escaped = str_replace("'", "''", $title); $cache[$cacheKey] = "'{$escaped}'!{$rangeA1}"; return $cache[$cacheKey]; } } } } catch (Throwable $exception) { // Fallback to default range. } $cache[$cacheKey] = $rangeA1; return $rangeA1; } function drive_test_get_cell(array $row, array $indexes, array $aliases, string $default = ''): string { foreach ($aliases as $alias) { $normalized = drive_test_normalize_header($alias); if (array_key_exists($normalized, $indexes)) { return trim((string) ($row[$indexes[$normalized]] ?? $default)); } } return $default; } function drive_test_extract_codigo_number(?string $codigo): ?int { $digits = preg_replace('/\D+/', '', trim((string) $codigo)); if ($digits === '') { return null; } return (int) $digits; } function drive_test_fetch_orders(int $limit = 10, int $startRow = 5552, string $storeKey = 'flower'): array { $storeConfig = drive_test_get_store_config($storeKey); $credentialsPath = __DIR__ . '/../google_credentials.json'; $spreadsheetId = (string) ($storeConfig['spreadsheet_id'] ?? ''); $sheetGid = array_key_exists('sheet_gid', $storeConfig) ? ($storeConfig['sheet_gid'] === null ? null : (int) $storeConfig['sheet_gid']) : null; $rangeA1 = 'A:Z'; if ($spreadsheetId === '') { throw new RuntimeException('Configuración de Drive para la tienda no válida.'); } if (!file_exists($credentialsPath)) { throw new RuntimeException('No se encontró el archivo de credenciales de Google.'); } $client = new Google\Client(); $client->setAuthConfig($credentialsPath); $client->addScope(Google\Service\Sheets::SPREADSHEETS_READONLY); $service = new Google\Service\Sheets($client); $range = drive_test_resolve_sheet_a1_range($service, $spreadsheetId, $sheetGid, $rangeA1); $response = $service->spreadsheets_values->get($spreadsheetId, $range); $values = $response->getValues(); if (empty($values)) { return [ 'headers' => [], 'orders' => [], 'total_rows' => 0, ]; } $headers = $values[0] ?? []; $headerIndexes = []; foreach ($headers as $index => $header) { $normalized = drive_test_normalize_header((string) $header); if ($normalized === '') { $normalized = $index === 0 ? 'CODIGO' : 'COL_' . $index; } $headerIndexes[$normalized] = $index; } $dataRows = array_slice($values, 1); $startIndex = max(0, $startRow - 2); $totalDataRows = count($dataRows); if ($startIndex >= $totalDataRows) { $dataRows = []; } elseif ($startIndex > 0) { $dataRows = array_slice($dataRows, $startIndex, null, true); } $previewRows = $limit > 0 ? array_slice($dataRows, -$limit, null, true) : $dataRows; $previewRows = array_reverse($previewRows, true); $orders = []; $minCodigoNumber = isset($storeConfig['min_codigo_number']) ? (int) ($storeConfig['min_codigo_number'] ?? 0) : 0; foreach ($previewRows as $rowIndex => $row) { $codigo = trim((string) ($row[0] ?? '')); $importId = drive_test_get_cell($row, $headerIndexes, ['ID']); $nombre = drive_test_get_cell($row, $headerIndexes, ['NOMBRE']); $celular = preg_replace('/\D+/', '', drive_test_get_cell($row, $headerIndexes, ['CELULAR'])); $producto = drive_test_get_cell($row, $headerIndexes, ['PRODUCTO']); $cantidad = drive_test_get_cell($row, $headerIndexes, ['CANTIDAD']); $precio = drive_test_get_cell($row, $headerIndexes, ['PRECIO']); $pais = drive_test_get_cell($row, $headerIndexes, ['PAIS']); $coordenadas = drive_test_get_cell($row, $headerIndexes, ['COORDENADAS']); $ciudad = drive_test_get_cell($row, $headerIndexes, ['CIUDAD']); $metodo = drive_test_get_cell($row, $headerIndexes, ['METODO']); $sede = drive_test_get_cell($row, $headerIndexes, ['SEDE / ID', 'SEDE/ID']); $dni = drive_test_get_cell($row, $headerIndexes, ['N° DNI', 'N° DNI ', 'NRO DNI', 'DNI']); $observaciones = drive_test_get_cell($row, $headerIndexes, ['OBSERVACIONES', 'OBSERVACIONES ']); $direccion = drive_test_get_cell($row, $headerIndexes, ['DIRECION', 'DIRECCION']); $referencia = drive_test_get_cell($row, $headerIndexes, ['REFERENCIA']); $distrito = drive_test_get_cell($row, $headerIndexes, ['DISTRITO']); $sourceRow = (int) $rowIndex + 2; $codigoNumber = drive_test_extract_codigo_number($codigo); if ($minCodigoNumber > 0 && ($codigoNumber === null || $codigoNumber < $minCodigoNumber)) { continue; } // Importante: para 'flower' mantenemos EXACTAMENTE el algoritmo anterior // para no romper el historial/tracking ya existente. $sourceKeyBase = implode('|', [$codigo, $importId, $nombre, $celular, $producto]); if (($storeConfig['key'] ?? 'flower') === 'flower') { $sourceKey = sha1($sourceKeyBase); } else { $sourceKey = sha1(($storeConfig['key'] ?? $storeKey) . '|' . $sourceKeyBase); } $orders[] = [ 'source_key' => $sourceKey, 'source_row' => $sourceRow, 'codigo' => $codigo, 'import_id' => $importId, 'drive_imported_at' => drive_test_parse_datetime_mysql($importId), 'nombre' => $nombre, 'direccion' => $direccion, 'referencia' => $referencia, 'agencia' => '', 'sede_agencia' => '', 'distrito' => $distrito, 'celular' => $celular, 'producto' => $producto, 'cantidad' => $cantidad, 'precio' => $precio, 'pais' => $pais, 'coordenadas' => $coordenadas, 'ciudad' => $ciudad, 'metodo' => $metodo, 'sede' => $sede, 'dni' => $dni, 'observaciones' => $observaciones, ]; } return [ 'headers' => $headers, 'orders' => $orders, 'total_rows' => count($dataRows), ]; } function drive_test_fetch_tracking(PDO $pdo, array $sourceKeys): array { if (empty($sourceKeys)) { return []; } cc_test_ensure_tracking_table($pdo); $placeholders = implode(',', array_fill(0, count($sourceKeys), '?')); $stmt = $pdo->prepare("SELECT source_key, estado, nota_seguimiento, user_id, assigned_at, direccion, referencia, agencia, sede_agencia, sede, ciudad, distrito, dni, numero_cuenta_sede_id, numero_cuenta_dni, observaciones, coordenadas, producto, cantidad, precio, monto_adelantado, confirmacion_producto, confirmacion_cantidad, confirmacion_precio, confirmacion_producto_extra, confirmacion_cantidad_extra, confirmacion_precio_extra, proxima_llamada_at, fecha_entrega_programada, numero_cuenta_enviado_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, ruta_contraentrega_subido_at, ruta_contraentrega_subido_por, pedido_rotulado_pedido_id, pedido_rotulado_subido_at, pedido_rotulado_subido_por, ultima_gestion_at, updated_at FROM callcenter_test_tracking WHERE source_key IN ($placeholders)"); $stmt->execute($sourceKeys); $tracking = []; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $tracking[$row['source_key']] = $row; } return $tracking; } function drive_test_merge_tracking(array $orders, array $tracking): array { $editableFields = ['direccion', 'referencia', 'agencia', 'sede_agencia', 'sede', 'ciudad', 'distrito', 'dni', 'numero_cuenta_sede_id', 'numero_cuenta_dni', 'observaciones', 'coordenadas', 'producto', 'cantidad', 'precio', 'monto_adelantado', 'confirmacion_producto', 'confirmacion_cantidad', 'confirmacion_precio', 'confirmacion_producto_extra', 'confirmacion_cantidad_extra', 'confirmacion_precio_extra']; foreach ($orders as &$order) { $current = $tracking[$order['source_key']] ?? null; $order['estado'] = $current['estado'] ?? 'POR LLAMAR'; $order['nota_seguimiento'] = $current['nota_seguimiento'] ?? ''; $userId = array_key_exists('user_id', (array) $current) ? $current['user_id'] : null; $order['user_id'] = $userId !== null ? ((int) $userId > 0 ? (int) $userId : null) : null; $order['seguimiento_actualizado'] = $current['updated_at'] ?? null; $order['assigned_at'] = $current['assigned_at'] ?? null; $order['proxima_llamada_at'] = $current['proxima_llamada_at'] ?? null; $order['fecha_entrega_programada'] = $current['fecha_entrega_programada'] ?? null; $order['numero_cuenta_enviado_at'] = $current['numero_cuenta_enviado_at'] ?? null; $order['promo_final_evidencia_path'] = $current['promo_final_evidencia_path'] ?? null; $order['promo_final_evidencia_subido_at'] = $current['promo_final_evidencia_subido_at'] ?? null; $order['promo_final_evidencia_subido_por'] = isset($current['promo_final_evidencia_subido_por']) && (int) $current['promo_final_evidencia_subido_por'] > 0 ? (int) $current['promo_final_evidencia_subido_por'] : null; $order['cancelado_evidencia_path'] = $current['cancelado_evidencia_path'] ?? null; $order['cancelado_evidencia_subido_at'] = $current['cancelado_evidencia_subido_at'] ?? null; $order['cancelado_evidencia_subido_por'] = isset($current['cancelado_evidencia_subido_por']) && (int) $current['cancelado_evidencia_subido_por'] > 0 ? (int) $current['cancelado_evidencia_subido_por'] : null; $order['eliminado_at'] = $current['eliminado_at'] ?? null; $order['eliminado_por'] = isset($current['eliminado_por']) && (int) $current['eliminado_por'] > 0 ? (int) $current['eliminado_por'] : null; $order['eliminado'] = trim((string) ($order['eliminado_at'] ?? '')) !== ''; $order['ruta_contraentrega_pedido_id'] = isset($current['ruta_contraentrega_pedido_id']) && (int) $current['ruta_contraentrega_pedido_id'] > 0 ? (int) $current['ruta_contraentrega_pedido_id'] : null; $order['ruta_contraentrega_subido_at'] = $current['ruta_contraentrega_subido_at'] ?? null; $order['ruta_contraentrega_subido_por'] = isset($current['ruta_contraentrega_subido_por']) && (int) $current['ruta_contraentrega_subido_por'] > 0 ? (int) $current['ruta_contraentrega_subido_por'] : null; $order['pedido_rotulado_pedido_id'] = isset($current['pedido_rotulado_pedido_id']) && (int) $current['pedido_rotulado_pedido_id'] > 0 ? (int) $current['pedido_rotulado_pedido_id'] : null; $order['pedido_rotulado_subido_at'] = $current['pedido_rotulado_subido_at'] ?? null; $order['pedido_rotulado_subido_por'] = isset($current['pedido_rotulado_subido_por']) && (int) $current['pedido_rotulado_subido_por'] > 0 ? (int) $current['pedido_rotulado_subido_por'] : null; $order['ultima_gestion_at'] = $current['ultima_gestion_at'] ?? ($current['updated_at'] ?? null); foreach ($editableFields as $field) { $order[$field . '_drive'] = $order[$field] ?? ''; $trackedValue = $current[$field] ?? null; $order[$field . '_editado'] = $trackedValue; if ($trackedValue !== null && trim((string) $trackedValue) !== '') { $order[$field] = $trackedValue; } } $digits = preg_replace('/\D+/', '', $order['celular'] ?? ''); $order['whatsapp_url'] = $digits !== '' ? 'https://wa.me/' . $digits : ''; $order['telefono_url'] = $digits !== '' ? 'tel:' . $digits : ''; } unset($order); return $orders; } function drive_test_parse_datetime_mysql(?string $value): ?string { $value = trim((string) $value); if ($value === "") { return null; } $formats = [ "Y-m-d\\TH:i:sP", "Y-m-d\\TH:i:s", "Y-m-d\\TH:i", "Y-m-d H:i:s", "Y-m-d H:i", DateTimeInterface::ATOM, "Y-m-d", ]; foreach ($formats as $format) { try { $date = DateTimeImmutable::createFromFormat($format, $value); if ($date instanceof DateTimeImmutable) { return $date->format("Y-m-d H:i:s"); } } catch (Throwable $exception) { // ignore and try next format } } try { return (new DateTimeImmutable($value))->format("Y-m-d H:i:s"); } catch (Throwable $exception) { return null; } } function drive_test_ensure_orders_table(PDO $pdo): void { static $checked = false; if ($checked) { return; } $pdo->exec("CREATE TABLE IF NOT EXISTS `callcenter_test_orders` ( `id` INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, `store_key` VARCHAR(50) NULL, `source_key` CHAR(40) NOT NULL, `codigo` VARCHAR(80) DEFAULT NULL, `import_id` VARCHAR(120) DEFAULT NULL, `source_row` INT NULL, `is_agregado` TINYINT(1) NOT NULL DEFAULT 0, `drive_imported_at` DATETIME NULL, `nombre` VARCHAR(255) DEFAULT NULL, `direccion_drive` TEXT NULL, `referencia_drive` TEXT NULL, `sede_drive` VARCHAR(120) NULL, `ciudad_drive` VARCHAR(120) NULL, `distrito_drive` VARCHAR(120) NULL, `dni_drive` LONGTEXT NULL, `observaciones_drive` TEXT NULL, `celular` VARCHAR(40) DEFAULT NULL, `producto` TEXT NULL, `cantidad` VARCHAR(60) NULL, `precio` VARCHAR(60) NULL, `pais` VARCHAR(80) NULL, `coordenadas` VARCHAR(255) NULL, `metodo` VARCHAR(120) NULL, `first_seen_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, `last_seen_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, UNIQUE KEY `uniq_callcenter_test_orders_source_key` (`source_key`), KEY `idx_callcenter_test_orders_drive_imported_at` (`drive_imported_at`), KEY `idx_callcenter_test_orders_last_seen_at` (`last_seen_at`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); // In case the existing table was created before we introduced store_key. cc_test_ensure_column($pdo, "callcenter_test_orders", "store_key", "VARCHAR(50) NULL"); cc_test_ensure_column($pdo, "callcenter_test_orders", "source_row", "INT NULL AFTER `import_id`"); // Asegura columna para pedidos cargados manualmente (Agregados) cc_test_ensure_column($pdo, "callcenter_test_orders", "is_agregado", "TINYINT(1) NOT NULL DEFAULT 0"); // Asegurar que `dni_drive` soporte valores grandes desde Google Sheets. try { $colStmt = $pdo->prepare(" SELECT DATA_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'callcenter_test_orders' AND COLUMN_NAME = 'dni_drive' LIMIT 1 "); $colStmt->execute(); $dataType = strtolower((string) $colStmt->fetchColumn()); if ($dataType !== 'longtext') { $pdo->exec("ALTER TABLE `callcenter_test_orders` MODIFY COLUMN `dni_drive` LONGTEXT NULL"); } } catch (Throwable $exception) { // No bloqueamos el panel si por alguna razón no se puede ajustar el tipo. error_log('drive_test_ensure_orders_table: ' . $exception->getMessage()); } $checked = true; } function drive_test_ensure_import_checkpoints_table(PDO $pdo): void { static $checked = false; if ($checked) { return; } $pdo->exec("CREATE TABLE IF NOT EXISTS `drive_test_import_checkpoints` ( `store_key` VARCHAR(50) NOT NULL, `last_processed_row` INT NOT NULL DEFAULT 0, `baseline_start_row` INT NOT NULL DEFAULT 0, `last_sync_at` DATETIME NULL, `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`store_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); cc_test_ensure_column($pdo, 'drive_test_import_checkpoints', 'baseline_start_row', 'INT NOT NULL DEFAULT 0 AFTER `last_processed_row`'); $checked = true; } function drive_test_sync_orders_incremental(PDO $pdo, string $storeKey, int $overlapRows = 50): array { $storeKey = mb_strtolower(trim($storeKey)); $storeConfig = drive_test_get_store_config($storeKey); $baselineStartRow = (int) ($storeConfig['startRow'] ?? 5552); drive_test_ensure_orders_table($pdo); drive_test_ensure_import_checkpoints_table($pdo); $stmtCheckpoint = $pdo->prepare('SELECT last_processed_row, baseline_start_row FROM drive_test_import_checkpoints WHERE store_key = ? LIMIT 1'); $stmtCheckpoint->execute([$storeKey]); $checkpointData = $stmtCheckpoint->fetch(PDO::FETCH_ASSOC) ?: []; $checkpointRow = (int) ($checkpointData['last_processed_row'] ?? 0); $storedBaselineStartRow = (int) ($checkpointData['baseline_start_row'] ?? 0); $overlapRows = max(0, $overlapRows); $mustResetToBaseline = $storedBaselineStartRow !== $baselineStartRow; $effectiveStartRow = $mustResetToBaseline ? $baselineStartRow : ($checkpointRow > 0 ? max($baselineStartRow, $checkpointRow - $overlapRows + 1) : $baselineStartRow); $preview = drive_test_fetch_orders(0, $effectiveStartRow, $storeKey); $driveOrders = $preview['orders'] ?? []; $driveTotalRows = (int) ($preview['total_rows'] ?? 0); $sheetLastRow = ($effectiveStartRow - 1) + $driveTotalRows; $newCheckpointRow = $mustResetToBaseline ? (int) $sheetLastRow : max($checkpointRow, (int) $sheetLastRow); if (!empty($driveOrders)) { $stmtUpsert = $pdo->prepare( "INSERT INTO callcenter_test_orders ( store_key, source_key, codigo, import_id, source_row, drive_imported_at, nombre, direccion_drive, referencia_drive, sede_drive, ciudad_drive, distrito_drive, dni_drive, observaciones_drive, celular, producto, cantidad, precio, pais, coordenadas, metodo ) VALUES ( :store_key, :source_key, :codigo, :import_id, :source_row, :drive_imported_at, :nombre, :direccion_drive, :referencia_drive, :sede_drive, :ciudad_drive, :distrito_drive, :dni_drive, :observaciones_drive, :celular, :producto, :cantidad, :precio, :pais, :coordenadas, :metodo ) ON DUPLICATE KEY UPDATE store_key = VALUES(store_key), codigo = VALUES(codigo), import_id = VALUES(import_id), source_row = VALUES(source_row), is_agregado = 0, drive_imported_at = VALUES(drive_imported_at), nombre = VALUES(nombre), direccion_drive = VALUES(direccion_drive), referencia_drive = VALUES(referencia_drive), sede_drive = VALUES(sede_drive), ciudad_drive = VALUES(ciudad_drive), distrito_drive = VALUES(distrito_drive), dni_drive = VALUES(dni_drive), observaciones_drive = VALUES(observaciones_drive), celular = VALUES(celular), producto = VALUES(producto), cantidad = VALUES(cantidad), precio = VALUES(precio), pais = VALUES(pais), coordenadas = VALUES(coordenadas), metodo = VALUES(metodo), last_seen_at = CURRENT_TIMESTAMP" ); foreach ($driveOrders as $order) { $driveImportedAt = drive_test_parse_datetime_mysql($order['import_id'] ?? null); $sourceRow = isset($order['source_row']) && (int) $order['source_row'] > 0 ? (int) $order['source_row'] : null; $stmtUpsert->execute([ ':store_key' => $storeKey, ':source_key' => $order['source_key'] ?? '', ':codigo' => ($order['codigo'] ?? '') !== '' ? ($order['codigo'] ?? null) : null, ':import_id' => ($order['import_id'] ?? '') !== '' ? ($order['import_id'] ?? null) : null, ':source_row' => $sourceRow, ':drive_imported_at' => $driveImportedAt, ':nombre' => ($order['nombre'] ?? '') !== '' ? ($order['nombre'] ?? null) : null, ':direccion_drive' => ($order['direccion'] ?? '') !== '' ? ($order['direccion'] ?? null) : null, ':referencia_drive' => ($order['referencia'] ?? '') !== '' ? ($order['referencia'] ?? null) : null, ':sede_drive' => ($order['sede'] ?? '') !== '' ? ($order['sede'] ?? null) : null, ':ciudad_drive' => ($order['ciudad'] ?? '') !== '' ? ($order['ciudad'] ?? null) : null, ':distrito_drive' => ($order['distrito'] ?? '') !== '' ? ($order['distrito'] ?? null) : null, ':dni_drive' => ($order['dni'] ?? '') !== '' ? ($order['dni'] ?? null) : null, ':observaciones_drive' => ($order['observaciones'] ?? '') !== '' ? ($order['observaciones'] ?? null) : null, ':celular' => ($order['celular'] ?? '') !== '' ? ($order['celular'] ?? null) : null, ':producto' => ($order['producto'] ?? '') !== '' ? ($order['producto'] ?? null) : null, ':cantidad' => ($order['cantidad'] ?? '') !== '' ? ($order['cantidad'] ?? null) : null, ':precio' => ($order['precio'] ?? '') !== '' ? ($order['precio'] ?? null) : null, ':pais' => ($order['pais'] ?? '') !== '' ? ($order['pais'] ?? null) : null, ':coordenadas' => ($order['coordenadas'] ?? '') !== '' ? ($order['coordenadas'] ?? null) : null, ':metodo' => ($order['metodo'] ?? '') !== '' ? ($order['metodo'] ?? null) : null, ]); } } $stmtCheckpointUpsert = $pdo->prepare( "INSERT INTO drive_test_import_checkpoints (store_key, last_processed_row, baseline_start_row, last_sync_at) VALUES (:store_key, :last_processed_row, :baseline_start_row, CURRENT_TIMESTAMP) ON DUPLICATE KEY UPDATE last_processed_row = VALUES(last_processed_row), baseline_start_row = VALUES(baseline_start_row), last_sync_at = CURRENT_TIMESTAMP" ); $stmtCheckpointUpsert->execute([ ':store_key' => $storeKey, ':last_processed_row' => $newCheckpointRow, ':baseline_start_row' => $baselineStartRow, ]); return [ 'checkpoint_was' => $checkpointRow, 'last_processed_row' => $newCheckpointRow, 'next_start_row' => $newCheckpointRow + 1, 'effective_start_row' => $effectiveStartRow, 'drive_rows_total' => $driveTotalRows, 'orders_synced_count' => count($driveOrders), ]; } function drive_test_fetch_orders_from_db(PDO $pdo, string $storeKey, ?bool $onlyAgregados = null): array { $storeKey = mb_strtolower(trim($storeKey)); $storeConfig = drive_test_get_store_config($storeKey); drive_test_ensure_orders_table($pdo); $where = 'WHERE store_key = ?'; $params = [$storeKey]; if ($onlyAgregados === true) { $where .= ' AND is_agregado = 1'; } elseif ($onlyAgregados === false) { $where .= ' AND (is_agregado = 0 OR is_agregado IS NULL)'; } $minVisibleRow = !empty($storeConfig['enforce_db_start_row']) ? (int) ($storeConfig['startRow'] ?? 0) : 0; if ($minVisibleRow > 0) { $where .= ' AND (is_agregado = 1 OR (source_row IS NOT NULL AND source_row >= ?))'; $params[] = $minVisibleRow; } $stmt = $pdo->prepare( "SELECT id, is_agregado, source_key, codigo, import_id, source_row, drive_imported_at, first_seen_at, nombre, celular, producto, cantidad, precio, pais, coordenadas, metodo, direccion_drive, referencia_drive, sede_drive, ciudad_drive, distrito_drive, dni_drive, observaciones_drive FROM callcenter_test_orders $where ORDER BY CASE WHEN source_row IS NULL THEN 1 ELSE 0 END ASC, source_row ASC, id DESC" ); $stmt->execute($params); $orders = []; $minCodigoNumber = isset($storeConfig['min_codigo_number']) ? (int) ($storeConfig['min_codigo_number'] ?? 0) : 0; foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) { $isAgregado = (int) ($row['is_agregado'] ?? 0); $codigo = (string) ($row['codigo'] ?? ''); $codigoNumber = drive_test_extract_codigo_number($codigo); if ($minCodigoNumber > 0 && $isAgregado !== 1 && ($codigoNumber === null || $codigoNumber < $minCodigoNumber)) { continue; } $orders[] = [ 'id' => (int) ($row['id'] ?? 0), 'is_agregado' => $isAgregado, 'source_key' => (string) ($row['source_key'] ?? ''), 'codigo' => $codigo, 'import_id' => (string) ($row['import_id'] ?? ''), 'source_row' => isset($row['source_row']) && (int) $row['source_row'] > 0 ? (int) $row['source_row'] : null, 'drive_imported_at' => (string) ($row['drive_imported_at'] ?? ''), 'first_seen_at' => (string) ($row['first_seen_at'] ?? ''), 'nombre' => (string) ($row['nombre'] ?? ''), 'direccion' => (string) ($row['direccion_drive'] ?? ''), 'referencia' => (string) ($row['referencia_drive'] ?? ''), 'agencia' => '', 'sede_agencia' => '', 'distrito' => (string) ($row['distrito_drive'] ?? ''), 'celular' => (string) ($row['celular'] ?? ''), 'producto' => (string) ($row['producto'] ?? ''), 'cantidad' => (string) ($row['cantidad'] ?? ''), 'precio' => (string) ($row['precio'] ?? ''), 'monto_adelantado' => '', 'pais' => (string) ($row['pais'] ?? ''), 'coordenadas' => (string) ($row['coordenadas'] ?? ''), 'ciudad' => (string) ($row['ciudad_drive'] ?? ''), 'metodo' => (string) ($row['metodo'] ?? ''), 'sede' => (string) ($row['sede_drive'] ?? ''), 'dni' => (string) ($row['dni_drive'] ?? ''), 'observaciones' => (string) ($row['observaciones_drive'] ?? ''), ]; } return $orders; }