using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using gehGassi.Core.Interfaces;
using gehGassi.Core.Services;
using gehGassi.Domain.Common;
using gehGassi.Dto.Walks;
using gehGassi.Dto;
using gehGassi.Dto.Common;
using gehGassi.Dto.Payment;
using gehGassi.Web.Helper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using gehGassi.Dto.Dogs;
using gehGassi.Domain.Payment;
using gehGassi.Dto.Messages;
using gehGassi.Web.Hubs;
using Microsoft.AspNetCore.Http;
using Asp.Versioning;
namespace gehGassi.Web.Controllers.Api
{
///
/// Controller für die Verwaltung von Zahlungen und Wallets
///
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[ApiVersion(1)]
[Route("api/payments")]
[Route("api/v{v:apiVersion}/payments")]
public class ApiPaymentController : ApiBaseController
{
private readonly IWalletService _walletService;
private readonly IMangoPayService _mangoPayService;
private readonly ITransactionFeeService _transactionFeeService;
private readonly IUserService _userService;
private readonly IWalkService _walkService;
private readonly ISystemMessageService _systemMessageService;
private readonly IAppHubSender _appHubSender;
private readonly IIdentityDocumentService _identityDocumentService;
private readonly IPayoutService _payoutService;
private readonly IPushNotificationService _pushNotificationService;
private readonly IVoucherCampaignService _voucherCampaignService;
///
/// Erstellt eine Instanz
///
/// Instanz eines IMapper
/// Instanz eines ILogger
/// Instanz von LocalizationOptions
/// Instanz eines IAppUserService
/// Instanz eines IWalletService
/// Instanz eines IMangoPayService
/// Instanz eines ITransactionFeeService
/// Instanz eines IUserService
/// Instanz eines IWalkService
/// Instanz eines ISystemMessageService
/// Instanz eines IAppHubSender
/// Instanz eines IIdentityDocumentService
/// Instanz eines IPayoutService
/// Instanz eines IPushNotificationService
/// Isntanz eines IVoucherCampaignService
public ApiPaymentController(IMapper mapper, ILogger logger, IOptions localizationOptions, IAppUserService appUserService,
IWalletService walletService, IMangoPayService mangoPayService, ITransactionFeeService transactionFeeService, IUserService userService, IWalkService walkService,
ISystemMessageService systemMessageService, IAppHubSender appHubSender, IIdentityDocumentService identityDocumentService, IPayoutService payoutService,
IPushNotificationService pushNotificationService, IVoucherCampaignService voucherCampaignService) : base(mapper, localizationOptions, appUserService)
{
_walletService = walletService;
_mangoPayService = mangoPayService;
_transactionFeeService = transactionFeeService;
_userService = userService;
_walkService = walkService;
_systemMessageService = systemMessageService;
_appHubSender = appHubSender;
_identityDocumentService = identityDocumentService;
_payoutService = payoutService;
_pushNotificationService = pushNotificationService;
_voucherCampaignService = voucherCampaignService;
}
#region Wallets
///
/// Liefert alle Wallets eines App-Users
///
/// Id des App-Users
/// Liste der Wallets
[HttpGet]
[Route("GetWallets")]
public async Task GetWallets(string appUserId)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var wallets = await _walletService.GetAllAsync(appUserId);
//Wenn Walltes vorhanden sind, dann den aktuellen Kontostand abfragen
if (wallets.Any())
{
var hasChanges = false;
foreach (var wallet in wallets)
{
var balanceResponse = await _mangoPayService.GetWalletBalanceAsync(wallet.WalletId);
if (balanceResponse.Success)
{
wallet.Balance = balanceResponse.Value;
hasChanges = true;
}
}
if (hasChanges)
await _walletService.CommitAsync("System", true);
}
var dtoList = Mapper.Map>(wallets);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Liefert den aktuellen Kontostand eines Wallets
///
/// Id des App-Users
/// Typ des Wallets
/// Aktueller Kontostand
[HttpGet]
[Route("GetWalletBalance")]
public async Task GetWalletBalance(string appUserId, WalletTypeDto walletType)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var wallet = await _walletService.GetAsync(appUserId, (WalletType)walletType);
if (wallet != null)
{
var balanceResponse = await _mangoPayService.GetWalletBalanceAsync(wallet.WalletId);
if (balanceResponse.Success)
{
wallet.Balance = balanceResponse.Value;
wallet.UpdatedAt = DateTimeOffset.UtcNow;
await _walletService.CommitAsync("System", true);
return Ok(wallet.Balance);
}
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region Bank-Verbindungen
///
/// Anlegen oder Aktualisieren einer Bankverbindung eines AppUsers
///
/// Model
/// 200 OK
[HttpPost]
[Route("CreateOrUpdateBankAccount")]
public async Task CreateOrUpdateBankAccount(BankAccountDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
if (user != null)
{
if (ModelState.IsValid)
{
var bankAccount = Mapper.Map(model);
if (bankAccount.IsBicValid())
{
if (bankAccount.IsIbanValid())
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
bool success = false;
//Wenn es noch kein Bankkonto gibt, dann anlegen
if (string.IsNullOrWhiteSpace(appUser.BankId))
{
var createBankAccountResult = await _mangoPayService.CreateBankAccountAsync(appUser.PaymentId, bankAccount.OwnerName, bankAccount.Address, bankAccount.Iban, bankAccount.Bic);
if (createBankAccountResult != null && createBankAccountResult.Success && !string.IsNullOrWhiteSpace(createBankAccountResult.Value))
{
appUser.BankId = createBankAccountResult.Value;
appUser.UpdatedAt = DateTimeOffset.UtcNow;
await AppUserService.CommitAsync(User.Identity.Name);
success = true;
}
if (createBankAccountResult != null && createBankAccountResult.Success == false)
{
success = false;
if (createBankAccountResult.ErrorMessages.ContainsKey("IBAN"))
return BadRequest(CommunicationErrors.BankAccount_Iban_Invalid);
if (createBankAccountResult.ErrorMessages.ContainsKey("BIC"))
return BadRequest(CommunicationErrors.BankAccount_Bic_Invalid);
}
}
else
{
//Die aktuelle Bankverbindung holen und mit den neuen Daten vergleichen
//Wenn sich diese geändert haben, ein neues Bankkonto anlegen und dem Benutzer zuweisen, das alte dann deaktivieren
var getBankAccountResult = await _mangoPayService.GetBankAccountAsync(appUser.Id, appUser.PaymentId, appUser.BankId);
if (getBankAccountResult.Success)
{
var createNewBankAccount = false;
var existingBankAccount = getBankAccountResult.Value;
if (existingBankAccount != null)
{
if (existingBankAccount.HasChanged(bankAccount))
{
createNewBankAccount = true;
//Das alte Bankkonto deaktivieren
await _mangoPayService.DeactivateBankAccountAsync(appUser.PaymentId, appUser.BankId);
}
else
{
return BadRequest(CommunicationErrors.BankAccount_CreateOrUpdate_Unchanged);
}
}
else
{
//Es gibt kein Bankkonto mehr, also neu anlegen
createNewBankAccount = true;
}
if (createNewBankAccount)
{
var createBankAccountResult = await _mangoPayService.CreateBankAccountAsync(appUser.PaymentId, bankAccount.OwnerName, bankAccount.Address, bankAccount.Iban, bankAccount.Bic);
if (createBankAccountResult != null && createBankAccountResult.Success && !string.IsNullOrWhiteSpace(createBankAccountResult.Value))
{
appUser.BankId = createBankAccountResult.Value;
appUser.UpdatedAt = DateTimeOffset.UtcNow;
await AppUserService.CommitAsync(User.Identity.Name);
success = true;
}
if (createBankAccountResult != null && createBankAccountResult.Success == false)
{
success = false;
if (createBankAccountResult.ErrorMessages.ContainsKey("IBAN"))
return BadRequest(CommunicationErrors.BankAccount_Iban_Invalid);
if (createBankAccountResult.ErrorMessages.ContainsKey("BIC"))
return BadRequest(CommunicationErrors.BankAccount_Bic_Invalid);
}
}
}
}
if (success)
{
var appUserDto = Mapper.Map(appUser);
var baseAddress = GetBaseAddress();
if (!string.IsNullOrWhiteSpace(appUserDto.Photo))
{
appUserDto.Photo = $"{baseAddress}/file/documents/thumbnails/{200}/{appUserDto.Photo}";
}
return Ok(appUserDto);
}
return BadRequest(CommunicationErrors.BankAccount_CreateOrUpdate_Failed);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.BankAccount_Iban_Invalid);
}
return BadRequest(CommunicationErrors.BankAccount_Bic_Invalid);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Gibt die Bankverbindung eines AppUsers zurück
///
/// Id des App-Users
/// 200 OK
[HttpGet]
[Route("GetBankAccount")]
public async Task GetBankAccount(string appUserId)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var appUser = await AppUserService.GetAsync(appUserId);
if (appUser != null)
{
if (!string.IsNullOrWhiteSpace(appUser.BankId))
{
var getBankAccountResult = await _mangoPayService.GetBankAccountAsync(appUser.Id, appUser.PaymentId, appUser.BankId);
if (getBankAccountResult.Success)
{
var bankAccount = getBankAccountResult.Value;
if (bankAccount != null)
{
var bankAccountDto = Mapper.Map(bankAccount);
return Ok(bankAccountDto);
}
}
}
return NotFound(CommunicationErrors.BankAccount_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region KYC
///
/// Gibt das aktuelle KYC-Dokument eines App-Users zurück
///
/// Id des App-Users
/// 200 OK
[HttpGet]
[Route("GetKycDocumentLatest")]
public async Task GetKycDocumentLatest(string appUserId)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
if (user != null)
{
var appUser = await AppUserService.GetAsync(appUserId);
if (appUser != null)
{
var identityDocument = await _identityDocumentService.GetLatestAsync(appUser.Id);
if (identityDocument != null)
{
//abgleich mit Mangopay-Dokument?
var kycDocumentResult = await _mangoPayService.GetKycDocumentAsync(identityDocument.MangoPayId);
if (kycDocumentResult != null && kycDocumentResult.Success)
{
if (kycDocumentResult.Value.Status != identityDocument.Status)
{
//Aktualisieren...
identityDocument.Status = kycDocumentResult.Value.Status;
identityDocument.Processed = kycDocumentResult.Value.ProcessedDate;
identityDocument.RefusedReasonType = kycDocumentResult.Value.RefusedReasonType;
identityDocument.RefusedReasonMessage = kycDocumentResult.Value.RefusedReasonMessage;
if (kycDocumentResult.Value.Flags != null && kycDocumentResult.Value.Flags.Any())
identityDocument.FlagsValue = string.Join(";", kycDocumentResult.Value.Flags);
else
identityDocument.FlagsValue = string.Empty;
identityDocument.UpdatedAt = DateTimeOffset.UtcNow;
await _identityDocumentService.CommitAsync(User.Identity.Name);
if (identityDocument.Status == IdentityDocumentStatus.VALIDATED && appUser.KycPassed == false)
{
appUser.KycPassed = true;
appUser.KycPassedDate = identityDocument.Processed ?? DateTimeOffset.UtcNow;
appUser.UpdatedAt = DateTimeOffset.UtcNow;
await AppUserService.CommitAsync(User.Identity.Name);
}
else if ((identityDocument.Status == IdentityDocumentStatus.REFUSED || identityDocument.Status == IdentityDocumentStatus.OUT_OF_DATE) && appUser.KycPassed)
{
appUser.KycPassed = false;
appUser.KycPassedDate = null;
appUser.UpdatedAt = DateTimeOffset.UtcNow;
await AppUserService.CommitAsync(User.Identity.Name);
}
}
}
var dto = Mapper.Map(identityDocument);
return Ok(dto);
}
return BadRequest(CommunicationErrors.Kyc_NoDocument);
}
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Erstellen eines KYC-Dokumentes für die Identitätsprüfung
///
/// Model mit Basis-Daten
/// Dateien die eingereicht werden sollen
/// 200 OK
[HttpPost]
[Route("CreatKycDocument")]
public async Task CreatKycDocument([ModelBinder(BinderType = typeof(JsonModelBinder))] IdentityDocumentCreateDto model, List files)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var user = await _userService.GetByUsernameAsync(User.Identity.Name);
if (user != null)
{
if (ModelState.IsValid)
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
if (files.Count > 0)
{
var fileList = new List();
foreach (var file in files)
{
using var ms = new MemoryStream();
await file.CopyToAsync(ms);
fileList.Add(ms.ToArray());
}
var createKycDocumentResult = await _mangoPayService.CreateKycDocumentAsync(appUser.PaymentId, IdentityDocumentType.IDENTITY_PROOF, fileList);
if (createKycDocumentResult.Success)
{
var documentId = createKycDocumentResult.Value;
var identityDocument = _identityDocumentService.Create(appUser.Id, documentId, appUser.PaymentId, IdentityDocumentType.IDENTITY_PROOF, (IdentityDocumentSource)model.Source, IdentityDocumentStatus.VALIDATION_ASKED, fileList.Count);
_identityDocumentService.Add(identityDocument);
await _identityDocumentService.CommitAsync(User.Identity.Name);
var dto = Mapper.Map(identityDocument);
return Ok(dto);
}
else
{
return BadRequest(CommunicationErrors.Kyc_CreationFailed);
}
}
return BadRequest(CommunicationErrors.Kyc_NoFiles);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region Payment
///
/// Authorisierung der Zahlung eines Walks mit einem vorhandenen Guthaben.
/// Das Geld wird auf das Transaktions-Konto überwiesen
///
/// Model
/// 200 OK
[HttpPost]
[Route("AuthorizeWithCredit")]
public async Task AuthorizeWithCredit(PayWalkWithCreditDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
var walk = await _walkService.GetAsync(model.WalkId);
if (walk != null && !walk.Deleted)
{
if (walk.Status != WalkStatus.Cancelled)
{
if (walk.PaymentStatus == PaymentStatus.Pending)
{
var ammount = (long)(model.Ammount * 100);
var tag = $"Walk_Authorize_{walk.Id}";
var transferMoneyResult = await _mangoPayService.TransferMoneyFromCreditToFeeAccountAsync(model.AppUserId, ammount, tag);
if (transferMoneyResult.Success)
{
walk.PaymentStatus = PaymentStatus.Authorized;
walk.UpdatedAt = DateTimeOffset.UtcNow;
await _walkService.CommitAsync(User.Identity.Name);
//Wallets aktualisieren
await _mangoPayService.GetWalletBalanceAsync(model.AppUserId, WalletType.Credits);
await _mangoPayService.GetWalletBalanceAsync(model.AppUserId, WalletType.Fees);
//Überlappende Walks die im Status "Request" sind, stornieren
await _walkService.CancelWalkRequestsAsync(walk.DogWalkerId, walk.Start, walk.End);
await _walkService.CommitAsync(User.Identity.Name);
//Walker informieren. TODO: pushnotification?
_systemMessageService.Add(walk.DogWalkerId, AppUserType.DogWalker, walk.Id, SystemMessageTables.Walk, SystemMessageType.WalkAdded, DateTimeOffset.UtcNow.AddDays(14));
await _systemMessageService.CommitAsync(User.Identity.Name);
await _appHubSender.SystemMessageAddedAsync(walk.DogWalkerId);
await _pushNotificationService.SendNewWalkAsync(walk.DogWalkerId, walk.Id);
var walkDto = Mapper.Map(walk);
return Ok(walkDto);
}
}
return BadRequest(CommunicationErrors.Walk_PaymentStatus_Invalid);
}
return BadRequest(CommunicationErrors.Walk_Cancelled);
}
return NotFound(CommunicationErrors.Walk_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Authorisierung der Zahlung eines komplett Walks mit einem Gutschein
///
/// Model
/// 200 OK
[HttpPost]
[Route("AuthorizeWithVoucher")]
public async Task AuthorizeWithVoucher(PayWalkWithVoucherDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
var walk = await _walkService.GetAsync(model.WalkId);
if (walk != null && !walk.Deleted)
{
if (walk.Status != WalkStatus.Cancelled)
{
if (walk.PaymentStatus == PaymentStatus.Pending)
{
var voucherUsed = await _voucherCampaignService.GetUsageAsync(model.VoucherId, model.AppUserId, model.WalkId);
if (voucherUsed != null && voucherUsed.UsageStatus == VoucherUsageStatus.Reserved && voucherUsed.VoucherAmmountUsed >= model.Ammount)
{
walk.PaymentStatus = PaymentStatus.Authorized;
walk.UpdatedAt = DateTimeOffset.UtcNow;
await _walkService.CommitAsync(User.Identity.Name);
//Überlappende Walks die im Status "Request" sind, stornieren
await _walkService.CancelWalkRequestsAsync(walk.DogWalkerId, walk.Start, walk.End);
await _walkService.CommitAsync(User.Identity.Name);
//Walker informieren. TODO: pushnotification?
_systemMessageService.Add(walk.DogWalkerId, AppUserType.DogWalker, walk.Id, SystemMessageTables.Walk, SystemMessageType.WalkAdded, DateTimeOffset.UtcNow.AddDays(14));
await _systemMessageService.CommitAsync(User.Identity.Name);
await _appHubSender.SystemMessageAddedAsync(walk.DogWalkerId);
await _pushNotificationService.SendNewWalkAsync(walk.DogWalkerId, walk.Id);
var walkDto = Mapper.Map(walk);
return Ok(walkDto);
}
return BadRequest(CommunicationErrors.Walk_VoucherInvalid);
}
return BadRequest(CommunicationErrors.Walk_PaymentStatus_Invalid);
}
return BadRequest(CommunicationErrors.Walk_Cancelled);
}
return NotFound(CommunicationErrors.Walk_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Startet das Einzahlen eines AppUsers
///
/// Einzahlungs-einstellungen
/// 200 OK
[HttpPost]
[Route("PayIn")]
public async Task PayIn(PayInDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
var walk = await _walkService.GetAsync(model.WalkId);
if (walk != null && !walk.Deleted)
{
if (walk.Status != WalkStatus.Cancelled)
{
if (walk.PaymentStatus == PaymentStatus.Pending)
{
var ammount = (long)(model.Ammount * 100);
var fees = (long)(model.Fees * 100);
var fromCredit = (long)(model.FromCredit * 100);
var returnUrl = Url.Action("PayInReturn", "MangoPay", null, protocol: HttpContext.Request.Scheme);
#if DEBUG
returnUrl = "http://10.0.0.31:54763/de/mangopay/payinreturn";// Url.Action("PayInReturn", "MangoPay", , protocol: "http");
#endif
if (model.PayInType == PayInTypeDto.CB_VISA_MASTERCARD)
{
var payInResult = await _mangoPayService.CreatePayInCardAsync(appUser.Id, walk.Id, ammount, fees, fromCredit, $"Walk_PayIn_{walk.Id}", returnUrl);
if (payInResult.Success)
{
var paymentResultDto = new PayInResponseDto
{
Url = payInResult.Value,
Success = true
};
return Ok(paymentResultDto);
}
return BadRequest(CommunicationErrors.PayIn_Failed);
}
if (model.PayInType == PayInTypeDto.MAESTRO)
{
var payInResult = await _mangoPayService.CreatePayInMaestroAsync(appUser.Id, walk.Id, ammount, fees, fromCredit, $"Walk_PayIn_{walk.Id}", returnUrl);
if (payInResult.Success)
{
var paymentResultDto = new PayInResponseDto
{
Url = payInResult.Value,
Success = true
};
return Ok(paymentResultDto);
}
return BadRequest(CommunicationErrors.PayIn_Failed);
}
if (model.PayInType == PayInTypeDto.KLARNA)
{
var payInResult = await _mangoPayService.CreatePayInKlarnaAsync(appUser.Id, walk.Id, ammount, fees, fromCredit, $"Walk_PayIn_{walk.Id}", returnUrl);
if (payInResult.Success)
{
var paymentResultDto = new PayInResponseDto
{
Url = payInResult.Value,
Success = true
};
return Ok(paymentResultDto);
}
return BadRequest(CommunicationErrors.PayIn_Failed);
}
if (model.PayInType == PayInTypeDto.PAYPAL)
{
var payInResult = await _mangoPayService.CreatePayInPayPalAsync(appUser.Id, walk.Id, ammount, fees, fromCredit, $"Walk_PayIn_{walk.Id}", returnUrl);
if (payInResult.Success)
{
var paymentResultDto = new PayInResponseDto
{
Url = payInResult.Value,
Success = true
};
return Ok(paymentResultDto);
}
return BadRequest(CommunicationErrors.PayIn_Failed);
}
}
return BadRequest(CommunicationErrors.Walk_PaymentStatus_Invalid);
}
return BadRequest(CommunicationErrors.Walk_Cancelled);
}
return NotFound(CommunicationErrors.Walk_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region Transaktionsgebühren
///
/// Gibt eine Liste von Transaktionsgebühren für die Synchronisierung mit der App zurück
///
/// Letztes Update oder null, wenn noch keines
/// HTTP 200 wenn erfolgreich
[Route("GetTransactionFees")]
[HttpGet]
public async Task GetTransactionFees(DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var transactionFees = await _transactionFeeService.GetForSyncAsync(lastUpdate);
var transactionFeesDto = Mapper.Map>(transactionFees);
return Ok(transactionFeesDto);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region Payouts / Auszahlungen
///
/// Abfrage der Auszahlungen eines AppUsers
///
/// Id des AppUsers
/// Letztes Update oder null, wenn noch keines
/// Liste der Anfragen
[HttpGet]
[Route("GetPayoutsForSync")]
public async Task GetPayoutsForSync(string appUserId, DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var payouts = await _payoutService.GetForSyncAppAsync(appUserId, lastUpdate);
var dtoList = Mapper.Map>(payouts);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Abfragen von Auszahlungen
///
/// Abfragemodel
/// Liste von Walks
[HttpPost]
[Route("GetPayouts")]
public async Task GetPayouts(PayoutQueryDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var baseAddress = GetBaseAddress();
var response = new ListResponseDto();
var sortList = Mapper.Map>(model.DynamicSortOrder);
var queryResult = await _payoutService.GetAsync(model.AppUserId, sortList, model.Skip, model.Take);
response.Total = queryResult.total;
var resultList = queryResult.list;
var dtoList = Mapper.Map>(resultList);
response.List = dtoList;
response.Take = model.Take;
response.Skip = model.Skip;
return Ok(response);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Eine Beantragung für eine Auszahlung erstellen
///
/// Model mit Daten
/// 200 OK
[HttpPost]
[Route("CreatePayout")]
public async Task CreatePayout(PayoutCreateDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var appUser = await AppUserService.GetAsync(model.AppUserId);
if (appUser != null)
{
//Wenn Benutzer gesperrt ist, dann keine Auszahlung
if (appUser.Locked)
{
return BadRequest(CommunicationErrors.PayOut_Failed);
}
//Prüfen ob der letzte Payout nicht älter als 24 Stunden ist
//TODO: in App als Fehlermeldung implementieren
var lastPayoutCount = await _payoutService.CountPayoutsInTimeRangeAsync(appUser.Id, DateTimeOffset.UtcNow.AddHours(-24), DateTimeOffset.UtcNow);
if (lastPayoutCount > 0)
{
//Wenn weniger als 24 Stunden, dann nicht erlaubt
return BadRequest(CommunicationErrors.PayOut_Failed);
}
//Kein KYC-Check, dann keine Auszahlung
if (!appUser.KycPassed)
{
return BadRequest(CommunicationErrors.PayOut_Failed);
}
//Wenn der erfolgreiche KYC-Check eines AppUsers nicht mindestens 48 Stunden zurückliegt, dann keine Auszahlung
if (appUser.KycPassedDate.HasValue && appUser.KycPassedDate.Value > DateTimeOffset.UtcNow.AddHours(-48))
{
return BadRequest(CommunicationErrors.PayOut_Failed);
}
//Wenn mmehr als 200 Euro, dann blockieren
//TODO: Überprüfen ob das für die App-User passt.
if (model.Ammount > 200)
{
return BadRequest(CommunicationErrors.PayOut_Failed);
}
var creditWallet = await _walletService.GetAsync(appUser.Id, WalletType.Credits);
if (creditWallet != null)
{
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 = (long)(model.Ammount * 100);
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(User.Identity.Name);
var dto = Mapper.Map(payout);
return Ok(dto);
}
return BadRequest(CommunicationErrors.PayOut_Failed);
}
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
///
/// Gibt eine Auszahlung eines AppUsers zurück
///
/// Id des App-Users
/// ID der Auszahlung
/// 200 OK
[HttpGet]
[Route("GetPayout")]
public async Task GetPayout(string appUserId, string payoutId)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var appUser = await AppUserService.GetAsync(appUserId);
if (appUser != null)
{
var payout = await _payoutService.GetAsync(payoutId);
if (payout != null)
{
var dto = Mapper.Map(payout);
return Ok(dto);
}
return NotFound(CommunicationErrors.PayOut_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
}
}