validateLoadArchives.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. <?php
  2. // Configuración de BD
  3. $host = 'localhost';
  4. $port = 3306;
  5. $database = 'samqa';
  6. $username = 'root';
  7. $password = 'root';
  8. // Archivo lock global
  9. $lockFile = __DIR__ . '/validation.lock';
  10. // 1. Verificar lock global
  11. if (file_exists($lockFile)) {
  12. echo "[" . date('Y-m-d H:i:s') . "] Otro proceso está en ejecución. Saliendo...\n";
  13. exit;
  14. }
  15. file_put_contents($lockFile, getmypid());
  16. // 2. Conectar BD
  17. try {
  18. $pdo = new PDO("mysql:host=$host;port=$port;dbname=$database", $username, $password);
  19. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  20. // 3. Buscar job pendiente, en progreso o fallido
  21. $pdo->beginTransaction();
  22. // Primero buscar un job que quedó a medias
  23. $stmt = $pdo->prepare("
  24. SELECT * FROM S002V01TVAJO
  25. WHERE VAJO_ESTA = 'processing' AND VAJO_PRPE < 100
  26. ORDER BY VAJO_FERE ASC
  27. LIMIT 1
  28. FOR UPDATE
  29. ");
  30. $stmt->execute();
  31. $job = $stmt->fetch(PDO::FETCH_ASSOC);
  32. // Si no hay, buscar jobs fallidos para reintentar
  33. if (!$job) {
  34. $stmt = $pdo->prepare("
  35. SELECT * FROM S002V01TVAJO
  36. WHERE VAJO_ESTA = 'failed'
  37. ORDER BY VAJO_FERE ASC
  38. LIMIT 1
  39. FOR UPDATE
  40. ");
  41. $stmt->execute();
  42. $job = $stmt->fetch(PDO::FETCH_ASSOC);
  43. if ($job) {
  44. echo "Reintentando job fallido: {$job['VAJO_IDJO']}\n";
  45. $update = $pdo->prepare("
  46. UPDATE S002V01TVAJO
  47. SET VAJO_ESTA = 'processing', VAJO_ERME = NULL, VAJO_FEMO = NOW()
  48. WHERE VAJO_IDJO = ?
  49. ");
  50. $update->execute([$job['VAJO_IDJO']]);
  51. }
  52. }
  53. // Si no hay, tomar uno en cola
  54. if (!$job) {
  55. $stmt = $pdo->prepare("
  56. SELECT * FROM S002V01TVAJO
  57. WHERE VAJO_ESTA = 'queued'
  58. ORDER BY VAJO_FERE ASC
  59. LIMIT 1
  60. FOR UPDATE
  61. ");
  62. $stmt->execute();
  63. $job = $stmt->fetch(PDO::FETCH_ASSOC);
  64. if ($job) {
  65. $update = $pdo->prepare("
  66. UPDATE S002V01TVAJO
  67. SET VAJO_ESTA = 'processing', VAJO_FEMO = NOW()
  68. WHERE VAJO_IDJO = ?
  69. ");
  70. $update->execute([$job['VAJO_IDJO']]);
  71. }
  72. }
  73. $pdo->commit();
  74. if (!$job) {
  75. echo "[" . date('Y-m-d H:i:s') . "] No hay trabajos pendientes.\n";
  76. unlink($lockFile);
  77. exit;
  78. }
  79. echo "Procesando Job ID: {$job['VAJO_IDJO']}\n";
  80. // 4. Determinar archivos ya procesados
  81. $results = json_decode($job['VAJO_RESU'], true) ?? ['processed_files' => []];
  82. $procesados = $results['processed_files'] ?? [];
  83. // 5. Buscar ruta del ZIP en base de datos
  84. $stmt = $pdo->prepare("SELECT ARTE_UBTE FROM s002v01tarte WHERE ARTE_IDAR = ?");
  85. $stmt->execute([$job['VAJO_ZITE']]);
  86. $zipData = $stmt->fetch(PDO::FETCH_ASSOC);
  87. if (!$zipData) {
  88. throw new Exception("ZIP ID no encontrado: {$job['VAJO_ZITE']}");
  89. }
  90. $zipPath = $zipData['ARTE_UBTE'];
  91. if (!file_exists($zipPath)) {
  92. throw new Exception("ZIP no encontrado: {$zipPath}");
  93. }
  94. // Guardar IDs de archivos temporales
  95. $tempFiles = [
  96. 'excel' => getEncrypt($job['VAJO_EXTE']),
  97. 'zip' => getEncrypt($job['VAJO_ZITE'])
  98. ];
  99. $individualTempFiles = [];
  100. $zip = new ZipArchive();
  101. if ($zip->open($zipPath) !== TRUE) {
  102. throw new Exception("No se pudo abrir el ZIP: {$zipPath}");
  103. }
  104. // Crear carpeta de extracción temporal
  105. $extractDir = __DIR__ . '/../storage/app/tempFiles/extracted_' . time();
  106. if (!mkdir($extractDir, 0755, true)) {
  107. throw new Exception("No se pudo crear directorio de extracción: {$extractDir}");
  108. }
  109. // Obtener solo archivos (no directorios)
  110. $archivos = [];
  111. for ($i = 0; $i < $zip->numFiles; $i++) {
  112. $stat = $zip->statIndex($i);
  113. $nombreArchivo = $stat['name'];
  114. // Solo procesar archivos, no directorios
  115. if (substr($nombreArchivo, -1) !== '/') {
  116. $archivos[] = basename($nombreArchivo); // Solo nombre sin ruta
  117. }
  118. }
  119. $totalArchivos = count($archivos);
  120. $faltantes = array_diff($archivos, $procesados);
  121. echo "Archivos totales: $totalArchivos, ya procesados: " . count($procesados) . ", faltantes: " . count($faltantes) . "\n";
  122. // 6. Procesar faltantes
  123. foreach ($faltantes as $nombreArchivo) {
  124. echo "Procesando: {$nombreArchivo}\n";
  125. // Extraer archivo del ZIP
  126. $archivoExtraido = $extractDir . '/' . $nombreArchivo;
  127. $contenido = null;
  128. // Buscar el archivo en el ZIP (puede estar en subdirectorios)
  129. for ($i = 0; $i < $zip->numFiles; $i++) {
  130. $stat = $zip->statIndex($i);
  131. if (basename($stat['name']) === $nombreArchivo) {
  132. $contenido = $zip->getFromIndex($i);
  133. break;
  134. }
  135. }
  136. if ($contenido === null) {
  137. echo "Archivo no encontrado en ZIP: {$nombreArchivo}\n";
  138. continue;
  139. }
  140. // Guardar archivo extraído
  141. file_put_contents($archivoExtraido, $contenido);
  142. // Enviar archivo al endpoint usando multipart/form-data
  143. $ch = curl_init('http://192.168.2.21:8000/api/upload-temp-file');
  144. curl_setopt($ch, CURLOPT_POST, true);
  145. curl_setopt($ch, CURLOPT_POSTFIELDS, [
  146. 'file' => new CURLFile($archivoExtraido, mime_content_type($archivoExtraido), $nombreArchivo),
  147. 'id_user' => $job['VAJO_IDUS'],
  148. 'linea' => $job['VAJO_NULI']
  149. ]);
  150. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  151. $response = curl_exec($ch);
  152. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  153. curl_close($ch);
  154. // Eliminar archivo temporal
  155. unlink($archivoExtraido);
  156. // Solo marcar como procesado si el endpoint respondió exitosamente
  157. if ($httpCode >= 200 && $httpCode < 300) {
  158. $responseData = json_decode($response, true);
  159. if (isset($responseData['response']['idArchivo'])) {
  160. $individualTempFiles[] = [
  161. 'original_name' => $nombreArchivo,
  162. 'temp_id' => $responseData['response']['idArchivo']
  163. ];
  164. }
  165. $procesados[] = $nombreArchivo;
  166. $progress = intval((count($procesados) / $totalArchivos) * 100);
  167. $results['processed_files'] = $procesados;
  168. $stmt = $pdo->prepare("
  169. UPDATE S002V01TVAJO
  170. SET VAJO_RESU = ?, VAJO_PRPE = ?, VAJO_FEMO = NOW()
  171. WHERE VAJO_IDJO = ?
  172. ");
  173. $stmt->execute([json_encode($results), $progress, $job['VAJO_IDJO']]);
  174. } else {
  175. echo "Error al procesar archivo {$nombreArchivo}: HTTP {$httpCode}\n";
  176. throw new Exception("Error al procesar archivo: {$nombreArchivo}");
  177. }
  178. }
  179. $zip->close();
  180. // Eliminar directorio de extracción
  181. rmdir($extractDir);
  182. // 7. Marcar como completado
  183. $stmt = $pdo->prepare("
  184. UPDATE S002V01TVAJO
  185. SET VAJO_ESTA = 'completed', VAJO_PRPE = 100, VAJO_FECO = NOW(), VAJO_FEMO = NOW()
  186. WHERE VAJO_IDJO = ?
  187. ");
  188. $stmt->execute([$job['VAJO_IDJO']]);
  189. // Enviar notificación de completado
  190. $parameters = [
  191. 'temp_files' => $tempFiles,
  192. 'individual_temp_files' => $individualTempFiles
  193. ];
  194. emitNotification(
  195. 'S002V01M15IDUE',
  196. 'Carga de archivos temporales completada',
  197. 'Los archivos del submodulo Carga de documentos relacionados han sido subidos al servidor y están listos para completar el proceso.',
  198. [['BOTON' => 'Completar proceso', 'FUNCION' => 'processLoadArchives', 'PARAMETROS' => json_encode($parameters)]],
  199. [$job['VAJO_IDUS']]
  200. );
  201. echo "Job completado: {$job['VAJO_IDJO']}\n";
  202. } catch (Exception $e) {
  203. echo "ERROR: " . $e->getMessage() . "\n";
  204. // Marcar job como fallido si hay job activo
  205. if (isset($job)) {
  206. $stmt = $pdo->prepare("UPDATE S002V01TVAJO SET VAJO_ESTA = 'failed', VAJO_ERME = ? WHERE VAJO_IDJO = ?");
  207. $stmt->execute([$e->getMessage(), $job['VAJO_IDJO']]);
  208. }
  209. } finally {
  210. // 8. Limpiar y eliminar lock global
  211. if (isset($extractDir) && is_dir($extractDir)) {
  212. $files = glob("$extractDir/*");
  213. foreach ($files as $file) {
  214. if (is_file($file)) {
  215. unlink($file);
  216. }
  217. }
  218. rmdir($extractDir);
  219. }
  220. if (file_exists($lockFile)) {
  221. unlink($lockFile);
  222. }
  223. }
  224. function getEncrypt($value){
  225. $ch = curl_init('http://192.168.2.21:8000/api/encrypt');
  226. curl_setopt($ch, CURLOPT_POST, true);
  227. curl_setopt($ch, CURLOPT_POSTFIELDS, ['value' => $value]);
  228. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  229. $response = curl_exec($ch);
  230. curl_close($ch);
  231. $responseData = json_decode($response, true);
  232. return $responseData['response']['encrypted'];
  233. }
  234. function emitNotification($module, $title, $content, $actions, $audience) {
  235. $ch = curl_init('http://192.168.2.21:8000/api/emitNotification');
  236. curl_setopt($ch, CURLOPT_POST, true);
  237. curl_setopt($ch, CURLOPT_POSTFIELDS, [
  238. 'module' => $module,
  239. 'title' => $title,
  240. 'content' => $content,
  241. 'actions' => json_encode($actions),
  242. 'audience' => $audience
  243. ]);
  244. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  245. $response = curl_exec($ch);
  246. $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
  247. curl_close($ch);
  248. if ($httpCode >= 200 && $httpCode < 300) {
  249. echo "Notificación enviada exitosamente\n";
  250. } else {
  251. echo "Error al enviar notificación: HTTP $httpCode\n";
  252. }
  253. }