laravel-sat-catalogs/Services/CsvDatabaseService.php

179 lines
5.4 KiB
PHP
Raw Permalink Normal View History

2025-03-10 18:25:41 -06:00
<?php
namespace Koneko\SatCatalogs\Services;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;
class CsvDatabaseService
{
/**
* Carga datos desde CSV a una tabla de la base de datos.
*/
public static function importCsvToTable(string $csvFilePath, string $tableName, array $columns, bool $updateExisting = false)
{
if (!file_exists($csvFilePath)) {
return ["error" => "Archivo CSV no encontrado: {$csvFilePath}"];
}
$handle = fopen($csvFilePath, 'r');
$batchSize = 5000;
$data = [];
$rowCount = 0;
$insertedCount = 0;
while (($row = fgetcsv($handle, 1000, ";")) !== false) {
$record = [];
foreach ($columns as $index => $column) {
$value = $row[$index] ?? null;
// Aplicar CAST según el tipo de dato
if ($value === '') {
$record[$column] = null;
} elseif (self::isDateColumn($column)) {
$record[$column] = self::formatDate($value);
} elseif (is_numeric($value)) {
$record[$column] = strpos($value, '.') !== false ? (float) $value : (int) $value;
} else {
$record[$column] = trim($value);
}
}
$data[] = $record;
$rowCount++;
if (count($data) >= $batchSize) {
self::insertOrUpdate($tableName, $data, $updateExisting);
$insertedCount += count($data);
$data = [];
}
}
fclose($handle);
if (!empty($data)) {
self::insertOrUpdate($tableName, $data, $updateExisting);
$insertedCount += count($data);
}
return [
"inserted" => $insertedCount,
"total_rows" => $rowCount
];
}
/**
* Inserta o actualiza datos en la tabla.
*/
private static function insertOrUpdate(string $tableName, array $data, bool $updateExisting)
{
if (empty($data)) {
echo "⚠️ Datos vacíos para {$tableName}\n";
return;
}
foreach ($data as &$record) {
foreach ($record as $key => $value) {
if ($value === '?') { // Si hay un '?', lo convertimos en NULL
$record[$key] = null;
}
}
}
unset($record);
try {
$primaryKeys = self::getPrimaryKeys($tableName);
$updateFields = array_diff(array_keys($data[0]), $primaryKeys);
if ($updateExisting && !empty($updateFields)) {
DB::table($tableName)->upsert($data, $primaryKeys, $updateFields);
echo "✅ Upsert ejecutado en {$tableName} (" . count($data) . " filas)\n";
} else {
DB::table($tableName)->insert($data);
echo "✅ Insert ejecutado en {$tableName} (" . count($data) . " filas)\n";
}
} catch (\Exception $e) {
Log::error("🚨 Error en {$tableName}: " . $e->getMessage());
echo "❌ ERROR en {$tableName}: {$e->getMessage()}\n";
die();
}
}
/**
* **Detecta si una columna es de tipo fecha.**
*/
private static function isDateColumn(string $columnName): bool
{
$dateFields = ['fecha_inicio_vigencia', 'fecha_fin_vigencia'];
return in_array($columnName, $dateFields);
}
/**
* **Convierte fechas de diferentes formatos a `YYYY-MM-DD`.**
*/
private static function formatDate($value)
{
if (!$value || strtolower($value) === 'null') {
return null;
}
try {
if (is_numeric($value) && $value > 10000) {
return Carbon::instance(\PhpOffice\PhpSpreadsheet\Shared\Date::excelToDateTimeObject($value))->format('Y-m-d');
}
if (preg_match('/^\d{2}\/\d{2}\/\d{4}$/', $value)) {
return Carbon::createFromFormat('d/m/Y', $value)->format('Y-m-d');
}
return Carbon::parse($value)->format('Y-m-d');
} catch (\Exception $e) {
return null;
}
}
/**
* **Obtiene las claves primarias de la tabla.**
*/
private static function getPrimaryKeys(string $tableName): array
{
$primaryKeys = [
'sat_forma_pago' => ['c_forma_pago'],
'sat_moneda' => ['c_moneda'],
'sat_codigo_postal' => ['c_codigo_postal'],
'sat_regimen_fiscal' => ['c_regimen_fiscal'],
'sat_pais' => ['c_pais'],
'sat_uso_cfdi' => ['c_uso_cfdi'],
'sat_clave_prod_serv' => ['c_clave_prod_serv'],
'sat_clave_unidad' => ['c_clave_unidad'],
'sat_aduana' => ['c_aduana'],
'sat_colonia' => ['c_colonia', 'c_codigo_postal'],
'sat_estado' => ['c_estado', 'c_pais'],
'sat_localidad' => ['c_localidad', 'c_estado'],
'sat_municipio' => ['c_municipio', 'c_estado'],
'sat_banco' => ['c_banco'],
'sat_deduccion' => ['c_deduccion'],
'sat_percepcion' => ['c_percepcion'],
'sat_regimen_contratacion' => ['c_regimen_contratacion'],
];
return $primaryKeys[$tableName] ?? ['id'];
}
}