380 lines
17 KiB
C#
380 lines
17 KiB
C#
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
|
|
{
|
|
/// <summary>
|
|
/// Service der die Verwaltung von Bannern realisiert
|
|
/// </summary>
|
|
public class BannerService : ServiceBase<Banner>, IBannerService
|
|
{
|
|
private readonly IRepository<BannerWithNames> _namesRepository;
|
|
private readonly IRepository<BannerStatistic> _statisticsRepository;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="unitOfWork">Instanz eines IUnitOfWork</param>
|
|
public BannerService(IUnitOfWork unitOfWork) : base(unitOfWork)
|
|
{
|
|
_namesRepository = unitOfWork.GetRepository<BannerWithNames>();
|
|
_statisticsRepository = unitOfWork.GetRepository<BannerStatistic>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine gefilterte Liste von Bannern zurück
|
|
/// </summary>
|
|
/// <param name="filter">Filterbegriff der in bestimmten Feldern gesucht wird</param>
|
|
/// <returns>List betroffener Banner</returns>
|
|
public IQueryable<Banner> Filter(string filter)
|
|
{
|
|
return Repository.Query(c => c.NameLocalized.Contains(filter));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Erstellen eines Banners
|
|
/// </summary>
|
|
/// <returns>Banner</returns>
|
|
public Banner Create()
|
|
{
|
|
var item = new Banner()
|
|
{
|
|
Id = Guid.NewGuid().ToString("N"),
|
|
Created = DateTimeOffset.UtcNow
|
|
};
|
|
return item;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine gefilterte Liste von Bannern zurück.
|
|
/// </summary>
|
|
/// <param name="filter">Filterbegriff der in bestimmten Feldern gesucht wird</param>
|
|
/// <returns>List betroffener Banner</returns>
|
|
public async Task<List<Banner>> SearchAsync(string filter)
|
|
{
|
|
return (await Repository.FindAsync(c => c.NameLocalized.Contains(filter))).ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine gefilterte Liste von Bannern mit Namen zurück in einer gewählten Sprache
|
|
/// </summary>
|
|
/// <param name="filter">Filterbegriff der in bestimmten Feldern gesucht wird</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="fallback">Fallback Sprache</param>
|
|
/// <param name="includeDeleted">Sollen gelöschte inkludiert werden?</param>
|
|
/// <param name="excludeDraft">Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden?</param>
|
|
/// <returns>Liste betroffener Banner</returns>
|
|
public IQueryable<BannerWithNames> FilterWithNames(string filter, string language, string fallback, bool includeDeleted, bool excludeDraft)
|
|
{
|
|
language = language.ToUpperInvariant();
|
|
fallback = fallback.ToUpperInvariant();
|
|
|
|
var baseQuery = _namesRepository.QueryStoredProcedure("SELECT * FROM tv_BannersWithNames({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 != BannerStatus.Draft);
|
|
|
|
return baseQuery;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine gefilterte Liste von Bannern mit Namen für Kunden zurück in einer gewählten Sprache
|
|
/// </summary>
|
|
/// <param name="customerId">Id des Kunden</param>
|
|
/// <param name="filter">Filterbegriff der in bestimmten Feldern gesucht wird</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="fallback">Fallback Sprache</param>
|
|
/// <param name="includeDeleted">Sollen gelöschte inkludiert werden?</param>
|
|
/// <param name="excludeDraft">Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden?</param>
|
|
/// <returns>Liste betroffener Banner</returns>
|
|
public IQueryable<BannerWithNames> 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_BannersWithNames({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 != BannerStatus.Draft);
|
|
|
|
return baseQuery;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt die Anzahl von Bannern zurück
|
|
/// </summary>
|
|
/// <param name="includeDeleted">Sollen gelöschte inkludiert werden?</param>
|
|
/// <param name="excludeDraft">Sollen Entitäten im Draft-Status (Cart) ausgeblendet werden?</param>
|
|
/// <returns>Anzahl Banner</returns>
|
|
public async Task<int> 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 != BannerStatus.Draft);
|
|
return await query.CountAsync().ConfigureAwait(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt die Anzahl von Bannern in einem Status zurück
|
|
/// </summary>
|
|
/// <param name="status">Gesuchter Status</param>
|
|
/// <param name="includeDeleted">Sollen gelöschte inkludiert werden?</param>
|
|
/// <returns>Anzahl Banner</returns>
|
|
public async Task<int> CountAsync(BannerStatus 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt einen Banner für einen Artikel im Warenkorb zurück
|
|
/// </summary>
|
|
/// <param name="cartItemId">Id des Artikels im Warenkorb</param>
|
|
/// <returns>Banner oder null, wenn nicht gefunden</returns>
|
|
public async Task<Banner> GetByCartItemAsync(long cartItemId)
|
|
{
|
|
return await Repository.FirstOrDefaultAsync(c => c.CartItemId == cartItemId && c.Status == BannerStatus.Draft);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt einen Banner für einen Artikel in einer Bestellung zurück
|
|
/// </summary>
|
|
/// <param name="orderItemId">Id des Artikels in der Bestellung</param>
|
|
/// <returns>Banner oder null, wenn nicht gefunden</returns>
|
|
public async Task<Banner> GetByOrderItemAsync(long orderItemId)
|
|
{
|
|
return await Repository.FirstOrDefaultAsync(c => c.OrderItemId == orderItemId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzen des Status von Bannern nach Bestellung
|
|
/// </summary>
|
|
/// <param name="orderId">Id der Bestellung</param>
|
|
/// <param name="status">Zu setzender Status</param>
|
|
/// <returns>Anzahl betroffener Banner</returns>
|
|
public async Task<int> SetStatusByOrderAsync(long orderId, BannerStatus status)
|
|
{
|
|
var items = await Repository.FindAsync(c => c.OrderId == orderId);
|
|
foreach (var item in items)
|
|
{
|
|
item.Status = status;
|
|
}
|
|
|
|
return items.Count();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Setzen des Bezahlstatus von Bannern nach Bestellung
|
|
/// </summary>
|
|
/// <param name="orderId">Id der Bestellung</param>
|
|
/// <param name="status">Zu setzender Status</param>
|
|
/// <returns>Anzahl betroffener Banner</returns>
|
|
public async Task<int> 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();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt einen Banner für eine Platzierung zurück
|
|
/// </summary>
|
|
/// <param name="bannerLocation">Platzierung des Banners</param>
|
|
/// <param name="currentBannerId">Optional: Id des Banners der gerade angezeigt wird</param>
|
|
/// <param name="country">Land</param>
|
|
/// <param name="state">Bundesland</param>
|
|
/// <param name="lat">Optional: Breitengrad</param>
|
|
/// <param name="lng">Optional: Längengrad</param>
|
|
/// <param name="language">Gewünschte Sprache</param>
|
|
/// <param name="fallback">Fallback Sprache</param>
|
|
/// <returns>Zufälliger Banner wenn gefunden, null sonst</returns>
|
|
public async Task<BannerWithNames> GetBannerForLocationAsync(BannerLocation bannerLocation, string currentBannerId, string country, string state, double lat, double lng, string language, string fallback)
|
|
{
|
|
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_BannersWithNames({0},{1})", c => c.Deleted == false && c.Status == BannerStatus.Running && c.BannerLocation == bannerLocation &&
|
|
(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 list = await baseQuery.ToListAsync().ConfigureAwait(false);
|
|
if (list.Any())
|
|
{
|
|
if (list.Count > 1 && !string.IsNullOrWhiteSpace(currentBannerId))
|
|
{
|
|
//Wenn aktuell ein Banner angezeigt wird, dann diesen aus der Liste entfernen.
|
|
//Das geht nur wenn mindestens 2 Banner in der Liste sind.
|
|
list = list.Where(c => c.Id != currentBannerId).ToList();
|
|
}
|
|
|
|
var random = new Random();
|
|
int index = random.Next(list.Count);
|
|
return list[index];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fügt eine Anzahl von Views zu einem Banner hinzu und beendet die Laufzeit wenn die Budgetgrenze erreicht wurde
|
|
/// </summary>
|
|
/// <param name="id">Id des Banners</param>
|
|
/// <param name="viewCount">Anzahl Views</param>
|
|
/// <param name="appMode">AppMode</param>
|
|
/// <param name="language">Sprache</param>
|
|
/// <param name="country">Land</param>
|
|
/// <param name="state">Bundesland</param>
|
|
/// <returns>Anzahl Views gesamt</returns>
|
|
public async Task<int> AddViewsAsync(string id, int viewCount, AppMode appMode, string language, string country, string state)
|
|
{
|
|
var banner = await GetAsync(id);
|
|
if (banner != null)
|
|
{
|
|
AddStatistic(id, appMode, BannerStatisticType.View, viewCount, language, country, state);
|
|
|
|
banner.CurrentViews += viewCount;
|
|
var budgetUsed = (banner.CurrentViews * banner.PriceView) + (banner.CurrentClicks * banner.PriceClick);
|
|
banner.BudgetUsed = budgetUsed;
|
|
|
|
if (banner.BudgetUsed >= banner.Budget)
|
|
{
|
|
banner.Status = BannerStatus.Ended;
|
|
banner.EndDate = DateTimeOffset.UtcNow;
|
|
}
|
|
|
|
return banner.CurrentViews;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fügt eine Anzahl von Klicks zu einem Banner hinzu und beendet die Laufzeit wenn die Budgetgrenze erreicht wurde
|
|
/// </summary>
|
|
/// <param name="id">Id des Banners</param>
|
|
/// <param name="clickCount">Anzahl Klicks</param>
|
|
/// <param name="appMode">AppMode</param>
|
|
/// <param name="language">Sprache</param>
|
|
/// <param name="country">Land</param>
|
|
/// <param name="state">Bundesland</param>
|
|
/// <returns>Anzahl Klicks gesamt</returns>
|
|
public async Task<int> AddClicksAsync(string id, int clickCount, AppMode appMode, string language, string country, string state)
|
|
{
|
|
var banner = await GetAsync(id);
|
|
if (banner != null)
|
|
{
|
|
AddStatistic(id, appMode, BannerStatisticType.Click, clickCount, language, country, state);
|
|
|
|
banner.CurrentClicks += clickCount;
|
|
var budgetUsed = (banner.CurrentViews * banner.PriceView) + (banner.CurrentClicks * banner.PriceClick);
|
|
banner.BudgetUsed = budgetUsed;
|
|
|
|
if (banner.BudgetUsed >= banner.Budget)
|
|
{
|
|
banner.Status = BannerStatus.Ended;
|
|
banner.EndDate = DateTimeOffset.UtcNow;
|
|
}
|
|
|
|
return banner.CurrentClicks;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hinzufügen einer Statstik für einen Banner
|
|
/// </summary>
|
|
/// <param name="id">Id des Banners</param>
|
|
/// <param name="appMode">AppMode</param>
|
|
/// <param name="type">Klick oder View</param>
|
|
/// <param name="value">Anzahl Klicks oder Views</param>
|
|
/// <param name="language">Sprache</param>
|
|
/// <param name="country">Land</param>
|
|
/// <param name="state">Bundesland</param>
|
|
/// <returns>Task</returns>
|
|
public void AddStatistic(string id, AppMode appMode, BannerStatisticType type, int value, string language, string country, string state)
|
|
{
|
|
var statistic = new BannerStatistic
|
|
{
|
|
BannerId = id,
|
|
AppMode = appMode,
|
|
StatisticType = type,
|
|
Value = value,
|
|
Language = language,
|
|
CountryCode = country,
|
|
StateCode = state,
|
|
EventDate = DateTimeOffset.UtcNow
|
|
};
|
|
|
|
statistic.Year = statistic.EventDate.Year;
|
|
statistic.Month = statistic.EventDate.Month;
|
|
statistic.Day = statistic.EventDate.Day;
|
|
statistic.Hour = statistic.EventDate.Hour;
|
|
|
|
_statisticsRepository.Add(statistic);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Starten von gebuchten Bannern wenn diese das Start-Datum erreicht haben
|
|
/// </summary>
|
|
/// <returns>Anzahl gestartete Banner</returns>
|
|
public async Task<int> StartBookedAsnyc()
|
|
{
|
|
var items = await Repository.FindAsync(c => c.Status == BannerStatus.Booked && c.Deleted == false && c.StartDate <= DateTimeOffset.UtcNow);
|
|
foreach (var item in items)
|
|
{
|
|
item.Status = BannerStatus.Running;
|
|
}
|
|
|
|
return items.Count();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Stoppen von abgelaufenen Bannern wenn diese das Enddatum erreicht haben
|
|
/// </summary>
|
|
/// <returns>Anzahl gestoppte Banner</returns>
|
|
public async Task<int> StopRunningAsync()
|
|
{
|
|
var items = await Repository.FindAsync(c => c.Status == BannerStatus.Running && c.Deleted == false && c.BudgetUsed >= c.Budget);
|
|
foreach (var item in items)
|
|
{
|
|
item.EndDate = DateTimeOffset.UtcNow;
|
|
item.Status = BannerStatus.Ended;
|
|
}
|
|
|
|
return items.Count();
|
|
}
|
|
}
|
|
}
|