Skip to content

Commit

Permalink
Merge pull request #14 from VladiTitov/feature/create_requests_from_c…
Browse files Browse the repository at this point in the history
…lient_ability_implementation

Added the ability to create requests via Wallet Pay Client from outside
  • Loading branch information
VladiTitov committed Jun 13, 2024
2 parents b556592 + 0604c04 commit 65d6665
Show file tree
Hide file tree
Showing 18 changed files with 367 additions and 13 deletions.
11 changes: 11 additions & 0 deletions src/Wallet.Pay/Enums/Currency.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
namespace Wallet.Pay.Enums;

public enum Currency
{
TON,
NOT,
BTC,
USDT,
EUR,
USD,
RUB
}

public enum ConversionCurrency
{
TON,
NOT,
Expand Down
2 changes: 2 additions & 0 deletions src/Wallet.Pay/Enums/ResponseStatus.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ public enum ResponseStatus
{
SUCCESS,
ALREADY,
CONFLICT,
ACCESS_DENIED,
INVALID_REQUEST,
INTERNAL_ERROR
}
100 changes: 100 additions & 0 deletions src/Wallet.Pay/Extensions/WalletPayClientExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Wallet.Pay.Requests.Orders;
using Wallet.Pay.Responses.Orders;

namespace Wallet.Pay.Extensions;

public static class WalletPayClientExtensions
{
/// <summary>
/// Create an order
/// </summary>
/// <param name="walletPayClient"></param>
/// <param name="amount"></param>
/// <param name="currency"></param>
/// <param name="description">Description of the order</param>
/// <param name="externalId">Order ID in Merchant system. Use to prevent orders duplication due to request retries</param>
/// <param name="timeoutSeconds">Order TTL, if the order is not paid within the timeout period</param>
/// <param name="customerTelegramUserId">The customer's telegram id (User_id)</param>
/// <param name="autoConversionCurrency">Crypto currency you want to receive no matter what crypto currency the payer will choose to pay.</param>
/// <param name="returnUrl">Url to redirect after paying order</param>
/// <param name="failReturnUrl">Url to redirect after unsuccessful order completion</param>
/// <param name="customData">Any custom string, will be provided through webhook and order status polling</param>
/// <param name="cancellationToken"></param>
/// <returns>CreateOrderResponse</returns>
public static Task<IResponse<CreateOrderResponse>> CreateOrderAsync(
this IWalletPayClient walletPayClient,
double amount,
Currency currency,
string description,
string externalId,
int timeoutSeconds,
int customerTelegramUserId,
ConversionCurrency? autoConversionCurrency = null,
string? returnUrl = default,
string? failReturnUrl = default,
string? customData = default,
CancellationToken cancellationToken = default)
=> walletPayClient.MakeRequestAsync(
request: new CreateOrderRequest()
{
Amount = new()
{
CurrencyCode = currency,
Value = amount.ToString()
},
Description = description,
ExternalId = externalId,
TimeoutSeconds = timeoutSeconds,
CustomerTelegramUserId = customerTelegramUserId,
AutoConversionCurrency = autoConversionCurrency,
ReturnUrl = returnUrl,
FailReturnUrl = failReturnUrl,
CustomData = customData
},
cancellationToken: cancellationToken);

/// <summary>
/// Retrieve the order information
/// </summary>
/// <param name="walletPayClient"></param>
/// <param name="id">Order id</param>
/// <param name="cancellationToken"></param>
/// <returns>GetPreviewOrderResponse</returns>
public static Task<IResponse<GetPreviewOrderResponse>> GetPreviewOrderAsync(
this IWalletPayClient walletPayClient,
string id,
CancellationToken cancellationToken = default)
=> walletPayClient.MakeRequestAsync(
request: new GetPreviewOrderRequest(id),
cancellationToken: cancellationToken);

/// <summary>
/// Return list of store orders sorted by creation time in ascending order
/// </summary>
/// <param name="walletPayClient"></param>
/// <param name="offset">Specifying the amount of excluded from a response the first N orders</param>
/// <param name="count">Specifying the limit of orders for the request</param>
/// <param name="cancellationToken"></param>
/// <returns>GetOrderListResponse</returns>
public static Task<IResponse<GetOrderListResponse>> GetOrderListAsync(
this IWalletPayClient walletPayClient,
int offset,
int count,
CancellationToken cancellationToken = default)
=> walletPayClient.MakeRequestAsync(
request: new GetOrderListRequest(offset, count),
cancellationToken: cancellationToken);

/// <summary>
/// Returns total count of all created orders in the Store, including all - paid and unpaid
/// </summary>
/// <param name="walletPayClient"></param>
/// <param name="cancellationToken"></param>
/// <returns>GetOrderAmountResponse</returns>
public static Task<IResponse<GetOrderAmountResponse>> GetOrderAmountAsync(
this IWalletPayClient walletPayClient,
CancellationToken cancellationToken = default)
=> walletPayClient.MakeRequestAsync(
request: new GetOrderAmountRequest(),
cancellationToken: cancellationToken);
}
12 changes: 11 additions & 1 deletion src/Wallet.Pay/IWalletPayClient.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
namespace Wallet.Pay;

/// <summary>
/// A client interface to use the Telegram Wallet Pay API
/// </summary>
public interface IWalletPayClient
{
Task<ResponseBase<TResponse>?> MakeRequestAsync<TResponse>(
/// <summary>
/// Send a request to Wallet Pay API
/// </summary>
/// <typeparam name="TResponse">Type of expected result in the response object</typeparam>
/// <param name="request">API request object</param>
/// <param name="cancellationToken"></param>
/// <returns>Result of the API request</returns>
Task<IResponse<TResponse>> MakeRequestAsync<TResponse>(
IRequest<TResponse> request,
CancellationToken cancellationToken = default) where TResponse : class;
}
14 changes: 14 additions & 0 deletions src/Wallet.Pay/Models/Amount.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
namespace Wallet.Pay.Models;

/// <summary>
/// Amount model
/// </summary>
#nullable disable
public class Amount
{
/// <summary>
/// Big decimal string representation.
/// Note that the max precision (number of digits after decimal point) depends on the currencyCode.
/// E.g. for all fiat currencies is 2 (0.01), for TON is 9, for BTC is 8, for USDT is 6.
/// There's also min order amount for creating an order.
/// It's 0.001 TON / 0.000001 BTC / 0.01 USDT / 0.01 USD / 0.01 EUR / 0.1 RUB.
/// </summary>
[JsonProperty("amount")]
public string Value { get; set; }

/// <summary>
/// Currency code
/// </summary>
public Currency CurrencyCode { get; set; }
}
28 changes: 27 additions & 1 deletion src/Wallet.Pay/Models/Order.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
namespace Wallet.Pay.Models;

/// <summary>
/// Order model
/// </summary>
#nullable disable
public class Order
{
/// <summary>
/// Order id
/// </summary>
public string Id { get; set; }

/// <summary>
/// Order status
/// </summary>
public OrderStatus Status { get; set; }

/// <summary>
/// <see cref="Amount"/>
/// </summary>
public Amount Amount { get; set; }
public Currency AutoConversionCurrency { get; set; }

/// <summary>
/// Crypto currency you want to receive no matter what crypto currency the payer will choose to pay.
/// </summary>
public Currency? AutoConversionCurrency { get; set; }

/// <summary>
/// ISO-8601 date time when order was created
/// </summary>
public DateTimeOffset CreatedDateTime { get; set; }

/// <summary>
/// ISO-8601 date time when order timeout expires
/// </summary>
public DateTimeOffset ExpirationDateTime { get; set; }
}
16 changes: 16 additions & 0 deletions src/Wallet.Pay/Requests/IRequest.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
namespace Wallet.Pay.Requests;

/// <summary>
/// Represents a request interface to Wallet Pay API
/// </summary>
/// <typeparam name="TResponse">Type of result expected in result</typeparam>
public interface IRequest<TResponse>
{
/// <summary>
/// HTTP method of request
/// </summary>
HttpMethod Method { get; }

/// <summary>
/// API uri path
/// </summary>
string UriPath { get; }

/// <summary>
/// Generate content of HTTP message
/// </summary>
/// <returns>Content of HTTP request</returns>
HttpContent? ToHttpContent();
}
46 changes: 42 additions & 4 deletions src/Wallet.Pay/Requests/Orders/CreateOrderRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,51 @@ namespace Wallet.Pay.Requests.Orders;
internal class CreateOrderRequest()
: RequestBase<CreateOrderResponse>("wpay/store-api/v1/order")
{
/// <summary>
/// <see cref="Amount"/>
/// </summary>
public Amount Amount { get; set; }
public string AutoConversionCurrency { get; set; }

/// <summary>
/// Description of the order
/// </summary>
public string Description { get; set; }
public string ReturnUrl { get; set; }
public string FailReturnUrl { get; set; }
public string CustomData { get; set; }

/// <summary>
/// Order ID in Merchant system. Use to prevent orders duplication due to request retries
/// </summary>
public string ExternalId { get; set; }

/// <summary>
/// Order TTL, if the order is not paid within the timeout period
/// </summary>
public int TimeoutSeconds { get; set; }

/// <summary>
/// The customer's telegram id (User_id). For more details please follow the link
/// </summary>
public int CustomerTelegramUserId { get; set; }

#nullable enable
/// <summary>
/// Crypto currency you want to receive no matter what crypto currency the payer will choose to pay
/// </summary>
public ConversionCurrency? AutoConversionCurrency { get; set; }

/// <summary>
/// Url to redirect after paying order.
/// Note: if you want to open your telegram WebApp (https://core.telegram.org/bots/webapps)
/// then you should use special link format here (https://core.telegram.org/api/links#named-bot-web-app-links).
/// </summary>
public string? ReturnUrl { get; set; }

/// <summary>
/// Url to redirect after unsuccessful order completion (expiration/cancelation/etc)
/// </summary>
public string? FailReturnUrl { get; set; }

/// <summary>
/// Any custom string, will be provided through webhook and order status polling
/// </summary>
public string? CustomData { get; set; }
}
10 changes: 10 additions & 0 deletions src/Wallet.Pay/Requests/RequestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

namespace Wallet.Pay.Requests;

/// <summary>
/// Represents a request to Wallet Pay API
/// </summary>
/// <typeparam name="TResponse">Type of result expected in result</typeparam>
/// <param name="uriPath">API uri path</param>
/// <param name="method">HTTP method of request</param>
public class RequestBase<TResponse>(
string uriPath, HttpMethod method) : IRequest<TResponse>
{
Expand All @@ -15,6 +21,10 @@ public RequestBase(string uriPath)
: this(uriPath, HttpMethod.Post)
{ }

/// <summary>
/// Generate content of HTTP message
/// </summary>
/// <returns>Content of HTTP request</returns>
public HttpContent? ToHttpContent()
{
var content = JsonConvert.SerializeObject(
Expand Down
21 changes: 17 additions & 4 deletions src/Wallet.Pay/Responses/IResponse.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,23 @@
using Wallet.Pay.Enums;
namespace Wallet.Pay.Responses;

namespace Wallet.Pay.Responses;

internal interface IResponse<TResponse>
/// <summary>
/// API response interface
/// </summary>
/// <typeparam name="TResponse">Type of result expected in result</typeparam>
public interface IResponse<TResponse>
{
/// <summary>
/// Response status
/// </summary>
public ResponseStatus Status { get; set; }

/// <summary>
/// Verbose reason of non-success result
/// </summary>
public string Message { get; set; }

/// <summary>
/// Response payload, present if status is SUCCESS
/// </summary>
public TResponse Data { get; set; }
}
19 changes: 19 additions & 0 deletions src/Wallet.Pay/Responses/Orders/CreateOrderResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,27 @@ namespace Wallet.Pay.Responses.Orders;
#nullable disable
public class CreateOrderResponse : Order
{
/// <summary>
/// Human-readable short order id shown to a customer
/// </summary>
public string Number { get; set; }

/// <summary>
/// ISO-8601 date time when order was completed (paid/expired/etc)
/// </summary>
public DateTimeOffset CompletedDateTime { get; set; }

/// <summary>
/// URL to be shown to the payer by the store. Сan be used in 'Telegram Bot' only.
/// Important: this link can be opened ONLY in dialog with Telegram-bot specified in your Store,
/// ONLY by user with telegramUserId specified in the Order.
/// </summary>
public string PayLink { get; set; }

/// <summary>
/// URL to be shown to the payer by the store. Can be used in 'Telegram Bot' and 'Telegram Web App'.
/// Important: this link can be opened ONLY in dialog with Telegram-bot specified in your Store,
/// ONLY by user with telegramUserId specified in the Order.
/// </summary>
public string DirectPayLink { get; set; }
}
3 changes: 3 additions & 0 deletions src/Wallet.Pay/Responses/Orders/GetOrderAmountResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
#nullable disable
public class GetOrderAmountResponse
{
/// <summary>
/// Store orders total amount
/// </summary>
public string TotalAmount { get; set; }
}
Loading

0 comments on commit 65d6665

Please sign in to comment.