diff --git a/src/NoFrixion.MoneyMoov/Enums/AccountIdentifierType.cs b/src/NoFrixion.MoneyMoov/Enums/AccountIdentifierType.cs
index 08de7a5..fb82923 100755
--- a/src/NoFrixion.MoneyMoov/Enums/AccountIdentifierType.cs
+++ b/src/NoFrixion.MoneyMoov/Enums/AccountIdentifierType.cs
@@ -42,5 +42,10 @@ public enum AccountIdentifierType
///
/// Bitcoin address.
///
- BTC = 4
+ BTC = 4,
+
+ ///
+ /// Bank Identifier Code. Used for international payments. In addition to the BIC an account number and country code are required.
+ ///
+ BIC = 5
}
\ No newline at end of file
diff --git a/src/NoFrixion.MoneyMoov/Mapping/CounterpartyMappers.cs b/src/NoFrixion.MoneyMoov/Mapping/CounterpartyMappers.cs
old mode 100644
new mode 100755
diff --git a/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifier.cs b/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifier.cs
index 2ca53eb..886d5a6 100755
--- a/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifier.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifier.cs
@@ -8,6 +8,7 @@
// History:
// 21 10 2021 Donal O'Connor Created, Carmichael House, Dublin, Ireland.
// 19 09 2023 Aaron Clauson Added Bitcoin support.
+// 20 03 2025 Aaron Clauson Added support for BIC identifier type.
//
// License:
// MIT.
@@ -30,14 +31,18 @@ public AccountIdentifierType Type
{
get
{
- if(!string.IsNullOrWhiteSpace(IBAN))
+ if (!string.IsNullOrWhiteSpace(IBAN))
{
return AccountIdentifierType.IBAN;
}
- else if(!string.IsNullOrWhiteSpace(SortCode) && !string.IsNullOrWhiteSpace(AccountNumber))
+ else if (!string.IsNullOrWhiteSpace(SortCode))
{
return AccountIdentifierType.SCAN;
}
+ else if (!string.IsNullOrWhiteSpace(BIC))
+ {
+ return AccountIdentifierType.BIC;
+ }
return AccountIdentifierType.Unknown;
}
@@ -157,6 +162,7 @@ public string BitcoinAddress
public string Summary =>
Type == AccountIdentifierType.IBAN ? Type.ToString() + ": " + IBAN :
Type == AccountIdentifierType.SCAN ? Type.ToString() + ": " + DisplayScanSummary :
+ Type == AccountIdentifierType.BIC ? Type.ToString() + ": " + DisplayBicSummary :
"No identifier.";
///
@@ -165,6 +171,7 @@ public string BitcoinAddress
public string DisplaySummary =>
Type == AccountIdentifierType.IBAN ? IBAN :
Type == AccountIdentifierType.SCAN ? DisplayScanSummary :
+ Type == AccountIdentifierType.BIC ? DisplayBicSummary :
"No identifier.";
public string DisplayScanSummary =>
@@ -172,6 +179,8 @@ public string BitcoinAddress
? $"{SortCode[..2]}-{SortCode.Substring(2, 2)}-{SortCode.Substring(4, 2)} {AccountNumber}"
: $"{SortCode} {AccountNumber}";
+ public string DisplayBicSummary => $"{BIC} {AccountNumber}";
+
public bool IsSameDestination(AccountIdentifier other)
{
if (other == null)
@@ -188,6 +197,7 @@ public bool IsSameDestination(AccountIdentifier other)
{
AccountIdentifierType.IBAN => IBAN == other.IBAN,
AccountIdentifierType.SCAN => SortCode == other.SortCode && AccountNumber == other.AccountNumber,
+ AccountIdentifierType.BIC => BIC == other.BIC && AccountNumber == other.AccountNumber,
_ => false
};
}
@@ -200,7 +210,8 @@ public virtual Dictionary ToDictionary(string keyPrefix)
{ keyPrefix + nameof(BIC), BIC ?? string.Empty},
{ keyPrefix + nameof(IBAN), IBAN ?? string.Empty},
{ keyPrefix + nameof(SortCode), SortCode ?? string.Empty},
- { keyPrefix + nameof(AccountNumber), AccountNumber ?? string.Empty}
+ { keyPrefix + nameof(AccountNumber), AccountNumber ?? string.Empty},
+ { keyPrefix + nameof(BIC), BIC ?? string.Empty},
};
}
@@ -236,30 +247,36 @@ public NoFrixionProblem Validate()
public IEnumerable Validate(ValidationContext validationContext)
{
- switch (Currency)
+ switch (Type)
{
- // GBP & USD support both IBAN and SCAN.
- case CurrencyTypeEnum.GBP:
- case CurrencyTypeEnum.USD:
+ case AccountIdentifierType.IBAN:
+ if (string.IsNullOrWhiteSpace(IBAN))
{
- if (string.IsNullOrWhiteSpace(IBAN) &&
- (string.IsNullOrWhiteSpace(SortCode) || string.IsNullOrWhiteSpace(AccountNumber)))
+ yield return new ValidationResult(
+ $"The IBAN value is required for a {AccountIdentifierType.IBAN} identifier.",
+ [nameof(IBAN)]);
+ }
+ break;
+
+ case AccountIdentifierType.SCAN:
+ {
+ if (string.IsNullOrWhiteSpace(SortCode) || string.IsNullOrWhiteSpace(AccountNumber))
{
yield return new ValidationResult(
- $"Either the IBAN or Sort code and account number are required for a {Currency} account identifier.",
- [nameof(IBAN), nameof(SortCode), nameof(AccountNumber)]);
+ $"The sort code and account number are required for a {AccountIdentifierType.SCAN} identifier.",
+ [nameof(SortCode), nameof(AccountNumber)]);
}
break;
}
- // EUR only supports IBAN.
- case CurrencyTypeEnum.EUR:
+ case AccountIdentifierType.BIC:
{
- if (string.IsNullOrEmpty(IBAN))
+ if (string.IsNullOrWhiteSpace(BIC) || string.IsNullOrWhiteSpace(AccountNumber))
{
- yield return new ValidationResult("IBAN is required for EUR account identifier.",
- [nameof(IBAN)]);
+ yield return new ValidationResult(
+ $"The BIC and account number are required for a {AccountIdentifierType.BIC} identifier.",
+ [nameof(BIC), nameof(AccountNumber)]);
}
break;
@@ -267,8 +284,8 @@ public IEnumerable Validate(ValidationContext validationContex
default:
{
- yield return new ValidationResult($"Currency {Currency} was not recognised when validating an account identifier.",
- [nameof(Currency)]);
+ yield return new ValidationResult($"Identifier {Type} was not recognised when validating an account identifier.",
+ [nameof(Type)]);
break;
}
}
diff --git a/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifierCreate.cs b/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifierCreate.cs
index 349b76e..4d73e76 100755
--- a/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifierCreate.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Account/AccountIdentifierCreate.cs
@@ -85,7 +85,7 @@ public string SortCode
}
///
- /// Bank account number. Only applicable for SCAN identifiers.
+ /// Bank account number. Only applicable for SCAN and BIC identifiers.
///
private string _accountNumber;
public string AccountNumber
diff --git a/src/NoFrixion.MoneyMoov/Models/Account/CounterpartyCreate.cs b/src/NoFrixion.MoneyMoov/Models/Account/CounterpartyCreate.cs
index d53dbff..7e2c18e 100755
--- a/src/NoFrixion.MoneyMoov/Models/Account/CounterpartyCreate.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Account/CounterpartyCreate.cs
@@ -42,10 +42,18 @@ public class CounterpartyCreate
///
public string? EmailAddress { get; set; }
- /// An email address for the counterparty. Optional to set and depending on the payment
+ ///
+ /// A phone number for the counterparty. Optional to set and depending on the payment
/// network does not always get set for pay ins.
+ ///
public string? PhoneNumber { get; set; }
+ ///
+ /// A country code for the counterparty. Optional to set and depending on the payment
+ /// network does not always get set for pay ins
+ ///
+ public string? CountryCode { get; set; }
+
///
/// The counterparty's account identifier. This identifier is what is used to send the payment
/// to them, or for a pay in is the source of the payment.
@@ -61,6 +69,7 @@ public virtual Dictionary ToDictionary(string keyPrefix)
{ keyPrefix + nameof(Name), Name ?? string.Empty },
{ keyPrefix + nameof(EmailAddress), EmailAddress ?? string.Empty },
{ keyPrefix + nameof(PhoneNumber), PhoneNumber ?? string.Empty },
+ { keyPrefix + nameof(CountryCode), CountryCode ?? string.Empty },
};
if(Identifier != null)
diff --git a/src/NoFrixion.MoneyMoov/Models/Payouts/Payout.cs b/src/NoFrixion.MoneyMoov/Models/Payouts/Payout.cs
index fffb472..841140a 100755
--- a/src/NoFrixion.MoneyMoov/Models/Payouts/Payout.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Payouts/Payout.cs
@@ -308,13 +308,22 @@ public Counterparty? DestinationAccount
/// For Bitcoin payouts, when this flag is set the network fee will be deducted from the send amount.
/// THis is particularly useful for sweeps where it can be difficult to calculate the exact fee required.
///
+ [Obsolete]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Newtonsoft.Json.JsonIgnore]
public bool BitcoinSubtractFeeFromAmount { get; set; }
///
/// The Bitcoin fee rate to apply in Satoshis per virtual byte.
///
+ [Obsolete]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Newtonsoft.Json.JsonIgnore]
public int BitcoinFeeSatsPerVbyte { get; set; }
+ [Obsolete]
+ [System.Text.Json.Serialization.JsonIgnore]
+ [Newtonsoft.Json.JsonIgnore]
public string FormattedBitcoinFee => $"{BitcoinFeeSatsPerVbyte} sats/vbyte" +
(BitcoinSubtractFeeFromAmount ? " (fee will be subtracted from amount)" : "");
diff --git a/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutCreate.cs b/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutCreate.cs
index 0317683..098df4f 100755
--- a/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutCreate.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutCreate.cs
@@ -39,7 +39,7 @@ public class PayoutCreate
public CurrencyTypeEnum Currency { get; set; }
[Required(ErrorMessage = "Amount is required.")]
- [Range(0.00001, double.MaxValue,ErrorMessage = "Minimum value of 0.00001 is required for Amount")]
+ [Range(0.00001, double.MaxValue,ErrorMessage = "Minimum value of 0.01 is required for Amount")]
public decimal Amount { get; set; }
///
@@ -151,11 +151,13 @@ public CounterpartyCreate? DestinationAccount
///
/// For Bitcoin payouts, when this flag is set the network fee will be deducted from the send amount. This is particularly useful for sweeps where it can be difficult to calculate the exact fee required.
///
+ [Obsolete]
public bool BitcoinSubtractFeeFromAmount { get; set; }
///
/// The Bitcoin fee rate to apply in Satoshis per virtual byte.
///
+ [Obsolete]
public int BitcoinFeeSatsPerVbyte { get; set; }
///
diff --git a/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutsValidator.cs b/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutsValidator.cs
index deae778..9a659a9 100755
--- a/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutsValidator.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Payouts/PayoutsValidator.cs
@@ -371,7 +371,7 @@ public static IEnumerable Validate(Payout payout, ValidationCo
}
if (payout.Destination != null &&
- !(payout.Type == AccountIdentifierType.IBAN || payout.Type == AccountIdentifierType.SCAN))
+ !(payout.Type == AccountIdentifierType.IBAN || payout.Type == AccountIdentifierType.SCAN || payout.Type == AccountIdentifierType.BIC))
{
yield return new ValidationResult("Only destination types of IBAN and SCAN are supported.", [ nameof(payout.Type) ]);
}
diff --git a/src/NoFrixion.MoneyMoov/Models/Transaction/Counterparty.cs b/src/NoFrixion.MoneyMoov/Models/Transaction/Counterparty.cs
index 27c2990..2e03bdb 100755
--- a/src/NoFrixion.MoneyMoov/Models/Transaction/Counterparty.cs
+++ b/src/NoFrixion.MoneyMoov/Models/Transaction/Counterparty.cs
@@ -52,10 +52,18 @@ public class Counterparty
///
public string? EmailAddress { get; set; }
- /// An email address for the counterparty. Optional to set and depending on the payment
+ ///
+ /// A phone number for the counterparty. Optional to set and depending on the payment
/// network does not always get set for pay ins.
+ ///
public string? PhoneNumber { get; set; }
+ ///
+ /// A country code for the counterparty. Optional to set and depending on the payment
+ /// network does not always get set for pay ins
+ ///
+ public string? CountryCode { get; set; }
+
///
/// The counterparty's account identifier. This identifier is what is used to send the payment
/// to them, or for a pay in is the source of the payment.
@@ -113,6 +121,7 @@ public virtual Dictionary ToDictionary(string keyPrefix)
{ keyPrefix + nameof(Name), Name ?? string.Empty },
{ keyPrefix + nameof(EmailAddress), EmailAddress ?? string.Empty },
{ keyPrefix + nameof(PhoneNumber), PhoneNumber ?? string.Empty },
+ { keyPrefix + nameof(CountryCode), CountryCode ?? string.Empty },
};
if(Identifier != null)
@@ -135,6 +144,7 @@ public virtual string GetApprovalHash()
(!string.IsNullOrEmpty(Name) ? Name : string.Empty) +
(!string.IsNullOrEmpty(EmailAddress) ? EmailAddress : string.Empty) +
(!string.IsNullOrEmpty(PhoneNumber) ? PhoneNumber : string.Empty) +
+ (!string.IsNullOrEmpty(CountryCode) ? CountryCode : string.Empty) +
(Identifier != null ? Identifier.GetApprovalHash() : string.Empty);
return HashHelper.CreateHash(input);
}