Skip to content

Commit 57bdd5e

Browse files
authored
Deprecates the PaymentMethodTypes flag enum property in favour of a List (#432)
* Repalce use of flag enums on public payment request models with list for openapi generator compatibility. * Simplified use of old and new payment method types properties. * Add ulong handler to flag enum extenions methods.
1 parent 18d6605 commit 57bdd5e

File tree

12 files changed

+204
-20
lines changed

12 files changed

+204
-20
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//-----------------------------------------------------------------------------
2+
// Filename: GuidExtensions.cs
3+
//
4+
// Description: Contains extension methods for Guid types:
5+
//
6+
// Author(s):
7+
// Aaron Clauson ([email protected])
8+
//
9+
// History:
10+
// 15 Oct 2024 Aaron Clauson Created, Carne, Wexford, Ireland.
11+
//
12+
// License:
13+
// Proprietary NoFrixion.
14+
//-----------------------------------------------------------------------------
15+
16+
namespace NoFrixion.MoneyMoov;
17+
18+
public static class EnumExtensions
19+
{
20+
/// <summary>
21+
/// This method converts an Enum with the Flags attribute to a list of Enums.
22+
/// </summary>
23+
public static List<T> ToList<T>(this T flags) where T : Enum
24+
{
25+
if (!typeof(T).IsDefined(typeof(FlagsAttribute), false))
26+
{
27+
throw new ArgumentException("The type parameter T must have the Flags attribute.", nameof(flags));
28+
}
29+
30+
// Check if the enum underlying type is ulong
31+
var underlyingType = Enum.GetUnderlyingType(typeof(T));
32+
33+
if (underlyingType == typeof(ulong))
34+
{
35+
return Enum.GetValues(typeof(T))
36+
.Cast<T>()
37+
.Where(value => flags.HasFlag(value) && Convert.ToUInt64(value) != 0) // Exclude None or 0
38+
.ToList();
39+
}
40+
else
41+
{
42+
return Enum.GetValues(typeof(T))
43+
.Cast<T>()
44+
.Where(value => flags.HasFlag(value) && Convert.ToInt32(value) != 0) // Exclude None or 0
45+
.ToList();
46+
}
47+
}
48+
49+
/// <summary>
50+
/// This method converts list of flag enum values to a single flag enum.
51+
/// </summary>
52+
public static T ToFlagEnum<T>(this IEnumerable<T> enumValues) where T : Enum
53+
{
54+
if (!typeof(T).IsDefined(typeof(FlagsAttribute), false))
55+
{
56+
throw new ArgumentException("The type parameter T must have the Flags attribute.", nameof(enumValues));
57+
}
58+
59+
// Check if the enum underlying type is ulong
60+
var underlyingType = Enum.GetUnderlyingType(typeof(T));
61+
62+
if (underlyingType == typeof(ulong))
63+
{
64+
ulong result = 0UL;
65+
66+
foreach (var value in enumValues)
67+
{
68+
result |= Convert.ToUInt64(value);
69+
}
70+
71+
return (T)Enum.ToObject(typeof(T), result);
72+
}
73+
else
74+
{
75+
int result = 0;
76+
77+
foreach (var value in enumValues)
78+
{
79+
result |= Convert.ToInt32(value);
80+
}
81+
82+
return (T)Enum.ToObject(typeof(T), result);
83+
}
84+
}
85+
}

src/NoFrixion.MoneyMoov/JsonConverters/NumericConverter.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
// MIT.
1515
//-----------------------------------------------------------------------------
1616

17-
using LanguageExt;
1817
using System.ComponentModel;
1918
using System.Text.Json;
2019
using System.Text.Json.Serialization;

src/NoFrixion.MoneyMoov/Models/PaymentRequests/IPaymentRequest.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@ public interface IPaymentRequest
2626

2727
public string? OrderID { get; set; }
2828

29-
public PaymentMethodTypeEnum PaymentMethodTypes { get; set; }
29+
[Obsolete("This field has been deprecated. Please use PaymentMethods instead.")]
30+
public PaymentMethodTypeEnum PaymentMethodTypes { get; }
31+
32+
public List<PaymentMethodTypeEnum> PaymentMethods { get; set; }
3033

3134
public string? Description { get; set; }
3235

src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequest.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,17 @@ public class PaymentRequest : IPaymentRequest, IWebhookPayload
5757
/// The payment methods that the payment request supports. When setting using form data
5858
/// should be supplied as a comma separated list, for example "card, pisp, lightning".
5959
/// </summary>
60-
public PaymentMethodTypeEnum PaymentMethodTypes { get; set; } = PaymentMethodTypeEnum.card;
60+
[Obsolete("This field has been deprecated. Please use PaymentMethods instead.")]
61+
public PaymentMethodTypeEnum PaymentMethodTypes
62+
{
63+
get =>
64+
PaymentMethods.Any() ? PaymentMethods.ToFlagEnum() : PaymentMethodTypeEnum.None;
65+
}
66+
67+
/// <summary>
68+
/// The payment methods that the payment request supports.
69+
/// </summary>
70+
public List<PaymentMethodTypeEnum> PaymentMethods { get; set; } = new List<PaymentMethodTypeEnum>();
6171

6272
/// <summary>
6373
/// An optional description for the payment request. If set this field will appear

src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestCreate.cs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
//-----------------------------------------------------------------------------
1515

1616
using NoFrixion.MoneyMoov.Attributes;
17+
using NoFrixion.MoneyMoov.Json;
1718
using System.ComponentModel.DataAnnotations;
1819

1920
namespace NoFrixion.MoneyMoov.Models;
@@ -62,7 +63,28 @@ public class PaymentRequestCreate : IValidatableObject, IPaymentRequest
6263
/// The payment methods that the payment request supports. When setting using form data
6364
/// should be supplied as a comma separated list, for example "card, pisp, lightning".
6465
/// </summary>
65-
public PaymentMethodTypeEnum PaymentMethodTypes { get; set; } = PaymentMethodTypeEnum.card;
66+
[Obsolete("This field has been deprecated. Please use PaymentMethods instead.")]
67+
public PaymentMethodTypeEnum PaymentMethodTypes {
68+
get =>
69+
PaymentMethods.Any() ? PaymentMethods.ToFlagEnum() : PaymentMethodTypeEnum.None;
70+
71+
init
72+
{
73+
if(value == PaymentMethodTypeEnum.None)
74+
{
75+
PaymentMethods.Clear();
76+
}
77+
else
78+
{
79+
PaymentMethods = value.ToList();
80+
}
81+
}
82+
}
83+
84+
/// <summary>
85+
/// The payment methods that the payment request supports.
86+
/// </summary>
87+
public List<PaymentMethodTypeEnum> PaymentMethods { get; set; } = new() { PaymentMethodTypeEnum.card };
6688

6789
/// <summary>
6890
/// An optional description for the payment request. If set this field will appear
@@ -376,7 +398,6 @@ public Dictionary<string, string> ToDictionary()
376398
dict.Add(nameof(Currency), Currency.ToString());
377399
dict.Add(nameof(CustomerID), CustomerID ?? string.Empty);
378400
dict.Add(nameof(OrderID), OrderID ?? string.Empty);
379-
dict.Add(nameof(PaymentMethodTypes), PaymentMethodTypes.ToString());
380401
dict.Add(nameof(Description), Description ?? string.Empty);
381402
dict.Add(nameof(BaseOriginUrl), BaseOriginUrl!);
382403
dict.Add(nameof(CallbackUrl), CallbackUrl!);
@@ -407,6 +428,16 @@ public Dictionary<string, string> ToDictionary()
407428
dict.Add(nameof(PartialPaymentSteps), PartialPaymentSteps ?? string.Empty);
408429
dict.Add(nameof(NotificationEmailAddresses), NotificationEmailAddresses ?? string.Empty);
409430

431+
if (PaymentMethods?.Count() > 0)
432+
{
433+
int paymentMethodNumber = 0;
434+
foreach (var paymentMethod in PaymentMethods)
435+
{
436+
dict.Add($"{nameof(PaymentMethods)}[{paymentMethodNumber}]", paymentMethod.ToString());
437+
paymentMethodNumber++;
438+
}
439+
}
440+
410441
if (TagIds?.Count() > 0)
411442
{
412443
int tagIdNumber = 0;

src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestMinimal.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,17 @@ public class PaymentRequestMinimal
6969
/// The payment methods that the payment request supports. When setting using form data
7070
/// should be supplied as a comma separated list, for example "card, pisp, lightning, applePay".
7171
/// </summary>
72-
public PaymentMethodTypeEnum PaymentMethods { get; set; }
72+
[Obsolete("This field has been deprecated. Please use PaymentMethodsList instead.")]
73+
public PaymentMethodTypeEnum PaymentMethods
74+
{
75+
get =>
76+
PaymentMethodsList.Aggregate(PaymentMethodTypeEnum.None, (current, method) => current | method);
77+
}
78+
79+
/// <summary>
80+
/// The payment methods that the payment request supports.
81+
/// </summary>
82+
public List<PaymentMethodTypeEnum> PaymentMethodsList { get; set; } = new List<PaymentMethodTypeEnum>();
7383

7484
/// <summary>
7585
/// This is the error returned from the bank which is recorded in payment request events.

src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestUpdate.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,37 @@ public class PaymentRequestUpdate
4545
/// The payment methods that the payment request supports. When setting using form data
4646
/// should be supplied as a comma separated list, for example "card, pisp, lightning".
4747
/// </summary>
48-
public PaymentMethodTypeEnum? PaymentMethodTypes { get; set; }
48+
[Obsolete("This field has been deprecated. Please use PaymentMethods instead.")]
49+
public PaymentMethodTypeEnum? PaymentMethodTypes
50+
{
51+
get =>
52+
PaymentMethods != null && PaymentMethods.Any() ? PaymentMethods.ToFlagEnum() : PaymentMethodTypeEnum.None;
53+
54+
init
55+
{
56+
if (value != null)
57+
{
58+
if (PaymentMethods == null)
59+
{
60+
PaymentMethods = new();
61+
}
62+
63+
if (value == PaymentMethodTypeEnum.None)
64+
{
65+
PaymentMethods.Clear();
66+
}
67+
else
68+
{
69+
PaymentMethods = value.Value.ToList();
70+
}
71+
}
72+
}
73+
}
74+
75+
/// <summary>
76+
/// The payment methods that the payment request supports.
77+
/// </summary>
78+
public List<PaymentMethodTypeEnum>? PaymentMethods { get; set; }
4979

5080
/// <summary>
5181
/// An optional description for the payment request. If set this field will appear
@@ -248,7 +278,6 @@ public Dictionary<string, string> ToDictionary()
248278
if (Currency != null) dict.Add(nameof(Currency), Currency.Value.ToString());
249279
if (CustomerID != null) dict.Add(nameof(CustomerID), CustomerID);
250280
if (OrderID != null) dict.Add(nameof(OrderID), OrderID);
251-
if (PaymentMethodTypes != null) dict.Add(nameof(PaymentMethodTypes), PaymentMethodTypes.Value.ToString());
252281
if (Description != null) dict.Add(nameof(Description), Description);
253282
if (PispAccountID != null) dict.Add(nameof(PispAccountID), PispAccountID.GetValueOrDefault().ToString());
254283
if (ShippingFirstName != null) dict.Add(nameof(ShippingFirstName), ShippingFirstName);
@@ -274,6 +303,16 @@ public Dictionary<string, string> ToDictionary()
274303
if (Title != null) dict.Add(nameof(Title), Title);
275304
if (PartialPaymentSteps != null) dict.Add(nameof(PartialPaymentSteps), PartialPaymentSteps);
276305

306+
if (PaymentMethods?.Count() > 0)
307+
{
308+
int paymentMethodNumber = 0;
309+
foreach (var paymentMethod in PaymentMethods)
310+
{
311+
dict.Add($"{nameof(PaymentMethods)}[{paymentMethodNumber}]", paymentMethod.ToString());
312+
paymentMethodNumber++;
313+
}
314+
}
315+
277316
return dict;
278317
}
279318
}

