false, 'message' => 'Método no permitido. Use POST']); exit(); } try { $input = json_decode(file_get_contents('php://input'), true); if (!$input) $input = $_POST; if (!isset($input['id'])) { http_response_code(400); echo json_encode(['success' => false, 'message' => 'Falta el campo obligatorio: id']); exit(); } $id = (int)$input['id']; $bloques_extra = isset($input['bloques_extra']) ? max(1, (int)$input['bloques_extra']) : 1; // 1) Obtener la reserva actual $stmt = $pdo->prepare(" SELECT r.id, r.codigo, r.usuario_id, r.mascota_id, r.cabina_id, r.fecha, r.hora_inicio, r.hora_fin_prevista, r.duracion_bloques, r.importe, r.estado, r.operador_aprobacion FROM reservas r WHERE r.id = ? "); $stmt->execute([$id]); $reserva = $stmt->fetch(); if (!$reserva) { http_response_code(404); echo json_encode(['success' => false, 'message' => 'Reserva no encontrada']); exit(); } // 2) Validar estado $estados_permitidos = ['activa', 'confirmada', 'finalizada', 'excedida']; if (!in_array($reserva['estado'], $estados_permitidos)) { http_response_code(400); echo json_encode([ 'success' => false, 'message' => "No se puede renovar una reserva en estado '{$reserva['estado']}'. Estados permitidos: " . implode(', ', $estados_permitidos) ]); exit(); } // 3) Calcular precio por bloque (basado en configuración o por defecto 3€) $precio_bloque = 3.00; try { $stmtCfg = $pdo->prepare("SELECT valor FROM configuracion WHERE clave = 'precio_bloque' LIMIT 1"); $stmtCfg->execute(); $cfg = $stmtCfg->fetch(); if ($cfg && $cfg['valor'] > 0) $precio_bloque = floatval($cfg['valor']); } catch (Exception $e) { // Si no existe tabla configuracion, usar precio por defecto } // 4) Nuevos valores $nuevos_bloques = $reserva['duracion_bloques'] + $bloques_extra; $nuevo_importe = $reserva['importe'] + ($bloques_extra * $precio_bloque); // Calcular nueva hora_fin_prevista = hora_inicio + nuevos_bloques * 30 min $nueva_hora_fin = null; if (!empty($reserva['hora_inicio'])) { $fechaHoraInicio = $reserva['fecha'] . ' ' . $reserva['hora_inicio']; $dt = new DateTime($fechaHoraInicio); $dt->add(new DateInterval('PT' . ($nuevos_bloques * 30) . 'M')); $nueva_hora_fin = $dt->format('H:i:s'); } // 5) Si la reserva estaba 'excedida', volver a 'activa' al renovar $nuevo_estado = ($reserva['estado'] === 'excedida') ? 'activa' : $reserva['estado']; // 6) UPDATE $stmt = $pdo->prepare(" UPDATE reservas SET duracion_bloques = :bloques, hora_fin_prevista = :hora_fin, importe = :importe, estado = :estado WHERE id = :id "); $stmt->execute([ ':bloques' => $nuevos_bloques, ':hora_fin' => $nueva_hora_fin, ':importe' => $nuevo_importe, ':estado' => $nuevo_estado, ':id' => $id ]); // 7) Registrar movimiento automático en caja (si la tabla existe) try { $stmtCheck = $pdo->query("SHOW TABLES LIKE 'movimientos_caja'"); if ($stmtCheck && $stmtCheck->rowCount() > 0) { $stmtMov = $pdo->prepare(" INSERT INTO movimientos_caja (fecha, concepto, tipo, importe, categoria, reserva_id, origen) VALUES (NOW(), :concepto, 'entrada', :importe, 'Reservas', :reserva_id, 'reserva') "); $stmtMov->execute([ ':concepto' => 'Renovación reserva ' . $reserva['codigo'] . ' (+' . $bloques_extra . ' bloque(s))', ':importe' => $bloques_extra * $precio_bloque, ':reserva_id' => $id ]); } } catch (Exception $e) { // No fallar si no se puede registrar en caja } // 8) Devolver la reserva actualizada $stmtGet = $pdo->prepare("SELECT * FROM reservas WHERE id = ?"); $stmtGet->execute([$id]); echo json_encode([ 'success' => true, 'message' => "Reserva renovada: +{$bloques_extra} bloque(s) de 30 min. Nuevo importe: {$nuevo_importe} €", 'data' => [ 'id' => $id, 'codigo' => $reserva['codigo'], 'duracion_bloques' => $nuevos_bloques, 'hora_fin_prevista' => $nueva_hora_fin, 'importe' => $nuevo_importe, 'estado' => $nuevo_estado, 'bloques_extra' => $bloques_extra ] ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); } catch (PDOException $e) { http_response_code(500); echo json_encode(['success' => false, 'message' => 'Error en el servidor', 'error' => $e->getMessage()]); } ?>