Skip to content

Commit 1bad829

Browse files
authored
Moov4785 payout four places for internal (#641)
* Allow 4 decimal place resolution for internal fait payouts. * Added tests for fait payout resol ution depdending on internal or external destination.
1 parent 8ea20af commit 1bad829

File tree

10 files changed

+120
-42
lines changed

10 files changed

+120
-42
lines changed

src/NoFrixion.MoneyMoov/Constants/PaymentsConstants.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ namespace NoFrixion.MoneyMoov;
1919
public static class PaymentsConstants
2020
{
2121
/// <summary>
22-
/// Round fiat (EUR, GBP etc) amounts to this many decimal places.
22+
/// Round fiat (EUR, GBP etc) amounts to this many decimal places for external payouts.
2323
/// </summary>
24-
public const int FIAT_ROUNDING_DECIMAL_PLACES = 2;
24+
public const int FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL = 2;
25+
26+
/// <summary>
27+
/// Internal payouts and transactions can optionally be specified down to 4 decimal places.
28+
/// </summary>
29+
public const int FIAT_ROUNDING_DECIMAL_PLACES_INTERNAL = 4;
2530

2631
/// <summary>
2732
/// Bitcoin Satoshis use 8 decimal places.

src/NoFrixion.MoneyMoov/Extensions/AmountMinorUnitExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public static long ToAmountMinorUnits(this decimal amount, CurrencyTypeEnum curr
2222
{
2323
decimal units = currency switch
2424
{
25-
var c when c.IsFiat() => amount * (int)Math.Pow(10, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
25+
var c when c.IsFiat() => amount * (int)Math.Pow(10, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
2626
CurrencyTypeEnum.BTC => amount * (int)Math.Pow(10, PaymentsConstants.BITCOIN_ROUNDING_DECIMAL_PLACES),
2727
_ => throw new ApplicationException($"Currency {currency} was not recognised in {nameof(ToAmountMinorUnits)}.")
2828
};

src/NoFrixion.MoneyMoov/Extensions/CurrencyExtensions.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,4 @@ public static bool IsFiat(this CurrencyTypeEnum currency) =>
3434
CurrencyTypeEnum.BTC => false,
3535
_ => true
3636
};
37-
38-
public static int GetDecimalPlaces(this CurrencyTypeEnum currency) =>
39-
currency switch
40-
{
41-
CurrencyTypeEnum.BTC => PaymentsConstants.BITCOIN_ROUNDING_DECIMAL_PLACES,
42-
_ => PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES
43-
};
4437
}

src/NoFrixion.MoneyMoov/Extensions/PaymentAmount.cs

100644100755
Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
// Proprietary NoFrixion.
1414
//-----------------------------------------------------------------------------
1515

16+
using System.Globalization;
17+
1618
namespace NoFrixion.MoneyMoov;
1719

1820
public static class PaymentAmount
@@ -23,10 +25,29 @@ public static class PaymentAmount
2325
public static string DisplayCurrencyAndAmount(CurrencyTypeEnum currency, decimal amount) =>
2426
currency.GetCurrencySymbol() + " " + GetDisplayAmount(currency, amount);
2527

26-
public static string GetDisplayAmount(CurrencyTypeEnum currency, decimal amount) =>
27-
currency.IsFiat() ? amount.ToString("N2") : amount.ToString("N8");
28+
// Decide decimals once, reuse everywhere.
29+
private static int GetDecimalPlaces(CurrencyTypeEnum currency, decimal amount)
30+
{
31+
if (!currency.IsFiat())
32+
{
33+
return PaymentsConstants.BITCOIN_ROUNDING_DECIMAL_PLACES;
34+
}
35+
36+
return decimal.Remainder(decimal.Abs(amount), 0.01m) != 0m
37+
? PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_INTERNAL // 4 decimal places option for internal payouts.
38+
: PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL; // 2 decimal places for external payouts.
39+
}
40+
41+
public static string GetDisplayAmount(CurrencyTypeEnum currency, decimal amount, IFormatProvider? culture = null)
42+
{
43+
var dps = GetDecimalPlaces(currency, amount);
44+
return amount.ToString($"N{dps}", culture ?? CultureInfo.CurrentCulture);
45+
}
2846

29-
public static decimal GetRoundedAmount(CurrencyTypeEnum currency, decimal amount) =>
30-
Math.Round(amount, currency.IsFiat() ? PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES : PaymentsConstants.BITCOIN_ROUNDING_DECIMAL_PLACES);
47+
public static decimal GetRoundedAmount(CurrencyTypeEnum currency, decimal amount, MidpointRounding mode = MidpointRounding.ToEven)
48+
{
49+
var dps = GetDecimalPlaces(currency, amount);
50+
return Math.Round(amount, dps, mode);
51+
}
3152
}
3253

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ public decimal DisplayAmount()
209209
return EventType switch
210210
{
211211
PaymentRequestEventTypesEnum.lightning_invoice_created => Math.Round(Amount, PaymentsConstants.BITCOIN_LIGHTNING_ROUNDING_DECIMAL_PLACES),
212-
_ => Math.Round(Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES)
212+
_ => Math.Round(Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL)
213213
};
214214
}
215215

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,15 @@ public PaymentRequestResult(PaymentRequest paymentRequest)
181181
OccurredAt = attempt.InitiatedAt,
182182
PaymentMethod = PaymentMethodTypeEnum.card,
183183
Amount = Math.Round(attempt.CardAuthorisedAmount,
184-
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
184+
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
185185
Currency = attempt.Currency,
186186
CardCapturedAmount = Math.Round(attempt.CaptureAttempts.Sum(x => x.CapturedAmount),
187-
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
187+
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
188188
CardAuthorizationID = attempt.AttemptKey,
189189
TokenisedCardID = attempt.TokenisedCardID,
190190
PaymentProcessor = attempt.PaymentProcessor,
191191
RefundedAmount = Math.Round(attempt.RefundAttempts.Sum(x => x.RefundSettledAmount),
192-
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
192+
PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
193193
CardIsVoided =
194194
attempt.CardAuthorisedAmount - attempt.RefundAttempts.Sum(x => x.RefundSettledAmount) == 0
195195
});
@@ -208,9 +208,9 @@ public PaymentRequestResult(PaymentRequest paymentRequest)
208208
PaymentRequestID = PaymentRequestID,
209209
OccurredAt = attempt.InitiatedAt,
210210
PaymentMethod = PaymentMethodTypeEnum.pisp,
211-
Amount = Math.Round(attempt.SettledAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
211+
Amount = Math.Round(attempt.SettledAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
212212
Currency = attempt.Currency,
213-
RefundedAmount = Math.Round(attempt.RefundAttempts.Sum(x => x.RefundSettledAmount), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
213+
RefundedAmount = Math.Round(attempt.RefundAttempts.Sum(x => x.RefundSettledAmount), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
214214
});
215215
}
216216
else if (attempt.Status == PaymentResultEnum.Authorized)
@@ -221,7 +221,7 @@ public PaymentRequestResult(PaymentRequest paymentRequest)
221221
PaymentRequestID = PaymentRequestID,
222222
OccurredAt = attempt.InitiatedAt,
223223
PaymentMethod = PaymentMethodTypeEnum.pisp,
224-
Amount = Math.Round(attempt.AuthorisedAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
224+
Amount = Math.Round(attempt.AuthorisedAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
225225
Currency = attempt.Currency,
226226
PispPaymentInitiationID = attempt.AttemptKey
227227
});
@@ -240,9 +240,9 @@ public PaymentRequestResult(PaymentRequest paymentRequest)
240240
PaymentRequestID = PaymentRequestID,
241241
OccurredAt = attempt.InitiatedAt,
242242
PaymentMethod = PaymentMethodTypeEnum.directDebit,
243-
Amount = Math.Round(attempt.SettledAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
243+
Amount = Math.Round(attempt.SettledAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
244244
Currency = attempt.Currency,
245-
RefundedAmount = Math.Round(attempt.RefundAttempts.Sum(x => x.RefundSettledAmount), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
245+
RefundedAmount = Math.Round(attempt.RefundAttempts.Sum(x => x.RefundSettledAmount), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
246246
});
247247
}
248248
else if (attempt.Status == PaymentResultEnum.Authorized)
@@ -253,7 +253,7 @@ public PaymentRequestResult(PaymentRequest paymentRequest)
253253
PaymentRequestID = PaymentRequestID,
254254
OccurredAt = attempt.InitiatedAt,
255255
PaymentMethod = PaymentMethodTypeEnum.directDebit,
256-
Amount = Math.Round(attempt.AuthorisedAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES),
256+
Amount = Math.Round(attempt.AuthorisedAmount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL),
257257
Currency = attempt.Currency,
258258
});
259259
}
@@ -286,7 +286,7 @@ public decimal AmountOutstanding()
286286
var outstanding = Currency switch
287287
{
288288
CurrencyTypeEnum.BTC => RequestedAmount - Amount,
289-
_ => Math.Round(RequestedAmount - (Amount + PispAmountAuthorized()), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES)
289+
_ => Math.Round(RequestedAmount - (Amount + PispAmountAuthorized()), PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL)
290290
};
291291

292292
return outstanding >= 0 ? outstanding : 0;

src/NoFrixion.MoneyMoov/Models/Payouts/PayoutCreate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public class PayoutCreate
4444
/// - For multi-currency payouts this property is optional. If FxDestinationAmount is set this field must be set to 0
4545
/// and it will be dynamically adjusted based on the FX rate.
4646
/// </summary>
47-
[Range(0.01, double.MaxValue,ErrorMessage = "Minimum value of 0.01 is required for Amount.")]
47+
[Range(0.0001, double.MaxValue, ErrorMessage = "Minimum value of 0.0001 is required for Amount.")]
4848
public decimal? Amount { get; set; }
4949

5050
/// <summary>

src/NoFrixion.MoneyMoov/Models/Payouts/PayoutsValidator.cs

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

17-
using LanguageExt;
1817
using System.ComponentModel.DataAnnotations;
1918
using System.Text;
2019
using System.Text.RegularExpressions;
@@ -70,7 +69,6 @@ public static class PayoutsValidator
7069
[Obsolete("Modulr is no longer used.")]
7170
public const string THEIR_REFERENCE_NON_COUNTED_CHARS_MODULR_REGEX = @"[\.\-/&\s]";
7271

73-
7472
/// <summary>
7573
/// The External Reference, or Your reference, field is the one that gets set locally on the
7674
/// payer's transaction record. It does not get sent out through the payment network.
@@ -127,9 +125,14 @@ public static class PayoutsValidator
127125
"comma (,), single quote ('), plus (+) and space. The total length must not exceed {1} characters. The first character cannot be ':' or '-'.";
128126

129127
/// <summary>
130-
/// Fiat currencies are only allowed to be specified to two decimal places.
128+
/// Fiat currencies are only allowed to be specified to two decimal places when being used for an external payout.
129+
/// </summary>
130+
public const decimal FIAT_CURRENCY_RESOLUTION_EXTERNAL = 0.01M;
131+
132+
/// <summary>
133+
/// Fiat currencies can be specified to four decimal places when being used for an internal payout.
131134
/// </summary>
132-
public const decimal FIAT_CURRENCY_RESOLUTION = 0.01M;
135+
public const decimal FIAT_CURRENCY_RESOLUTION_INTERNAL = 0.0001M;
133136

134137
/// <summary>
135138
/// The minimum amount that must be set for the source or destination amount when dong a multi-currency payout.
@@ -311,12 +314,17 @@ public static IEnumerable<ValidationResult> Validate(Payout payout, ValidationCo
311314
yield return new ValidationResult($"Amount must be supplied when FxUseDestinationAmount is false.", [ nameof(payout.Amount) ]);
312315
}
313316

314-
if (payout.Amount > 0 && payout.Currency.IsFiat() && payout.Amount % FIAT_CURRENCY_RESOLUTION != 0)
317+
if (payout.Amount > 0 && payout.Currency.IsFiat() && payout.Destination?.AccountID == null && payout.Amount % FIAT_CURRENCY_RESOLUTION_EXTERNAL != 0)
315318
{
316319
yield return new ValidationResult($"The payout amount must only be specified to two decimal places for currency {payout.Currency}.", [ nameof(payout.Amount) ]);
317320
}
318321

319-
if (payout.FxDestinationAmount > 0 && payout.FxDestinationCurrency != null && payout.FxDestinationCurrency.Value.IsFiat() && payout.FxDestinationAmount % FIAT_CURRENCY_RESOLUTION != 0)
322+
if (payout.Amount > 0 && payout.Currency.IsFiat() && payout.Destination?.AccountID != null && payout.Amount % FIAT_CURRENCY_RESOLUTION_INTERNAL != 0)
323+
{
324+
yield return new ValidationResult($"The payout amount must only be specified to four decimal places for currency {payout.Currency} and an internal destination.", [nameof(payout.Amount)]);
325+
}
326+
327+
if (payout.FxDestinationAmount > 0 && payout.FxDestinationCurrency != null && payout.FxDestinationCurrency.Value.IsFiat() && payout.FxDestinationAmount % FIAT_CURRENCY_RESOLUTION_EXTERNAL != 0)
320328
{
321329
yield return new ValidationResult($"The payout FxDestinationAmount must only be specified to two decimal places for currency {payout.FxDestinationCurrency}.", [nameof(payout.FxDestinationAmount)]);
322330
}

test/MoneyMoov.UnitTests/Models/PaymentRequestResultTests.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ public void Multiple_Pisp_Success_Events_With_One_Settle_Event_PartiallyPaid_Res
520520
entity.Events = new List<PaymentRequestEvent> { yapilyCompletedEvent, plaidExecutedEvent, yapilyCompletedWebhookEvent, pisSettleEvent };
521521
var result = new PaymentRequestResult(entity);
522522

523-
Assert.Equal(Math.Round(entity.Amount / 3, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.Amount);
523+
Assert.Equal(Math.Round(entity.Amount / 3, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.Amount);
524524
Assert.Equal(entity.Currency, result.Currency);
525525
Assert.Equal(PaymentResultEnum.PartiallyPaid, result.Result);
526526
}
@@ -597,9 +597,9 @@ public void Mixed_Payment_Events_Check_Outstanding_Amount()
597597
entity.Events = new List<PaymentRequestEvent> { yapilyCompletedEvent, plaidExecutedEvent, yapilyCompletedWebhookEvent, pisSettleEvent };
598598
var result = new PaymentRequestResult(entity);
599599

600-
Assert.Equal(Math.Round(entity.Amount / 4, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.Amount);
601-
Assert.Equal(Math.Round(entity.Amount / 4, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.PispAmountAuthorized());
602-
Assert.Equal(Math.Round((entity.Amount / 4) * 2, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.AmountOutstanding());
600+
Assert.Equal(Math.Round(entity.Amount / 4, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.Amount);
601+
Assert.Equal(Math.Round(entity.Amount / 4, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.PispAmountAuthorized());
602+
Assert.Equal(Math.Round((entity.Amount / 4) * 2, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.AmountOutstanding());
603603
Assert.Equal(entity.Currency, result.Currency);
604604
Assert.Equal(PaymentResultEnum.PartiallyPaid, result.Result);
605605
}
@@ -652,9 +652,9 @@ public void Payment_Events_With_Zero_Amount_Check_Outstanding_Amount()
652652
entity.Events = new List<PaymentRequestEvent> { yapilyCompletedWebhookEvent, yapilyInitiatedEvent, yapilyCompletedEvent };
653653
var result = new PaymentRequestResult(entity);
654654

655-
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.Amount);
656-
Assert.Equal(Math.Round(entity.Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.PispAmountAuthorized());
657-
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.AmountOutstanding());
655+
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.Amount);
656+
Assert.Equal(Math.Round(entity.Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.PispAmountAuthorized());
657+
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.AmountOutstanding());
658658
Assert.Equal(entity.Currency, result.Currency);
659659
Assert.Equal(PaymentResultEnum.Authorized, result.Result);
660660
}
@@ -721,9 +721,9 @@ public void Payment_Events_Mulitple_PIS_Failures_NonAuthorized_Status()
721721
entity.Events = new List<PaymentRequestEvent> { plaidWebHookEvent, plaidInitiatedEvent, yapilyInitiatedEvent, yapilyAuthorisationErrorEvent };
722722
var result = new PaymentRequestResult(entity);
723723

724-
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.Amount);
725-
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.PispAmountAuthorized());
726-
Assert.Equal(Math.Round(entity.Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES), result.AmountOutstanding());
724+
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.Amount);
725+
Assert.Equal(Math.Round(decimal.Zero, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.PispAmountAuthorized());
726+
Assert.Equal(Math.Round(entity.Amount, PaymentsConstants.FIAT_ROUNDING_DECIMAL_PLACES_EXTERNAL), result.AmountOutstanding());
727727
Assert.Equal(entity.Currency, result.Currency);
728728
Assert.Equal(PaymentResultEnum.None, result.Result);
729729
}

test/MoneyMoov.UnitTests/Models/PayoutsValidatorTests.cs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,57 @@ public void Payout_Validator_Currency_Resolution(CurrencyTypeEnum currency, deci
482482
{
483483
Assert.False(result.IsEmpty);
484484
}
485+
}
486+
487+
/// <summary>
488+
/// Tests that the currency resolution check is working as expected for an internal payout where 4 decimal places
489+
/// of resolution are supported.
490+
/// </summary>
491+
[Theory]
492+
[InlineData(CurrencyTypeEnum.EUR, 0.01, true)]
493+
[InlineData(CurrencyTypeEnum.EUR, 0.001, true)]
494+
[InlineData(CurrencyTypeEnum.EUR, 0.0001, true)]
495+
[InlineData(CurrencyTypeEnum.EUR, 0.00001, false)]
496+
[InlineData(CurrencyTypeEnum.GBP, 0.01, true)]
497+
[InlineData(CurrencyTypeEnum.GBP, 0.001, true)]
498+
[InlineData(CurrencyTypeEnum.GBP, 0.0001, true)]
499+
[InlineData(CurrencyTypeEnum.GBP, 0.00001, false)]
500+
[InlineData(CurrencyTypeEnum.USD, 0.01, true)]
501+
[InlineData(CurrencyTypeEnum.USD, 0.001, true)]
502+
[InlineData(CurrencyTypeEnum.USD, 0.0001, true)]
503+
[InlineData(CurrencyTypeEnum.USD, 0.00001, false)]
504+
public void Payout_Internal_Validator_Currency_Resolution(CurrencyTypeEnum currency, decimal amount, bool isValid)
505+
{
506+
var payout = new Payout
507+
{
508+
ID = Guid.NewGuid(),
509+
AccountID = Guid.NewGuid(),
510+
Type = AccountIdentifierType.IBAN,
511+
Currency = currency,
512+
Amount = amount,
513+
YourReference = "your ref",
514+
TheirReference = "their ref",
515+
Status = PayoutStatus.PENDING_INPUT,
516+
InvoiceID = "18ead957-e3bc-4b12-b5c6-d12e4bef9d24",
517+
Destination = new Counterparty
518+
{
519+
Name = "Joe Bloggs",
520+
AccountID = Guid.NewGuid()
521+
}
522+
};
523+
524+
var result = payout.Validate();
525+
526+
_logger.LogDebug(result.ToTextErrorMessage());
527+
528+
if (isValid)
529+
{
530+
Assert.True(result.IsEmpty);
531+
}
532+
else
533+
{
534+
Assert.False(result.IsEmpty);
535+
}
485536
}
486537

487538
/// <summary>

0 commit comments

Comments
 (0)