Small fixes

This commit is contained in:
KazanskiyMaks 2023-05-17 18:25:47 +03:00
parent bdb1378868
commit d6eded539d
9 changed files with 377 additions and 225 deletions

View File

@ -1,4 +1,5 @@
using System.Buffers.Text;
using System.Dynamic;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
@ -9,47 +10,99 @@ using static System.Net.WebRequestMethods;
namespace LiqPayIntegration
{
public class LiqPay
{
private readonly HttpClient _http;
public class LiqPay
{
private readonly HttpClient _http;
public const string API_URL = "https://www.liqpay.ua/api/request";
public string PublicKey { get; init; }
public string PrivateKey { get; init; }
public LiqPay(string publicKey, string privateKey)
{
_http = new HttpClient();
PublicKey = publicKey;
PrivateKey = privateKey;
public const string API_URL = "https://www.liqpay.ua/api/request";
public string PublicKey { get; private set; }
public string PrivateKey { get; private set; }
public string CallbackUrl { get; private set; }
public LiqPay(string publicKey, string privateKey)
{
_http = new HttpClient();
PublicKey = publicKey;
PrivateKey = privateKey;
}
public LiqPay(string publicKey, string privateKey, string callbackUrl) : this (publicKey, privateKey)
{
CallbackUrl = callbackUrl;
}
public async ValueTask<PaymentResponse[]> PaymentArchive(DateTime from, DateTime to)
{
var json = JsonContent.Create(new
{
action = "reports",
version = 3,
public_key = PublicKey,
date_from = (long)from.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds,
date_to = (long)to.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds
public async ValueTask<PaymentResponse[]> PaymentArchive(DateTimeOffset from, DateTimeOffset to)
{
var json = JsonContent.Create(new
{
action = "reports",
version = 3,
public_key = PublicKey,
date_from = from.ToUnixTimeMilliseconds(),
date_to = to.ToUnixTimeMilliseconds(),
//server_url = CallbackUrl
/*date_from = (long)from.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds,
date_to = (long)to.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds*/
});
var data = Convert.ToBase64String(await json.ReadAsByteArrayAsync());
var signString = PrivateKey + data + PrivateKey;
var signature = Convert.ToBase64String(SHA1.HashData(Encoding.UTF8.GetBytes(signString)));
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("data", data),
new KeyValuePair<string, string>("signature", signature)
var data = Convert.ToBase64String(await json.ReadAsByteArrayAsync());
var signString = PrivateKey + data + PrivateKey;
var signature = Convert.ToBase64String(SHA1.HashData(Encoding.UTF8.GetBytes(signString)));
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("data", data),
new KeyValuePair<string, string>("signature", signature)
});
var response = await _http.PostAsync(API_URL, requestContent);
var rawResponse = await response.Content.ReadAsStringAsync();
var jsonResponse = JsonNode.Parse(rawResponse);
if (jsonResponse["result"] == null)
throw new NullReferenceException("jsonResponse[\"result\"]");
var result = jsonResponse["result"].Deserialize<string>();
if (result != "success")
throw new Exception("result isn't success");
var paymentResponses = jsonResponse["data"].Deserialize<PaymentResponse[]>();
return paymentResponses;
}
public async ValueTask<(string data, string signature)> GetCheckout(double amount, string description, string order_id)
{
var json = JsonContent.Create(new
{
action = "pay",
version = 3,
public_key = PublicKey,
amount = amount,
currency = "UAH",
description = description,
order_id = order_id,
server_url = CallbackUrl
});
var response = await _http.PostAsync(API_URL, requestContent);
var rawResponse = await response.Content.ReadAsStringAsync();
var jsonResponse = JsonNode.Parse(rawResponse);
if (jsonResponse["result"] == null)
throw new NullReferenceException("jsonResponse[\"result\"]");
var result = jsonResponse["result"].Deserialize<string>();
if (result != "success")
throw new Exception("result isn't success");
var paymentResponses = jsonResponse["data"].Deserialize<PaymentResponse[]>();
return paymentResponses;
var data = Convert.ToBase64String(await json.ReadAsByteArrayAsync());
var signString = PrivateKey + data + PrivateKey;
var signature = Convert.ToBase64String(SHA1.HashData(Encoding.UTF8.GetBytes(signString)));
return (data, signature);
}
public string GetPaymentUrl(string data, string signature)
{
return "https://www.liqpay.ua/api/3/checkout?data=" + data + "&signature=" + signature;
}
}
public async ValueTask<string> GetPaymentUrl(double amount, string description, string order_id)
{
var vars = await GetCheckout(amount, description, order_id);
return "https://www.liqpay.ua/api/3/checkout?data=" + vars.data + "&signature=" + vars.signature;
}
/*public async void ReceiptOfReceipt(string orderId, string email)
{
var json = JsonContent.Create(new
{
action = "reports",
version = 3,
public_key = PublicKey,
date_from = (long)from.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds,
date_to = (long)to.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds
});
}*/
}
}

View File

@ -7,193 +7,193 @@ using System.Threading.Tasks;
namespace LiqPayIntegration
{
public class PaymentResponse
{
/// <summary>
/// Id платежу в системі LiqPay
/// </summary>
[JsonPropertyName("payment_id")]
public long PaymentId { get; set; }
/// <summary>
/// Тип операції.
/// Можливі значення: <c>pay</c> - платіж,
/// <c>hold</c> - блокування коштів на рахунку відправника,
/// <c>paysplit</c> - розщеплення платежу,
/// <c>subscribe</c> - створення регулярного платежу,
/// <c>paydonate</c> - пожертвування,
/// <c>auth</c> - предавторізація картки,
/// <c>regular</c> - регулярний платіж
/// </summary>
[JsonPropertyName("action")]
public string Action { get; set; }
/// <summary>
/// Статус платежу.
/// Можливі значення:
/// </summary>
[JsonPropertyName("status")]
public string Status { get; set; }
/// <summary>
/// Версія API. Поточне значення - <c>3</c>
/// </summary>
[JsonPropertyName("version")]
public int Version { get; set; }
/// <summary>
/// Тип платежу
/// </summary>
[JsonPropertyName("type")]
public string Type { get; set; }
/// <summary>
/// Спосіб оплати.
/// Можливі значення:
/// </summary>
[JsonPropertyName("paytype")]
public string PayType { get; set; }
/// <summary>
/// Публічний ключ магазину
/// </summary>
[JsonPropertyName("public_key")]
public string PublicKey { get; set; }
/// <summary>
/// ID еквайера
/// </summary>
[JsonPropertyName("acq_id")]
public int AcqId { get; set; }
/// <summary>
/// Order_id платежу
/// </summary>
[JsonPropertyName("order_id")]
public string OrderId { get; set; }
/// <summary>
/// Order_id платежу в системі LiqPay
/// </summary>
[JsonPropertyName("liqpay_order_id")]
public string LiqPayOrderId { get; set; }
/// <summary>
/// Коментар до платежу
/// </summary>
[JsonPropertyName("description")]
public string Description { get; set; }
/// <summary>
/// Карта відправника
/// </summary>
[JsonPropertyName("sender_card_mask2")]
public string SenderCardMask2 { get; set; }
/// <summary>
/// Банк відправника
/// </summary>
[JsonPropertyName("sender_card_bank")]
public string SenderCardBank { get; set; }
/// <summary>
/// Тип картки відправника MC/Visa
/// </summary>
[JsonPropertyName("sender_card_type")]
public string SenderCardType { get; set; }
/// <summary>
/// Країна картки відправника. Цифровий <see href="https://uk.wikipedia.org/wiki/ISO_3166-1">ISO 3166-1 код</see>
/// </summary>
[JsonPropertyName("sender_card_country")]
public int SenderCardCountry { get; set; }
public class PaymentResponse
{
/// <summary>
/// Id платежу в системі LiqPay
/// </summary>
[JsonPropertyName("payment_id")]
public long PaymentId { get; set; }
/// <summary>
/// Тип операції.
/// Можливі значення: <c>pay</c> - платіж,
/// <c>hold</c> - блокування коштів на рахунку відправника,
/// <c>paysplit</c> - розщеплення платежу,
/// <c>subscribe</c> - створення регулярного платежу,
/// <c>paydonate</c> - пожертвування,
/// <c>auth</c> - предавторізація картки,
/// <c>regular</c> - регулярний платіж
/// </summary>
[JsonPropertyName("action")]
public string Action { get; set; }
/// <summary>
/// Статус платежу.
/// Можливі значення:
/// </summary>
[JsonPropertyName("status")]
public string Status { get; set; }
/// <summary>
/// Версія API. Поточне значення - <c>3</c>
/// </summary>
[JsonPropertyName("version")]
public int Version { get; set; }
/// <summary>
/// Тип платежу
/// </summary>
[JsonPropertyName("type")]
public string Type { get; set; }
/// <summary>
/// Спосіб оплати.
/// Можливі значення:
/// </summary>
[JsonPropertyName("paytype")]
public string PayType { get; set; }
/// <summary>
/// Публічний ключ магазину
/// </summary>
[JsonPropertyName("public_key")]
public string PublicKey { get; set; }
/// <summary>
/// ID еквайера
/// </summary>
[JsonPropertyName("acq_id")]
public int AcqId { get; set; }
/// <summary>
/// Order_id платежу
/// </summary>
[JsonPropertyName("order_id")]
public string OrderId { get; set; }
/// <summary>
/// Order_id платежу в системі LiqPay
/// </summary>
[JsonPropertyName("liqpay_order_id")]
public string LiqPayOrderId { get; set; }
/// <summary>
/// Коментар до платежу
/// </summary>
[JsonPropertyName("description")]
public string Description { get; set; }
/// <summary>
/// Карта відправника
/// </summary>
[JsonPropertyName("sender_card_mask2")]
public string SenderCardMask2 { get; set; }
/// <summary>
/// Банк відправника
/// </summary>
[JsonPropertyName("sender_card_bank")]
public string SenderCardBank { get; set; }
/// <summary>
/// Тип картки відправника MC/Visa
/// </summary>
[JsonPropertyName("sender_card_type")]
public string SenderCardType { get; set; }
/// <summary>
/// Країна картки відправника. Цифровий <see href="https://uk.wikipedia.org/wiki/ISO_3166-1">ISO 3166-1 код</see>
/// </summary>
[JsonPropertyName("sender_card_country")]
public int SenderCardCountry { get; set; }
/// <summary>
///
/// </summary>
[JsonPropertyName("ip")]
public string Ip { get; set; }
/// <summary>
/// Сума платежу
/// </summary>
[JsonPropertyName("amount")]
public double Amount { get; set; }
/// <summary>
/// Валюта платежу
/// </summary>
[JsonPropertyName("currency")]
public string Currency { get; set; }
/// <summary>
/// Комісія з відправника у валюті платежу
/// </summary>
[JsonPropertyName("sender_commission")]
public double SenderCommission { get; set; }
/// <summary>
/// Комісія з одержувача у валюті платежу
/// </summary>
[JsonPropertyName("receiver_commission")]
public double ReceiverCommission { get; set; }
/// <summary>
/// Комісія агента в валюті платежу
/// </summary>
[JsonPropertyName("agent_commission")]
public double AgentCommission { get; set; }
/// <summary>
/// Сума транзакції debit у валюті <see cref="CurrencyDebit">currency_debit</see>
/// </summary>
[JsonPropertyName("amount_debit")]
public double AmountDebit { get; set; }
/// <summary>
/// Сума транзакції credit в валюті <see cref="CurrencyCredit">amount_credit</see>
/// </summary>
[JsonPropertyName("amount_credit")]
public double AmountCredit { get; set; }
/// <summary>
/// Комісія з відправника у валюті <see cref="CurrencyDebit">currency_debit</see>
/// </summary>
[JsonPropertyName("commission_debit")]
public double CommissionDebit { get; set; }
/// <summary>
/// Комісія з одержувача у валюті <see cref="CurrencyCredit">currency_credit</see>
/// </summary>
[JsonPropertyName("commission_credit")]
public double CommissionCredit { get; set; }
/// <summary>
/// Валюта транзакції debit
/// </summary>
[JsonPropertyName("currency_debit")]
public string CurrencyDebit { get; set; }
/// <summary>
/// Валюта транзакції credit
/// </summary>
[JsonPropertyName("currency_credit")]
public string CurrencyCredit { get; set; }
/// <summary>
/// Бонус відправника у валюті платежу
/// </summary>
[JsonPropertyName("sender_bonus")]
public double SenderBonus { get; set; }
/// <summary>
/// Бонус відправника у валюті платежу debit
/// </summary>
[JsonPropertyName("amount_bonus")]
public double AmountBonus { get; set; }
/// <summary>
/// Можливі значення: 5 - транзакція пройшла з 3DS (емітент і еквайєр підтримують технологію 3D-Secure), 6 - емітент картки платника не підтримує технологію 3D-Secure, 7 - операція пройшла без 3D-Secure
/// </summary>
[JsonPropertyName("mpi_eci")]
public string MpiEci { get; set; }
/// <summary>
/// Можливі значення:
/// <c>true</c> - транзакція пройшла з 3DS перевіркою,
/// <c>false</c> - транзакція пройшла без 3DS перевірки
/// </summary>
[JsonPropertyName("is_3ds")]
public bool Is3ds { get; set; }
[JsonPropertyName("ip")]
public string Ip { get; set; }
/// <summary>
/// Сума платежу
/// </summary>
[JsonPropertyName("amount")]
public double Amount { get; set; }
/// <summary>
/// Валюта платежу
/// </summary>
[JsonPropertyName("currency")]
public string Currency { get; set; }
/// <summary>
/// Комісія з відправника у валюті платежу
/// </summary>
[JsonPropertyName("sender_commission")]
public double SenderCommission { get; set; }
/// <summary>
/// Комісія з одержувача у валюті платежу
/// </summary>
[JsonPropertyName("receiver_commission")]
public double ReceiverCommission { get; set; }
/// <summary>
/// Комісія агента в валюті платежу
/// </summary>
[JsonPropertyName("agent_commission")]
public double AgentCommission { get; set; }
/// <summary>
/// Сума транзакції debit у валюті <see cref="CurrencyDebit">currency_debit</see>
/// </summary>
[JsonPropertyName("amount_debit")]
public double AmountDebit { get; set; }
/// <summary>
/// Сума транзакції credit в валюті <see cref="CurrencyCredit">amount_credit</see>
/// </summary>
[JsonPropertyName("amount_credit")]
public double AmountCredit { get; set; }
/// <summary>
/// Комісія з відправника у валюті <see cref="CurrencyDebit">currency_debit</see>
/// </summary>
[JsonPropertyName("commission_debit")]
public double CommissionDebit { get; set; }
/// <summary>
/// Комісія з одержувача у валюті <see cref="CurrencyCredit">currency_credit</see>
/// </summary>
[JsonPropertyName("commission_credit")]
public double CommissionCredit { get; set; }
/// <summary>
/// Валюта транзакції debit
/// </summary>
[JsonPropertyName("currency_debit")]
public string CurrencyDebit { get; set; }
/// <summary>
/// Валюта транзакції credit
/// </summary>
[JsonPropertyName("currency_credit")]
public string CurrencyCredit { get; set; }
/// <summary>
/// Бонус відправника у валюті платежу
/// </summary>
[JsonPropertyName("sender_bonus")]
public double SenderBonus { get; set; }
/// <summary>
/// Бонус відправника у валюті платежу debit
/// </summary>
[JsonPropertyName("amount_bonus")]
public double AmountBonus { get; set; }
/// <summary>
/// Можливі значення: 5 - транзакція пройшла з 3DS (емітент і еквайєр підтримують технологію 3D-Secure), 6 - емітент картки платника не підтримує технологію 3D-Secure, 7 - операція пройшла без 3D-Secure
/// </summary>
[JsonPropertyName("mpi_eci")]
public string MpiEci { get; set; }
/// <summary>
/// Можливі значення:
/// <c>true</c> - транзакція пройшла з 3DS перевіркою,
/// <c>false</c> - транзакція пройшла без 3DS перевірки
/// </summary>
[JsonPropertyName("is_3ds")]
public bool Is3ds { get; set; }
/// <summary>
///
/// </summary>
[JsonPropertyName("language")]
public string Language { get; set; }
/// <summary>
/// Дата створення платежу
/// </summary>
[JsonPropertyName("create_date")]
public long CreateDate { get; set; }
/// <summary>
/// Дата завершення/зміни платежу
/// </summary>
[JsonPropertyName("end_date")]
public long EndDate { get; set; }
/// <summary>
/// Id транзакції в системі LiqPay
/// </summary>
[JsonPropertyName("transaction_id")]
public long TransactionId { get; set; }
}
[JsonPropertyName("language")]
public string Language { get; set; }
/// <summary>
/// Дата створення платежу
/// </summary>
[JsonPropertyName("create_date")]
public long CreateDate { get; set; }
/// <summary>
/// Дата завершення/зміни платежу
/// </summary>
[JsonPropertyName("end_date")]
public long EndDate { get; set; }
/// <summary>
/// Id транзакції в системі LiqPay
/// </summary>
[JsonPropertyName("transaction_id")]
public long TransactionId { get; set; }
}
}

View File

@ -0,0 +1,27 @@
using Microsoft.AspNetCore.Mvc;
using Server.Services;
using SharedModels.DataTransferObjects;
[Route("api/payment")]
[ApiController]
public class PaymentController : ControllerBase
{
private readonly IPaymentsService _paymentsService;
public PaymentController(IPaymentsService paymentsService)
{
_paymentsService = paymentsService;
}
[HttpGet]
public async Task<IActionResult> GetPaymentLink([FromQuery] PaymentDto payment)
{
var result = await _paymentsService.GetPaymentUrl(payment);
if (!result.isSucceed)
{
return result.actionResult;
}
return Ok(result.url);
}
}

View File

@ -149,6 +149,8 @@ services.AddScoped<VehicleEnrollmentSearchService>();
services.AddScoped<IReportService, ReportService>();
services.AddScoped<IStatisticsService, StatisticsService>();
builder.Services.AddScoped<IPaymentsService, PaymentsService>();
// Adding DB Context with PostgreSQL
var connectionString = configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<ApplicationDbContext>(options =>

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
@ -36,8 +36,9 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LiqPayIntegration\LiqPayIntegration.csproj" />
<ProjectReference Include="..\SharedModels\SharedModels.csproj" />
<ProjectReference Include="..\Utils\Utils.csproj" />
<ProjectReference Include="..\Utils\Utils.csproj" />
</ItemGroup>
</Project>

View File

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

View File

@ -0,0 +1,23 @@
using LiqPayIntegration;
using Microsoft.AspNetCore.Mvc;
using SharedModels.DataTransferObjects;
namespace Server.Services;
public class PaymentsService : IPaymentsService
{
// LiqpayIntegration
LiqPay liqPay = new LiqPay("sandbox_i23432845039", "sandbox_gymL9PdryqdfAznNQbb7ynLvASDQ5SJCCNJvF2iV");
public async Task<(bool isSucceed, IActionResult? actionResult, IEnumerable<PaymentResponse> payments)> GetPayments(DateTime from, DateTime to)
{
return(true, null, (await liqPay.PaymentArchive(from, to)).AsEnumerable());
}
public async Task<(bool isSucceed, IActionResult? actionResult, string url)> GetPaymentUrl(PaymentDto payment)
{
return (true, null, (await liqPay.GetPaymentUrl(payment.Amount, payment.Description, payment.OrderId)));
}
}

View File

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
namespace SharedModels.DataTransferObjects;
public class PaymentDto
{
[Required]
public double Amount { get; set; }
[Required]
public string Description { get; set; }
[Required]
[StringLength(maximumLength: 255, ErrorMessage = "Order Id is too long")]
public string OrderId { get; set; }
}

View File

@ -1,8 +1,14 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Server", "Server\Server.csproj", "{0DCB2130-10E7-4C98-AB94-5F8D68032B9F}"
# Visual Studio Version 17
VisualStudioVersion = 17.5.33516.290
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "Server\Server.csproj", "{0DCB2130-10E7-4C98-AB94-5F8D68032B9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharedModels", "SharedModels\SharedModels.csproj", "{34E01155-5DA4-45DA-8F58-63AEFCC56B4B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharedModels", "SharedModels\SharedModels.csproj", "{34E01155-5DA4-45DA-8F58-63AEFCC56B4B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiqPayIntegration", "LiqPayIntegration\LiqPayIntegration.csproj", "{D1DE3296-E918-4702-997D-A10B755FF2CB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utils", "..\auto.bus_api\Utils\Utils.csproj", "{B1AC0E7C-E77C-4F2F-82A0-A2AB2D126B71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -18,5 +24,19 @@ Global
{34E01155-5DA4-45DA-8F58-63AEFCC56B4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34E01155-5DA4-45DA-8F58-63AEFCC56B4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34E01155-5DA4-45DA-8F58-63AEFCC56B4B}.Release|Any CPU.Build.0 = Release|Any CPU
{D1DE3296-E918-4702-997D-A10B755FF2CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1DE3296-E918-4702-997D-A10B755FF2CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1DE3296-E918-4702-997D-A10B755FF2CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1DE3296-E918-4702-997D-A10B755FF2CB}.Release|Any CPU.Build.0 = Release|Any CPU
{B1AC0E7C-E77C-4F2F-82A0-A2AB2D126B71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B1AC0E7C-E77C-4F2F-82A0-A2AB2D126B71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B1AC0E7C-E77C-4F2F-82A0-A2AB2D126B71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B1AC0E7C-E77C-4F2F-82A0-A2AB2D126B71}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {067793F9-205E-4946-A13B-5C70752D57A3}
EndGlobalSection
EndGlobal