Sumup payment integration finished (almost)

This commit is contained in:
Adam 2024-05-30 18:50:16 +02:00
parent 066c279a48
commit 9c39b15e05
8 changed files with 543 additions and 19 deletions

View File

@ -21,7 +21,7 @@
subject.Price = 17000;
subject.ContactEmail = "fyloruta@citmo.net";
subject.OrderId = 1232132;
var paymentLink = await SumUpService.CreatePaymentLinkAsync(subject);
var paymentLink = await SumUpService.CreatePaymentAsync(subject);
checkoutId = paymentLink;
checkoutUrl = "sumuppayment/" + checkoutId;
Console.WriteLine($"Payment Link: {paymentLink}");

View File

@ -5,11 +5,15 @@
@using AyCode.Services.Loggers
@using TIAM.Core.Loggers
@using TIAM.Core.Enums
@using TIAMWebApp.Shared.Application.Services
@using TIAMWebApp.Shared.Application.Utility
@inject HttpClient Http
@inject NavigationManager navManager
@inject IEnumerable<IAcLogWriterClientBase> LogWriters
@inject ITransferDataService transferDataService
@inject SumupService SumUpService
@inject NavigationManager navigationManager
<PageTitle>Transfer details</PageTitle>
<div class="text-center m-5">
<h1>Transfer details</h1>
@ -77,7 +81,7 @@ else
<div class="vr"></div>
<h5 class="fw-normal mb-0"><a href="#!" class="text-decoration-none">Cancel</a></h5>
<div class="vr"></div>
<h5 class="fw-normal mb-0"><a class="btn btn-primary">Pay</a></h5>
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="Pay">Pay</DxButton>
<div class="vr"></div>
<h5 class="fw-normal mb-0"><a class="btn btn-secondary" @onclick="SetEditMode">Modify</a></h5>
</div>
@ -187,7 +191,7 @@ else
</div>
<div class="card-footer p-4">
<div class="d-flex justify-content-between">
<DxButton Click="UpdateTransfer">Save Changes</DxButton>
<DxButton Click="@((e) => UpdateTransferEventHandler(e, true))">Save Changes</DxButton>
</div>
</div>
@ -217,6 +221,34 @@ else
List<string> StatusTypes = new List<string>();
private bool editMode = false;
private async Task Pay()
{
if (transfer != null)
{
string paymentId = "";
if(transfer.PaymentId!=null)
{
//if we have already
paymentId = transfer.PaymentId;
}
else
{
//if we have no paymentId yet
paymentId = await SumUpService.CreatePaymentAsync(transfer);
transfer.PaymentId = paymentId;
//and save it to Db
var resultTransfer = await UpdateTransfer(false);
if (resultTransfer.PaymentId != null)
{
_logger.Debug("Added paymentId to Db: "+ resultTransfer.PaymentId);
}
}
string checkoutUrl = "sumuppayment/" + paymentId;
Console.WriteLine($"Payment Link: {paymentId}");
navigationManager.NavigateTo(checkoutUrl);
}
}
protected override async Task OnInitializedAsync()
{
foreach (var t in Enum.GetValues(typeof(TransferStatusType)).OfType<TransferStatusType>().ToList())
@ -261,23 +293,32 @@ else
isLoading = false;
}
private async Task UpdateTransfer()
private async Task UpdateTransferEventHandler(MouseEventArgs e, bool shouldRedirect = false)
{
var result = await UpdateTransfer(shouldRedirect);
if (result != null && shouldRedirect)
navManager.NavigateTo("/mytransfers"); // Redirect to a list or another page after successful update
}
private async Task<Transfer> UpdateTransfer(bool shouldRedirect = false)
{
try
{
var responseTransfer = await transferDataService.UpdateTransferAsync(transfer);
if (responseTransfer != null)
{
navManager.NavigateTo("/mytransfers"); // Redirect to a list or another page after successful update
{
return responseTransfer;
}
else
{
errorMessage = $"Error updating transfer: {transfer.Id}";
return null;
}
}
catch (Exception ex)
{
errorMessage = $"Exception: {ex.Message}";
return null;
}
}
}

View File

