733 lines
33 KiB
C#

using System;
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using gehGassi.Core.Interfaces;
using gehGassi.Core.Services;
using gehGassi.Domain.Common;
using gehGassi.Domain.Dogs;
using gehGassi.Domain.Messages;
using gehGassi.Dto.Messages;
using gehGassi.External.Services;
using gehGassi.Web.Helper;
using gehGassi.Web.Hubs;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NetTopologySuite.Geometries;
using NetTopologySuite;
namespace gehGassi.Web.BackgroundServices
{
/// <summary>
/// Hintergrundservice der regelmäßige Aufgaben übernimmt
/// </summary>
public class BackgroundService : IHostedService, IDisposable
{
private Timer _timer;
private int _syncPoint = 0;
private readonly IServiceProvider _services;
private readonly ILogger<BackgroundService> _logger;
private readonly IOptions<BackgroundServiceOptions> _backgroundServiceOptions;
private readonly IDistributedCache _cache;
private readonly IServiceScopeFactory _resolver;
private readonly IWebHostEnvironment _webHostEnvironment;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="services">Instanz eine IServiceProvider</param>
/// <param name="logger">Instanz eines ILogger</param>
/// <param name="backgroundServiceOptions">Instanz eines IOptions BackgroundServiceOptions</param>
/// <param name="cache">Instanz eines IDistributedCache</param>
/// <param name="resolver">Instanz eines IServiceScopeFactory</param>
/// <param name="webHostEnvironment">Instanz eines IWebHostEnvironment</param>
public BackgroundService(IServiceProvider services, ILogger<BackgroundService> logger, IOptions<BackgroundServiceOptions> backgroundServiceOptions, IDistributedCache cache, IServiceScopeFactory resolver,
IWebHostEnvironment webHostEnvironment)
{
_services = services;
_logger = logger;
_backgroundServiceOptions = backgroundServiceOptions;
_cache = cache;
_resolver = resolver;
_webHostEnvironment = webHostEnvironment;
}
/// <inheritdoc />
public Task StartAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("BackgroundService started");
_timer = new Timer(async o => await DoWorkAsync(cancellationToken), null, TimeSpan.Zero, TimeSpan.FromSeconds(_backgroundServiceOptions.Value.TimerIntervalInSeconds));
return Task.CompletedTask;
}
/// <summary>
/// Task der die Abarbeitung übernimmt
/// </summary>
/// <param name="stoppingToken">CancellationToken</param>
/// <returns>Task</returns>
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
//Achtung: in Azure muss in den Slots eine Variable "Slot" angelegt sein und in der Production-Slot muss diese auf "Production" stehen
var slotName = Environment.GetEnvironmentVariable("Slot");
var runTasks = true;
if (!string.IsNullOrWhiteSpace(slotName) && slotName.ToLower() != "production")
runTasks = false;
int sync = Interlocked.CompareExchange(ref _syncPoint, 1, 0);
if (sync == 0)
{
try
{
if (runTasks)
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_logger.LogInformation("BackgroundService - Do Work");
await DeleteOldTempFilesAsync();
await RemoveExpiredRefreshTokensAsync();
await RemovePersistedTicketsAsync();
await InvalidateExpiredAppUserSubscription();
await ResetReservedListingsAsync();
await HandleKlarnaOrdersShipmentAsync();
await StartAndStopSpecialEntitiesAsync();
await AutoUnlockAppUsersAsync();
await CorrectInvalidAppUserLocationsAsync();
await TimeoutPublicWalkRequestsAsync();
await CancelTimedOutWalksAsync();
await CancelPendingWalksAsync();
if (_backgroundServiceOptions.Value.AutoComplete)
await CompleteWalksAsync();
if (_backgroundServiceOptions.Value.AutoConfirm)
{
await ConfirmCompletedWalksAsync();
await ConfirmCompletedWalksReminderAsync();
}
await SendSystemMessagesAsync();
await RemoveExpiredSystemMessagesAsync();
await RemoveExpiredBlocksAsync();
await RemoveExpiredMessagesAsync();
await SendPublicWalkRequestNotificationsAsync();
if (DateTimeOffset.UtcNow.DayOfWeek == DayOfWeek.Monday && DateTimeOffset.UtcNow.Hour == 3)
{
//Jeden Montag um 3 Uhr Auszahlungen durchführen
//Vorher noch prüfen ob diese bereits durchgeführt wurden
var lastPayout = await _cache.GetStringAsync("LastPayout");
if (lastPayout == null || string.IsNullOrWhiteSpace(lastPayout))
{
var options = new DistributedCacheEntryOptions();
options.SetAbsoluteExpiration(DateTimeOffset.UtcNow.AddHours(2));
await _cache.SetStringAsync("LastPayout", DateTimeOffset.UtcNow.ToString(), options);
//Jetzt Payout starten
_ = Task.Run(() => DoAutoPayoutAsync(_backgroundServiceOptions.Value.MinPayoutAmmount, _resolver));
}
}
_logger.LogInformation("BackgroundService - Do Work done");
}
}
catch (Exception ex)
{
_logger.LogError("BackgroundService Exception: {ex}", ex);
}
finally
{
_syncPoint = 0;
_timer.Change(TimeSpan.FromSeconds(_backgroundServiceOptions.Value.TimerIntervalInSeconds), TimeSpan.FromSeconds(_backgroundServiceOptions.Value.TimerIntervalInSeconds));
}
}
}
/// <summary>
/// Löschen alter Dateien im Temp-Ordner
/// </summary>
/// <returns>Task</returns>
private async Task DeleteOldTempFilesAsync()
{
using var scope = _services.CreateScope();
var fileService = scope.ServiceProvider.GetRequiredService<IFileService>();
await fileService.DeleteOldFilesAsync(FileServiceHelper.TempContainer, "", DateTimeOffset.UtcNow.AddMinutes(-60));
}
/// <summary>
/// Löschen abgelaufener Refreshtokens
/// </summary>
/// <returns></returns>
private async Task RemoveExpiredRefreshTokensAsync()
{
using var scope = _services.CreateScope();
var refreshTokenService = scope.ServiceProvider.GetRequiredService<IRefreshTokenService>();
await refreshTokenService.RemoveExpiredAsync("System");
await refreshTokenService.CommitAsync("System");
}
/// <summary>
/// Löschen abgelaufener PersistedTickets
/// </summary>
/// <returns></returns>
private async Task RemovePersistedTicketsAsync()
{
using var scope = _services.CreateScope();
var persistedTicketService = scope.ServiceProvider.GetRequiredService<IPersistedTicketService>();
await persistedTicketService.RemoveExpiredAsync();
await persistedTicketService.CommitAsync("System");
}
/// <summary>
/// Invalidierung abgelaufener AppUser-Abonnements
/// </summary>
/// <returns>Task</returns>
private async Task InvalidateExpiredAppUserSubscription()
{
using var scope = _services.CreateScope();
var subscriptionService = scope.ServiceProvider.GetRequiredService<ISubscriptionService>();
var count = await subscriptionService.InvalidateExipredAppUserSubscriptionsAsync(DateTimeOffset.UtcNow);
await subscriptionService.CommitAsync("System");
}
/// <inheritdoc />
public Task StopAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("BackgroundService stopped");
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
#region Tasks die dann in Webjobs ausgelagert werden sollten
//1. Reservierung für Listungen
/// <summary>
/// Zurücksetzen von reservierten Listungen wenn keine Zahlung erfolgt ist
/// </summary>
/// <returns>Task</returns>
private async Task ResetReservedListingsAsync()
{
using var scope = _services.CreateScope();
var listingService = scope.ServiceProvider.GetRequiredService<IListingService>();
await listingService.ResetReservedAsync(DateTimeOffset.UtcNow);
await listingService.CommitAsync("System");
}
//2. Klarna-Versand wenn nur digitale Produkte
//Besteht aus 2 Teilen - setzen der Bestellungen welche nur digitale Produkte beinhalten auf "Shipped"
//Dann noch für alle Bestellungen die "Shipped" wurden das an Klarna melden
/// <summary>
/// Klarna-Versand wenn nur digitale Produkte
/// </summary>
/// <returns>Task</returns>
private async Task HandleKlarnaOrdersShipmentAsync()
{
using var scope = _services.CreateScope();
var orderService = scope.ServiceProvider.GetRequiredService<IOrderService>();
await orderService.SetShipmentForKlarnaDigitalOnlyAsync();
await orderService.CommitAsync("System");
var orders = await orderService.GetOrdersKlarnaToShipAsync();
if (orders.Any())
{
try
{
var klarnaService = scope.ServiceProvider.GetRequiredService<IKlarnaService>();
var shopSettingsService = scope.ServiceProvider.GetRequiredService<IShopSettingsService>();
var shopSettings = await shopSettingsService.GetAsync();
int ordersHandled = 0;
foreach (var order in orders)
{
if (order.KlarnaShipmentError)
continue;
var result = await klarnaService.CaptureOrderAsync(order.Id, shopSettings.KlarnaClientId, shopSettings.KlarnaSecret);
switch (result)
{
case CaptureOrderResult.Success:
order.KlarnaShipmentSentDate = DateTime.UtcNow;
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Shipment success" + Environment.NewLine + order.PaymentInfo;
break;
case CaptureOrderResult.CaptureNotAllowed:
order.KlarnaShipmentError = true;
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: Capture not allowed" + Environment.NewLine + order.PaymentInfo;
break;
case CaptureOrderResult.RemainingAuthorizedAmount:
order.KlarnaShipmentError = true;
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: RemainingAuthorizedAmount 0" + Environment.NewLine + order.PaymentInfo;
break;
case CaptureOrderResult.OrderNotFound:
order.KlarnaShipmentError = true;
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: Order not found" + Environment.NewLine + order.PaymentInfo;
break;
case CaptureOrderResult.Timeout:
//Nichts tun, soll nochmal probiert werden
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: Timeout" + Environment.NewLine + order.PaymentInfo;
break;
case CaptureOrderResult.AuthorizationFailed:
//Nichts tun, soll nochmal probiert werden
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: Authorization failed" + Environment.NewLine + order.PaymentInfo;
break;
//Auth failed
default:
//Nichts tun, soll nochmal probiert werden
order.PaymentInfo = $"{DateTime.UtcNow.ToString()} Error: Unknown Error" + Environment.NewLine + order.PaymentInfo;
break;
}
}
await orderService.CommitAsync("klarna shipment service");
}
catch{}
}
}
//3. Starten und Stoppen von Listungen, Werbungen, Bannern, News und Gutscheinkampagnen und Pins nach Datum
/// <summary>
/// Starten und Stoppen von Listungen, Werbungen, Bannern und Pins nach Datum
/// </summary>
/// <returns>Task</returns>
private async Task StartAndStopSpecialEntitiesAsync()
{
using var scope = _services.CreateScope();
var listingService = scope.ServiceProvider.GetRequiredService<IListingService>();
var advertisementService = scope.ServiceProvider.GetRequiredService<IAdvertisementService>();
var bannerService = scope.ServiceProvider.GetRequiredService<IBannerService>();
var pinService = scope.ServiceProvider.GetRequiredService<IPinService>();
var newsService = scope.ServiceProvider.GetRequiredService<INewsService>();
var voucherCampaignService = scope.ServiceProvider.GetRequiredService<IVoucherCampaignService>();
await listingService.StartBookedAsnyc();
await listingService.StopRunningAsync();
await listingService.CommitAsync("System");
await advertisementService.StartBookedAsnyc();
await advertisementService.StopRunningAsync();
await advertisementService.CommitAsync("System");
await bannerService.StartBookedAsnyc();
await bannerService.StopRunningAsync();
await bannerService.CommitAsync("System");
await pinService.StartBookedAsnyc();
await pinService.StopRunningAsync();
await pinService.CommitAsync("System");
await newsService.StartApprovedAsnyc();
await newsService.StopRunningAsync();
await newsService.CommitAsync("System");
await voucherCampaignService.StartBookedAsnyc();
await voucherCampaignService.StopRunningAsync();
await voucherCampaignService.CommitAsync("System");
}
//4. Clear (das sind Log-Dateien hier konkret Audits die älter als z.B. ein Jahr sind
//5. Auto-Entsperren von App-Usern
/// <summary>
/// Automatisches Entsperren von App-Usern deren Sperrdatum erreicht wurde
/// </summary>
/// <returns>Task</returns>
private async Task AutoUnlockAppUsersAsync()
{
using var scope = _services.CreateScope();
var appUserService = scope.ServiceProvider.GetRequiredService<IAppUserService>();
await appUserService.AutoUnlockAsync();
await appUserService.CommitAsync("System");
}
/// <summary>
/// Bei AppUsern deren Location nicht korrekt eingetragen wurde, diese korrigieren wenn möglich
/// </summary>
/// <returns>Task</returns>
private async Task CorrectInvalidAppUserLocationsAsync()
{
using var scope = _services.CreateScope();
var appUserService = scope.ServiceProvider.GetRequiredService<IAppUserService>();
var geoLocationService = scope.ServiceProvider.GetRequiredService<IGeoLocationService>();
var appUsers = await appUserService.GetWithInvalidLocationAsync();
if (appUsers.Any())
{
foreach (var appUser in appUsers)
{
var location = await geoLocationService.GetLocationAsync(appUser.Address, CultureInfo.CurrentCulture.TwoLetterISOLanguageName);
if (location.Success)
{
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
var geoLocation = geometryFactory.CreatePoint(new Coordinate(location.Longitude, location.Latitude));
appUser.Location = geoLocation;
appUser.UpdatedAt = DateTimeOffset.UtcNow;
}
}
await appUserService.CommitAsync("System");
}
}
/// <summary>
/// Timeout von abgelaufenen öffentlichen Anfragen setzen
/// </summary>
/// <returns>Task</returns>
private async Task TimeoutPublicWalkRequestsAsync()
{
using var scope = _services.CreateScope();
var publicWalkRequestService = scope.ServiceProvider.GetRequiredService<IPublicWalkRequestService>();
await publicWalkRequestService.SetTimedOutAsync(DateTimeOffset.UtcNow);
await publicWalkRequestService.CommitAsync("System");
}
/// <summary>
/// Abgelaufene Walks stornieren.
/// Diese sind im Status "Request" und das Startdatum wurde bereits erreicht
/// </summary>
/// <returns>Task</returns>
private async Task CancelTimedOutWalksAsync()
{
using var scope = _services.CreateScope();
var walkService = scope.ServiceProvider.GetRequiredService<IWalkService>();
await walkService.CancelTimedOutAsync(DateTimeOffset.UtcNow);
await walkService.CommitAsync("System");
}
/// <summary>
/// Walks stornieren die direkt gebucht wurden und nach X Minuten nicht bezahlt wurden
/// </summary>
/// <returns>Task</returns>
private async Task CancelPendingWalksAsync()
{
using var scope = _services.CreateScope();
var walkService = scope.ServiceProvider.GetRequiredService<IWalkService>();
await walkService.CancelPendingAsync(DateTimeOffset.UtcNow, _backgroundServiceOptions.Value.CancelPendingMinutes);
await walkService.CommitAsync("System");
}
/// <summary>
/// Walks abschliessen, welche nicht innerhalb von X Minuten abgeschlossen wurden
/// </summary>
/// <returns>Task</returns>
private async Task CompleteWalksAsync()
{
using var scope = _services.CreateScope();
var walkService = scope.ServiceProvider.GetRequiredService<IWalkService>();
await walkService.CompleteAutoAsync(DateTimeOffset.UtcNow, _backgroundServiceOptions.Value.CompleteMinutes);
await walkService.CommitAsync("System");
}
/// <summary>
/// Walks bestätigen die abgeschlossen, aber innerhalb von X Minuten nicht bestätigt wurden
/// </summary>
/// <returns>Task</returns>
private async Task ConfirmCompletedWalksAsync()
{
using var scope = _services.CreateScope();
var walkService = scope.ServiceProvider.GetRequiredService<IWalkService>();
await walkService.ConfirmCompletedAsync(DateTimeOffset.UtcNow, _backgroundServiceOptions.Value.ConfirmationMinutes);
await walkService.CommitAsync("System");
}
/// <summary>
/// Walks bestätigen die abgeschlossen Erinnerung senden
/// </summary>
/// <returns>Task</returns>
private async Task ConfirmCompletedWalksReminderAsync()
{
using var scope = _services.CreateScope();
var walkService = scope.ServiceProvider.GetRequiredService<IWalkService>();
await walkService.ConfirmCompletedReminderAsync(DateTimeOffset.UtcNow, _backgroundServiceOptions.Value.ConfirmationReminderMinutes);
await walkService.CommitAsync("System");
}
/// <summary>
/// Löschen abgelaufener Systemnachrichten
/// </summary>
/// <returns></returns>
private async Task RemoveExpiredSystemMessagesAsync()
{
using var scope = _services.CreateScope();
var systemMessageService = scope.ServiceProvider.GetRequiredService<ISystemMessageService>();
await systemMessageService.RemoveExpiredAsync(DateTimeOffset.UtcNow);
await systemMessageService.CommitAsync("System");
}
/// <summary>
/// Löschen abgelaufener Blockierungen
/// </summary>
/// <returns></returns>
private async Task RemoveExpiredBlocksAsync()
{
using var scope = _services.CreateScope();
var applicationUserService = scope.ServiceProvider.GetRequiredService<IAppUserService>();
await applicationUserService.RemoveExpiredBlocksAsync(DateTimeOffset.UtcNow);
await applicationUserService.CommitAsync("System");
}
/// <summary>
/// Löschen von Nachrichten die nicht abgehlot wurden
/// </summary>
/// <returns></returns>
private async Task RemoveExpiredMessagesAsync()
{
using var scope = _services.CreateScope();
var messageService = scope.ServiceProvider.GetRequiredService<IMessageService>();
var removedCount = await messageService.RemoveUnreadMessagesAsync(DateTimeOffset.UtcNow.AddMonths(-1));
if(removedCount > 0)
await messageService.CommitAsync("System");
removedCount = await messageService.RemoveMessageCopiesAsync(DateTimeOffset.UtcNow.AddDays(-7));
if (removedCount > 0)
await messageService.CommitAsync("System");
}
/// <summary>
/// Senden von Systemnachtichten die gesendet werden sollen
/// </summary>
/// <returns>Task</returns>
private async Task SendSystemMessagesAsync()
{
using var scope = _services.CreateScope();
var systemMessageService = scope.ServiceProvider.GetRequiredService<ISystemMessageService>();
var appUserService = scope.ServiceProvider.GetRequiredService<IAppUserService>();
var pushNotificationService = scope.ServiceProvider.GetRequiredService<IPushNotificationService>();
var messagesToSend = await systemMessageService.GetToSendAsync(DateTimeOffset.UtcNow);
if (messagesToSend != null && messagesToSend.Any())
{
foreach (var message in messagesToSend)
{
message.AppUserCount = await appUserService.CountForSystemMessageAsync(new SystemMessageAppUserQuery() { AppUserType = message.AppUserType, City = message.City, Country = message.Country, Sex = message.Sex, State = message.State, VerifiedOnly = message.VerifiedOnly, Zip = message.Zip });
message.SentCount = message.AppUserCount;
message.HasBeenSent = true;
message.SentDate = DateTimeOffset.UtcNow;
message.SentBy = "System";
await systemMessageService.CommitAsync("System");
var appUsers = await appUserService.GetForSystemMessageAsync(new SystemMessageAppUserQuery() {AppUserType = message.AppUserType, City = message.City, Country = message.Country, Sex = message.Sex, State = message.State, VerifiedOnly = message.VerifiedOnly, Zip = message.Zip });
var sentCount = 0;
foreach (var appUser in appUsers)
{
sentCount += 1;
systemMessageService.Add(appUser.Id, appUser.Type, message.Id.ToString(), DateTimeOffset.UtcNow.AddDays(14), message.Message);
if (message.SendPushNotification)
{
await pushNotificationService.SendNewTextMessageAsync(appUser.Id, message.Id.ToString());
}
}
if (sentCount > 0)
{
await systemMessageService.CommitAsync("System");
}
}
}
}
/// <summary>
/// Senden von Benachrichtigungen wenn eine öffentliche Anfrage erstellt wurde und Walker in der Nähe benachrichtigt werden sollen
/// </summary>
/// <returns>Task</returns>
private async Task SendPublicWalkRequestNotificationsAsync()
{
using var scope = _services.CreateScope();
var publicWalkRequestService = scope.ServiceProvider.GetRequiredService<IPublicWalkRequestService>();
var pushNotificationService = scope.ServiceProvider.GetRequiredService<IPushNotificationService>();
var appUserService = scope.ServiceProvider.GetRequiredService<IAppUserService>();
var notificationsToSend = await publicWalkRequestService.GetNotificationsToSendAsync();
if (notificationsToSend != null && notificationsToSend.Any())
{
foreach (var notification in notificationsToSend)
{
var walkers = await appUserService.GetWalkersForNotificationAsync(notification.DogOwnerId, notification.Location);
int sentCount = 0;
if (walkers != null && walkers.Any())
sentCount = walkers.Count;
notification.HasBeenSent = true;
notification.SentCount = sentCount;
notification.SentDate = DateTimeOffset.UtcNow;
await publicWalkRequestService.CommitAsync("System");
//Senden wenn geht
if (walkers != null && walkers.Any())
{
foreach (var walker in walkers)
{
await pushNotificationService.SendPublicWalkRequestAvailableAsync(walker.Id, notification.PublicWalkRequestId);
}
}
}
}
}
#endregion
#region Payout
/// <summary>
/// Task der für alle App-User eine Autoauszahlung durchführt, sofern der Benutzer dies aktiviert hat
/// </summary>
/// <param name="minPayoutAmmount">Mindestbetrag für Auszahlung</param>
/// <param name="resolver">IServiceScopeFactory</param>
/// <returns>Task</returns>
private async Task DoAutoPayoutAsync(long minPayoutAmmount, IServiceScopeFactory resolver)
{
try
{
using var scope = resolver.CreateScope();
var svcProvider = scope.ServiceProvider;
var appUserService = svcProvider.GetRequiredService<IAppUserService>();
var walletService = svcProvider.GetRequiredService<IWalletService>();
var mangoPayService = svcProvider.GetRequiredService<IMangoPayService>();
var payoutService = svcProvider.GetRequiredService<IPayoutService>();
var systemMessageService = svcProvider.GetRequiredService<ISystemMessageService>();
var appHubSender = svcProvider.GetRequiredService<IAppHubSender>();
var pushnotificationService = svcProvider.GetRequiredService<IPushNotificationService>();
if (appUserService != null && walletService != null && mangoPayService != null && payoutService != null && pushnotificationService != null)
{
var appUsers = await appUserService.GetForAutoPayoutAsync();
if (appUsers != null && appUsers.Any())
{
foreach (var appUser in appUsers)
{
if(appUser.Locked)
continue;
try
{
var creditWallet = await walletService.GetAsync(appUser.Id, WalletType.Credits);
if (creditWallet != null)
{
if (creditWallet.Balance >= minPayoutAmmount)
{
var getBankAccountResult = await mangoPayService.GetBankAccountAsync(appUser.Id, appUser.PaymentId, appUser.BankId);
if (getBankAccountResult.Success)
{
var iban = string.Empty;
if (!string.IsNullOrWhiteSpace(getBankAccountResult.Value.Iban))
iban = getBankAccountResult.Value.Iban;
var bic = string.Empty;
if (!string.IsNullOrWhiteSpace(getBankAccountResult.Value.Bic))
bic = getBankAccountResult.Value.Bic;
if (iban.Length >= 4)
{
iban = iban.Substring(iban.Length - 4);
}
if (bic.Length >= 4)
{
bic = bic.Substring(bic.Length - 4);
}
var ammount = creditWallet.Balance;
var payout = payoutService.Create(appUser.Id, appUser.PaymentId, "", creditWallet.Id, creditWallet.WalletId, appUser.BankId, iban, bic, ammount, "EUR");
var payoutResult = await mangoPayService.CreatePayoutAsync(appUser.PaymentId, creditWallet.WalletId, appUser.BankId, ammount, $"Payout_{payout.Id}");
if (payoutResult.Success)
{
payout.MangoPayId = payoutResult.Value.PayoutId;
payout.Status = payoutResult.Value.Status;
payout.ResultCode = payoutResult.Value.ResultCode;
payout.ResultMessage = payoutResult.Value.ResultMessage;
payout.ExecutionDate = payoutResult.Value.ExecutionDate;
payout.UpdatedAt = DateTimeOffset.UtcNow;
payoutService.Add(payout);
await payoutService.CommitAsync("System");
//Wallet aktualisieren
await mangoPayService.GetWalletBalanceAsync(appUser.Id, WalletType.Credits);
//Benachrichtigung
if (systemMessageService != null && appHubSender != null)
{
if (appUser.Type == AppUserType.DogOwner || appUser.Type == AppUserType.Both)
{
systemMessageService.Add(appUser.Id, AppUserType.DogOwner, payout.Id, SystemMessageTables.Payout, SystemMessageType.PayoutUpdate, DateTimeOffset.UtcNow.AddDays(14));
await systemMessageService.CommitAsync("System");
await appHubSender.SystemMessageAddedAsync(appUser.Id);
await pushnotificationService.SendPayoutUpdateAsync(appUser.Id, payout.Id);
}
else if (appUser.Type == AppUserType.DogWalker || appUser.Type == AppUserType.Both)
{
systemMessageService.Add(appUser.Id, AppUserType.DogWalker, payout.Id, SystemMessageTables.Payout, SystemMessageType.PayoutUpdate, DateTimeOffset.UtcNow.AddDays(14));
await systemMessageService.CommitAsync("System");
await appHubSender.SystemMessageAddedAsync(appUser.Id);
await pushnotificationService.SendPayoutUpdateAsync(appUser.Id, payout.Id);
}
}
}
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
#endregion
/// <inheritdoc />
public void Dispose()
{
_timer?.Dispose();
}
}
}