using System.Threading.Tasks;
using Asp.Versioning;
using AutoMapper;
using gehGassi.Core.Interfaces;
using gehGassi.Domain.Common;
using gehGassi.Domain.Vouchers;
using gehGassi.Dto;
using gehGassi.Dto.Common;
using gehGassi.Dto.Vouchers;
using gehGassi.Web.Helper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace gehGassi.Web.Controllers.Api
{
///
/// Controller für die Verwaltung von Gutscheinen
///
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[ApiController]
[ApiVersion(1)]
[Route("api/vouchers")]
[Route("api/v{v:apiVersion}/vouchers")]
public class ApiVoucherController : ApiBaseController
{
private readonly ILogger _logger;
private readonly IVoucherCampaignService _voucherCampaignService;
private readonly IMangoPayService _mangoPayService;
private readonly IWebHostEnvironment _hostEnvironment;
private readonly IWalletService _walletService;
private readonly IWalkService _walkService;
private readonly ICustomerService _customerService;
///
/// Erstellt eine Instanz
///
/// Instanz eines IMapper
/// Instanz eines ILogger
/// Instanz von LocalizationOptions
/// Instanz eines IAppUserService
/// Instanz eines IVoucherCampaignService
/// Instanz eines IMangoPayService
/// Instanz eines IWebHostEnvironment
/// Instanz eines IWalletService
/// Instanz eines IWalkService
/// Instanz eines ICustomerService
public ApiVoucherController(IMapper mapper, ILogger logger, IOptions localizationOptions, IAppUserService appUserService,
IVoucherCampaignService voucherCampaignService, IMangoPayService mangoPayService, IWebHostEnvironment hostEnvironment, IWalletService walletService,
IWalkService walkService, ICustomerService customerService) : base(mapper, localizationOptions, appUserService)
{
_logger = logger;
_voucherCampaignService = voucherCampaignService;
_mangoPayService = mangoPayService;
_hostEnvironment = hostEnvironment;
_walletService = walletService;
_walkService = walkService;
_customerService = customerService;
}
///
/// Prüfen eines Gutscheincodes für einen AppUser
///
/// Model mit Code und AppUserId
/// HTTP 200 OK wenn erfolgreich
[HttpPost]
[Route("CheckVoucherCode")]
public async Task CheckVoucherCode(CheckVoucherCodeDto dto)
{
var validationResult = await _voucherCampaignService.ValidateVoucherCodeAsync(dto.Code, dto.AppUserId);
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var result = new CheckVoucherCodeResultDto()
{
VoucherId = string.Empty,
VoucherCampaignId = string.Empty,
VoucherAmmount = 0,
CampaignType = VoucherCampaignTypeDto.SingleVoucher,
ValidationResult = (VoucherValidationResultDto)validationResult
};
if (validationResult == VoucherValidationResult.Valid)
{
var voucher = await _voucherCampaignService.GetVoucherByCodeAsync(dto.Code);
result.VoucherId = voucher.Id;
result.VoucherCampaignId = voucher.VoucherCampaignId;
result.VoucherAmmount = voucher.VoucherAmmount;
var campaign = await _voucherCampaignService.GetAsync(voucher.VoucherCampaignId);
if (campaign != null)
{
result.CampaignType = (VoucherCampaignTypeDto)campaign.CampaignType;
//Nun noch das Budget gegen das Wallet prüfen
if (!_hostEnvironment.IsDevelopment())
result.ValidationResult = (VoucherValidationResultDto)await CheckBalance(campaign.WalletCreditId, voucher.VoucherAmmount);
}
}
return Ok(result);
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Holt einen Gutscheincode anhand des QR-Codes
///
/// Model mit QR-Code
/// HTTP 200 OK wenn erfolgreich
[HttpPost]
[Route("GetVoucherCodeByQrCode")]
public async Task GetVoucherCodeByQrCode(GetVoucherByQrCodeDto dto)
{
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
var result = new VoucherByQrCodeResultDto()
{
Exists = false,
Code = string.Empty
};
var voucher = await _voucherCampaignService.GetVoucherByQrCodeAsync(dto.QrCode);
if (voucher != null)
{
result.Exists = true;
result.Code = voucher.Code;
}
return Ok(result);
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Reserviert einen Gutschein für einen Walk
///
/// Model mit nötigen Daten
/// HTTP 200 OK wenn erfolgreich
[HttpPost]
[Route("ReserveVoucher")]
public async Task ReserveVoucher(ReserveVoucherDto dto)
{
var result = new ReserveVoucherResultDto()
{
Success = false,
VoucherUsageId = -1
};
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
//1. Prüfen ob der Gutschein existiert und gültig ist
var validationResult = await _voucherCampaignService.ValidateVoucherCodeAsync(dto.Code, dto.AppUserId);
if (validationResult == VoucherValidationResult.Valid)
{
var voucher = await _voucherCampaignService.GetVoucherByCodeAsync(dto.Code);
if (voucher != null && voucher.Id == dto.VoucherId)
{
var campaign = await _voucherCampaignService.GetAsync(voucher.VoucherCampaignId);
if (campaign != null)
{
var customer = await _customerService.GetAsync(campaign.CustomerId);
if (customer != null)
{
//2. Prüfen ob noch genug Budget in der Kampagne vorhanden ist
validationResult = await CheckBalance(campaign.WalletCreditId, voucher.VoucherAmmount);
if (validationResult == VoucherValidationResult.Valid)
{
//3. Geld vom Guthabenkonto der Kamapgne auf das Transferskonto überweisen mit Verweis auf den Walk und Transaktion erfassen
var ammount = (int)(dto.Ammount * 100);
var transferResult = await _mangoPayService.TransferMoneyAsync(customer.MangopayPaymentId, campaign.WalletCreditId,
customer.MangopayPaymentId, campaign.WalletFeeId, dto.WalkId, ammount, 0, $"VoucherId_{voucher.Id}_WalkId_{dto.WalkId}", "", "");
if (transferResult.Success)
{
//4. Reservieren durch die Anlage einer VoucherUsage
var voucherUsage = await _voucherCampaignService.ReserveVoucherAsync(voucher.Id, dto.AppUserId, dto.WalkId, voucher.VoucherAmmount, dto.Ammount);
//5. Den Gutschein beim Walk eintragen
await _walkService.AddVoucherToWalk(dto.WalkId, voucher.Id, dto.Ammount);
//6. Usage in der Kampagne eintragen (VouchersUsed, BudgetUsed)
campaign.VouchersUsed += 1;
campaign.BudgetUsed += dto.Ammount;
//7. Usage beim voucher eintragen (UsedCount, IsValid wenn Einzelgutschein)
voucher.UsedCount += 1;
voucher.IsValid = campaign.CampaignType != VoucherCampaignType.MultiVoucher;
await _voucherCampaignService.CommitAsync(User.Identity.Name);
result.Success = true;
result.VoucherUsageId = voucherUsage.Id;
}
else
{
result.TransferFailed = true;
}
}
}
else
{
result.CustomerNotFound = true;
}
}
else
{
result.CampaignNotFound = true;
}
}
else
{
result.VoucherNotFound = true;
}
}
result.ValidationResult = (VoucherValidationResultDto)validationResult;
return Ok(result);
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
///
/// Stornieren eines Gutscheins
///
/// Model mit nötigen Daten
/// HTTP 200 OK wenn erfolgreich
[HttpPost]
[Route("CancelVoucher")]
public async Task CancelVoucher(CancelVoucherDto dto)
{
if (User?.Identity != null && User.Identity.IsAuthenticated)
{
if (ModelState.IsValid)
{
var usage = await _voucherCampaignService.GetUsageAsync(dto.VoucherId, dto.AppUserId, dto.WalkId);
if (usage != null)
{
var voucher = await _voucherCampaignService.GetVoucherAsync(usage.VoucherId);
if (voucher != null && voucher.Id == dto.VoucherId)
{
var campaign = await _voucherCampaignService.GetAsync(voucher.VoucherCampaignId);
if (campaign != null)
{
var customer = await _customerService.GetAsync(campaign.CustomerId);
if (customer != null)
{
//Geld vom Transferkonto der Kamapgne auf das Guthabenkonto überweisen mit Verweis auf den Walk und Transaktion erfassen
var ammount = (int)(usage.VoucherAmmountUsed * 100);
var transferResult = await _mangoPayService.TransferMoneyAsync(customer.MangopayPaymentId, campaign.WalletFeeId,
customer.MangopayPaymentId, campaign.WalletCreditId, dto.WalkId, ammount, 0, $"VoucherId_{voucher.Id}_WalkId_{dto.WalkId}", "", "");
if (transferResult.Success)
{
//Usage beim voucher zurücksetzen (UsedCount, IsValid wenn Einzelgutschein)
voucher.UsedCount -= 1;
if (voucher.UsedCount < 0)
voucher.UsedCount = 0;
voucher.IsValid = true;
//Usage in der Kampagne zurücksetzen (VouchersUsed, BudgetUsed)
campaign.VouchersUsed -= 1;
if (campaign.VouchersUsed < 0)
campaign.VouchersUsed = 0;
campaign.BudgetUsed -= usage.VoucherAmmountUsed;
if(campaign.BudgetUsed < 0)
campaign.BudgetUsed = 0;
//Den Gutschein vom Walk entfernen
await _walkService.RemoveVoucherFromWalk(dto.WalkId, voucher.Id);
//Reservieren durch die Anlage einer VoucherUsage
_voucherCampaignService.RemoveUsage(usage);
await _voucherCampaignService.CommitAsync(User.Identity.Name);
return Ok();
}
}
}
}
}
return NotFound(CommunicationErrors.Common_NotFound);
}
}
return BadRequest(CommunicationErrors.Common_Model_Invalid);
}
#region Private
///
/// Prüft ob ein Wallet genug Guthaben hat
///
/// Id des Wallets
/// Minimum Guthaben
/// VoucherValidationResultDto
private async Task CheckBalance(string walletId, decimal minAmmount)
{
var wallet = await _walletService.GetAsync(walletId);
if (wallet != null)
{
var mangoPayResult = await _mangoPayService.GetWalletBalanceAsync(wallet.WalletId);
if (mangoPayResult.Success)
{
if ((decimal)(mangoPayResult.Value / 100) < minAmmount)
{
return VoucherValidationResult.CampaignBudgetUsedUp;
}
return VoucherValidationResult.Valid;
}
return VoucherValidationResult.Invalid;
}
return VoucherValidationResult.Invalid;
}
#endregion
}
}