URL generation for ticket payment and processing of its response

This commit is contained in:
KazanskiyMaks 2023-05-22 13:23:41 +03:00
parent d6eded539d
commit 261b928533
5 changed files with 130 additions and 20 deletions

View File

@ -1,27 +1,37 @@
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Server.Models;
using Server.Services; using Server.Services;
using SharedModels.DataTransferObjects; using SharedModels.Responses;
namespace Server.Controllers;
[Route("api/payment")] [Route("api/payment")]
[ApiController] [ApiController]
public class PaymentController : ControllerBase public class PaymentController : ControllerBase
{ {
private readonly IPaymentsService _paymentsService; readonly IPaymentsService _paymentsService;
public PaymentController(IPaymentsService paymentsService) public PaymentController(IPaymentsService paymentsService)
{ {
_paymentsService = paymentsService; _paymentsService = paymentsService;
} }
[HttpGet] [HttpPost("link")]
public async Task<IActionResult> GetPaymentLink([FromQuery] PaymentDto payment) public async Task<IActionResult?> GetPaymentLink([FromBody] IList<StrippedFlattenedEnrollment> input)
{ {
var result = await _paymentsService.GetPaymentUrl(payment); var result = await _paymentsService.GetPaymentUrl(input);
if (!result.isSucceed)
{
return result.actionResult;
}
return Ok(result.url); return Ok(result.url);
} }
[HttpPost("callback")]
public async Task<IActionResult> ReceiveCallback()
{
if (HttpContext.Request.ContentType != "application/x-www-form-urlencoded")
return BadRequest();
var result = await _paymentsService.ReceiveCallback(HttpContext.Request.Form);
return result.actionResult;
}
} }

View File

@ -7,7 +7,7 @@ public class TicketGroup
[Key] [Key]
public int Id { get; set; } public int Id { get; set; }
public DateTime PurchaseDateTimeUtc { get; set; } = DateTime.UtcNow; public DateTime PurchaseDateTimeUtc { get; set; } = DateTime.MinValue;
public bool IsReturned { get; set; } = false; public bool IsReturned { get; set; } = false;
public string UserId { get; set; } = null!; public string UserId { get; set; } = null!;

View File

@ -1,12 +1,12 @@
using LiqPayIntegration; using LiqPayIntegration;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using SharedModels.DataTransferObjects; using SharedModels.Responses;
using System.Dynamic;
namespace Server.Services; namespace Server.Services;
public interface IPaymentsService public interface IPaymentsService
{ {
Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<PaymentResponse> payments)> GetPayments(DateTime from, DateTime to); Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<PaymentResponse> payments)> GetPayments(DateTime from, DateTime to);
Task<(bool isSucceed, IActionResult? actionResult, string url)> GetPaymentUrl(PaymentDto payment); Task<(bool isSucceed, IActionResult? actionResult, string url)> GetPaymentUrl(IList<StrippedFlattenedEnrollment> input);
Task<(bool isSucceed, IActionResult? actionResult)> ReceiveCallback(IFormCollection forms);
} }

View File

