false, 'message' => 'Método no permitido']); exit(); } // Leer datos JSON $input = json_decode(file_get_contents('php://input'), true); if (!isset($input['id']) || !isset($input['motivo'])) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Faltan datos obligatorios (id y motivo)']); exit(); } $id = (int)$input['id']; $motivo = trim($input['motivo']); if (empty($motivo)) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'El motivo no puede estar vacío']); exit(); } try { // 1. Verificar que la reserva existe $stmt = $pdo->prepare(" SELECT id, estado, codigo, cabina_id, importe, referencia_bizum, usuario_id, fecha, hora_inicio FROM reservas WHERE id = ? "); $stmt->execute([$id]); $reserva = $stmt->fetch(PDO::FETCH_ASSOC); if (!$reserva) { http_response_code(404); echo json_encode(['success' => false, 'message' => 'Reserva no encontrada']); exit(); } // 2. No permitir devolver si ya está cancelada o finalizada $estadosNoCancelables = ['cancelada', 'finalizada']; if (in_array($reserva['estado'], $estadosNoCancelables)) { http_response_code(400); echo json_encode([ 'success' => false, 'message' => 'No se puede cancelar una reserva en estado: ' . $reserva['estado'] ]); exit(); } // 3. Iniciar transacción $pdo->beginTransaction(); // 4. Cancelar la reserva y registrar el motivo $stmt = $pdo->prepare(" UPDATE reservas SET estado = 'cancelada', hora_salida_real = NOW(), motivo_cancelacion = ? WHERE id = ? "); $stmt->execute([$motivo, $id]); if ($stmt->rowCount() === 0) { $pdo->rollBack(); http_response_code(500); echo json_encode(['success' => false, 'message' => 'No se pudo actualizar la reserva']); exit(); } // 5. Liberar la cabina si estaba ocupada o reservada if (in_array($reserva['estado'], ['confirmada', 'activa', 'pagada_pendiente_aprobacion', 'reservada'])) { $stmtCabina = $pdo->prepare(" UPDATE cabinas SET estado = 'disponible' WHERE id = ? AND estado IN ('ocupada', 'reservada') "); $stmtCabina->execute([$reserva['cabina_id']]); } // 6. Desactivar el QR si estaba activo $stmtQR = $pdo->prepare("UPDATE reservas SET qr_activo = 0, codigo_qr = NULL WHERE id = ?"); $stmtQR->execute([$id]); // ============================================================ // 7. ✅ NUEVO: Registrar la devolución en movimientos_caja // (solo si la reserva tenía referencia_bizum y la tabla existe) // ============================================================ $movimiento_registrado = false; $importe_devolver = floatval($reserva['importe']); if (!empty($reserva['referencia_bizum']) && $importe_devolver > 0) { try { // Verificar que la tabla movimientos_caja existe $stmtCheck = $pdo->query("SHOW TABLES LIKE 'movimientos_caja'"); if ($stmtCheck && $stmtCheck->rowCount() > 0) { $fechaMov = $reserva['fecha'] . ' ' . ($reserva['hora_inicio'] ?? '00:00:00'); $conceptoMov = 'Devolución Bizum reserva ' . $reserva['codigo'] . ' (ref: ' . $reserva['referencia_bizum'] . ')'; $stmtMov = $pdo->prepare(" INSERT INTO movimientos_caja (fecha, concepto, tipo, importe, categoria, reserva_id, origen) VALUES (NOW(), :concepto, 'salida', :importe, 'Reservas', :reserva_id, 'reserva') "); $stmtMov->execute([ ':concepto' => $conceptoMov, ':importe' => $importe_devolver, ':reserva_id' => $id ]); $movimiento_registrado = true; } } catch (Exception $eMov) { // No fallar toda la operación si no se puede registrar en caja // Pero avisar en el log error_log('Aviso: no se pudo registrar devolución en movimientos_caja: ' . $eMov->getMessage()); } } // 8. Confirmar transacción $pdo->commit(); // 9. Respuesta exitosa $mensaje = 'Reserva cancelada correctamente.'; if (!empty($reserva['referencia_bizum']) && $movimiento_registrado) { $mensaje .= ' Devolución de ' . number_format($importe_devolver, 2, ',', '.') . ' € registrada en Flujo de Caja. Recuerda hacer la transferencia manualmente en tu app del banco.'; } elseif (!empty($reserva['referencia_bizum'])) { $mensaje .= ' Recuerda devolver ' . number_format($importe_devolver, 2, ',', '.') . ' € al cliente (Bizum: ' . $reserva['referencia_bizum'] . ').'; } echo json_encode([ 'success' => true, 'message' => $mensaje, 'data' => [ 'id' => $id, 'codigo' => $reserva['codigo'], 'estado_anterior' => $reserva['estado'], 'estado_nuevo' => 'cancelada', 'importe_devolver' => $importe_devolver, 'referencia_bizum' => $reserva['referencia_bizum'], 'motivo_cancelacion' => $motivo, 'cabina_liberada' => $reserva['cabina_id'], 'movimiento_caja_id' => $movimiento_registrado ? (int)$pdo->lastInsertId() : null, 'requiere_devolucion' => !empty($reserva['referencia_bizum']) ] ]); } catch (PDOException $e) { // Revertir transacción en caso de error if ($pdo->inTransaction()) { $pdo->rollBack(); } http_response_code(500); echo json_encode([ 'success' => false, 'message' => 'Error en el servidor', 'error' => $e->getMessage() ]); } ?>