src/NoFrixion.MoneyMoov/Models/PaymentRequests/PaymentRequestValidator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ public static IEnumerable<ValidationResult> Validate(
3030
IPaymentRequest paymentRequest,
3131
ValidationContext validationContext)
3232
{
33+
#pragma warning disable CS0618 // Type or member is obsolete
3334
if (paymentRequest.PaymentMethodTypes == PaymentMethodTypeEnum.None)
3435
{
3536
yield return new ValidationResult($"At least one payment method type must be specified.", new string[] { nameof(paymentRequest.PaymentMethodTypes) });
3637
}
38+
3739
if (paymentRequest.PaymentMethodTypes.HasFlag(PaymentMethodTypeEnum.pisp) &&
3840
paymentRequest.Currency == CurrencyTypeEnum.EUR &&
3941
!ValidateAmount(paymentRequest.Amount, paymentRequest.PaymentMethodTypes, paymentRequest.Currency))
@@ -66,6 +68,7 @@ public static IEnumerable<ValidationResult> Validate(
6668
yield return new ValidationResult($"The amount can only be set to 0 when the payment methods are set to a single option of card.",
6769
new string[] { nameof(paymentRequest.Amount) });
6870
}
71+
#pragma warning restore CS0618 // Type or member is obsolete
6972

7073
if (!string.IsNullOrEmpty(paymentRequest.BaseOriginUrl))
7174
{

test/MoneyMoov.UnitTests/Mapping/CsvMapperTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ public void CarDealer_Payment_Request_Create_Success()
104104
Assert.Equal(39400M, results[0].Model.Amount);
105105
Assert.Equal(CurrencyTypeEnum.EUR, results[0].Model.Currency);
106106
Assert.Equal("5001834", results[0].Model.OrderID);
107+
#pragma warning disable CS0618 // Type or member is obsolete
107108
Assert.Equal(PaymentMethodTypeEnum.pisp, results[0].Model.PaymentMethodTypes);
109+
#pragma warning restore CS0618 // Type or member is obsolete
108110
Assert.Equal("RANGE ROVER TDV8", results[0].Model.Description);
109111
Assert.Equal("Jane", results[0].Model.ShippingFirstName);
110112
Assert.Equal("Doe", results[0].Model.ShippingLastName);
@@ -160,7 +162,9 @@ public void CarDealer_UpdateSep2023_Payment_Request_Create_Success()
160162
Assert.Equal(10000M, results[0].Model.Amount);
161163
Assert.Equal(CurrencyTypeEnum.EUR, results[0].Model.Currency);
162164
Assert.Equal("5002027", results[0].Model.OrderID);
165+
#pragma warning disable CS0618 // Type or member is obsolete
163166
Assert.Equal(PaymentMethodTypeEnum.pisp, results[0].Model.PaymentMethodTypes);
167+
#pragma warning restore CS0618 // Type or member is obsolete
164168
Assert.Equal("Order for car XXX", results[0].Model.Description);
165169
Assert.Equal(string.Empty, results[0].Model.ShippingFirstName);
166170
Assert.Equal(string.Empty, results[0].Model.ShippingLastName);

test/MoneyMoov.UnitTests/Models/PaymentRequestCreateTests.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ public void Create_PaymentRequest_Zero_Amount_Failure()
161161
Currency = CurrencyTypeEnum.EUR,
162162
CallbackUrl = "https://localhost/good",
163163
BaseOriginUrl = "https://localhost",
164-
PaymentMethodTypes = PaymentMethodTypeEnum.card | PaymentMethodTypeEnum.lightning
164+
PaymentMethods = new() { PaymentMethodTypeEnum.card, PaymentMethodTypeEnum.lightning }
165165
};
166166

167167
var context = new ValidationContext(this, serviceProvider: null, items: null);
@@ -231,7 +231,7 @@ public void Create_PaymentRequestCreate_Amount_Too_Low_EUR_PIS()
231231
Amount = 0.99M,
232232
Currency = CurrencyTypeEnum.EUR,
233233
CallbackUrl = "https://localhost/callback",
234-
PaymentMethodTypes = PaymentMethodTypeEnum.pisp
234+
PaymentMethods = new() { PaymentMethodTypeEnum.pisp }
235235
};
236236

