using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Web; using gehGassi.Core.Interfaces; using gehGassi.Core.Services; using gehGassi.Domain.Common; using gehGassi.Domain.Payment; using gehGassi.Domain.Walks; using gehGassi.Dto.Messages; using gehGassi.External.Services; using gehGassi.Persistence.Migrations; using gehGassi.Web.Hubs; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace gehGassi.Web.Controllers { /// /// Controller für die Kommunikation mit MangoPay /// [Authorize] public class MangoPayController : BaseController { private readonly IMangoPayService _mangoPayService; private readonly IPaymentTransactionService _paymentTransactionService; private readonly IWalkService _walkService; private readonly ISystemMessageService _systemMessageService; private readonly IAppHubSender _appHubSender; private readonly IServiceScopeFactory _resolver; private readonly IPushNotificationService _pushNotificationService; private readonly ILogger _logger; /// /// Erstellt eine Instanz /// /// Instanz eines IMangoPayService /// Instanz eines IPaymentTransactionService /// Instanz eines IWalkService /// Instanz eines ISystemMessageService /// Instanz eines IAppHubSender /// Instanz einer IServiceScopeFactory /// Instanz eines ILogger /// Instanz eines IPushNotificationService public MangoPayController(IMangoPayService mangoPayService, IPaymentTransactionService paymentTransactionService, IWalkService walkService, ISystemMessageService systemMessageService, IAppHubSender appHubSender, IServiceScopeFactory resolver, ILogger logger, IPushNotificationService pushNotificationService) { _mangoPayService = mangoPayService; _paymentTransactionService = paymentTransactionService; _walkService = walkService; _systemMessageService = systemMessageService; _appHubSender = appHubSender; _resolver = resolver; _pushNotificationService = pushNotificationService; //_logger = logger; } /// /// Nimmt das Ergebnis einer Einzahlungsatkion bei MangoPay entgegen /// /// TransaktionsId bei Mangopay /// 200 ok [AllowAnonymous] public async Task PayInReturn(string transactionId) { //Zuerst prüfen ob die Tranksation bei MangoPay erfolgreich war... var transactionResponse = await _mangoPayService.GetTransactionAsync(transactionId); //_logger.LogWarning($"PayInReturn: TransactionId {transactionId}"); if (transactionResponse.Success) { var mangoPayTransaction = transactionResponse.Value; if (mangoPayTransaction.Status == PaymentTransactionStatus.SUCCEEDED) { //_logger.LogWarning($"PayInReturn: Transaction SUCCEDED"); //nun die Transaktion lokal holen und sehen ob eine mit dem Status CREATED existiert... var paymentTransaction = await _paymentTransactionService.GetAsync(mangoPayTransaction.TransactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.CREATED); if (paymentTransaction != null) { //_logger.LogWarning($"PayInReturn: PaymentTansaction with status CREATED exists"); var paymentTransactionSuccess = await _paymentTransactionService.GetAsync(mangoPayTransaction.TransactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.SUCCEEDED); if (paymentTransactionSuccess != null) return BadRequest(); //_logger.LogWarning($"PayInReturn: PaymentTansaction with status SUCCEEDED does not exist --> OK"); paymentTransactionSuccess = _paymentTransactionService.Create(mangoPayTransaction.TransactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.SUCCEEDED, paymentTransaction.WalkId, paymentTransaction.TargetAppUserId, paymentTransaction.TargetWalletId, string.Empty, string.Empty, paymentTransaction.Ammount, paymentTransaction.FromCredit, "EUR", paymentTransaction.PayInType); _paymentTransactionService.Add(paymentTransactionSuccess); await _paymentTransactionService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: PaymentTansaction with status SUCCEEDED created"); //Die Zahlung war erfolgreich. Also dies nun beim Walk ablegen und die Benutzer benachrichtigen var walk = await _walkService.GetAsync(paymentTransactionSuccess.WalkId); if (walk != null) { //_logger.LogWarning($"PayInReturn: Walk exists"); //Wenn noch ein Teil vom Guthabenkonto genommen werden muss if (paymentTransactionSuccess.FromCredit > 0) { var tag = $"Walk_Authorize_{walk.Id}"; await _mangoPayService.TransferMoneyFromCreditToFeeAccountAsync(walk.DogOwnerId, paymentTransactionSuccess.FromCredit, tag); //_logger.LogWarning($"PayInReturn: TransferMoneyFromCreditToFeeAccountAsync done"); } walk.PaymentStatus = PaymentStatus.Authorized; walk.UpdatedAt = DateTimeOffset.UtcNow; await _walkService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: Paymentstatus set to Authorized"); //Wallets aktualisieren await _mangoPayService.GetWalletBalanceAsync(walk.DogOwnerId, WalletType.Credits); await _mangoPayService.GetWalletBalanceAsync(walk.DogOwnerId, WalletType.Fees); //_logger.LogWarning($"PayInReturn: Wallets updated"); //Überlappende Walks die im Status "Request" sind, stornieren await _walkService.CancelWalkRequestsAsync(walk.DogWalkerId, walk.Start, walk.End); await _walkService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: CancelWalkRequestsAsync done"); //Walker informieren. TODO: pushnotification? _systemMessageService.Add(walk.DogWalkerId, AppUserType.DogWalker, walk.Id, SystemMessageTables.Walk, SystemMessageType.WalkAdded, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync("System"); await _appHubSender.SystemMessageAddedAsync(walk.DogWalkerId); await _pushNotificationService.SendNewWalkAsync(walk.DogWalkerId, walk.Id); //_logger.LogWarning($"PayInReturn: Systemmessage sent"); var returnUrl = Url.Action("PayInSuccess", "MangoPay", new{walkId = walk.Id}, protocol: HttpContext.Request.Scheme); //_logger.LogWarning($"PayInReturn: redirecting to: {returnUrl}"); #if DEBUG returnUrl = $"http://10.0.0.31:54763/de/mangopay/payinsuccess?walkId={HttpUtility.UrlEncode(walk.Id)}";// Url.Action("PayInReturn", "MangoPay", , protocol: "http"); #endif return Redirect(returnUrl); } else { //_logger.LogWarning($"PayInReturn: Walk does not exist"); } } } else { //Gescheitert. Kann diverse Gründe haben. z.B. nicht genügend Geld auf dem Wallet //nun die Transaktion lokal holen und sehen ob eine mit dem Status CREATED existiert... var paymentTransaction = await _paymentTransactionService.GetAsync(mangoPayTransaction.TransactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.CREATED); if (paymentTransaction != null) { //_logger.LogWarning($"PayInReturn: Transaction FAILED"); var paymentTransactionFailed = _paymentTransactionService.Create(mangoPayTransaction.TransactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.FAILED, paymentTransaction.WalkId, paymentTransaction.TargetAppUserId, paymentTransaction.TargetWalletId, string.Empty, string.Empty, paymentTransaction.Ammount, paymentTransaction.FromCredit, "EUR", transactionResponse.Value.ResultMessage, transactionResponse.Value.ResultCode, new Dictionary(), paymentTransaction.PayInType); _paymentTransactionService.Add(paymentTransactionFailed); await _paymentTransactionService.CommitAsync("System"); var returnUrl = Url.Action("PayInFailed", "MangoPay", new { walkId = paymentTransaction.WalkId }, protocol: HttpContext.Request.Scheme); //_logger.LogWarning($"PayInReturn: redirecting to: {returnUrl}"); #if DEBUG returnUrl = $"http://10.0.0.31:54763/de/mangopay/payinfailed?walkId={HttpUtility.UrlEncode(paymentTransaction.WalkId)}";// Url.Action("PayInReturn", "MangoPay", , protocol: "http"); #endif return Redirect(returnUrl); } } } else { var paymentTransaction = await _paymentTransactionService.GetAsync(transactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.CREATED); if (paymentTransaction != null) { var paymentTransactionFailed = _paymentTransactionService.Create(transactionId, PaymentTransactionType.PayIn, PaymentTransactionStatus.FAILED, paymentTransaction.WalkId, paymentTransaction.TargetAppUserId, paymentTransaction.TargetWalletId, string.Empty, string.Empty, paymentTransaction.Ammount, paymentTransaction.FromCredit, "EUR", transactionResponse.ErrorMessage, transactionResponse.ErrorType, transactionResponse.ErrorMessages, paymentTransaction.PayInType); _paymentTransactionService.Add(paymentTransactionFailed); await _paymentTransactionService.CommitAsync("System"); var returnUrl = Url.Action("PayInFailed", "MangoPay", new { walkId = paymentTransaction.WalkId }, protocol: HttpContext.Request.Scheme); #if DEBUG returnUrl = $"http://10.0.0.31:54763/de/mangopay/payinfailed?walkId={HttpUtility.UrlEncode(paymentTransaction.WalkId)}";// Url.Action("PayInReturn", "MangoPay", , protocol: "http"); #endif return Redirect(returnUrl); } } return BadRequest(); } /// /// Signal, dass eine Zahlung erfolgreich war für einen Walk /// /// ID des Walks /// 200 OK [AllowAnonymous] public async Task PayInSuccess(string walkId) { //_logger.LogWarning($"PayInSuccess: called for walkid {walkId}"); await Task.Delay(1); ViewBag.DarkMode = false; return View(); } /// /// Signal, dass eine Zahlung nicht erfolgreich war für einen Walk /// /// ID des Walks /// 200 OK [AllowAnonymous] public async Task PayInFailed(string walkId) { //_logger.LogWarning($"PayInFailed: called for walkid {walkId}"); await Task.Delay(1); ViewBag.DarkMode = false; return View(); } /// /// Webhook für MangoPay /// /// Event-Typ /// Id der Ressource /// 200 OK [AllowAnonymous] public async Task WebHook(string eventType, string ressourceId) { if (!string.IsNullOrWhiteSpace(eventType) && !string.IsNullOrWhiteSpace(ressourceId)) { var serviceProvider = HttpContext.RequestServices; if (eventType == "KYC_SUCCEEDED") { var documentId = ressourceId; _ = Task.Run(() => HandleKycSucceded(documentId, _resolver)); } else if (eventType == "KYC_FAILED") { var documentId = ressourceId; _ = Task.Run(() => HandleKycFailed(documentId, _resolver)); } else if (eventType == "KYC_OUTDATED") { var documentId = ressourceId; _ = Task.Run(() => HandleKycOutdated(documentId, _resolver)); } else if (eventType == "PAYOUT_NORMAL_SUCCEEDED") { var payoutId = ressourceId; _ = Task.Run(() => HandlePayOutSucceeded(payoutId, _resolver)); } else if (eventType == "PAYOUT_NORMAL_FAILED") { var payoutId = ressourceId; _ = Task.Run(() => HandlePayOutFailed(payoutId, _resolver)); } else if (eventType == "PAYOUT_REFUND_SUCCEEDED") { var payoutId = ressourceId; _ = Task.Run(() => HandlePayOutRefunded(payoutId, _resolver)); } else if (eventType == "PAYIN_NORMAL_SUCCEEDED") { var payinId = ressourceId; _ = Task.Run(() => HandlePayInSucceeded(payinId, _resolver)); } else if (eventType == "PAYIN_NORMAL_FAILED") { var payinId = ressourceId; _ = Task.Run(() => HandlePayInFailed(payinId, _resolver)); } } return Ok(); } #region Private /// /// Eine KYC-Überprüfung war erfolgreich /// /// Id des Kyc-Dokumentes bei MangoPay /// IServiceScopeFactory /// Task private async Task HandleKycSucceded(string documentId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var identityDocumentService = (IIdentityDocumentService)svcProvider.GetService(typeof(IIdentityDocumentService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (identityDocumentService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var identityDocument = await identityDocumentService.GetByMangoPayIdAsync(documentId); if (identityDocument != null) { var documentResult = await _mangoPayService.GetKycDocumentAsync(documentId); if (documentResult != null && documentResult.Success) { identityDocument.Status = documentResult.Value.Status; identityDocument.Processed = documentResult.Value.ProcessedDate; identityDocument.UpdatedAt = DateTimeOffset.UtcNow; await identityDocumentService.CommitAsync("System"); var appUser = await appUserService.GetAsync(identityDocument.AppUserId); if (appUser != null) { appUser.KycPassed = true; appUser.KycPassedDate = DateTimeOffset.UtcNow; appUser.UpdatedAt = DateTimeOffset.UtcNow; if (!appUser.Verified) { appUser.Verified = true; appUser.VerifiedDate = DateTimeOffset.UtcNow; } await appUserService.CommitAsync("System"); } //Benachrichtigung if (appUser != null) { if (appUser.Type == AppUserType.DogOwner || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogOwner, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } else if (appUser.Type == AppUserType.DogWalker || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogWalker, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine KYC-Überprüfung ist gescheitert /// /// Id des Kyc-Dokumentes bei MangoPay /// IServiceScopeFactory /// Task private async Task HandleKycFailed(string documentId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var identityDocumentService = (IIdentityDocumentService)svcProvider.GetService(typeof(IIdentityDocumentService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (identityDocumentService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var identityDocument = await identityDocumentService.GetByMangoPayIdAsync(documentId); if (identityDocument != null) { var documentResult = await _mangoPayService.GetKycDocumentAsync(documentId); if (documentResult != null && documentResult.Success) { identityDocument.Status = documentResult.Value.Status; identityDocument.Processed = documentResult.Value.ProcessedDate; identityDocument.RefusedReasonType = documentResult.Value.RefusedReasonType; identityDocument.RefusedReasonMessage = documentResult.Value.RefusedReasonMessage; if (documentResult.Value.Flags != null && documentResult.Value.Flags.Any()) identityDocument.FlagsValue = string.Join(";", documentResult.Value.Flags); else identityDocument.FlagsValue = string.Empty; identityDocument.UpdatedAt = DateTimeOffset.UtcNow; await identityDocumentService.CommitAsync("System"); var appUser = await appUserService.GetAsync(identityDocument.AppUserId); if (appUser != null) { appUser.KycPassed = false; appUser.KycPassedDate = null; appUser.UpdatedAt = DateTimeOffset.UtcNow; await appUserService.CommitAsync("System"); } //Benachrichtigung if (appUser != null) { if (appUser.Type == AppUserType.DogOwner || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogOwner, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } else if (appUser.Type == AppUserType.DogWalker || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogWalker, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine KYC-Überprüfung ist gescheitert /// /// Id des Kyc-Dokumentes bei MangoPay /// IServiceScopeFactory /// Task private async Task HandleKycOutdated(string documentId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var identityDocumentService = (IIdentityDocumentService)svcProvider.GetService(typeof(IIdentityDocumentService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (identityDocumentService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var identityDocument = await identityDocumentService.GetByMangoPayIdAsync(documentId); if (identityDocument != null) { var documentResult = await _mangoPayService.GetKycDocumentAsync(documentId); if (documentResult != null && documentResult.Success) { identityDocument.Status = documentResult.Value.Status; identityDocument.Processed = documentResult.Value.ProcessedDate; identityDocument.RefusedReasonType = documentResult.Value.RefusedReasonType; identityDocument.RefusedReasonMessage = documentResult.Value.RefusedReasonMessage; if (documentResult.Value.Flags != null && documentResult.Value.Flags.Any()) identityDocument.FlagsValue = string.Join(";", documentResult.Value.Flags); else identityDocument.FlagsValue = string.Empty; identityDocument.UpdatedAt = DateTimeOffset.UtcNow; await identityDocumentService.CommitAsync("System"); var appUser = await appUserService.GetAsync(identityDocument.AppUserId); var latestIdentityDocument = await identityDocumentService.GetLatestAsync(identityDocument.AppUserId); if (latestIdentityDocument != null && latestIdentityDocument.Id == identityDocument.Id) { //Wenn das das aktuell gültige KYC-Dokument ist, dann KYC vom App-User wieder entfernen if (appUser != null) { appUser.KycPassed = false; appUser.KycPassedDate = null; appUser.UpdatedAt = DateTimeOffset.UtcNow; await appUserService.CommitAsync("System"); } } //Benachrichtigung if (appUser != null) { if (appUser.Type == AppUserType.DogOwner || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogOwner, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } else if (appUser.Type == AppUserType.DogWalker || appUser.Type == AppUserType.Both) { systemMessageService.Add(appUser.Id, AppUserType.DogWalker, identityDocument.Id, SystemMessageTables.IdentityDocument, SystemMessageType.IdentityDocumentUpdate, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendIdentityDocumentUpdateAsync(appUser.Id, identityDocument.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine Auszahlung war erfolgreich /// /// Id der Auszahlung /// IServiceScopeFactory /// Task private async Task HandlePayOutSucceeded(string payoutId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var payoutService = (IPayoutService)svcProvider.GetService(typeof(IPayoutService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (payoutService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var payout = await payoutService.GetByMangoPayIdAsync(payoutId); if (payout != null) { var payoutResult = await _mangoPayService.GetPayoutAsync(payoutId); if (payoutResult != null && payoutResult.Success) { payout.Status = payoutResult.Value.Status; payout.ExecutionDate = payoutResult.Value.ExecutionDate; payout.ResultCode = payoutResult.Value.ResultCode; payout.ResultMessage = payoutResult.Value.ResultMessage; payout.UpdatedAt = DateTimeOffset.UtcNow; await payoutService.CommitAsync("System"); var appUser = await appUserService.GetAsync(payout.AppUserId); //Benachrichtigung if (appUser != 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(User.Identity.Name); 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(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendPayoutUpdateAsync(appUser.Id, payout.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine Auszahlung ist gescheitert /// /// Id der Auszahlung /// IServiceScopeFactory /// Task private async Task HandlePayOutFailed(string payoutId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var payoutService = (IPayoutService)svcProvider.GetService(typeof(IPayoutService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (payoutService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var payout = await payoutService.GetByMangoPayIdAsync(payoutId); if (payout != null) { var payoutResult = await _mangoPayService.GetPayoutAsync(payoutId); if (payoutResult != null && payoutResult.Success) { payout.Status = payoutResult.Value.Status; payout.ExecutionDate = payoutResult.Value.ExecutionDate; payout.ResultCode = payoutResult.Value.ResultCode; payout.ResultMessage = payoutResult.Value.ResultMessage; payout.UpdatedAt = DateTimeOffset.UtcNow; await payoutService.CommitAsync("System"); var appUser = await appUserService.GetAsync(payout.AppUserId); //Benachrichtigung if (appUser != 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(User.Identity.Name); 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(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendPayoutUpdateAsync(appUser.Id, payout.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine Auszahlung ist gescheitert und wurde zurücküberwiesen /// /// Id der Rückzahlung /// IServiceScopeFactory /// Task private async Task HandlePayOutRefunded(string refundId, IServiceScopeFactory resolver) { try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var payoutService = (IPayoutService)svcProvider.GetService(typeof(IPayoutService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (payoutService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var refundResult = await _mangoPayService.GetRefundAsync(refundId); if (refundResult.Success && refundResult.Value.Status == PaymentTransactionStatus.SUCCEEDED) { var payout = await payoutService.GetByMangoPayIdAsync(refundResult.Value.OriginalTransactionId); if (payout != null) { payout.Status = PaymentTransactionStatus.FAILED; payout.Refunded = true; payout.RefundReasonType = refundResult.Value.RefundReasonType; payout.RefundReasonMessage = refundResult.Value.RefundReasonMessage; payout.UpdatedAt = DateTimeOffset.UtcNow; await payoutService.CommitAsync("System"); var appUser = await appUserService.GetAsync(payout.AppUserId); //Benachrichtigung if (appUser != 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(User.Identity.Name); 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(User.Identity.Name); await _appHubSender.SystemMessageAddedAsync(appUser.Id); await _pushNotificationService.SendPayoutUpdateAsync(appUser.Id, payout.Id); } } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine Einzahlung war erfolgreich /// /// Id der Einzahlung /// IServiceScopeFactory /// Task private async Task HandlePayInSucceeded(string payinId, IServiceScopeFactory resolver) { //30 Sekunden warten, falls der Event schneller kommen sollte als in der App await Task.Delay(30000); try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var paymentTransactionService = (IPaymentTransactionService)svcProvider.GetService(typeof(IPaymentTransactionService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (paymentTransactionService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var paymentTransaction = await paymentTransactionService.GetAsync(payinId, PaymentTransactionType.PayIn); if (paymentTransaction != null) { //Es muss zumindest eine Transaktion geben die den Status CREATED hat if (paymentTransaction.Status == PaymentTransactionStatus.CREATED) { var paymentTransactionSuccess = _paymentTransactionService.Create(payinId, PaymentTransactionType.PayIn, PaymentTransactionStatus.SUCCEEDED, paymentTransaction.WalkId, paymentTransaction.TargetAppUserId, paymentTransaction.TargetWalletId, string.Empty, string.Empty, paymentTransaction.Ammount, paymentTransaction.FromCredit, "EUR", paymentTransaction.PayInType); _paymentTransactionService.Add(paymentTransactionSuccess); await _paymentTransactionService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: PaymentTansaction with status SUCCEEDED created"); //Die Zahlung war erfolgreich. Also dies nun beim Walk ablegen und die Benutzer benachrichtigen var walk = await _walkService.GetAsync(paymentTransactionSuccess.WalkId); if (walk != null) { //_logger.LogWarning($"PayInReturn: Walk exists"); //Wenn noch ein Teil vom Guthabenkonto genommen werden muss if (paymentTransactionSuccess.FromCredit > 0) { var tag = $"Walk_Authorize_{walk.Id}"; await _mangoPayService.TransferMoneyFromCreditToFeeAccountAsync(walk.DogOwnerId, paymentTransactionSuccess.FromCredit, tag); //_logger.LogWarning($"PayInReturn: TransferMoneyFromCreditToFeeAccountAsync done"); } walk.PaymentStatus = PaymentStatus.Authorized; walk.UpdatedAt = DateTimeOffset.UtcNow; await _walkService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: Paymentstatus set to Authorized"); //Wallets aktualisieren await _mangoPayService.GetWalletBalanceAsync(walk.DogOwnerId, WalletType.Credits); await _mangoPayService.GetWalletBalanceAsync(walk.DogOwnerId, WalletType.Fees); //_logger.LogWarning($"PayInReturn: Wallets updated"); //Überlappende Walks die im Status "Request" sind, stornieren await _walkService.CancelWalkRequestsAsync(walk.DogWalkerId, walk.Start, walk.End); await _walkService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: CancelWalkRequestsAsync done"); //Walker informieren. TODO: pushnotification? _systemMessageService.Add(walk.DogWalkerId, AppUserType.DogWalker, walk.Id, SystemMessageTables.Walk, SystemMessageType.WalkAdded, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync("System"); await _appHubSender.SystemMessageAddedAsync(walk.DogWalkerId); await _pushNotificationService.SendNewWalkAsync(walk.DogWalkerId, walk.Id); } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } /// /// Eine Einzahlung war nicht erfolgreich /// /// Id der Einzahlung /// IServiceScopeFactory /// Task private async Task HandlePayInFailed(string payinId, IServiceScopeFactory resolver) { //30 Sekunden warten, falls der Event schneller kommen sollte als in der App await Task.Delay(30000); try { using var scope = resolver.CreateScope(); var svcProvider = scope.ServiceProvider; var paymentTransactionService = (IPaymentTransactionService)svcProvider.GetService(typeof(IPaymentTransactionService)); var appUserService = (IAppUserService)svcProvider.GetService(typeof(IAppUserService)); var systemMessageService = (ISystemMessageService)svcProvider.GetService(typeof(ISystemMessageService)); var appHubSender = (IAppHubSender)svcProvider.GetService(typeof(IAppHubSender)); if (paymentTransactionService != null && appUserService != null && systemMessageService != null && appHubSender != null) { var paymentTransaction = await paymentTransactionService.GetAsync(payinId, PaymentTransactionType.PayIn); if (paymentTransaction != null) { //Es muss zumindest eine Transaktion geben die den Status CREATED hat if (paymentTransaction.Status == PaymentTransactionStatus.CREATED) { var paymentTransactionFailed = _paymentTransactionService.Create(payinId, PaymentTransactionType.PayIn, PaymentTransactionStatus.FAILED, paymentTransaction.WalkId, paymentTransaction.TargetAppUserId, paymentTransaction.TargetWalletId, string.Empty, string.Empty, paymentTransaction.Ammount, paymentTransaction.FromCredit, "EUR", paymentTransaction.PayInType); _paymentTransactionService.Add(paymentTransactionFailed); await _paymentTransactionService.CommitAsync("System"); //_logger.LogWarning($"PayInReturn: PaymentTansaction with status SUCCEEDED created"); //Die Zahlung war erfolgreich. Also dies nun beim Walk ablegen und die Benutzer benachrichtigen var walk = await _walkService.GetAsync(paymentTransactionFailed.WalkId); if (walk != null) { walk.PaymentStatus = PaymentStatus.Pending; walk.UpdatedAt = DateTimeOffset.UtcNow; await _walkService.CommitAsync("System"); //Owner informieren. _systemMessageService.Add(walk.DogOwnerId, AppUserType.DogOwner, walk.Id, SystemMessageTables.Walk, SystemMessageType.WalkChanged, DateTimeOffset.UtcNow.AddDays(14)); await _systemMessageService.CommitAsync("System"); await _appHubSender.SystemMessageAddedAsync(walk.DogOwnerId); await _pushNotificationService.SendWalkPaymentFailedAsync(walk.DogOwnerId, walk.Id); } } } } await Task.Delay(1); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); } } #endregion } }