diff --git a/src/CheckoutSdk/CheckoutApi.cs b/src/CheckoutSdk/CheckoutApi.cs index b310977d..979ba5e4 100644 --- a/src/CheckoutSdk/CheckoutApi.cs +++ b/src/CheckoutSdk/CheckoutApi.cs @@ -8,6 +8,7 @@ using Checkout.Forward; using Checkout.Instruments; using Checkout.Metadata; +using Checkout.NetworkTokens; using Checkout.Payments; using Checkout.Payments.Contexts; using Checkout.Payments.Hosted; @@ -45,6 +46,7 @@ public class CheckoutApi : ICheckoutApi private readonly IPaymentContextsClient _paymentContextsClient; private readonly IPaymentSessionsClient _paymentSessionsClient; private readonly IForwardClient _forwardClient; + private readonly INetworkTokensClient _networkTokensClient; public CheckoutApi(CheckoutConfiguration configuration) { @@ -75,6 +77,7 @@ public CheckoutApi(CheckoutConfiguration configuration) _paymentContextsClient = new PaymentContextsClient(baseApiClient, configuration); _paymentSessionsClient = new PaymentSessionsClient(baseApiClient, configuration); _forwardClient = new ForwardClient(baseApiClient, configuration); + _networkTokensClient = new NetworkTokensClient(baseApiClient, configuration); } private static ApiClient BaseApiClient(CheckoutConfiguration configuration) @@ -212,5 +215,11 @@ public IForwardClient ForwardClient() { return _forwardClient; } + + public INetworkTokensClient NetworkTokensClient() + { + return _networkTokensClient; + } + } -} \ No newline at end of file +} diff --git a/src/CheckoutSdk/Common/Resource.cs b/src/CheckoutSdk/Common/Resource.cs index d824460d..e986936a 100644 --- a/src/CheckoutSdk/Common/Resource.cs +++ b/src/CheckoutSdk/Common/Resource.cs @@ -23,6 +23,11 @@ public Link GetUploadLink() return GetLink("upload"); } + public Link GetCryptogramLink() + { + return GetLink("cryptogram"); + } + public bool HasLink(string relation) { return Links.ContainsKey(relation); diff --git a/src/CheckoutSdk/Forward/ForwardClient.cs b/src/CheckoutSdk/Forward/ForwardClient.cs index a460282e..4ffca6c1 100644 --- a/src/CheckoutSdk/Forward/ForwardClient.cs +++ b/src/CheckoutSdk/Forward/ForwardClient.cs @@ -1,11 +1,13 @@ using Checkout.Forward.Requests; using Checkout.Forward.Responses; -using System; using System.Threading; using System.Threading.Tasks; namespace Checkout.Forward { + /// + /// Forward + /// public class ForwardClient : AbstractClient, IForwardClient { private const string Forward = "forward"; @@ -15,6 +17,12 @@ public ForwardClient(IApiClient apiClient, CheckoutConfiguration configuration) { } + /// + /// Forward an API request + /// [BETA] + /// Forwards an API request to a third-party endpoint. + /// For example, you can forward payment credentials you've stored in our Vault to a third-party payment processor. + /// public Task ForwardAnApiRequest(ForwardRequest forwardRequest, CancellationToken cancellationToken = default) { @@ -27,6 +35,11 @@ public Task ForwardAnApiRequest(ForwardRequest forwardRequ ); } + /// + /// Get forward request + /// Retrieve the details of a successfully forwarded API request. + /// The details can be retrieved for up to 14 days after the request was initiated. + /// public Task GetForwardRequest(string forwardId, CancellationToken cancellationToken = default) { diff --git a/src/CheckoutSdk/Forward/IForwardClient.cs b/src/CheckoutSdk/Forward/IForwardClient.cs index bfe4bc05..8d192a9a 100644 --- a/src/CheckoutSdk/Forward/IForwardClient.cs +++ b/src/CheckoutSdk/Forward/IForwardClient.cs @@ -5,21 +5,24 @@ namespace Checkout.Forward { + /// + /// Forward + /// public interface IForwardClient { /// - /// Forward an API request
- /// Beta
- /// Forwards an API request to a third-party endpoint.
- /// For example, you can forward payment credentials you've stored in our Vault to a third-party payment processor. + /// Forward an API request + /// [BETA] + /// Forwards an API request to a third-party endpoint. + /// For example, you can forward payment credentials you've stored in our Vault to a third-party payment processor. ///
Task ForwardAnApiRequest(ForwardRequest forwardRequest, CancellationToken cancellationToken = default); /// - /// Get forward request
- /// Retrieve the details of a successfully forwarded API request.
- /// The details can be retrieved for up to 14 days after the request was initiated. + /// Get forward request + /// Retrieve the details of a successfully forwarded API request. + /// The details can be retrieved for up to 14 days after the request was initiated. ///
Task GetForwardRequest(string forwardId, CancellationToken cancellationToken = default); } diff --git a/src/CheckoutSdk/ICheckoutApi.cs b/src/CheckoutSdk/ICheckoutApi.cs index ac042857..9d924002 100644 --- a/src/CheckoutSdk/ICheckoutApi.cs +++ b/src/CheckoutSdk/ICheckoutApi.cs @@ -8,6 +8,7 @@ using Checkout.Forward; using Checkout.Instruments; using Checkout.Metadata; +using Checkout.NetworkTokens; using Checkout.Payments; using Checkout.Payments.Contexts; using Checkout.Payments.Hosted; @@ -65,5 +66,7 @@ public interface ICheckoutApi : ICheckoutApiClient IPaymentSessionsClient PaymentSessionsClient(); IForwardClient ForwardClient(); + + INetworkTokensClient NetworkTokensClient(); } -} \ No newline at end of file +} diff --git a/src/CheckoutSdk/NetworkTokens/Common/Responses/Card.cs b/src/CheckoutSdk/NetworkTokens/Common/Responses/Card.cs new file mode 100644 index 00000000..bf3b68df --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/Common/Responses/Card.cs @@ -0,0 +1,14 @@ +namespace Checkout.NetworkTokens.Common.Responses +{ + public class Card + { + /// The last four digits of the card number (Required, constraints: ^[0-9]{4}$) + public string Last4 { get; set; } + + /// The card's expiration month (Required, constraints: [ 1 .. 12 ], ^[0-9]{1,2}$) + public string ExpiryMonth { get; set; } + + /// The card's expiration year (Required, constraints: ^[0-9]{4}$) + public string ExpiryYear { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkToken.cs b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkToken.cs new file mode 100644 index 00000000..fbeebc9c --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkToken.cs @@ -0,0 +1,45 @@ +namespace Checkout.NetworkTokens.Common.Responses +{ + public class NetworkToken + { + /// Unique token ID assigned by Checkout.com for each token (Required) + public string Id { get; set; } + + /// Token status (Required) + public StateType State { get; set; } + + /// + /// The network token number. This field is only returned when the network token status is one of the + /// following: active, suspended, inactive (Constraints: ^[0-9]+$) + /// + public string Number { get; set; } + + /// + /// The network token's expiration month. This field is only returned when the network token status is + /// one of the following: active, suspended, inactive (Constraints: ^[0-9]{1,2}$) + /// + public string ExpiryMonth { get; set; } + + /// + /// The network token's expiration year. This field is only returned when the network token status is + /// one of the following: active, suspended, inactive (Constraints: ^[0-9]{4}$) + /// + public string ExpiryYear { get; set; } + + /// The type of token (Required) + public NetworkTokenType Type { get; set; } + + /// When the network token was created (Required) + public string CreatedOn { get; set; } + + /// When the network token was modified (Required) + public string ModifiedOn { get; set; } + + /// + /// Unique Payment account reference value assigned to payment account. All affiliated payment tokens, + /// as well as the underlying PAN, have the same payment_account_reference (Optional) + /// + public string PaymentAccountReference { get; set; } + + } +} diff --git a/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenResponse.cs b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenResponse.cs new file mode 100644 index 00000000..3d937a49 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenResponse.cs @@ -0,0 +1,16 @@ +using Checkout.Common; + +namespace Checkout.NetworkTokens.Common.Responses +{ + public class NetworkTokenResponse : Resource + { + /// The card details (Required) + public Card Card { get; set; } + + /// Network token details (Required) + public NetworkToken NetworkToken { get; set; } + + /// Token requestor ID (Optional) + public string TokenRequestorId { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenType.cs b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenType.cs new file mode 100644 index 00000000..b36635e0 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/Common/Responses/NetworkTokenType.cs @@ -0,0 +1,12 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.Common.Responses +{ + public enum NetworkTokenType + { + [EnumMember(Value = "vts")] Vts, + + [EnumMember(Value = "mdes")] Mdes, + + } +} diff --git a/src/CheckoutSdk/NetworkTokens/Common/Responses/StateType.cs b/src/CheckoutSdk/NetworkTokens/Common/Responses/StateType.cs new file mode 100644 index 00000000..0ad54446 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/Common/Responses/StateType.cs @@ -0,0 +1,22 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.Common.Responses +{ + public enum StateType + { + [EnumMember(Value = "active")] + Active, + + [EnumMember(Value = "suspended")] + Suspended, + + [EnumMember(Value = "inactive")] + Inactive, + + [EnumMember(Value = "declined")] + Declined, + + [EnumMember(Value = "requested")] + Requested + } +} diff --git a/src/CheckoutSdk/NetworkTokens/GetNetworkTokens/Responses/NetworkTokenByIdResponse.cs b/src/CheckoutSdk/NetworkTokens/GetNetworkTokens/Responses/NetworkTokenByIdResponse.cs new file mode 100644 index 00000000..4d5cfe0d --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/GetNetworkTokens/Responses/NetworkTokenByIdResponse.cs @@ -0,0 +1,9 @@ +using Checkout.NetworkTokens.Common.Responses; + +namespace Checkout.NetworkTokens.GetNetworkTokens.Responses +{ + public class NetworkTokenByIdResponse : NetworkTokenResponse + { + + } +} diff --git a/src/CheckoutSdk/NetworkTokens/INetworkTokensClient.cs b/src/CheckoutSdk/NetworkTokens/INetworkTokensClient.cs new file mode 100644 index 00000000..174f3a28 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/INetworkTokensClient.cs @@ -0,0 +1,59 @@ +using Checkout.NetworkTokens.GetNetworkTokens.Responses; +using Checkout.NetworkTokens.PatchDelete.Requests; +using Checkout.NetworkTokens.PostCryptograms.Requests; +using Checkout.NetworkTokens.PostCryptograms.Responses; +using Checkout.NetworkTokens.PostNetworkTokens.Requests; +using Checkout.NetworkTokens.PostNetworkTokens.Responses; +using System.Threading; +using System.Threading.Tasks; + +namespace Checkout.NetworkTokens +{ + /// + /// Network Tokens + /// + public interface INetworkTokensClient + { + /// + /// Provision a Network Token + /// [BETA] + /// Provisions a network token synchronously. If the merchant stores their cards with Checkout.com, then + /// source ID can be used to request a network token for the given card. If the merchant does not store their + /// cards with Checkout.com, then card details have to be provided. + /// + Task ProvisionANetworkToken( + ProvisionANetworkTokenRequest provisionANetworkTokenRequest, + CancellationToken cancellationToken = default); + + /// + /// Get Network Token + /// [BETA] + /// Given network token ID, this endpoint returns network token details: DPAN, expiry date, state, TRID and also + /// card details like last four and expiry date. + /// + Task GetNetworkToken( + string networkTokenId, + CancellationToken cancellationToken = default); + + /// + /// Request a cryptogram + /// [BETA] + /// Using network token ID as an input, this endpoint returns token cryptogram. + /// + Task RequestACryptogram( + string networkTokenId, + NetworkTokenCryptogramRequest networkTokenCryptogramRequest, + CancellationToken cancellationToken = default); + + /// + /// Permanently deletes a network token + /// [BETA] + /// This endpoint is for permanently deleting a network token. A network token should be deleted when a payment + /// instrument it is associated with is removed from file or if the security of the token has been compromised. + /// + Task PermanentlyDeletesANetworkToken( + string networkTokenId, + PermanentlyDeleteANetworkTokenRequest permanentlyDeleteANetworkTokenRequest, + CancellationToken cancellationToken = default); + } +} diff --git a/src/CheckoutSdk/NetworkTokens/NetworkTokensClient.cs b/src/CheckoutSdk/NetworkTokens/NetworkTokensClient.cs new file mode 100644 index 00000000..20ddde27 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/NetworkTokensClient.cs @@ -0,0 +1,108 @@ +using Checkout.NetworkTokens.GetNetworkTokens.Responses; +using Checkout.NetworkTokens.PatchDelete.Requests; +using Checkout.NetworkTokens.PostCryptograms.Requests; +using Checkout.NetworkTokens.PostCryptograms.Responses; +using Checkout.NetworkTokens.PostNetworkTokens.Requests; +using Checkout.NetworkTokens.PostNetworkTokens.Responses; +using System.Threading; +using System.Threading.Tasks; + +namespace Checkout.NetworkTokens +{ + /// + /// Network Tokens + /// + public class NetworkTokensClient : AbstractClient, INetworkTokensClient + { + private const string NetworkTokensPath = "network-tokens"; + private const string CryptogramsPath = "cryptograms"; + private const string DeletePath = "delete"; + + public NetworkTokensClient(IApiClient apiClient, + CheckoutConfiguration configuration) : + base(apiClient, configuration, SdkAuthorizationType.OAuth) + { + } + + /// + /// Provision a Network Token + /// [BETA] + /// Provisions a network token synchronously. If the merchant stores their cards with Checkout.com, then + /// source ID can be used to request a network token for the given card. If the merchant does not store their + /// cards with Checkout.com, then card details have to be provided. + /// + public Task ProvisionANetworkToken( + ProvisionANetworkTokenRequest provisionANetworkTokenRequest, + CancellationToken cancellationToken = default) + { + CheckoutUtils.ValidateParams("provisionANetworkTokenRequest", provisionANetworkTokenRequest); + return ApiClient.Post( + NetworkTokensPath, + SdkAuthorization(), + provisionANetworkTokenRequest, + cancellationToken); + } + + /// + /// Get Network Token + /// [BETA] + /// Given network token ID, this endpoint returns network token details: DPAN, expiry date, state, TRID and also + /// card details like last four and expiry date. + /// + public Task GetNetworkToken(string networkTokenId, + CancellationToken cancellationToken = default) + { + CheckoutUtils.ValidateParams("networkTokenId", networkTokenId); + return ApiClient.Get( + BuildPath(NetworkTokensPath, + networkTokenId), + SdkAuthorization(), + cancellationToken); + } + + /// + /// Request a cryptogram + /// [BETA] + /// Using network token ID as an input, this endpoint returns token cryptogram. + /// + public Task RequestACryptogram(string networkTokenId, + NetworkTokenCryptogramRequest networkTokenCryptogramRequest, + CancellationToken cancellationToken = default) + { + CheckoutUtils.ValidateParams("networkTokenId", + networkTokenId, + "networkTokenCryptogramRequest", + networkTokenCryptogramRequest); + return ApiClient.Post( + BuildPath(NetworkTokensPath, + networkTokenId, + CryptogramsPath), + SdkAuthorization(), + networkTokenCryptogramRequest, + cancellationToken); + } + + /// + /// Permanently deletes a network token + /// [BETA] + /// This endpoint is for permanently deleting a network token. A network token should be deleted when a payment + /// instrument it is associated with is removed from file or if the security of the token has been compromised. + /// + public Task PermanentlyDeletesANetworkToken(string networkTokenId, + PermanentlyDeleteANetworkTokenRequest permanentlyDeleteANetworkTokenRequest, + CancellationToken cancellationToken = default) + { + CheckoutUtils.ValidateParams("networkTokenId", + networkTokenId, + "permanentlyDeleteANetworkTokenRequest", + permanentlyDeleteANetworkTokenRequest); + return ApiClient.Patch( + BuildPath(NetworkTokensPath, + networkTokenId, + DeletePath), + SdkAuthorization(), + permanentlyDeleteANetworkTokenRequest, + cancellationToken); + } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/InitiatedByType.cs b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/InitiatedByType.cs new file mode 100644 index 00000000..ecdc5b77 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/InitiatedByType.cs @@ -0,0 +1,14 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.PatchDelete.Requests +{ + public enum InitiatedByType + { + [EnumMember(Value = "cardholder")] + Cardholder, + + [EnumMember(Value = "token_requestor")] + TokenRequestor, + + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/PermanentlyDeleteANetworkTokenRequest.cs b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/PermanentlyDeleteANetworkTokenRequest.cs new file mode 100644 index 00000000..cb490d57 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/PermanentlyDeleteANetworkTokenRequest.cs @@ -0,0 +1,11 @@ +namespace Checkout.NetworkTokens.PatchDelete.Requests +{ + public class PermanentlyDeleteANetworkTokenRequest + { + /// Who initiated/requested the deletion of the token. + public InitiatedByType InitiatedBy { get; set; } + + /// The reason for deletion the token. + public ReasonType Reason { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/ReasonType.cs b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/ReasonType.cs new file mode 100644 index 00000000..9b7b077f --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PatchDelete/Requests/ReasonType.cs @@ -0,0 +1,13 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.PatchDelete.Requests +{ + public enum ReasonType + { + [EnumMember(Value = "fraud")] + Fraud, + + [EnumMember(Value = "other")] + Other, + } +} \ No newline at end of file diff --git a/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/NetworkTokenCryptogramRequest.cs b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/NetworkTokenCryptogramRequest.cs new file mode 100644 index 00000000..81ba2d44 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/NetworkTokenCryptogramRequest.cs @@ -0,0 +1,8 @@ +namespace Checkout.NetworkTokens.PostCryptograms.Requests +{ + public class NetworkTokenCryptogramRequest + { + /// Transaction type the cryptogram is requested for. ยบ + public TransactionType TransactionType { get; set; } + } +} \ No newline at end of file diff --git a/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/TransactionType.cs b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/TransactionType.cs new file mode 100644 index 00000000..0d577f69 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Requests/TransactionType.cs @@ -0,0 +1,19 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.PostCryptograms.Requests +{ + public enum TransactionType + { + [EnumMember(Value = "ecom")] + Ecom, + + [EnumMember(Value = "recurring")] + Recurring, + + [EnumMember(Value = "pos")] + Pos, + + [EnumMember(Value = "aft")] + Aft, + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostCryptograms/Responses/NetworkTokenCryptogramResponse.cs b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Responses/NetworkTokenCryptogramResponse.cs new file mode 100644 index 00000000..876ff894 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostCryptograms/Responses/NetworkTokenCryptogramResponse.cs @@ -0,0 +1,16 @@ +using Checkout.Common; + +namespace Checkout.NetworkTokens.PostCryptograms.Responses +{ + public class NetworkTokenCryptogramResponse : Resource + { + /// + /// The cryptogram from the network token. Will only be refreshed for active network tokens and returned when + /// the network token isn't declined or pending + /// + public string Cryptogram { get; set; } + + /// Electronic Commerce Indicator (ECI) from the issuer. + public string Eci { get; set; } + } +} \ No newline at end of file diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/ProvisionANetworkTokenRequest.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/ProvisionANetworkTokenRequest.cs new file mode 100644 index 00000000..6a7a1604 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/ProvisionANetworkTokenRequest.cs @@ -0,0 +1,10 @@ +using Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources; + +namespace Checkout.NetworkTokens.PostNetworkTokens.Requests +{ + public class ProvisionANetworkTokenRequest + { + /// The source object (Required) + public AbstractSource Source { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/AbstractSource.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/AbstractSource.cs new file mode 100644 index 00000000..d866393d --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/AbstractSource.cs @@ -0,0 +1,9 @@ +namespace Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources +{ + public abstract class AbstractSource + { + /// The source type + public SourceType? Type { get; set; } + protected AbstractSource(SourceType type) { Type = type; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/CardSource.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/CardSource.cs new file mode 100644 index 00000000..9462df18 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/CardSource.cs @@ -0,0 +1,20 @@ +namespace Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources +{ + public class CardSource : AbstractSource + { + /// Initializes a new instance of the CardSource class. + public CardSource() : base(SourceType.Card) { } + + /// The card number (Required, constraints: [ 12 .. 19 ] characters, ^[0-9]+$, [ 12 .. 19 ]) + public string Number { get; set; } + + /// The expiry month of the card (Required, constraints: [ 1 .. 12 ], ^[0-9]{1,2}$) + public string ExpiryMonth { get; set; } + + /// The four-digit expiry year of the card (Required, constraints: ^[0-9]{4}$) + public string ExpiryYear { get; set; } + + /// The CVV number for the card (Optional, constraints: [ 1 .. 9999 ]) + public string Cvv { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/IdSource.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/IdSource.cs new file mode 100644 index 00000000..e81b7c0d --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/IdSource.cs @@ -0,0 +1,11 @@ +namespace Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources +{ + public class IdSource : AbstractSource + { + /// Initializes a new instance of the IdSource class. + public IdSource() : base(SourceType.Id) { } + + /// The card instrument (Required, constraints: ^(src)_(\w{26})$) + public string Id { get; set; } + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/SourceType.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/SourceType.cs new file mode 100644 index 00000000..00ab8e96 --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Requests/Sources/SourceType.cs @@ -0,0 +1,14 @@ +using System.Runtime.Serialization; + +namespace Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources +{ + public enum SourceType + { + [EnumMember(Value = "id")] + Id, + + [EnumMember(Value = "card")] + Card, + + } +} diff --git a/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Responses/ProvisionANetworkTokenResponse.cs b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Responses/ProvisionANetworkTokenResponse.cs new file mode 100644 index 00000000..25d92efa --- /dev/null +++ b/src/CheckoutSdk/NetworkTokens/PostNetworkTokens/Responses/ProvisionANetworkTokenResponse.cs @@ -0,0 +1,9 @@ +using Checkout.NetworkTokens.Common.Responses; + +namespace Checkout.NetworkTokens.PostNetworkTokens.Responses +{ + public class ProvisionANetworkTokenResponse : NetworkTokenResponse + { + + } +} diff --git a/src/CheckoutSdk/OAuthScope.cs b/src/CheckoutSdk/OAuthScope.cs index 29c41196..315baf5e 100644 --- a/src/CheckoutSdk/OAuthScope.cs +++ b/src/CheckoutSdk/OAuthScope.cs @@ -51,5 +51,6 @@ public enum OAuthScope [OAuthScope("issuing:transactions-read")] IssuingTransactionsRead, [OAuthScope("Payment Context")] PaymentContext, [OAuthScope("forward")] Forward, + [OAuthScope("vault:network-tokens")] VaultNetworkTokens, } } diff --git a/test/CheckoutSdkTest/NetworkTokens/NetworkTokenIntegrationTest.cs b/test/CheckoutSdkTest/NetworkTokens/NetworkTokenIntegrationTest.cs new file mode 100644 index 00000000..087476a9 --- /dev/null +++ b/test/CheckoutSdkTest/NetworkTokens/NetworkTokenIntegrationTest.cs @@ -0,0 +1,75 @@ +using Checkout.NetworkTokens.PatchDelete.Requests; +using Checkout.NetworkTokens.PostCryptograms.Requests; +using Checkout.NetworkTokens.PostNetworkTokens.Requests; +using Checkout.NetworkTokens.PostNetworkTokens.Requests.Sources; +using Shouldly; +using System.Threading.Tasks; +using Xunit; + +namespace Checkout.NetworkTokens +{ + public class NetworkTokenIntegrationTest : SandboxTestFixture + { + public NetworkTokenIntegrationTest() : base(PlatformType.DefaultOAuth) + { + } + + [Fact(Skip = "use on demand")] + private async Task ShouldProvisionANetworkToken() + { + var request = new ProvisionANetworkTokenRequest + { + Source = new IdSource() + { + Id = "src_wmlfc3zyhqzehihu7giusaaawu" + }, + }; + + var response = await DefaultApi.NetworkTokensClient().ProvisionANetworkToken(request); + + response.ShouldNotBeNull(); + response.Card.ShouldNotBeNull(); + response.NetworkToken.ShouldNotBeNull(); + } + + [Fact(Skip = "use on demand")] + private async Task ShouldGetNetworkToken() + { + var networkTokenId = "nt_xgu3isllqfyu7ktpk5z2yxbwna"; + var response = await DefaultApi.NetworkTokensClient().GetNetworkToken(networkTokenId); + + response.ShouldNotBeNull(); + response.Card.ShouldNotBeNull(); + response.NetworkToken.ShouldNotBeNull(); + } + + [Fact(Skip = "use on demand")] + private async Task ShouldGetNetworkTokens() + { + var networkTokenId = "nt_xgu3isllqfyu7ktpk5z2yxbwna"; + + var request = new NetworkTokenCryptogramRequest() { TransactionType = TransactionType.Ecom }; + + var response = await DefaultApi.NetworkTokensClient().RequestACryptogram(networkTokenId, request); + + response.ShouldNotBeNull(); + response.Cryptogram.ShouldNotBeEmpty(); + } + + [Fact(Skip = "use on demand")] + private async Task ShouldPatchNetworkToken() + { + var networkTokenId = "nt_xgu3isllqfyu7ktpk5z2yxbwna"; + + var request = new PermanentlyDeleteANetworkTokenRequest + { + InitiatedBy = InitiatedByType.TokenRequestor, Reason = ReasonType.Other + }; + + var response = await DefaultApi.NetworkTokensClient() + .PermanentlyDeletesANetworkToken(networkTokenId, request); + + response.HttpStatusCode.ShouldBe(204); + } + } +} diff --git a/test/CheckoutSdkTest/NetworkTokens/NetworkTokensClientTest.cs b/test/CheckoutSdkTest/NetworkTokens/NetworkTokensClientTest.cs new file mode 100644 index 00000000..a5f22710 --- /dev/null +++ b/test/CheckoutSdkTest/NetworkTokens/NetworkTokensClientTest.cs @@ -0,0 +1,125 @@ +using Checkout.NetworkTokens.GetNetworkTokens.Responses; +using Checkout.NetworkTokens.PatchDelete.Requests; +using Checkout.NetworkTokens.PostCryptograms.Requests; +using Checkout.NetworkTokens.PostCryptograms.Responses; +using Checkout.NetworkTokens.PostNetworkTokens.Requests; +using Checkout.NetworkTokens.PostNetworkTokens.Responses; +using Moq; +using Shouldly; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Checkout.NetworkTokens +{ + public class NetworkTokensClientTest : UnitTestFixture + { + private readonly SdkAuthorization _authorization = new SdkAuthorization(PlatformType.DefaultOAuth, ValidDefaultSk); + private readonly Mock _apiClient = new Mock(); + private readonly Mock _sdkCredentials = new Mock(PlatformType.DefaultOAuth); + private readonly Mock _httpClientFactory = new Mock(); + private readonly Mock _configuration; + + public NetworkTokensClientTest() + { + _sdkCredentials.Setup(credentials => credentials.GetSdkAuthorization(SdkAuthorizationType.OAuth)) + .Returns(_authorization); + + _configuration = new Mock(_sdkCredentials.Object, + Environment.Sandbox, _httpClientFactory.Object); + } + + [Fact] + private async Task ShouldProvisionANetworkToken() + { + ProvisionANetworkTokenRequest provisionANetworkTokenRequest = new ProvisionANetworkTokenRequest(); + ProvisionANetworkTokenResponse provisionANetworkTokenResponse = new ProvisionANetworkTokenResponse(); + + _apiClient.Setup(apiClient => + apiClient.Post( + "network-tokens", + _authorization, + provisionANetworkTokenRequest, + CancellationToken.None, null)) + .ReturnsAsync(() => provisionANetworkTokenResponse); + + INetworkTokensClient client = + new NetworkTokensClient(_apiClient.Object, _configuration.Object); + + ProvisionANetworkTokenResponse response = await client.ProvisionANetworkToken(provisionANetworkTokenRequest); + + response.ShouldNotBeNull(); + response.ShouldBeSameAs(provisionANetworkTokenResponse); + } + + [Fact] + private async Task ShouldGetNetworkToken() + { + string networkTokenId = "network_token_id"; + NetworkTokenByIdResponse networkTokenByIdResponse = new NetworkTokenByIdResponse(); + + _apiClient.Setup(apiClient => + apiClient.Get( + "network-tokens/" + networkTokenId, + _authorization, + CancellationToken.None)) + .ReturnsAsync(() => networkTokenByIdResponse); + + INetworkTokensClient client = + new NetworkTokensClient(_apiClient.Object, _configuration.Object); + + NetworkTokenByIdResponse response = await client.GetNetworkToken(networkTokenId); + + response.ShouldNotBeNull(); + response.ShouldBeSameAs(networkTokenByIdResponse); + } + + [Fact] + private async Task ShouldRequestACryptogram() + { + string networkTokenId = "network_token_id"; + NetworkTokenCryptogramRequest networkTokenCryptogramRequest = new NetworkTokenCryptogramRequest(); + NetworkTokenCryptogramResponse networkTokenCryptogramResponse = new NetworkTokenCryptogramResponse(); + + _apiClient.Setup(apiClient => + apiClient.Post( + "network-tokens/" + networkTokenId + "/cryptograms", + _authorization, + networkTokenCryptogramRequest, + CancellationToken.None, null)) + .ReturnsAsync(() => networkTokenCryptogramResponse); + + INetworkTokensClient client = + new NetworkTokensClient(_apiClient.Object, _configuration.Object); + + NetworkTokenCryptogramResponse response = await client.RequestACryptogram(networkTokenId, networkTokenCryptogramRequest); + + response.ShouldNotBeNull(); + response.ShouldBeSameAs(networkTokenCryptogramResponse); + } + + [Fact] + private async Task ShouldPermanentlyDeleteANetworkToken() + { + string networkTokenId = "network_token_id"; + PermanentlyDeleteANetworkTokenRequest permanentlyDeleteANetworkTokenRequest = new PermanentlyDeleteANetworkTokenRequest(); + EmptyResponse emptyResponse = new EmptyResponse(); + + _apiClient.Setup(apiClient => + apiClient.Patch( + "network-tokens/" + networkTokenId + "/delete", + _authorization, + permanentlyDeleteANetworkTokenRequest, + CancellationToken.None, null)) + .ReturnsAsync(() => emptyResponse); + + INetworkTokensClient client = + new NetworkTokensClient(_apiClient.Object, _configuration.Object); + + EmptyResponse response = await client.PermanentlyDeletesANetworkToken(networkTokenId, permanentlyDeleteANetworkTokenRequest); + + response.ShouldNotBeNull(); + response.ShouldBeSameAs(emptyResponse); + } + } +} \ No newline at end of file diff --git a/test/CheckoutSdkTest/TestCardSource.cs b/test/CheckoutSdkTest/TestCardSource.cs index 3f5fd4d9..ffd2bd0f 100644 --- a/test/CheckoutSdkTest/TestCardSource.cs +++ b/test/CheckoutSdkTest/TestCardSource.cs @@ -13,7 +13,7 @@ static TestCardSource() Visa.Name = "Mr. Test"; Visa.Number = "4242424242424242"; Visa.ExpiryMonth = 6; - Visa.ExpiryYear = 2025; + Visa.ExpiryYear = 2030; Visa.Cvv = "100"; }