@ -1,22 +1,117 @@
@page "/sumuppayment/{checkoutId}"
@using AyCode.Services.Loggers
@using System.Text.Json.Serialization
@using TIAM.Core.Loggers
@using TIAMWebApp.Shared.Application.Services
@using TIAMWebApp.Shared.Application.Utility
@inject IEnumerable<IAcLogWriterClientBase> LogWriters
@inject NavigationManager navigationManager
@inject SumupService _sumupService
@inject IJSRuntime JSRuntime
<PageTitle>Sumup Payment</PageTitle>
<div class="text-center m-5">
<h1>SUMUP safe payment</h1>
<h2 style="font-size:small">Pay your transfer here</h2>
</div>
<p hidden=@(!isSumupHidden)>@resultMessage</p>
<div id="sumup-card" hidden=@isSumupHidden></div>
@code {
[Parameter]
public string checkoutId { get; set; } = "";
private LoggerClient<SumupPayment> _logger;
private DotNetObjectReference<SumupPayment> _objectReference;
private string resultMessage = "";
private bool isSumupHidden = false;
private void Toggle()
{
isSumupHidden = !isSumupHidden;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JSRuntime.InvokeVoidAsync("loadSumUpPaymentWidget", checkoutId);
_logger = new LoggerClient<SumupPayment>(LogWriters.ToArray());
_objectReference = DotNetObjectReference.Create(this);
await JSRuntime.InvokeVoidAsync("loadSumUpPaymentWidget", checkoutId, _objectReference);
}
}
[JSInvokable]
public async Task HandleSumUpResponse(string type, object body)
{
// Handle the response here
JSPaymentResponse jsPresponse = body as JSPaymentResponse;
_logger.Debug($"Resonse received 2!");
_logger.Debug($"Type: {type}, Body: {body}");
//let's check the result
var status = await _sumupService.GetPaymentAsync(checkoutId);
Toggle();
if(status == "payed")
{
resultMessage = "Thank you, payment successful";
StateHasChanged();
}
else
{
resultMessage = $"Ooops something is not ok!";
StateHasChanged();
}
}
public void Dispose()
{
_objectReference?.Dispose();
}
public class JSPaymentResponse
{
[JsonPropertyName("amount")]
public int Amount { get; set; }
[JsonPropertyName("checkout_reference")]
public string CheckoutReference { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("merchant_name")]
public string MerchantName { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("transaction_code")]
public string TransactionCode { get; set; }
[JsonPropertyName("transaction_id")]
public string TransactionId { get; set; }
}
}
<div id="sumup-card"></div>
<script>
window.loadSumUpPaymentWidget = function (checkoutId) {
window.loadSumUpPaymentWidget = function (checkoutId, dotNetObjectRef) {
const script = document.createElement('script');
script.src = 'https://gateway.sumup.com/gateway/ecom/card/v2/sdk.js';
script.onload = () => {
@ -24,11 +119,14 @@
id: 'sumup-card',
checkoutId: checkoutId,
onResponse: function (type, body) {
console.log('Reponse received');
console.log('Type', type);
console.log('Body', body);
dotNetObjectRef.invokeMethodAsync('HandleSumUpResponse', type, body);
}
});
};
document.head.appendChild(script);
};
</script>
</script>

View File

@ -93,7 +93,16 @@
<Columns>
<DxGridCommandColumn NewButtonVisible="false" Width="8%" FixedPosition="GridColumnFixedPosition.Left" />
<DxGridDataColumn FieldName="Id" ShowInColumnChooser="false" SortIndex="0" Visible="false" />
<DxGridDataColumn FieldName="Id" ShowInColumnChooser="false" SortIndex="0" Visible="true">
<CellDisplayTemplate>
@{
Guid? idKeyField = context.Value as Guid?;
string editUri = $"mytransfers/{idKeyField}";
<NavLink href="@editUri">
<span>@idKeyField</span>
</NavLink> }
</CellDisplayTemplate>
</DxGridDataColumn>
<DxGridDataColumn FieldName="OrderId" />
<DxGridDataColumn FieldName="PaymentId" />
<DxGridDataColumn FieldName="FromAddress" />

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.Net.Http;
using System.Text.Json;
using TIAM.Database.DataLayers.Admins;
using TIAM.Database.DataLayers.Users;
@ -52,19 +53,44 @@ namespace TIAMWebApp.Server.Controllers
{
_logger.Detail($"CreatePayment called! {paymentItem.ToString()}");
var transferToPay = JObject.Parse(paymentItem.GetRawText()).ToObject<Transfer>();
if (transferToPay.Price == null)
{
transferToPay.Price = 1000;
}
else return "false";
var paymentRequest = new SumupPaymentRequest
{
CheckoutReference = transferToPay.OrderId.ToString(),
Amount = transferToPay.Price.ToString(),
Currency = "HUF",
PayToEmail = "adam.g@aycode.com",
PayToEmail = "6befaf69f97f4320bff2b9adf1a3894d@developer.sumup.com",
Description = "Test transfer payment"
};
var result = await _sumupService.CreateCheckout(paymentRequest);
_logger.Detail($"CreatePayment result: {result}");
var checkoutUrl = result.CheckoutUrl;
var checkoutUrl = result.Id.ToString();
return checkoutUrl;
}
[AllowAnonymous]
[HttpGet]
[Route(APIUrls.GetPaymentRouteName+"/{checkoutId}")]
public async Task<ActionResult<string>> GetPaymentById(string checkoutId)
{
_logger.Detail($"GetPayment called! {checkoutId.ToString()}");
var result = await _sumupService.GetPayment(checkoutId);
if (result == null)
{
return BadRequest();
}
else
{
return Ok(result);
}
}
}
}

