prepare($query); $stmt->bindParam(':rut', $rut, PDO::PARAM_STR); $stmt->execute(); if ($stmt->rowCount() === 0) { $_SESSION['mensaje'] = 'Negocio no encontrado'; $_SESSION['tipo_mensaje'] = 'danger'; redirigir(BASE_URL . '/negocio/index.php'); exit; } $negocio = $stmt->fetch(PDO::FETCH_ASSOC); // Obtener información del plan seleccionado $query_plan = "SELECT * FROM planes WHERE id = :plan_id"; $stmt = $conexion->prepare($query_plan); $stmt->bindParam(':plan_id', $plan_id, PDO::PARAM_INT); $stmt->execute(); $resultado_plan = $stmt->fetch(PDO::FETCH_ASSOC); // Crear un plan predeterminado en caso de que no se encuentre en la base de datos $plan = []; if (!$resultado_plan) { // Si no se encuentra el plan en la base de datos, crear uno predeterminado según el plan_id $plan['nombre'] = 'Plan Predeterminado'; $plan['descripcion'] = 'Plan de suscripción'; $plan['duracion_meses'] = 1; // Valor predeterminado $plan['precio_uf'] = 0.5; // Precio predeterminado $plan['sesiones_incluidas'] = 2; // Sesiones predeterminadas $plan['precio_sesion_adicional'] = 0.20; // Precio sesión adicional predeterminado } else { $plan = $resultado_plan; // Asignar valores predeterminados a los campos nuevos si no existen if (!isset($plan['sesiones_incluidas'])) { $plan['sesiones_incluidas'] = 2; // Valor predeterminado } if (!isset($plan['precio_sesion_adicional'])) { $plan['precio_sesion_adicional'] = 0.20; // Valor predeterminado } } // Definir precios fijos en pesos chilenos (CORREGIDOS - igual que en renovar_licencia.php) $precios_clp_planes = [ 1 => 12000, // Plan 1 Mes: $12.000 + IVA 2 => 33000, // Plan 3 Meses: $11.000/mes x 3 = $33.000 + IVA 3 => 60000, // Plan 6 Meses: $10.000/mes x 6 = $60.000 + IVA 4 => 108000 // Plan 1 Año: $9.000/mes x 12 = $108.000 + IVA ]; // Obtener valor UF para conversión $valor_uf_conversion = obtenerIndicadorUF($conexion); if (!$valor_uf_conversion || $valor_uf_conversion <= 0) { $valor_uf_conversion = 37500; // Valor por defecto } // Verificar que la duración del plan sea correcta según el plan_id seleccionado // Esto asegura que se muestre la duración correcta en el resumen de compra if ($plan_id == 1) { $plan['duracion_meses'] = 1; $plan['precio_uf'] = round($precios_clp_planes[1] / $valor_uf_conversion, 4); $plan['nombre'] = 'Plan 1 Mes'; $plan['descripcion'] = 'Plan básico mensual con 2 puntos de venta incluidos'; } else if ($plan_id == 2) { $plan['duracion_meses'] = 3; $plan['precio_uf'] = round($precios_clp_planes[2] / $valor_uf_conversion, 4); $plan['nombre'] = 'Plan 3 Meses'; $plan['descripcion'] = 'Plan trimestral con 2 puntos de venta incluidos'; } else if ($plan_id == 3) { $plan['duracion_meses'] = 6; $plan['precio_uf'] = round($precios_clp_planes[3] / $valor_uf_conversion, 4); $plan['nombre'] = 'Plan 6 Meses'; $plan['descripcion'] = 'Plan semestral con 2 puntos de venta incluidos'; } else if ($plan_id == 4) { $plan['duracion_meses'] = 12; $plan['precio_uf'] = round($precios_clp_planes[4] / $valor_uf_conversion, 4); $plan['nombre'] = 'Plan 1 Año'; $plan['descripcion'] = 'Plan anual con 2 puntos de venta incluidos'; } // Calcular la nueva fecha de vencimiento $fecha_actual = new DateTime($negocio['fecha_vencimiento_licencia']); $fecha_actual_hoy = new DateTime(); // Si la licencia ya venció, usar la fecha actual como base if ($fecha_actual < $fecha_actual_hoy) { $fecha_actual = $fecha_actual_hoy; } $nueva_fecha = clone $fecha_actual; $nueva_fecha->add(new DateInterval('P' . $plan['duracion_meses'] . 'M')); // Definir precios escalonados por punto por mes (corregidos en pesos chilenos) $precios_escalonados_clp = [ 1 => 5000, // $5.000 por punto 2 => 4500, // $4.500 por punto 3 => 4000, // $4.000 por punto 4 => 3500, // $3.500 por punto 5 => 3000 // $3.000 por punto ]; // Convertir precios CLP a UF para cálculos internos $precios_escalonados = []; $valor_uf_para_puntos = obtenerIndicadorUF($conexion); if ($valor_uf_para_puntos && $valor_uf_para_puntos > 0) { foreach ($precios_escalonados_clp as $cantidad => $precio_clp) { $precios_escalonados[$cantidad] = round($precio_clp / $valor_uf_para_puntos, 4); } } else { // Valores por defecto en UF si no se puede obtener el valor UF $precios_escalonados = [ 1 => 0.13, // Aproximado 2 => 0.12, // Aproximado 3 => 0.11, // Aproximado 4 => 0.09, // Aproximado 5 => 0.08 // Aproximado ]; } // Verificar si el formulario fue enviado (POST) $precio_total_uf = $plan['precio_uf']; $sesiones_adicionales = $puntos_adicionales; // Usar los puntos adicionales de la página anterior $subtotal_plan = $plan['precio_uf']; $subtotal_sesiones = 0; if ($sesiones_adicionales > 0 && isset($precios_escalonados[$sesiones_adicionales])) { $precio_por_punto_actual = $precios_escalonados[$sesiones_adicionales]; $subtotal_sesiones = $precio_por_punto_actual * $sesiones_adicionales * $plan['duracion_meses']; } $subtotal = $subtotal_plan + $subtotal_sesiones; // Calcular IVA basado en el subtotal (CORREGIDO - solo una vez) $iva = $subtotal * TASA_IVA; // Usar constante $precio_total_uf = $subtotal + $iva; // Precio final UF con IVA (CORREGIDO) // --- Obtener valor UF y calcular estimado CLP --- $valor_uf_actual = obtenerIndicadorUF($conexion); // Asume que esta función existe y devuelve float $monto_estimado_clp = null; if ($valor_uf_actual && $valor_uf_actual > 0) { $monto_estimado_clp = round($precio_total_uf * $valor_uf_actual); } else { // Manejar caso donde no se pudo obtener UF (mostrar 0 o un mensaje) $valor_uf_actual = null; // Para indicar que no se pudo obtener error_log("[Procesar Pago] No se pudo obtener el valor de la UF actual para mostrar el estimado CLP."); } // --- Fin UF/CLP --- // Solo procesar el pago si es POST if ($_SERVER['REQUEST_METHOD'] === 'POST') { // Debug - Mostrar los datos recibidos error_log("[DEBUG] POST Data: " . print_r($_POST, true)); // Si se está actualizando los puntos adicionales, redirigir a la misma página con los nuevos valores if (isset($_POST['actualizar'])) { $nuevos_puntos_adicionales = isset($_POST['puntos_adicionales']) ? intval($_POST['puntos_adicionales']) : 0; // Añadir urlencode al rut por si contiene caracteres especiales redirigir(BASE_URL . '/negocio/procesar_pago.php?plan_id=' . $plan_id . '&rut=' . urlencode($rut) . '&puntos_adicionales=' . $nuevos_puntos_adicionales); exit; } // Solo proceder con el pago si se presionó el botón de procesar if (isset($_POST['procesar'])) { // Capturar el método de pago seleccionado if (!empty($_POST['metodo_pago_confirmado'])) { $metodo_pago = $_POST['metodo_pago_confirmado']; error_log("[DEBUG] Usando método de pago confirmado: " . $metodo_pago); } else { $metodo_pago = isset($_POST['metodo_pago']) ? $_POST['metodo_pago'] : 'mercadopago'; error_log("[DEBUG] Usando método de pago del radio button: " . $metodo_pago); } // Verificar el método de pago para depuración error_log("[DEBUG] Método de pago seleccionado: " . $metodo_pago); error_log("[DEBUG] Datos POST completos: " . print_r($_POST, true)); // --- INICIO: Recalcular precio con valores del POST USANDO PRECIOS ESCALONADOS --- $puntos_adicionales_post = isset($_POST['puntos_adicionales']) ? intval($_POST['puntos_adicionales']) : 0; $sesiones_adicionales_post = $puntos_adicionales_post; $subtotal_sesiones_post = 0; if ($sesiones_adicionales_post > 0 && isset($precios_escalonados[$sesiones_adicionales_post])) { $precio_por_punto_post = $precios_escalonados[$sesiones_adicionales_post]; $subtotal_sesiones_post = $precio_por_punto_post * $sesiones_adicionales_post * $plan['duracion_meses']; } $subtotal_uf_post = $plan['precio_uf'] + $subtotal_sesiones_post; $iva_post = $subtotal_uf_post * TASA_IVA; // Calcular IVA una sola vez $precio_total_uf_post = $subtotal_uf_post + $iva_post; // Precio final UF con IVA para procesar // --- FIN: Recalcular precio con valores del POST --- // Usar $precio_total_uf_post y $puntos_adicionales_post en el resto del procesamiento $puntos_adicionales_a_guardar = $puntos_adicionales_post; $precio_total_uf_a_guardar = $precio_total_uf_post; $pago_id = null; $conexion->beginTransaction(); // Iniciar transacción ANTES de cualquier inserción try { // --- PASO 1: Registrar el pago SIEMPRE como pendiente --- $estado_pago = 'pendiente'; $referencia_pago = 'REF-' . strtoupper(substr(md5(uniqid(rand(), true)), 0, 10)); $fecha_pago = date('Y-m-d H:i:s'); $stmt_pago = $conexion->prepare( "INSERT INTO pagos (negocio_rut, plan_id, monto, estado, transaccion_id, fecha_pago, metodo_pago, puntos_adicionales) VALUES (:negocio_rut, :plan_id, :monto, :estado, :transaccion_id, :fecha_pago, :metodo_pago, :puntos)" ); $stmt_pago->bindParam(':negocio_rut', $negocio['rut'], PDO::PARAM_STR); $stmt_pago->bindParam(':plan_id', $plan_id, PDO::PARAM_INT); $stmt_pago->bindParam(':monto', $precio_total_uf_a_guardar, PDO::PARAM_STR); $stmt_pago->bindParam(':estado', $estado_pago, PDO::PARAM_STR); $stmt_pago->bindParam(':transaccion_id', $referencia_pago, PDO::PARAM_STR); $stmt_pago->bindParam(':fecha_pago', $fecha_pago, PDO::PARAM_STR); $stmt_pago->bindParam(':metodo_pago', $metodo_pago, PDO::PARAM_STR); $stmt_pago->bindParam(':puntos', $puntos_adicionales_a_guardar, PDO::PARAM_INT); $stmt_pago->execute(); $pago_id = $conexion->lastInsertId(); if (!$pago_id) { throw new Exception("No se pudo obtener el ID del pago insertado."); } error_log("[Procesar Pago] Pago $pago_id registrado como pendiente para negocio {$negocio['rut']}, método: $metodo_pago"); } catch (Exception $e) { $conexion->rollBack(); $_SESSION['mensaje'] = 'Error interno al registrar el inicio del pago: ' . $e->getMessage(); $_SESSION['tipo_mensaje'] = 'danger'; error_log("[Procesar Pago] Error al registrar pago inicial para {$negocio['rut']}: " . $e->getMessage()); redirigir(BASE_URL . '/negocio/renovar_licencia.php'); exit; } // --- PASO 2: Procesar según método de pago --- if ($metodo_pago === 'flow') { // Flow eliminado - integración no funcional $conexion->rollBack(); $_SESSION['mensaje'] = 'Flow ya no está disponible. Por favor seleccione otro método de pago.'; $_SESSION['tipo_mensaje'] = 'warning'; error_log("[Procesar Pago] Intento de usar Flow eliminado para pago $pago_id / negocio {$negocio['rut']}"); redirigir(BASE_URL . '/negocio/renovar_licencia.php'); exit; } elseif ($metodo_pago === 'mercadopago') { try { error_log("[Procesar Pago - MP] Iniciando flujo de Checkout Pro (Pago Manual)."); $valor_uf_float = obtenerIndicadorUF($conexion); if ($valor_uf_float === null || $valor_uf_float <= 0) { throw new Exception("No se pudo obtener el valor de la UF actual para Mercado Pago."); } $monto_clp_mp = round($precio_total_uf_post * $valor_uf_float, 2); if ($monto_clp_mp <= 0) { throw new Exception("El monto calculado en CLP para Mercado Pago es inválido ($monto_clp_mp)."); } $negocio_email = $negocio['email'] ?? 'comprador-test@tu-dominio.com'; $nombre_negocio = $negocio['nombre'] ?? 'Usuario SGB'; $payerInfo = ['email' => $negocio_email, 'name' => $nombre_negocio]; $orden_compra = (string)$pago_id; $titulo = "Renovación SGB - Plan " . $plan['nombre']; $descripcion = "Renovación licencia SGB Negocios - Pago ID: {$pago_id}"; if ($puntos_adicionales_a_guardar > 0) $titulo .= " + {$puntos_adicionales_a_guardar} puntos"; $urlNotificacion = BASE_URL . '/negocio/mercadopago/notificacion.php'; $urlExito = BASE_URL . '/negocio/pago_resultado.php?status=success&pago_id=' . $pago_id; $urlFallo = BASE_URL . '/negocio/pago_resultado.php?status=failure&pago_id=' . $pago_id; $urlPendiente = BASE_URL . '/negocio/pago_resultado.php?status=pending&pago_id=' . $pago_id; $mpService = new MercadoPagoService(); $preferencia = $mpService->crearPreferenciaPago($monto_clp_mp, $titulo, $descripcion, $orden_compra, $urlNotificacion, $urlExito, $urlFallo, $urlPendiente, $payerInfo); if ($preferencia && isset($preferencia['init_point']) && isset($preferencia['id'])) { $mp_init_point = $preferencia['init_point']; $mp_preference_id = $preferencia['id']; $stmt_update_pref = $conexion->prepare("UPDATE pagos SET mercadopago_preference_id = :pref_id WHERE id = :id"); $stmt_update_pref->bindParam(':pref_id', $mp_preference_id, PDO::PARAM_STR); $stmt_update_pref->bindParam(':id', $pago_id, PDO::PARAM_INT); $stmt_update_pref->execute(); $conexion->commit(); error_log("[Procesar Pago - MP Pro] Pago $pago_id iniciado. Pref ID: $mp_preference_id. Redirigiendo a MP..."); header('Location: ' . $mp_init_point); exit; } else { throw new Exception("Mercado Pago no pudo generar el enlace de pago."); } } catch (Exception $e) { if ($conexion->inTransaction()) $conexion->rollBack(); error_log("[Procesar Pago - MP Pro] Error para Negocio {$negocio['rut']} / Pago ID {$pago_id}: " . $e->getMessage()); $_SESSION['mensaje'] = 'Error al procesar el pago con Mercado Pago: ' . $e->getMessage(); $_SESSION['tipo_mensaje'] = 'danger'; $redirectParams = 'plan_id=' . $plan_id . '&rut=' . urlencode($rut) . '&puntos_adicionales=' . $puntos_adicionales_a_guardar; redirigir(BASE_URL . '/negocio/procesar_pago.php?' . $redirectParams . '&error=mp_process'); exit; } } elseif ($metodo_pago === 'transferencia') { try { $conexion->commit(); error_log("[Procesar Pago - Transferencia] Pago {$pago_id} registrado como pendiente para negocio {$negocio['rut']}"); $_SESSION['mensaje'] = 'Tu solicitud de pago por transferencia ha sido registrada. Por favor, realiza la transferencia y envía el comprobante como se indica.'; $_SESSION['tipo_mensaje'] = 'info'; redirigir(BASE_URL . '/negocio/pago_resultado.php?status=transfer_pending&pago_id=' . $pago_id); exit; } catch (Exception $e) { if ($conexion->inTransaction()) $conexion->rollBack(); error_log("[Procesar Pago - Transferencia] Error para pago {$pago_id} / negocio {$negocio['rut']}: " . $e->getMessage()); $_SESSION['mensaje'] = 'Error al registrar el pago por transferencia: ' . $e->getMessage(); $_SESSION['tipo_mensaje'] = 'danger'; redirigir(BASE_URL . '/negocio/renovar_licencia.php?plan_id=' . $plan_id . '&rut=' . urlencode($rut) . '&error=db_transfer'); exit; } } elseif ($metodo_pago === 'khipu') { error_log("[DEBUG] Iniciando procesamiento con método Khipu para Pago ID: $pago_id"); try { $valor_uf_float = obtenerIndicadorUF($conexion); if ($valor_uf_float === null || $valor_uf_float <= 0) { throw new Exception("No se pudo obtener el valor de la UF actual para Khipu."); } $monto_clp_khipu = round($precio_total_uf_post * $valor_uf_float, 0); if ($monto_clp_khipu <= 0) { throw new Exception("El monto calculado en CLP para Khipu es inválido ($monto_clp_khipu)."); } $negocio_email = $negocio['email'] ?? 'no-reply@tusistema.com'; $orden_compra = (string)$pago_id; $concepto = "Renovación SGB - Plan " . $plan['nombre']; if ($puntos_adicionales_a_guardar > 0) { $concepto .= " + " . $puntos_adicionales_a_guardar . " puntos"; } // Detectar si es entorno local y usar URLs públicas para evitar error 403 $isLocalhost = ( strpos(BASE_URL, 'localhost') !== false || strpos(BASE_URL, '127.0.0.1') !== false || strpos(BASE_URL, '::1') !== false ); if ($isLocalhost && KHIPU_IS_TEST_MODE) { // En localhost y modo sandbox, usar URLs públicas dummy $urlRetorno = 'https://httpbin.org/status/200'; $urlNotificacion = 'https://httpbin.org/post'; error_log("[Procesar Pago - Khipu] Usando URLs públicas dummy para localhost"); } else { // En producción o servidor público, usar URLs reales $urlRetorno = BASE_URL . '/negocio/khipu/khipu_retorno.php'; $urlNotificacion = BASE_URL . '/negocio/khipu/khipu_notificacion.php'; } $khipuService = new KhipuService(); error_log("[Procesar Pago - Khipu] Preparando para llamar a crearPago. Monto: $monto_clp_khipu, OC: $orden_compra"); $khipu_response = $khipuService->crearPago($monto_clp_khipu, $orden_compra, $concepto, $negocio_email, $urlRetorno, $urlNotificacion); if ($khipu_response && isset($khipu_response['url']) && isset($khipu_response['payment_id'])) { $khipu_url = $khipu_response['url']; $khipu_token = $khipu_response['payment_id']; $stmt_update_token = $conexion->prepare("UPDATE pagos SET khipu_token = :token WHERE id = :id"); $stmt_update_token->bindParam(':token', $khipu_token, PDO::PARAM_STR); $stmt_update_token->bindParam(':id', $pago_id, PDO::PARAM_INT); $stmt_update_token->execute(); $conexion->commit(); error_log("[Procesar Pago - Khipu] Pago $pago_id iniciado. Token: $khipu_token. Redirigiendo a Khipu..."); header('Location: ' . $khipu_url); exit; } else { throw new Exception("Khipu no pudo procesar la solicitud de pago. Respuesta: " . print_r($khipu_response, true)); } } catch (Exception $e) { if ($conexion->inTransaction()) $conexion->rollBack(); $_SESSION['mensaje'] = 'Error al iniciar el pago con Khipu: ' . $e->getMessage(); $_SESSION['tipo_mensaje'] = 'danger'; error_log("[Procesar Pago - Khipu] Error para pago $pago_id / negocio {$negocio['rut']}: " . $e->getMessage()); $redirectParams = 'plan_id=' . $plan_id . '&rut=' . urlencode($rut) . '&puntos_adicionales=' . $puntos_adicionales_a_guardar; redirigir(BASE_URL . '/negocio/procesar_pago.php?' . $redirectParams . '&error=khipu_process'); exit; } } } // Fin if (isset($_POST['procesar'])) } // Fin if ($_SERVER['REQUEST_METHOD'] === 'POST') // --- HTML para mostrar el resumen y el formulario de pago (si no es POST) --- // Si la solicitud no es POST, muestra la página de confirmación de pago cargarEstilosUnificados("Confirmar Pago - SGB"); ?>
|
Banco:
Banco de Chile
|
Tipo cuenta:
Cuenta Corriente
|
|
N° cuenta:
00-169-43666-07
|
Nombre:
SGB ERP SPA
|
|
RUT:
17.669.023-2
|
Email:
sistemadenegociodebarriosgb@gmail.com
|