public async Task<IReadOnlyList<TourMarketplaceItemDto>> GetOwnerToursAsync( int ownerUserId, int topRows, CancellationToken cancellationToken = default){ var sql = $@" SELECT TOP (@TopRows) t.TourId, t.Title, t.LocationLabel, t.ImageList, t.Status, t.CreatedAt FROM {tourTable} t WHERE t.OwnerUserId = @OwnerUserId ORDER BY t.CreatedAt DESC"; // Load tours with ticket types and ratings}
For each tour, the system loads reservation statistics:
Services/Tour/TourService.cs:1897
public async Task<TourReservationStatsDto> GetTourReservationStatsAsync( int tourId, int recentDays = 30, CancellationToken cancellationToken = default){ var sql = $@" SELECT CAST(r.CreatedAt AS date) AS DayDate, COUNT(*) AS ReservationCount, COALESCE(SUM(r.AmountPaid), 0) AS TotalAmount, SUM(CASE WHEN r.PaymentStatus = 1 THEN 1 ELSE 0 END) AS PaidCount, SUM(CASE WHEN r.PaymentStatus <> 1 THEN 1 ELSE 0 END) AS PendingCount FROM {reservationTable} r WHERE r.TourId = @TourId GROUP BY CAST(r.CreatedAt AS date) ORDER BY DayDate ASC;";}
public sealed record TourReservationStatsDto( int TourId, int TotalReservations, decimal TotalAmount, IReadOnlyList<TourReservationDayStat> Daily);public sealed record TourReservationDayStat( DateTime Date, int Count, decimal Amount, int PaidCount, int PendingCount, decimal PaidAmount, decimal PendingAmount);
private void EditService(TourBookingViewModel item){ if (!item.IsOwner) { ShowModal("Error", "Solo el creador puede editar este servicio."); return; } Navigation.NavigateTo($"/tour/edit/{item.Tour.TourId}");}
Deletion is prevented if the tour has existing reservations.
Services/Tour/TourService.cs:479
public async Task DeleteTourAsync( int tourId, CancellationToken cancellationToken = default){ // Check for existing reservations var countSql = $"SELECT COUNT(1) FROM {reservationTable} WHERE TourId = @TourId;"; var count = await ExecuteScalarAsync<int>(countSql, new { TourId = tourId }); if (count > 0) { throw new InvalidOperationException( "Este servicio tiene reservas/ventas y no puede eliminarse." ); } // Delete tour and related data await ExecuteAsync("sp_Tour_DeleteCascade", new { TourId = tourId });}
Only the tour owner can perform management actions (edit, delete, generate URLs).
Permission checks are performed before each action:
public sealed class TourBookingViewModel{ public bool IsOwner => Tour.OwnerUserId == _currentUserId; // Disable actions if not owner public bool CanEdit => IsOwner; public bool CanDelete => IsOwner && ReservationCount == 0;}