From 00e10a5359cff20fb3f7ecedd1a7b1bd5493f838 Mon Sep 17 00:00:00 2001 From: Aaron Clauson Date: Mon, 17 Jun 2024 09:37:44 +0100 Subject: [PATCH] Adds a dedicated method for determining payment request expiry (#358) * Improve payment request expiry checking. * Added pay by bank expiry method for payment attempts. * Added new model for sandbox pay by bank simulations. --- .../Extensions/JsonExtensions.cs | 34 +++++++++---------- .../PaymentRequestPaymentAttemptExtensions.cs | 26 ++++++++++++++ .../PaymentRequestPispSandboxCallback.cs | 29 ++++++++++++++++ src/NoFrixion.MoneyMoov/MoneyMoovJson.cs | 24 +++++++++---- 4 files changed, 90 insertions(+), 23 deletions(-) create mode 100755 src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestPispSandboxCallback.cs diff --git a/src/NoFrixion.MoneyMoov/Extensions/JsonExtensions.cs b/src/NoFrixion.MoneyMoov/Extensions/JsonExtensions.cs index c0219eb3..3b4af799 100755 --- a/src/NoFrixion.MoneyMoov/Extensions/JsonExtensions.cs +++ b/src/NoFrixion.MoneyMoov/Extensions/JsonExtensions.cs @@ -22,43 +22,43 @@ namespace NoFrixion.MoneyMoov; public static class JsonExtensions { - public static string ToJsonFlat(this T obj) - => obj.ToJsonFlatNewtonsoft(); + public static string ToJsonFlat(this T obj, bool usePascalCase = false) + => obj.ToJsonFlatNewtonsoft(usePascalCase); - public static string ToJsonFormatted(this T obj) - => obj.ToJsonFormattedNewtonsoft(); + public static string ToJsonFormatted(this T obj, bool usePascalCase = false) + => obj.ToJsonFormattedNewtonsoft(usePascalCase); - public static T? FromJson(this string json) - => json.FromJsonNewtonsoft(); + public static T? FromJson(this string json, bool usePascalCase = false) + => json.FromJsonNewtonsoft(usePascalCase); public static JsonContent ToJsonContent(this T obj) { return JsonContent.Create(obj, options: MoneyMoovJson.GetSystemTextSerialiserOptions()); } - private static string ToJsonFlatSystemText(this T obj) + private static string ToJsonFlatSystemText(this T obj, bool usePascalCase = false) => System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions()); - private static string ToJsonFormattedSystemText(this T obj) - => System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions(true)); + private static string ToJsonFormattedSystemText(this T obj, bool usePascalCase) + => System.Text.Json.JsonSerializer.Serialize(obj, MoneyMoovJson.GetSystemTextSerialiserOptions(true, usePascalCase: usePascalCase)); - private static T? FromJsonSystemText(this string json) + private static T? FromJsonSystemText(this string json, bool usePascalCase) { Guard.Against.NullOrWhiteSpace(json, nameof(json)); - return System.Text.Json.JsonSerializer.Deserialize(json, MoneyMoovJson.GetSystemTextSerialiserOptions()); + return System.Text.Json.JsonSerializer.Deserialize(json, MoneyMoovJson.GetSystemTextSerialiserOptions(usePascalCase: usePascalCase)); } - private static string ToJsonFlatNewtonsoft(this T obj) - => JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings()); + private static string ToJsonFlatNewtonsoft(this T obj, bool usePascalCase) + => JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(usePascalCase: usePascalCase)); - private static string ToJsonFormattedNewtonsoft(this T obj) - => JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(true)); + private static string ToJsonFormattedNewtonsoft(this T obj, bool usePascalCase) + => JsonConvert.SerializeObject(obj, MoneyMoovJson.GetNewtonsoftSerialiserSettings(true, usePascalCase: usePascalCase)); - private static T? FromJsonNewtonsoft(this string json) + private static T? FromJsonNewtonsoft(this string json, bool usePascalCase) { Guard.Against.NullOrWhiteSpace(json, nameof(json)); - return JsonConvert.DeserializeObject(json, MoneyMoovJson.GetNewtonsoftSerialiserSettings()); + return JsonConvert.DeserializeObject(json, MoneyMoovJson.GetNewtonsoftSerialiserSettings(usePascalCase: usePascalCase)); } } diff --git a/src/NoFrixion.MoneyMoov/Extensions/PaymentRequestPaymentAttemptExtensions.cs b/src/NoFrixion.MoneyMoov/Extensions/PaymentRequestPaymentAttemptExtensions.cs index f7dea18d..cb870367 100755 --- a/src/NoFrixion.MoneyMoov/Extensions/PaymentRequestPaymentAttemptExtensions.cs +++ b/src/NoFrixion.MoneyMoov/Extensions/PaymentRequestPaymentAttemptExtensions.cs @@ -19,6 +19,12 @@ namespace NoFrixion.MoneyMoov.Extensions; public static class PaymentRequestPaymentAttemptExtensions { + /// + /// When calculating if a payment request has expired this is the margin to + /// apply to the expiry date. + /// + private const int PAYBYBANK_EXPIRY_MARGIN_SECONDS = 10; + public static PaymentResultEnum GetPaymentAttemptStatus(this PaymentRequestPaymentAttempt attempt) { var amountReceived = attempt switch @@ -71,4 +77,24 @@ public static decimal GetAmountAvailableToVoid(this PaymentRequestPaymentAttempt attempt.RefundAttempts.Where(x => x.IsCardVoid) .Sum(y => y.RefundSettledAmount); } + + /// + /// 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) + /// + /// The payment attempt to check the pay by bank expiry for. + /// The point the pay by bank attempt should expire At. + /// True if the attempt meets the criteria for expiry. False if not. + 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); + } } \ No newline at end of file diff --git a/src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestPispSandboxCallback.cs b/src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestPispSandboxCallback.cs new file mode 100755 index 00000000..c8223e30 --- /dev/null +++ b/src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestPispSandboxCallback.cs @@ -0,0 +1,29 @@ +//----------------------------------------------------------------------------- +// Filename: PaymentRequestPispSandboxCallback.cs +// +// Description: Payment initiation callback model for pay by bank simulations. +// +// Author(s): +// Aaron Clauson (aaron@nofrixion.com) +// +// 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; } +} diff --git a/src/NoFrixion.MoneyMoov/MoneyMoovJson.cs b/src/NoFrixion.MoneyMoov/MoneyMoovJson.cs index 77e88b66..78bd029a 100755 --- a/src/NoFrixion.MoneyMoov/MoneyMoovJson.cs +++ b/src/NoFrixion.MoneyMoov/MoneyMoovJson.cs @@ -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 = { @@ -49,21 +48,34 @@ public static JsonSerializerOptions GetSystemTextSerialiserOptions(bool writeInd new NumericConverter() } }; + + 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; } }