Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/Viincenttt/MollieApi
Browse files Browse the repository at this point in the history
  • Loading branch information
Viincenttt committed Mar 5, 2019
2 parents 17dbe28 + 0502be1 commit 544cf2f
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 28 deletions.
6 changes: 5 additions & 1 deletion Mollie.Api/Client/Abstract/IOrganizationsClient.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
using System.Threading.Tasks;
using Mollie.Api.Models.List;
using Mollie.Api.Models.Organization;
using Mollie.Api.Models.Url;

namespace Mollie.Api.Client.Abstract {
public interface IOrganizationsClient {
public interface IOrganizationsClient
{
Task<OrganizationResponse> GetCurrentOrganizationAsync();
Task<OrganizationResponse> GetOrganizationAsync(string organizationId);
Task<ListResponse<OrganizationResponse>> GetOrganizationsListAsync(string from = null, int? limit = null);
Task<OrganizationResponse> GetOrganizationAsync(UrlObjectLink<OrganizationResponse> url);
}
}
6 changes: 3 additions & 3 deletions Mollie.Api/Client/Abstract/IPaymentMethodClient.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
using System.Threading.Tasks;
using Mollie.Api.Models;
using Mollie.Api.Models.List;

using Mollie.Api.Models.Payment;
using Mollie.Api.Models.PaymentMethod;
using Mollie.Api.Models.Url;

namespace Mollie.Api.Client.Abstract {
public interface IPaymentMethodClient {
Task<PaymentMethodResponse> GetPaymentMethodAsync(PaymentMethod paymentMethod, bool? includeIssuers = null, string locale = null);
Task<ListResponse<PaymentMethodResponse>> GetPaymentMethodListAsync(SequenceType? sequenceType = null, string locale = null, Amount amount = null);
Task<PaymentMethodResponse> GetPaymentMethodAsync(PaymentMethod paymentMethod, bool? includeIssuers = null, string locale = null, bool? includePricing = null, string profileId = null, bool? testmode = null);
Task<ListResponse<PaymentMethodResponse>> GetAllPaymentMethodListAsync(string locale = null, bool? includeIssuers = null, bool? includePricing = null);
Task<ListResponse<PaymentMethodResponse>> GetPaymentMethodListAsync(SequenceType? sequenceType = null, string locale = null, Amount amount = null, bool? includeIssuers = null, bool? includePricing = null, string profileId = null, bool? testmode = null);
Task<PaymentMethodResponse> GetPaymentMethodAsync(UrlObjectLink<PaymentMethodResponse> url);
}
}
6 changes: 6 additions & 0 deletions Mollie.Api/Client/OrganizationsClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Net.Http;
using System.Threading.Tasks;
using Mollie.Api.Client.Abstract;
using Mollie.Api.Models.List;
using Mollie.Api.Models.Organization;
using Mollie.Api.Models.Url;

Expand All @@ -17,6 +18,11 @@ public async Task<OrganizationResponse> GetOrganizationAsync(string organization
return await this.GetAsync<OrganizationResponse>($"organizations/{organizationId}").ConfigureAwait(false);
}

public async Task<ListResponse<OrganizationResponse>> GetOrganizationsListAsync(string from = null, int? limit = null)
{
return await this.GetListAsync<ListResponse<OrganizationResponse>>("organizations", from, limit, null).ConfigureAwait(false);
}

public async Task<OrganizationResponse> GetOrganizationAsync(UrlObjectLink<OrganizationResponse> url) {
return await this.GetAsync(url).ConfigureAwait(false);
}
Expand Down
64 changes: 47 additions & 17 deletions Mollie.Api/Client/PaymentMethodClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,73 @@
using Mollie.Api.Extensions;
using Mollie.Api.Models;
using Mollie.Api.Models.List;

using Mollie.Api.Models.Payment;
using Mollie.Api.Models.PaymentMethod;
using Mollie.Api.Models.Url;

namespace Mollie.Api.Client {
public class PaymentMethodClient : BaseMollieClient, IPaymentMethodClient {
namespace Mollie.Api.Client
{
public class PaymentMethodClient : BaseMollieClient, IPaymentMethodClient
{
public PaymentMethodClient(string apiKey, HttpClient httpClient = null) : base(apiKey, httpClient) {
}

public async Task<ListResponse<PaymentMethodResponse>> GetPaymentMethodListAsync(SequenceType? sequenceType = null, string locale = null, Amount amount = null) {
public async Task<PaymentMethodResponse> GetPaymentMethodAsync(PaymentMethod paymentMethod, bool? includeIssuers = null, string locale = null, bool? includePricing = null, string profileId = null, bool? testmode = null) {
Dictionary<string, string> parameters = new Dictionary<string, string>();

parameters.AddValueIfNotNullOrEmpty("locale", locale);
this.AddOauthParameters(parameters, profileId, testmode);
this.AddIncludeParameters(parameters, includeIssuers, includePricing);

return await this.GetAsync<PaymentMethodResponse>($"methods/{paymentMethod.ToString().ToLower()}{parameters.ToQueryString()}").ConfigureAwait(false);
}

public async Task<ListResponse<PaymentMethodResponse>> GetAllPaymentMethodListAsync(string locale = null, bool? includeIssuers = null, bool? includePricing = null) {
Dictionary<string, string> parameters = new Dictionary<string, string>();

parameters.AddValueIfNotNullOrEmpty("locale", locale);
this.AddIncludeParameters(parameters, includeIssuers, includePricing);

return await this.GetListAsync<ListResponse<PaymentMethodResponse>>("methods/all", null, null, parameters).ConfigureAwait(false);
}

public async Task<ListResponse<PaymentMethodResponse>> GetPaymentMethodListAsync(SequenceType? sequenceType = null, string locale = null, Amount amount = null, bool? includeIssuers = null, bool? includePricing = null, string profileId = null, bool? testmode = null) {
Dictionary<string, string> parameters = new Dictionary<string, string>() {
{nameof(sequenceType), sequenceType.ToString().ToLower()},
{nameof(locale), locale},
{"sequenceType", sequenceType.ToString().ToLower()},
{"locale", locale},
{"amount[value]", amount?.Value},
{"amount[currency]", amount?.Currency}
};

this.AddOauthParameters(parameters, profileId, testmode);
this.AddIncludeParameters(parameters, includeIssuers, includePricing);

return await this.GetListAsync<ListResponse<PaymentMethodResponse>>("methods", null, null, parameters).ConfigureAwait(false);
}

public async Task<PaymentMethodResponse> GetPaymentMethodAsync(UrlObjectLink<PaymentMethodResponse> url) {
return await this.GetAsync(url).ConfigureAwait(false);
}

public async Task<PaymentMethodResponse> GetPaymentMethodAsync(PaymentMethod paymentMethod, bool? includeIssuers = null, string locale = null) {
var parameters = new Dictionary<string, string>();
if (includeIssuers == true) {
parameters.Add("include", "issuers");
private void AddOauthParameters(Dictionary<string, string> parameters, string profileId = null, bool? testmode = null) {
if (!string.IsNullOrWhiteSpace(profileId) || testmode.HasValue) {
this.ValidateApiKeyIsOauthAccesstoken();

parameters.AddValueIfNotNullOrEmpty("profileId", profileId);
if (testmode.HasValue) {
parameters.AddValueIfNotNullOrEmpty("testmode", testmode.Value.ToString().ToLower());
}
}
if (locale != null) {
parameters.Add(nameof(locale), locale);
}

private void AddIncludeParameters(Dictionary<string, string> parameters, bool? includeIssuers = null, bool? includePricing = null) {
if (includeIssuers == true) {
parameters.Add("include", "issuers");
}

string queryString = parameters.ToQueryString();

return await this.GetAsync<PaymentMethodResponse>($"methods/{paymentMethod.ToString().ToLower()}{queryString}").ConfigureAwait(false);
}
}
if (includePricing == true) {
parameters.Add("include", "pricing");
}
}
}
}
2 changes: 2 additions & 0 deletions Mollie.Api/Extensions/DictionaryExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Mollie.Tests.Integration")]
namespace Mollie.Api.Extensions {
internal static class DictionaryExtensions {
public static string ToQueryString(this IDictionary<string, string> parameters) {
Expand Down
3 changes: 3 additions & 0 deletions Mollie.Api/Models/Payment/PaymentMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,8 @@ public enum PaymentMethod {
[EnumMember(Value = "paysafecard")] PaySafeCard,
[EnumMember(Value = "sofort")] Sofort,
[EnumMember(Value = "refund")] Refund,
[EnumMember(Value = "klarnapaylater")] KlarnaPayLater,
[EnumMember(Value = "klarnasliceit")] KlarnaSliceIt,
[EnumMember(Value = "przelewy24")] Przelewy24,
}
}
15 changes: 15 additions & 0 deletions Mollie.Api/Models/Payment/Request/Przelewy24PaymentRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Mollie.Api.Models.Payment.Request
{
public class Przelewy24PaymentRequest : PaymentRequest
{
public Przelewy24PaymentRequest()
{
this.Method = PaymentMethod.Przelewy24;
}

/// <summary>
/// Consumer’s email address, this is required for Przelewy24 payments.
/// </summary>
public string BillingEmail { get; set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ public enum CreditCardFailureReason {
[EnumMember(Value = "invalid_card_type")] InvalidCardType,
[EnumMember(Value = "refused_by_issuer")] RefusedByIssuer,
[EnumMember(Value = "insufficient_funds")] InsufficientFunds,
[EnumMember(Value = "inactive_card")] InactiveCard
[EnumMember(Value = "inactive_card")] InactiveCard,
[EnumMember(Value = "unknown_reason")] UnknownReason
}

/// <summary>
Expand All @@ -114,7 +115,8 @@ public enum CreditCardLabel {
Dankort,
[EnumMember(Value = "Diners Club")] DinersClub,
Discover,
[EnumMember(Value = "JCB Laser")] JcbLaser,
[EnumMember(Value = "JCB")] Jcb,
[EnumMember(Value = "Laser")] Laser,
Maestro,
Mastercard,
Unionpay,
Expand Down
12 changes: 9 additions & 3 deletions Mollie.Api/Models/PaymentMethod/PaymentMethodResponse.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using System.Collections.Generic;
using Mollie.Api.Models.Issuer;
using Mollie.Api.Models.PaymentMethod.Pricing;

namespace Mollie.Api.Models.PaymentMethod {
public class PaymentMethodResponse : IResponseObject {
Expand All @@ -15,20 +16,25 @@ public class PaymentMethodResponse : IResponseObject {
public Payment.PaymentMethod Id { get; set; }

/// <summary>
/// The full name of the payment method.
/// The full name of the payment method.
/// </summary>
public string Description { get; set; }

/// <summary>
/// URLs of images representing the payment method.
/// URLs of images representing the payment method.
/// </summary>
public PaymentMethodResponseImage Image { get; set; }

/// <summary>
/// List of Issuers
/// List of Issuers
/// </summary>
public List<IssuerResponse> Issuers { get; set; }

/// <summary>
/// Pricing set of the payment method what will be include if you add the parameter.
/// </summary>
public List<PricingResponse> Pricing { get; set; }

/// <summary>
/// An object with several URL objects relevant to the payment method. Every URL object will contain an href and a type field.
/// </summary>
Expand Down
14 changes: 14 additions & 0 deletions Mollie.Api/Models/PaymentMethod/Pricing/FixedPricingResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Mollie.Api.Models.PaymentMethod.Pricing
{
public class FixedPricingResponse : IResponseObject {
/// <summary>
/// The ISO 4217 currency code.
/// </summary>
public string Currency { get; set; }

/// <summary>
/// A string containing the exact amount in the given currency.
/// </summary>
public decimal Value { get; set; }
}
}
19 changes: 19 additions & 0 deletions Mollie.Api/Models/PaymentMethod/Pricing/PricingResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace Mollie.Api.Models.PaymentMethod.Pricing
{
public class PricingResponse : IResponseObject {
/// <summary>
/// The area or product-type where the pricing is applied for, translated in the optional locale passed.
/// </summary>
public string Description { get; set; }

/// <summary>
/// The fixed price per transaction
/// </summary>
public FixedPricingResponse Fixed { get; set; }

/// <summary>
/// A string containing the percentage what will be charged over the payment amount besides the fixed price.
/// </summary>
public decimal Variable { get; set; }
}
}
58 changes: 57 additions & 1 deletion Mollie.Tests.Integration/Api/PaymentMethodTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System.Linq;
using System.Threading.Tasks;
using Mollie.Api.Models.List;

using Mollie.Api.Models.Payment;
using Mollie.Api.Models.PaymentMethod;
using Mollie.Tests.Integration.Framework;
Expand All @@ -10,6 +9,7 @@
namespace Mollie.Tests.Integration.Api {
[TestFixture]
public class PaymentMethodTests : BaseMollieApiTestClass {

[Test]
public async Task CanRetrievePaymentMethodList() {
// When: Retrieve payment list with default settings
Expand Down Expand Up @@ -66,5 +66,61 @@ public async Task DoNotRetrieveIssuersWhenIncludeIsNull() {
// Then: Issuers should not be included
Assert.IsNull(paymentMethod.Issuers);
}

[Test]
public async Task CanRetrievePricing() {
// When: retrieving the ideal method we can include the issuers
PaymentMethodResponse paymentMethod = await this._paymentMethodClient.GetPaymentMethodAsync(PaymentMethod.Ideal, includePricing: true);

// Then: We should have one or multiple issuers
Assert.IsNotNull(paymentMethod);
Assert.IsTrue(paymentMethod.Pricing.Any());
}

[Test]
public async Task DoNotRetrievePricingWhenIncludeIsFalse() {
// When: retrieving the ideal method with the include parameter set to false
PaymentMethodResponse paymentMethod = await this._paymentMethodClient.GetPaymentMethodAsync(PaymentMethod.Ideal, includePricing: false);

// Then: Issuers should not be included
Assert.IsNull(paymentMethod.Pricing);
}

[Test]
public async Task DoNotRetrievePricingWhenIncludeIsNull() {
// When: retrieving the ideal method with the include parameter set to null
PaymentMethodResponse paymentMethod = await this._paymentMethodClient.GetPaymentMethodAsync(PaymentMethod.Ideal, includePricing: null);

// Then: Issuers should not be included
Assert.IsNull(paymentMethod.Pricing);
}

[Test]
public async Task CanRetrieveAllMethods() {
// When: retrieving the all mollie payment methods
ListResponse<PaymentMethodResponse> paymentMethods = await this._paymentMethodClient.GetAllPaymentMethodListAsync();

// Then: We should have multiple issuers
Assert.IsNotNull(paymentMethods);
Assert.IsTrue(paymentMethods.Items.Any());
}

[Test]
public async Task CanRetrievePricingForAllMethods() {
// When: retrieving the ideal method we can include the issuers
ListResponse<PaymentMethodResponse> paymentMethods = await this._paymentMethodClient.GetAllPaymentMethodListAsync(includePricing: true);

// Then: We should have prices available
Assert.IsTrue(paymentMethods.Items.Any(x => x.Pricing != null && x.Pricing.Any(y => y.Fixed.Value > 0)));
}

[Test]
public async Task CanRetrieveIssuersForAllMethods() {
// When: retrieving the all mollie payment methods we can include the issuers
ListResponse<PaymentMethodResponse> paymentMethods = await this._paymentMethodClient.GetAllPaymentMethodListAsync(includeIssuers: true);

// Then: We should have one or multiple issuers
Assert.IsTrue(paymentMethods.Items.Any(x => x.Issuers != null));
}
}
}
8 changes: 7 additions & 1 deletion Mollie.Tests.Integration/Api/PaymentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

namespace Mollie.Tests.Integration.Api {
using System.Linq;

using Mollie.Api.Models.Customer;
using Mollie.Api.Models.Mandate;

Expand Down Expand Up @@ -115,6 +114,7 @@ public async Task CanCreateDefaultPaymentWithAllFields() {
[TestCase(typeof(PaymentRequest), PaymentMethod.Belfius, typeof(BelfiusPaymentResponse))]
[TestCase(typeof(KbcPaymentRequest), PaymentMethod.Kbc, typeof(KbcPaymentResponse))]
[TestCase(typeof(PaymentRequest), null, typeof(PaymentResponse))]
//[TestCase(typeof(Przelewy24PaymentRequest), PaymentMethod.Przelewy24, typeof(PaymentResponse))] // Payment option is not enabled in website profile
public async Task CanCreateSpecificPaymentType(Type paymentType, PaymentMethod? paymentMethod, Type expectedResponseType) {
// If: we create a specific payment type with some bank transfer specific values
PaymentRequest paymentRequest = (PaymentRequest) Activator.CreateInstance(paymentType);
Expand All @@ -123,6 +123,12 @@ public async Task CanCreateSpecificPaymentType(Type paymentType, PaymentMethod?
paymentRequest.RedirectUrl = this.DefaultRedirectUrl;
paymentRequest.Method = paymentMethod;

// Set required billing email for Przelewy24
if (paymentRequest is Przelewy24PaymentRequest request)
{
request.BillingEmail = "[email protected]";
}

// When: We send the payment request to Mollie
PaymentResponse result = await this._paymentClient.CreatePaymentAsync(paymentRequest);

Expand Down
Loading

0 comments on commit 544cf2f

Please sign in to comment.