Skip to content

Commit

Permalink
Adds a dedicated method for determining payment request expiry (#358)
Browse files Browse the repository at this point in the history
* Improve payment request expiry checking.

* Added pay by bank expiry method for payment attempts.

* Added new model for sandbox pay by bank simulations.
  • Loading branch information
sipsorcery authored Jun 17, 2024
1 parent afe98a5 commit 00e10a5
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 23 deletions.
34 changes: 17 additions & 17 deletions src/NoFrixion.MoneyMoov/Extensions/JsonExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,43 +22,43 @@ namespace NoFrixion.MoneyMoov;

public static class JsonExtensions
{
public static string ToJsonFlat<T>(this T obj)
=> obj.ToJsonFlatNewtonsoft();
public static string ToJsonFlat<T>(this T obj, bool usePascalCase = false)
=> obj.ToJsonFlatNewtonsoft(usePascalCase);

public static string ToJsonFormatted<T>(this T obj)
=> obj.ToJsonFormattedNewtonsoft();
public static string ToJsonFormatted<T>(this T obj, bool usePascalCase = false)
=> obj.ToJsonFormattedNewtonsoft(usePascalCase);

public static T? FromJson<T>(this string json)
=> json.FromJsonNewtonsoft<T>();
public static T? FromJson<T>(this string json, bool usePascalCase = false)
=> json.FromJsonNewtonsoft<T>(usePascalCase);

public static JsonContent ToJsonContent<T>(this T obj)
{
return JsonContent.Create(obj, options: MoneyMoovJson.GetSystemTextSerialiserOptions());
}

private static string ToJsonFlatSystemText<T>(this T obj)
private static string ToJsonFlatSystemText<T>(this T obj, bool usePascalCase = false)
=> System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions());

private static string ToJsonFormattedSystemText<T>(this T obj)
=> System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions(true));
private static string ToJsonFormattedSystemText<T>(this T obj, bool usePascalCase)
=> System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions(true, usePascalCase: usePascalCase));

private static T? FromJsonSystemText<T>(this string json)
private static T? FromJsonSystemText<T>(this string json, bool usePascalCase)
{
Guard.Against.NullOrWhiteSpace(json, nameof(json));

return System.Text.Json.JsonSerializer.Deserialize<T>(json, MoneyMoovJson.GetSystemTextSerialiserOptions());
return System.Text.Json.JsonSerializer.Deserialize<T>(json, MoneyMoovJson.GetSystemTextSerialiserOptions(usePascalCase: usePascalCase));
}

private static string ToJsonFlatNewtonsoft<T>(this T obj)
=> JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings());
private static string ToJsonFlatNewtonsoft<T>(this T obj, bool usePascalCase)
=> JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(usePascalCase: usePascalCase));

private static string ToJsonFormattedNewtonsoft<T>(this T obj)
=> JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(true));
private static string ToJsonFormattedNewtonsoft<T>(this T obj, bool usePascalCase)
=> JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(true, usePascalCase: usePascalCase));

private static T? FromJsonNewtonsoft<T>(this string json)
private static T? FromJsonNewtonsoft<T>(this string json, bool usePascalCase)
{
Guard.Against.NullOrWhiteSpace(json, nameof(json));

return JsonConvert.DeserializeObject<T>(json, MoneyMoovJson.GetNewtonsoftSerialiserSettings());
return JsonConvert.DeserializeObject<T>(json, MoneyMoovJson.GetNewtonsoftSerialiserSettings(usePascalCase: usePascalCase));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ namespace NoFrixion.MoneyMoov.Extensions;

public static class PaymentRequestPaymentAttemptExtensions
{
/// <summary>
/// When calculating if a payment request has expired this is the margin to
/// apply to the expiry date.
/// </summary>
private const int PAYBYBANK_EXPIRY_MARGIN_SECONDS = 10;

public static PaymentResultEnum GetPaymentAttemptStatus(this PaymentRequestPaymentAttempt attempt)
{
var amountReceived = attempt switch
Expand Down Expand Up @@ -71,4 +77,24 @@ public static decimal GetAmountAvailableToVoid(this PaymentRequestPaymentAttempt
attempt.RefundAttempts.Where(x => x.IsCardVoid)
.Sum(y => y.RefundSettledAmount);
}

/// <summary>
/// Used to check whether a pay by bank (pisp) attempt has expired after geing authorised.
/// The expiry occurs if the funds don't arrive into the destination account within the prescribed
/// period (e.g. 2 business days)
/// </summary>
/// <param name="attempt">The payment attempt to check the pay by bank expiry for.</param>
/// <param name="expiresAt">The point the pay by bank attempt should expire At.</param>
/// <returns>True if the attempt meets the criteria for expiry. False if not.</returns>
public static bool IsPayByBankExpired(this PaymentRequestPaymentAttempt attempt, DateTimeOffset expiresAt)
{
if(attempt.PaymentMethod != PaymentMethodTypeEnum.pisp ||
attempt.Status != PaymentResultEnum.Authorized ||
attempt.AuthorisedAt == null)
{
return false;
}

return expiresAt < DateTimeOffset.UtcNow.AddSeconds(PAYBYBANK_EXPIRY_MARGIN_SECONDS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
//-----------------------------------------------------------------------------
// Filename: PaymentRequestPispSandboxCallback.cs
//
// Description: Payment initiation callback model for pay by bank simulations.
//
// Author(s):
// Aaron Clauson ([email protected])
//
// History:
// 16 Jun 2024 Aaron Clauson Created, Stillorgan Wood, Dublin, Ireland.
//
// License:
// Proprietary NoFrixion.
//-----------------------------------------------------------------------------

namespace NoFrixion.MoneyMoov.Models;

public class PaymentRequestPispSandboxCallback
{
public decimal Amount { get; set; }

public string? Institution { get; set; }

public string? PaymentInitiationID { get; set; }

public string? ErrorDescription { get; set; }

public bool DoSimulateSettlementFailure { get; set; }
}
24 changes: 18 additions & 6 deletions src/NoFrixion.MoneyMoov/MoneyMoovJson.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,13 @@ namespace NoFrixion.MoneyMoov;

public class MoneyMoovJson
{
public static JsonSerializerOptions GetSystemTextSerialiserOptions(bool writeIndented = false)
public static JsonSerializerOptions GetSystemTextSerialiserOptions(bool writeIndented = false, bool usePascalCase = false)
{
return new JsonSerializerOptions
var options = new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
ReferenceHandler = ReferenceHandler.IgnoreCycles,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = writeIndented,
Converters =
{
Expand All @@ -49,21 +48,34 @@ public static JsonSerializerOptions GetSystemTextSerialiserOptions(bool writeInd
new NumericConverter<decimal>()
}
};

if(usePascalCase)
{
options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
}

return options;
}

public static JsonSerializerSettings GetNewtonsoftSerialiserSettings(bool writeIndented = false)
public static JsonSerializerSettings GetNewtonsoftSerialiserSettings(bool writeIndented = false, bool usePascalCase = false)
{
return new JsonSerializerSettings
var settings = new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
NullValueHandling = NullValueHandling.Ignore,
Formatting = writeIndented ? Formatting.Indented : Formatting.None,
ObjectCreationHandling = ObjectCreationHandling.Replace,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
Converters =
{
new Newtonsoft.Json.Converters.StringEnumConverter()
}
};

if(usePascalCase == false)
{
settings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}

return settings;
}
}

0 comments on commit 00e10a5

Please sign in to comment.