237237
var validationProb = paymentRequest.Validate();
@@ -251,7 +251,7 @@ public void Create_PaymentRequestCreate_EUR_PIS()
251251
Amount = 1.00M,
252252
Currency = CurrencyTypeEnum.EUR,
253253
CallbackUrl = "https://localhost/callback",
254-
PaymentMethodTypes = PaymentMethodTypeEnum.pisp
254+
PaymentMethods = new() { PaymentMethodTypeEnum.pisp }
255255
};
256256

257257
var validationProb = paymentRequest.Validate();
@@ -271,7 +271,7 @@ public void Create_PaymentRequestCreate_Amount_Too_Low_GBP_PIS()
271271
Amount = 1.99M,
272272
Currency = CurrencyTypeEnum.GBP,
273273
CallbackUrl = "https://localhost/callback",
274-
PaymentMethodTypes = PaymentMethodTypeEnum.pisp
274+
PaymentMethods = new() { PaymentMethodTypeEnum.pisp }
275275
};
276276

277277
var validationProb = paymentRequest.Validate();
@@ -291,7 +291,7 @@ public void Create_PaymentRequestCreate_GBP_PIS()
291291
Amount = 2.00M,
292292
Currency = CurrencyTypeEnum.GBP,
293293
CallbackUrl = "https://localhost/callback",
294-
PaymentMethodTypes = PaymentMethodTypeEnum.pisp
294+
PaymentMethods = new() { PaymentMethodTypeEnum.pisp }
295295
};
296296

