using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using gehGassi.Core.Interfaces; using gehGassi.Domain.Advertisements; using gehGassi.Domain.Common; using Microsoft.EntityFrameworkCore; using NetTopologySuite.Geometries; using NetTopologySuite; namespace gehGassi.Core.Services { /// /// Service für die Verwaltung von Werbungen /// public class AdvertisementService : ServiceBase, IAdvertisementService { private readonly IRepository _namesRepository; /// /// Erstellt eine Instanz /// /// Instanz einer IUnitOfWork public AdvertisementService(IUnitOfWork unitOfWork) : base(unitOfWork) { _namesRepository = unitOfWork.GetRepository(); } /// /// Gibt eine gefilterte Liste von Werbungen zurück /// /// Filterbegriff der in bestimmten Feldern gesucht wird /// List betroffener Werbungen public IQueryable Filter(string filter) { return Repository.Query(c => c.NameLocalized.Contains(filter)); } /// /// Erstellen einer Werbung /// /// Listung public Advertisement Create() { var item = new Advertisement() { Id = Guid.NewGuid().ToString("N"), Created = DateTimeOffset.UtcNow }; return item; } /// /// Gibt eine gefilterte Liste von Werbungen zurück. /// /// Filterbegriff der in bestimmten Feldern gesucht wird /// List betroffener Werbungen public async Task> SearchAsync(string filter) { return (await Repository.FindAsync(c => c.NameLocalized.Contains(filter))).ToList(); } /// /// Gibt eine gefilterte Liste von Werbungen mit Namen zurück in einer gewählten Sprache /// /// Filterbegriff der in bestimmten Feldern gesucht wird /// Gewünschte Sprache /// Fallback Sprache /// Sollen gelöschte inkludiert werden? /// Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden? /// Liste betroffener Werbungen public IQueryable FilterWithNames(string filter, string language, string fallback, bool includeDeleted, bool excludeDraft) { language = language.ToUpperInvariant(); fallback = fallback.ToUpperInvariant(); var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_AdvertisementsWithNames({0},{1})", c => c.Name.Contains(filter) || c.CustomerName.Contains(filter), language, fallback); if (!includeDeleted) baseQuery = baseQuery.Where(c => c.Deleted == false); if (excludeDraft) baseQuery = baseQuery.Where(c => c.Status != AdvertisementStatus.Draft); return baseQuery; } /// /// Gibt eine gefilterte Liste von Werbungen mit Namen für Kunden zurück in einer gewählten Sprache /// /// Id des Kunden /// Filterbegriff der in bestimmten Feldern gesucht wird /// Gewünschte Sprache /// Fallback Sprache /// Sollen gelöschte inkludiert werden? /// Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden? /// Liste betroffener Werbungen public IQueryable FilterWithNamesCustomer(long customerId, string filter, string language, string fallback, bool includeDeleted, bool excludeDraft) { language = language.ToUpperInvariant(); fallback = fallback.ToUpperInvariant(); var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_AdvertisementsWithNames({0},{1})", c => c.CustomerId == customerId && (c.Name.Contains(filter) || c.CustomerName.Contains(filter)), language, fallback); if (!includeDeleted) baseQuery = baseQuery.Where(c => c.Deleted == false); if (excludeDraft) baseQuery = baseQuery.Where(c => c.Status != AdvertisementStatus.Draft); return baseQuery; } /// /// Löschen von Werbungen basierend auf einer Rubrik /// /// Id der Rubrik /// Wenn true, dann wirklich löschen, auf gelöscht setzen sonst /// Task public async Task DeleteByCategoryAsync(string categoryId, bool forceDelete) { var items = await Repository.FindAsync(c => c.AdvertisementCategoryId == categoryId).ConfigureAwait(false); foreach (var listing in items) { if (!forceDelete) listing.Deleted = true; else Repository.Remove(listing); } } /// /// Gibt die Anzahl von Werbungen zurück /// /// Sollen gelöschte inkludiert werden? /// Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden? /// Anzahl Werbungen public async Task CountAsync(bool includeDeleted, bool excludeDraft) { var query = Repository.Query(c => c.Id != ""); if (!includeDeleted) query = query.Where(c => c.Deleted == false); if (excludeDraft) query = query.Where(c => c.Status != AdvertisementStatus.Draft); return await query.CountAsync().ConfigureAwait(false); } /// /// Gibt die Anzahl von Werbungen in einem Status zurück /// /// Gesuchter Status /// Sollen gelöschte inkludiert werden? /// Anzahl Werbungen public async Task CountAsync(AdvertisementStatus status, bool includeDeleted) { var query = Repository.Query(c => c.Status == status); if (!includeDeleted) query = query.Where(c => c.Deleted == false); return await query.CountAsync().ConfigureAwait(false); } /// /// Gibt eine Werbung für einen Artikel im Warenkorb zurück /// /// Id des Artikels im Warenkorb /// Werbung oder null, wenn nicht gefunden public async Task GetByCartItemAsync(long cartItemId) { return await Repository.FirstOrDefaultAsync(c => c.CartItemId == cartItemId && c.Status == AdvertisementStatus.Draft); } /// /// Gibt eine Werbung für einen Artikel in einer Bestellung zurück /// /// Id des Artikels in der Bestellung /// Werbung oder null, wenn nicht gefunden public async Task GetByOrderItemAsync(long orderItemId) { return await Repository.FirstOrDefaultAsync(c => c.OrderItemId == orderItemId); } /// /// Setzen des Status von Werbungen nach Bestellung /// /// Id der Bestellung /// Zu setzender Status /// Anzahl betroffener Werbungen public async Task SetStatusByOrderAsync(long orderId, AdvertisementStatus status) { var items = await Repository.FindAsync(c => c.OrderId == orderId); foreach (var item in items) { item.Status = status; } return items.Count(); } /// /// Setzen des Bezahlstatus von Werbungen nach Bestellung /// /// Id der Bestellung /// Zu setzender Status /// Anzahl betroffener Werbungen public async Task SetPaymentStatusByOrderAsync(long orderId, PaymentStatus status) { var items = await Repository.FindAsync(c => c.OrderId == orderId); foreach (var item in items) { item.PaymentStatus = status; } return items.Count(); } /// /// Gibt eine Liste von Werbungen zurück für die Anzeige der Werbungen die bald enden und in der Nähe sind /// /// Land /// Bundesland /// Optional: Breitengrad /// Optional: Längengrad /// Gewünschte Sprache /// Fallback Sprache /// Datensätze auslassen /// Datensätze nehmen /// Liste passender Listungen public async Task<(int total, List list)> GetNearEndForAppAsync(string country, string state, double lat, double lng, string language, string fallback, int skip, int take) { language = language.ToUpperInvariant(); fallback = fallback.ToUpperInvariant(); if (!string.IsNullOrWhiteSpace(country)) country = country.ToUpperInvariant(); if (!string.IsNullOrWhiteSpace(state)) state = state.ToUpperInvariant(); var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326); var location = geometryFactory.CreatePoint(new Coordinate(lng, lat)); var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_AdvertisementsWithNames({0},{1})", c => c.Deleted == false && c.Status == AdvertisementStatus.Running && c.EndDate > DateTimeOffset.UtcNow && (c.GeoMode == GeoMode.None || (c.GeoMode == GeoMode.Country && c.Address_CountryCode == country) || (c.GeoMode == GeoMode.CountryAndState && c.Address_CountryCode == country && c.Address_State == state) || (c.GeoMode == GeoMode.Location && c.Location.IsWithinDistance(location, c.Radius * 1000))), language, fallback); var total = await baseQuery.CountAsync().ConfigureAwait(false); //TODO: noch überlegen wie wir eine Lokalisierung machen können var list = await baseQuery.OrderBy(c => c.EndDate).Skip(skip).Take(take).ToListAsync().ConfigureAwait(false); return (total, list); } /// /// Gibt eine Liste von Werbungen je Kategorie zurück /// /// Id der Kategorie /// Land /// Bundesland /// Optional: Breitengrad /// Optional: Längengrad /// Gewünschte Sprache /// Fallback Sprache /// Datensätze auslassen /// Datensätze nehmen /// Liste passender Listungen public async Task<(int total, List list)> GetByCategoryForAppAsync(string categoryId, string country, string state, double lat, double lng, string language, string fallback, int skip, int take) { language = language.ToUpperInvariant(); fallback = fallback.ToUpperInvariant(); if (!string.IsNullOrWhiteSpace(country)) country = country.ToUpperInvariant(); if (!string.IsNullOrWhiteSpace(state)) state = state.ToUpperInvariant(); var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326); var location = geometryFactory.CreatePoint(new Coordinate(lng, lat)); var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_AdvertisementsWithNames({0},{1})", c => c.Deleted == false && c.Status == AdvertisementStatus.Running && c.EndDate > DateTimeOffset.UtcNow && c.AdvertisementCategoryId == categoryId && (c.GeoMode == GeoMode.None || (c.GeoMode == GeoMode.Country && c.Address_CountryCode == country) || (c.GeoMode == GeoMode.CountryAndState && c.Address_CountryCode == country && c.Address_State == state) || (c.GeoMode == GeoMode.Location && c.Location.IsWithinDistance(location, c.Radius * 1000))), language, fallback); var total = await baseQuery.CountAsync().ConfigureAwait(false); //TODO: noch überlegen wie wir eine Lokalisierung machen können var list = await baseQuery.OrderBy(c => c.EndDate).Skip(skip).Take(take).ToListAsync().ConfigureAwait(false); return (total, list); } /// /// Gibt eine Werbung in einer gewünschten Sprache zurück /// /// Id der Werbung /// Gewünschte Sprache /// Fallback Sprache /// Gefundene Werbung, null sonst public async Task GetRunningWithNamesAsync(string id, string language, string fallback) { language = language.ToUpperInvariant(); fallback = fallback.ToUpperInvariant(); var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_AdvertisementsWithNames({0},{1})", c => c.Id == id && c.Deleted == false && c.Status == AdvertisementStatus.Running && c.EndDate > DateTimeOffset.UtcNow, language, fallback); var result = await baseQuery.FirstOrDefaultAsync().ConfigureAwait(false); return result; } /// /// Starten von gebuchten Werbungen wenn diese das Start-Datum erreicht haben /// /// Anzahl gestartete Werbungen public async Task StartBookedAsnyc() { var items = await Repository.FindAsync(c => c.Status == AdvertisementStatus.Booked && c.Deleted == false && c.StartDate <= DateTimeOffset.UtcNow && c.EndDate.Value >= DateTimeOffset.UtcNow); foreach (var item in items) { item.Status = AdvertisementStatus.Running; } return items.Count(); } /// /// Stoppen von abgelaufenen Werbungen wenn diese das Enddatum erreicht haben /// /// Anzahl gestoppte Werbungen public async Task StopRunningAsync() { var items = await Repository.FindAsync(c => c.Status == AdvertisementStatus.Running && c.Deleted == false && c.EndDate.Value <= DateTimeOffset.UtcNow); foreach (var item in items) { item.Status = AdvertisementStatus.Ended; } return items.Count(); } } }