308 lines
11 KiB
C#
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();
|
|
}
|
|
}
|