297297
var validationProb = paymentRequest.Validate();
@@ -312,7 +312,7 @@ public void Create_PaymentRequestCreate_Card_Token_With_Customer_Email()
312312
Currency = CurrencyTypeEnum.EUR,
313313
CallbackUrl = "https://localhost/callback",
314314
BaseOriginUrl = "https://localhost",
315-
PaymentMethodTypes = PaymentMethodTypeEnum.card,
315+
PaymentMethods = new() { PaymentMethodTypeEnum.card },
316316
CardCreateToken = true,
317317
CardCreateTokenMode = CardTokenCreateModes.ConsentNotRequired,
318318
CustomerEmailAddress = "[email protected]"
@@ -336,7 +336,7 @@ public void Create_PaymentRequestCreate_Card_Token_But_No_Customer_Email()
336336
Currency = CurrencyTypeEnum.GBP,
337337
CallbackUrl = "https://localhost/callback",
338338
BaseOriginUrl = "https://localhost",
339-
PaymentMethodTypes = PaymentMethodTypeEnum.card,
339+
PaymentMethods = new() { PaymentMethodTypeEnum.card },
340340
CardCreateToken = true
341341
};
342342

@@ -359,7 +359,7 @@ public void Create_PaymentRequestCreate_Card_Token_With_Invalid_Customer_Email()
359359
Currency = CurrencyTypeEnum.EUR,
360360
CallbackUrl = "https://localhost/callback",
361361
BaseOriginUrl = "https://localhost",
362-
PaymentMethodTypes = PaymentMethodTypeEnum.card,
362+
PaymentMethods = new() { PaymentMethodTypeEnum.card },
363363
CardCreateToken = true,
364364
CustomerEmailAddress = "qa-nofrixion.com"
365365
};

0 commit comments

Comments
 (0)