@ -1,23 +1,113 @@
using System.Text;
using System.Text.Json;
using LiqPayIntegration; using LiqPayIntegration;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using SharedModels.DataTransferObjects; using Microsoft.EntityFrameworkCore;
using Server.Constants;
using Server.Data;
using Server.Models;
using SharedModels.Responses;
namespace Server.Services; namespace Server.Services;
public class PaymentsService : IPaymentsService public class PaymentsService : IPaymentsService
{ {
readonly ApplicationDbContext _dbContext;
// LiqpayIntegration readonly string _userId;
LiqPay liqPay = new LiqPay("sandbox_i23432845039", "sandbox_gymL9PdryqdfAznNQbb7ynLvASDQ5SJCCNJvF2iV");
// LiqpayIntegration. Change 3-rd argument` address to current machine address in its network. Don't forget about port.
LiqPay liqPay = new LiqPay("sandbox_i23432845039", "sandbox_gymL9PdryqdfAznNQbb7ynLvASDQ5SJCCNJvF2iV", "http://localhost:5006/api/payment/callback/");
public PaymentsService(ApplicationDbContext dbContext, IHttpContextAccessor httpContextAccessor)
{
_dbContext = dbContext;
_userId = httpContextAccessor.HttpContext.User.Claims
.FirstOrDefault(c => c.Properties.Values.Any(v => v == JwtStandardClaimNames.Sub))?.Value;
}
public async Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<PaymentResponse> payments)> GetPayments(DateTime from, DateTime to) public async Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<PaymentResponse> payments)> GetPayments(DateTime from, DateTime to)
{ {
return(true, null, (await liqPay.PaymentArchive(from, to)).AsEnumerable()); return(true, null, (await liqPay.PaymentArchive(from, to)).AsEnumerable());
} }
public async Task<(bool isSucceed, IActionResult? actionResult, string url)> GetPaymentUrl(PaymentDto payment) public async Task<(bool isSucceed, IActionResult? actionResult, string url)> GetPaymentUrl(IList<StrippedFlattenedEnrollment> input)
{ {
return (true, null, (await liqPay.GetPaymentUrl(payment.Amount, payment.Description, payment.OrderId))); if (input.Count < 1)
return (false, new BadRequestResult(), "");
input.ToList().OrderBy(e => e.Order);
List<Ticket> tickets = new List<Ticket>();
foreach (StrippedFlattenedEnrollment e in input)
{
tickets.Add(new Ticket
{
VehicleEnrollmentId = e.Id,
FirstRouteAddressId = e.DepartureAddressId,
LastRouteAddressId = e.ArrivalAddressId
});
}
TicketGroup ticketGroup = new TicketGroup
{
Tickets = tickets,
UserId = _userId
};
_dbContext.TicketGroups.Add(ticketGroup);
await _dbContext.SaveChangesAsync();
int orderId = ticketGroup.Id;
var ticketGroups = _dbContext.TicketGroups;
var dbTicketGroup = await _dbContext.TicketGroups
.Include(tg => tg.Tickets)
.ThenInclude(t => t.VehicleEnrollment)
.ThenInclude(ve => ve.RouteAddressDetails)
.ThenInclude(ve => ve.RouteAddress)
.ThenInclude(ra => ra.Route)
.ThenInclude(r => r.RouteAddresses)
.ThenInclude(ra => ra.Address)
.ThenInclude(a => a.City)
.ThenInclude(c => c.State)
.ThenInclude(s => s.Country)
.FirstAsync(tg => tg.Id == orderId);
double cost = dbTicketGroup.GetCost();
string description =
$"Ïî¿çäêà ç { dbTicketGroup.GetDepartureAddress().GetFullName()}\n"+
$"Äî { dbTicketGroup.GetArrivalAddress().GetFullName()}";
string text = await liqPay.GetPaymentUrl(cost, description, orderId.ToString());
return (true, new OkResult(), text);
} }
public async Task<(bool isSucceed, IActionResult? actionResult)> ReceiveCallback(IFormCollection forms)
{
if (!forms.Keys.Contains("data"))
return (false, new BadRequestResult());
var baseData = forms["data"].First();
var data = Encoding.UTF8.GetString(Convert.FromBase64String(baseData));
var jsonData = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(data);
if (!jsonData.ContainsKey("status") || !jsonData.ContainsKey("order_id"))
return (false, new BadRequestResult());
if (jsonData["status"].GetString() != "success")
return (true, new OkResult());
var orderId = int.Parse(jsonData["order_id"].GetString());
var ticket = _dbContext.TicketGroups
.Find(orderId);
ticket.PurchaseDateTimeUtc = DateTime.UtcNow;
_dbContext.Update(ticket);
await _dbContext.SaveChangesAsync();
return (true, new OkResult());
}
} }

View File

@ -0,0 +1,10 @@
namespace SharedModels.Responses
{
public class StrippedFlattenedEnrollment
{
public int Id { get; set; }
public int DepartureAddressId { get; set; }
public int ArrivalAddressId { get; set; }
public int Order { get; set; }
}
}