gehgassi_backend/gehGassi.Web/Controllers/Api/ApiPaymentController.cs

923 lines
47 KiB
C#

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
{
/// <summary>
/// Controller für die Verwaltung von Zahlungen und Wallets
/// </summary>
[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;
/// <summary>
/// Erstellt eine Instanz
/// </summary>
/// <param name="mapper">Instanz eines IMapper</param>
/// <param name="logger">Instanz eines ILogger</param>
/// <param name="localizationOptions">Instanz von LocalizationOptions</param>
/// <param name="appUserService">Instanz eines IAppUserService</param>
/// <param name="walletService">Instanz eines IWalletService</param>
/// <param name="mangoPayService">Instanz eines IMangoPayService</param>
/// <param name="transactionFeeService">Instanz eines ITransactionFeeService</param>
/// <param name="userService">Instanz eines IUserService</param>
/// <param name="walkService">Instanz eines IWalkService</param>
/// <param name="systemMessageService">Instanz eines ISystemMessageService</param>
/// <param name="appHubSender">Instanz eines IAppHubSender</param>
/// <param name="identityDocumentService">Instanz eines IIdentityDocumentService</param>
/// <param name="payoutService">Instanz eines IPayoutService</param>
/// <param name="pushNotificationService">Instanz eines IPushNotificationService</param>
/// <param name="voucherCampaignService">Isntanz eines IVoucherCampaignService</param>
public ApiPaymentController(IMapper mapper, ILogger<ApiPaymentController> logger, IOptions<LocalizationOptions> 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
/// <summary>
/// Liefert alle Wallets eines App-Users
/// </summary>
/// <param name="appUserId">Id des App-Users</param>
/// <returns>Liste der Wallets</returns>
[HttpGet]
[Route("GetWallets")]
public async Task<IActionResult> 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<List<WalletDto>>(wallets);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Liefert den aktuellen Kontostand eines Wallets
/// </summary>
/// <param name="appUserId">Id des App-Users</param>
/// <param name="walletType">Typ des Wallets</param>
/// <returns>Aktueller Kontostand</returns>
[HttpGet]
[Route("GetWalletBalance")]
public async Task<IActionResult> 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
/// <summary>
/// Anlegen oder Aktualisieren einer Bankverbindung eines AppUsers
/// </summary>
/// <param name="model">Model</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("CreateOrUpdateBankAccount")]
public async Task<IActionResult> 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<BankAccount>(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<AppUserDto>(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);
}
/// <summary>
/// Gibt die Bankverbindung eines AppUsers zurück
/// </summary>
/// <param name="appUserId">Id des App-Users</param>
/// <returns>200 OK</returns>
[HttpGet]
[Route("GetBankAccount")]
public async Task<IActionResult> 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<BankAccountDto>(bankAccount);
return Ok(bankAccountDto);
}
}
}
return NotFound(CommunicationErrors.BankAccount_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region KYC
/// <summary>
/// Gibt das aktuelle KYC-Dokument eines App-Users zurück
/// </summary>
/// <param name="appUserId">Id des App-Users</param>
/// <returns>200 OK</returns>
[HttpGet]
[Route("GetKycDocumentLatest")]
public async Task<IActionResult> 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<IdentityDocumentDto>(identityDocument);
return Ok(dto);
}
return BadRequest(CommunicationErrors.Kyc_NoDocument);
}
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Erstellen eines KYC-Dokumentes für die Identitätsprüfung
/// </summary>
/// <param name="model">Model mit Basis-Daten</param>
/// <param name="files">Dateien die eingereicht werden sollen</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("CreatKycDocument")]
public async Task<IActionResult> CreatKycDocument([ModelBinder(BinderType = typeof(JsonModelBinder))] IdentityDocumentCreateDto model, List<IFormFile> 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<byte[]>();
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<IdentityDocumentDto>(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
/// <summary>
/// Authorisierung der Zahlung eines Walks mit einem vorhandenen Guthaben.
/// Das Geld wird auf das Transaktions-Konto überwiesen
/// </summary>
/// <param name="model">Model</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("AuthorizeWithCredit")]
public async Task<IActionResult> 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<WalkDto>(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);
}
/// <summary>
/// Authorisierung der Zahlung eines komplett Walks mit einem Gutschein
/// </summary>
/// <param name="model">Model</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("AuthorizeWithVoucher")]
public async Task<IActionResult> 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<WalkDto>(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);
}
/// <summary>
/// Startet das Einzahlen eines AppUsers
/// </summary>
/// <param name="model">Einzahlungs-einstellungen</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("PayIn")]
public async Task<IActionResult> 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
/// <summary>
/// Gibt eine Liste von Transaktionsgebühren für die Synchronisierung mit der App zurück
/// </summary>
/// <param name="lastUpdate">Letztes Update oder null, wenn noch keines</param>
/// <returns>HTTP 200 wenn erfolgreich</returns>
[Route("GetTransactionFees")]
[HttpGet]
public async Task<IActionResult> GetTransactionFees(DateTimeOffset? lastUpdate)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var transactionFees = await _transactionFeeService.GetForSyncAsync(lastUpdate);
var transactionFeesDto = Mapper.Map<List<TransactionFeeDto>>(transactionFees);
return Ok(transactionFeesDto);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
#region Payouts / Auszahlungen
/// <summary>
/// Abfrage der Auszahlungen eines AppUsers
/// </summary>
/// <param name="appUserId">Id des AppUsers</param>
/// <param name="lastUpdate">Letztes Update oder null, wenn noch keines</param>
/// <returns>Liste der Anfragen</returns>
[HttpGet]
[Route("GetPayoutsForSync")]
public async Task<IActionResult> 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<List<PayoutDto>>(payouts);
return Ok(dtoList);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Abfragen von Auszahlungen
/// </summary>
/// <param name="model">Abfragemodel</param>
/// <returns>Liste von Walks</returns>
[HttpPost]
[Route("GetPayouts")]
public async Task<IActionResult> GetPayouts(PayoutQueryDto model)
{
var clientOffset = GetClientDateOffset();
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var baseAddress = GetBaseAddress();
var response = new ListResponseDto<PayoutDto>();
var sortList = Mapper.Map<List<DynamicSortOrder>>(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<List<PayoutDto>>(resultList);
response.List = dtoList;
response.Take = model.Take;
response.Skip = model.Skip;
return Ok(response);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
/// <summary>
/// Eine Beantragung für eine Auszahlung erstellen
/// </summary>
/// <param name="model">Model mit Daten</param>
/// <returns>200 OK</returns>
[HttpPost]
[Route("CreatePayout")]
public async Task<IActionResult> 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<PayoutDto>(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);
}
/// <summary>
/// Gibt eine Auszahlung eines AppUsers zurück
/// </summary>
/// <param name="appUserId">Id des App-Users</param>
/// <param name="payoutId">ID der Auszahlung</param>
/// <returns>200 OK</returns>
[HttpGet]
[Route("GetPayout")]
public async Task<IActionResult> 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<PayoutDto>(payout);
return Ok(dto);
}
return NotFound(CommunicationErrors.PayOut_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
return NotFound(CommunicationErrors.Common_NotFound);
}
#endregion
}
}