View File

@ -11,6 +11,7 @@ using TIAM.Core.Loggers;
using TIAMWebApp.Shared.Application.Models.ClientSide.Payment;
using TIAMWebApp.Shared.Application.Services;
using TIAMWebApp.Shared.Application.Utility;
using static System.Net.WebRequestMethods;
namespace TIAMWebApp.Server.Services
{
@ -46,7 +47,7 @@ namespace TIAMWebApp.Server.Services
return tokenResponse.AccessToken;
}
public async Task<string> CreatePaymentLinkAsync(SumupPaymentRequest paymentRequest)
public async Task<PaymentResponse> CreatePaymentLinkAsync(SumupPaymentRequest paymentRequest)
{
var accessToken = await GetAccessTokenAsync();
//_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
@ -60,7 +61,7 @@ namespace TIAMWebApp.Server.Services
var responseContent = await response.Content.ReadAsStringAsync();
var paymentResponse = JsonSerializer.Deserialize<PaymentResponse>(responseContent);
return paymentResponse.CheckoutUrl;
return paymentResponse;
}
public async Task<PaymentResponse> CreateCheckout(SumupPaymentRequest request)
@ -91,6 +92,46 @@ namespace TIAMWebApp.Server.Services
throw new Exception($"Unable to create checkout. Response: {errorResponse}");
}
public async Task<string> GetPayment(string checkoutId)
{
string url = $"https://api.sumup.com/v0.1/checkouts/{checkoutId}";
// Replace with your actual access token
string accessToken = "sup_sk_0rt9IFrMpE9qA6328vqMwCtiCntRXZxGR";
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
var response = await _httpClient.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
return "error";
}
else
{
var jsonResponse = await response.Content.ReadAsStringAsync();
var checkoutResponse = JsonSerializer.Deserialize<GetPaymentResponse>(jsonResponse);
//if we have to do something with the payment, we can do it here
string paymentStatus = checkoutResponse.Status;
switch (paymentStatus)
{
case "pending":
//update in DB?
break;
case "failed":
//update in DB?
break;
case "payed":
//update in DB?
break;
}
return jsonResponse;
}
}
}
@ -106,8 +147,173 @@ namespace TIAMWebApp.Server.Services
public class PaymentResponse
{
[JsonPropertyName("checkout_url")]
public string CheckoutUrl { get; set; }
[JsonPropertyName("amount")]
public int Amount { get; set; }
[JsonPropertyName("checkout_reference")]
public string CheckoutReference { get; set; }
[JsonPropertyName("checkout_type")]
public string CheckoutType { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("date")]
public DateTimeOffset Date { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("merchant_country")]
public string MerchantCountry { get; set; }
[JsonPropertyName("merchant_name")]
public string MerchantName { get; set; }
[JsonPropertyName("pay_to_email")]
public string PayToEmail { get; set; }
[JsonPropertyName("product")]
public string Product { get; set; }
[JsonPropertyName("purpose")]
public string Purpose { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("transactions")]
public object[] Transactions { get; set; }
}
public class GetPaymentResponse
{
[JsonPropertyName("amount")]
public double Amount { get; set; }
[JsonPropertyName("checkout_reference")]
public string CheckoutReference { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("customer_id")]
public string CustomerId { get; set; }
[JsonPropertyName("date")]
public DateTimeOffset Date { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("mandate")]
public Mandate Mandate { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("pay_to_email")]
public string PayToEmail { get; set; }
[JsonPropertyName("return_url")]
public string ReturnUrl { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("transactions")]
public Transaction[] Transactions { get; set; }
[JsonPropertyName("valid_until")]
public DateTime ValidUntil { get; set; }
[JsonPropertyName("merchant_name")]
public string MerchantName { get; set; }
[JsonPropertyName("payment_instrument")]
public PaymentInstrument PaymentInstrument { get; set; }
[JsonPropertyName("redirect_url")]
public string RedirectUrl { get; set; }
[JsonPropertyName("transaction_code")]
public string TransactionCode { get; set; }
[JsonPropertyName("transaction_id")]
public Guid TransactionId { get; set; }
}
public partial class Mandate
{
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
}
public partial class PaymentInstrument
{
[JsonPropertyName("token")]
public Guid Token { get; set; }
}
public partial class Transaction
{
[JsonPropertyName("amount")]
public double Amount { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("installments_count")]
public string InstallmentsCount { get; set; }
[JsonPropertyName("payment_type")]
public string PaymentType { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("timestamp")]
public DateTimeOffset Timestamp { get; set; }
[JsonPropertyName("transaction_code")]
public string TransactionCode { get; set; }
[JsonPropertyName("auth_code")]
public string AuthCode { get; set; }
[JsonPropertyName("entry_mode")]
public string EntryMode { get; set; }
[JsonPropertyName("internal_id")]
public long InternalId { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("tip_amount")]
public long TipAmount { get; set; }
[JsonPropertyName("vat_amount")]
public long VatAmount { get; set; }
}
public class LowercaseNamingPolicy : JsonNamingPolicy

