http-api/src/Application/Payments/LiqPay/TicketGroups/Commands/ProcessCallback/ProcessCallbackCommandHandler.cs

308 lines
11 KiB
C#

using MediatR;
using cuqmbr.TravelGuide.Application.Common.Persistence;
using cuqmbr.TravelGuide.Application.Common.Services;
using cuqmbr.TravelGuide.Application.Common.Exceptions;
using System.Text;
using Newtonsoft.Json;
using cuqmbr.TravelGuide.Domain.Enums;
using Microsoft.Extensions.Localization;
using cuqmbr.TravelGuide.Domain.Entities;
namespace cuqmbr.TravelGuide.Application.Payments.LiqPay
.TicketGroups.Commands.ProcessCallback;
public class ProcessCallbackCommandHandler :
IRequestHandler<ProcessCallbackCommand>
{
private readonly UnitOfWork _unitOfWork;
private readonly LiqPayPaymentService _liqPayPaymentService;
private readonly IStringLocalizer _localizer;
private readonly EmailSenderService _emailSender;
public ProcessCallbackCommandHandler(
UnitOfWork unitOfWork,
LiqPayPaymentService liqPayPaymentService,
IStringLocalizer localizer,
EmailSenderService emailSender)
{
_unitOfWork = unitOfWork;
_liqPayPaymentService = liqPayPaymentService;
_localizer = localizer;
_emailSender = emailSender;
}
public async Task Handle(
ProcessCallbackCommand request,
CancellationToken cancellationToken)
{
// Validate signature.
var isSignatureValid = _liqPayPaymentService
.IsValidSignature(request.Data, request.Signature);
if (!isSignatureValid)
{
throw new ForbiddenException();
}
// Parse request data.
var dataBytes = Convert.FromBase64String(request.Data);
var dataJson = Encoding.UTF8.GetString(dataBytes);
var data = JsonConvert.DeserializeObject<dynamic>(dataJson);
string status = data.status;
var ticketGroupGuid = Guid.Parse((string)data.order_id);
var ticketGroup = await _unitOfWork.TicketGroupRepository
.GetOneAsync(e => e.Guid == ticketGroupGuid,
e => e.Tickets, cancellationToken);
if (ticketGroup == null ||
ticketGroup.Status == TicketStatus.Purchased)
{
throw new ForbiddenException();
}
// Process callback status
if (status.Equals("error") || status.Equals("failure"))
{
await _unitOfWork.TicketGroupRepository
.DeleteOneAsync(ticketGroup, cancellationToken);
}
else if (status.Equals("success"))
{
// Update ticket status
ticketGroup.Status = TicketStatus.Purchased;
await _unitOfWork.TicketGroupRepository
.UpdateOneAsync(ticketGroup, cancellationToken);
// Hydrate ticket group
var vehicleEnrollmentIds =
ticketGroup.Tickets.Select(t => t.VehicleEnrollmentId);
var vehicleEnrollments = (await _unitOfWork.VehicleEnrollmentRepository
.GetPageAsync(
ve => vehicleEnrollmentIds.Contains(ve.Id),
ve => ve.Route.RouteAddresses,
1, vehicleEnrollmentIds.Count(), cancellationToken))
.Items;
var routeAddressIds = vehicleEnrollments
.SelectMany(ve => ve.Route.RouteAddresses)
.Select(ra => ra.Id);
var routeAddressDetails = (await _unitOfWork.RouteAddressDetailRepository
.GetPageAsync(
rad => routeAddressIds.Contains(rad.RouteAddressId),
1, routeAddressIds.Count(), cancellationToken))
.Items;
var addressIds = vehicleEnrollments
.SelectMany(ve => ve.Route.RouteAddresses)
.Select(ra => ra.AddressId);
var addresses = (await _unitOfWork.AddressRepository
.GetPageAsync(
a => addressIds.Contains(a.Id),
a => a.City.Region.Country,
1, addressIds.Count(), cancellationToken))
.Items;
var vehicleIds = vehicleEnrollments
.Select(ve => ve.VehicleId);
var vehicles = (await _unitOfWork.VehicleRepository
.GetPageAsync(
v => vehicleIds.Contains(v.Id),
v => v.Company,
1, vehicleIds.Count(), cancellationToken))
.Items;
foreach (var ve in vehicleEnrollments)
{
ve.Vehicle = vehicles.Single(v => v.Id == ve.VehicleId);
foreach (var ra in ve.Route.RouteAddresses)
{
ra.Address = addresses.Single(a => a.Id == ra.AddressId);
ra.Details = routeAddressDetails
.Where(rad => rad.RouteAddressId == ra.Id)
.ToArray();
}
}
foreach (var t in ticketGroup.Tickets)
{
t.VehicleEnrollment = vehicleEnrollments
.Single(ve => ve.Id == t.VehicleEnrollmentId);
}
// Send email
if (ticketGroup.PassangerEmail != null)
{
var subject =
_localizer["PaymentProcessing.Ticket" +
".Email.PaymentCompleted.Subject"];
var ticketDetails = GetTicketDetails(ticketGroup);
var body = String.Format(
_localizer["PaymentProcessing.Ticket" +
".Email.PaymentCompleted.Body"],
ticketDetails);
await _emailSender.SendAsync(
new[] { ticketGroup.PassangerEmail }, subject,
body, cancellationToken);
}
}
await _unitOfWork.SaveAsync(cancellationToken);
_unitOfWork.Dispose();
}
private string GetTicketDetails(TicketGroup ticketGroup)
{
var sb = new StringBuilder();
sb.AppendLine("General:");
sb.AppendLine();
sb.AppendLine($"Ticket uuid: {ticketGroup.Guid}");
sb.AppendLine($"Purchase Time: {ticketGroup.PurchaseTime}");
sb.AppendLine();
var departureRouteAddressId =
ticketGroup.Tickets.First().DepartureRouteAddressId;
var arrivalRouteAddressId =
ticketGroup.Tickets.Last().ArrivalRouteAddressId;
var departureTime =
ticketGroup.Tickets.First()
.VehicleEnrollment.GetDepartureTime(departureRouteAddressId);
var arrivalTime =
ticketGroup.Tickets.Last()
.VehicleEnrollment.GetArrivalTime(arrivalRouteAddressId);
var departureAddress =
ticketGroup.Tickets.First()
.VehicleEnrollment.Route.RouteAddresses
.Single(ra => ra.Id == departureRouteAddressId)
.Address;
var arrivalAddress =
ticketGroup.Tickets.Last()
.VehicleEnrollment.Route.RouteAddresses
.Single(ra => ra.Id == arrivalRouteAddressId)
.Address;
var departureAddressName =
$"{departureAddress.City.Region.Country.Name}, " +
$"{departureAddress.City.Region.Name}, " +
$"{departureAddress.City.Name}, " +
$"{departureAddress.Name}";
var arrivalAddressName =
$"{arrivalAddress.City.Region.Country.Name}, " +
$"{arrivalAddress.City.Region.Name}, " +
$"{arrivalAddress.City.Name}, " +
$"{arrivalAddress.Name}";
sb.AppendLine($"Departure: {departureAddressName} at {departureTime}.");
sb.AppendLine($"Arrival: {arrivalAddressName} at {arrivalTime}.");
sb.AppendLine();
sb.AppendLine();
sb.AppendLine($"Passanger details:");
sb.AppendLine();
sb.AppendLine($"First Name: {ticketGroup.PassangerFirstName}.");
sb.AppendLine($"Last Name: {ticketGroup.PassangerLastName}.");
sb.AppendLine($"Patronymic: {ticketGroup.PassangerPatronymic}.");
sb.AppendLine($"Sex: {ticketGroup.PassangerSex}.");
sb.AppendLine($"Birth Date: {ticketGroup.PassangerBirthDate}.");
sb.AppendLine($"Email: {ticketGroup.PassangerEmail}.");
sb.AppendLine();
sb.AppendLine();
sb.AppendLine("Vehicle enrollments' details:");
sb.AppendLine();
foreach (var t in ticketGroup.Tickets)
{
departureRouteAddressId = t.DepartureRouteAddressId;
arrivalRouteAddressId = t.ArrivalRouteAddressId;
departureTime =
t.VehicleEnrollment.GetDepartureTime(departureRouteAddressId);
arrivalTime =
t.VehicleEnrollment.GetArrivalTime(arrivalRouteAddressId);
departureAddress =
t.VehicleEnrollment.Route.RouteAddresses
.Single(ra => ra.Id == departureRouteAddressId)
.Address;
arrivalAddress =
t.VehicleEnrollment.Route.RouteAddresses
.Single(ra => ra.Id == arrivalRouteAddressId)
.Address;
departureAddressName =
$"{departureAddress.City.Region.Country.Name}, " +
$"{departureAddress.City.Region.Name}, " +
$"{departureAddress.City.Name}, " +
$"{departureAddress.Name}";
arrivalAddressName =
$"{arrivalAddress.City.Region.Country.Name}, " +
$"{arrivalAddress.City.Region.Name}, " +
$"{arrivalAddress.City.Name}, " +
$"{arrivalAddress.Name}";
var vehicle = t.VehicleEnrollment.Vehicle;
var company = vehicle.Company;
sb.AppendLine($"Departure: {departureAddressName} at {departureTime}.");
sb.AppendLine($"Arrival: {arrivalAddressName} at {arrivalTime}.");
if (vehicle is Bus)
{
sb.AppendLine($"Vehicle: Bus, {((Bus)vehicle).Model}, " +
$"{((Bus)vehicle).Number}.");
}
else if (vehicle is Aircraft)
{
sb.AppendLine($"Vehicle: Aircraft, {((Aircraft)vehicle).Model}, " +
$"{((Aircraft)vehicle).Number}.");
}
else if (vehicle is Train)
{
sb.AppendLine($"Vehicle: Train, {((Train)vehicle).Model}, " +
$"{((Train)vehicle).Number}.");
}
else
{
throw new NotImplementedException();
}
sb.AppendLine($"Company: {company.Name}, ({company.ContactEmail}, " +
$"{company.ContactPhoneNumber}).");
var cost = t.Currency.Round(
t.VehicleEnrollment
.GetCost(departureRouteAddressId,arrivalRouteAddressId));
sb.AppendLine($"Cost: {cost} {t.Currency.Name}");
sb.AppendLine();
}
return sb.ToString();
}
}