View File

@ -172,6 +172,8 @@ namespace TIAMWebApp.Shared.Application.Models
//payment
public const string CreatePaymentRouteName = "CreatePayment";
public const string CreatePayment = PaymentAPI + CreatePaymentRouteName;
public const string GetPaymentRouteName = "GetPaymentById";
public const string GetPaymentById = PaymentAPI + GetPaymentRouteName;
}
}

View File

@ -12,8 +12,9 @@ using TIAMWebApp.Shared.Application.Utility;
using TIAM.Core.Loggers;
using TIAMWebApp.Shared.Application.Models.ClientSide.Payment;
using static System.Net.WebRequestMethods;
using Newtonsoft.Json;
using System.Text.Json;
using TIAM.Models.Dtos.Users;
using System.Text.Json.Serialization;
namespace TIAMWebApp.Shared.Application.Services
{
@ -29,7 +30,7 @@ namespace TIAMWebApp.Shared.Application.Services
}
public async Task<string> CreatePaymentLinkAsync(Transfer transferToPay)
public async Task<string> CreatePaymentAsync(Transfer transferToPay)
{
var url = $"{Setting.ApiBaseUrl}/{APIUrls.CreatePayment}";
//var url = $"{APIUrls.GetTransferDestinations}";
@ -43,5 +44,146 @@ namespace TIAMWebApp.Shared.Application.Services
var paymentLink = result;
return paymentLink;
}
public async Task<string> GetPaymentAsync(string paymentId)
{
var url = $"{Setting.ApiBaseUrl}/{APIUrls.GetPaymentById}/"+paymentId;
//var url = $"{APIUrls.GetTransferDestinations}";
_logger.Info(url);
var jsonResponse = await _http.GetStringAsync(url);
if (jsonResponse == null || jsonResponse == "error")
return "error";
else
{
var checkoutResponse = JsonSerializer.Deserialize<GetPaymentResponse>(jsonResponse);
return checkoutResponse.Status;
}
}
}
public class GetPaymentResponse
{
[JsonPropertyName("amount")]
public double Amount { get; set; }
[JsonPropertyName("checkout_reference")]
public string CheckoutReference { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("customer_id")]
public string CustomerId { get; set; }
[JsonPropertyName("date")]
public DateTimeOffset Date { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("mandate")]
public Mandate Mandate { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("pay_to_email")]
public string PayToEmail { get; set; }
[JsonPropertyName("return_url")]
public string ReturnUrl { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("transactions")]
public Transaction[] Transactions { get; set; }
[JsonPropertyName("valid_until")]
public DateTime ValidUntil { get; set; }
[JsonPropertyName("merchant_name")]
public string MerchantName { get; set; }
[JsonPropertyName("payment_instrument")]
public PaymentInstrument PaymentInstrument { get; set; }
[JsonPropertyName("redirect_url")]
public string RedirectUrl { get; set; }
[JsonPropertyName("transaction_code")]
public string TransactionCode { get; set; }
[JsonPropertyName("transaction_id")]
public Guid TransactionId { get; set; }
}
public partial class Mandate
{
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
}
public partial class PaymentInstrument
{
[JsonPropertyName("token")]
public Guid Token { get; set; }
}
public partial class Transaction
{
[JsonPropertyName("amount")]
public double Amount { get; set; }
[JsonPropertyName("currency")]
public string Currency { get; set; }
[JsonPropertyName("id")]
public Guid Id { get; set; }
[JsonPropertyName("installments_count")]
public string InstallmentsCount { get; set; }
[JsonPropertyName("payment_type")]
public string PaymentType { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("timestamp")]
public DateTimeOffset Timestamp { get; set; }
[JsonPropertyName("transaction_code")]
public string TransactionCode { get; set; }
[JsonPropertyName("auth_code")]
public string AuthCode { get; set; }
[JsonPropertyName("entry_mode")]
public string EntryMode { get; set; }
[JsonPropertyName("internal_id")]
public long InternalId { get; set; }
[JsonPropertyName("merchant_code")]
public string MerchantCode { get; set; }
[JsonPropertyName("tip_amount")]
public long TipAmount { get; set; }
[JsonPropertyName("vat_amount")]
public long VatAmount { get; set; }
}
}