Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#396: Fix issue where ApplicationFee was set on wrong level #399

Merged
merged 3 commits into from
Sep 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 2 additions & 7 deletions src/Mollie.Api/Models/Order/Request/OrderRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Mollie.Api.JsonConverters;
using Mollie.Api.Models.Order.Request.PaymentSpecificParameters;
using Newtonsoft.Json;

namespace Mollie.Api.Models.Order.Request {
Expand Down Expand Up @@ -101,7 +102,7 @@ public string? Method {
/// <summary>
/// Optional - Any payment specific properties can be passed here.
/// </summary>
public PaymentSpecificParameters.PaymentSpecificParameters? Payment { get; set; }
public OrderPaymentParameters? Payment { get; set; }

/// <summary>
/// Provide any data you like, and we will save the data alongside the subscription. Whenever you fetch the subscription
Expand All @@ -122,12 +123,6 @@ public string? Method {
/// </summary>
public bool? ShopperCountryMustMatchBillingCountry { get; set; }

/// <summary>
/// Adding an application fee allows you to charge the merchant for the payment and transfer this to your own account.
/// </summary>
[JsonProperty("payment.applicationFee")]
public ApplicationFee? ApplicationFee { get; set; }

/// <summary>
/// Oauth only - The payment profile's unique identifier, for example pfl_3RkSN1zuPE.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record ApplePaySpecificParameters : PaymentSpecificParameters {
public record ApplePaySpecificParameters : OrderPaymentParameters {
/// <summary>
/// Optional - The Apple Pay Payment Token object (encoded as JSON) that is part of the result of authorizing a payment
/// request. The token contains the payment information needed to authorize the payment.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record BillieSpecificParameters : PaymentSpecificParameters {
public record BillieSpecificParameters : OrderPaymentParameters {
/// <summary>
/// Billie is a B2B payment method, thus it requires some extra information to identify the business
/// that is creating the order. It is recommended to include these parameters as part of the create
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record CreditCardSpecificParameters : PaymentSpecificParameters {
public record CreditCardSpecificParameters : OrderPaymentParameters {
/// <summary>
/// The card token you get from Mollie Components. The token contains the card information
/// (such as card holder, card number and expiry date) needed to complete the payment.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record GiftcardSpecificParameters : PaymentSpecificParameters {
public record GiftcardSpecificParameters : OrderPaymentParameters {
/// <summary>
/// The gift card brand to use for the payment. These issuers are not dynamically available through the Issuers API,
/// but can be retrieved by using the issuers include in the Methods API. If you need a brand not in the list, contact
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record IDealSpecificParameters : PaymentSpecificParameters {
public record IDealSpecificParameters : OrderPaymentParameters {
/// <summary>
/// Optional - iDEAL issuer id. The id could for example be ideal_INGBNL2A. The returned paymentUrl will then directly
/// point to the ING web site.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record KbcSpecificParameters : PaymentSpecificParameters {
public record KbcSpecificParameters : OrderPaymentParameters {
/// <summary>
/// The issuer to use for the KBC/CBC payment. These issuers are not dynamically available through the Issuers API,
/// but can be retrieved by using the issuers include in the Methods API. See the Mollie.Api.Models.Payment.Request.KbcIssuer
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record KlarnaSpecificParameters<T> : PaymentSpecificParameters where T : class {
public record KlarnaSpecificParameters<T> : OrderPaymentParameters where T : class {
public T? ExtraMerchantData { get; set; }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record PaymentSpecificParameters {
public record OrderPaymentParameters {
public string? CustomerId { get; set; }
/// <summary>
/// See the Mollie.Api.Models.Payment.SequenceType class for a full list of known values.
/// </summary>
public string? SequenceType { get; set; }
public string? WebhookUrl { get; set; }

/// <summary>
/// Adding an application fee allows you to charge the merchant for the payment and transfer this to your own account.
/// </summary>
public ApplicationFee? ApplicationFee { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record PaySafeCardSpecificParameters : PaymentSpecificParameters {
public record PaySafeCardSpecificParameters : OrderPaymentParameters {
/// <summary>
/// Used for consumer identification. For example, you could use the consumer’s IP address.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
namespace Mollie.Api.Models.Order.Request.PaymentSpecificParameters {
public record SepaDirectDebitSpecificParameters : PaymentSpecificParameters {
public record SepaDirectDebitSpecificParameters : OrderPaymentParameters {
/// <summary>
/// Optional - IBAN of the account holder.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public record SubscriptionResponse {
/// </summary>
public string? WebhookUrl { get; set; }

/// <summary>
/// The customer this subscription belongs to.
/// </summary>
public required string CustomerId { get; init; }

/// <summary>
/// The optional metadata you provided upon subscription creation. Metadata can for example be used to link a plan to a
/// subscription.
Expand Down
32 changes: 31 additions & 1 deletion tests/Mollie.Tests.Integration/Api/OrderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ public async Task CreateOrderAsync_OrderWithRequiredFields_OrderIsCreated() {
orderResponseLine.Metadata.Should().Be(expectedMetadataString);
}

[DefaultRetryFact]
public async Task CreateOrderAsync_OrderWithApplicationFee_OrderIsCreated() {
// If: we create a order request with only the required parameters
OrderRequest orderRequest = CreateOrder() with {
Payment = new OrderPaymentParameters {
ApplicationFee = new ApplicationFee {
Amount = new Amount(Currency.EUR, 0.25m),
Description = "Test"
}
}
};

// When: We send the order request to Mollie
OrderResponse result = await _orderClient.CreateOrderAsync(orderRequest);

// Then: Make sure we get a valid response
result.Should().NotBeNull();
result.Amount.Should().Be(orderRequest.Amount);
result.OrderNumber.Should().Be(orderRequest.OrderNumber);
result.Lines.Should().HaveCount(orderRequest.Lines.Count());
result.Links.Should().NotBeNull();
OrderLineRequest orderLineRequest = orderRequest.Lines.First();
OrderLineResponse orderResponseLine = result.Lines.First();
orderResponseLine.Type.Should().Be(orderLineRequest.Type);
orderResponseLine.Links.ImageUrl!.Href.Should().Be(orderLineRequest.ImageUrl);
orderResponseLine.Links.ProductUrl!.Href.Should().Be(orderLineRequest.ProductUrl);
var expectedMetadataString = result.Lines.First().Metadata;
orderResponseLine.Metadata.Should().Be(expectedMetadataString);
}

[DefaultRetryFact]
public async Task CreateOrderAsync_WithMultiplePaymentMethods_OrderIsCreated() {
// When: we create a order request and specify multiple payment methods
Expand Down Expand Up @@ -179,7 +209,7 @@ public async Task CreateOrderAsync_WithSinglePaymentMethod_OrderIsCreated() {
[DefaultRetryTheory]
[MemberData(nameof(PaymentSpecificParameters))]
public async Task CreateOrderAsync_WithPaymentSpecificParameters_OrderIsCreated(
PaymentSpecificParameters paymentSpecificParameters) {
OrderPaymentParameters paymentSpecificParameters) {

// If: we create a order request with payment specific parameters
OrderRequest orderRequest = CreateOrder();
Expand Down
46 changes: 29 additions & 17 deletions tests/Mollie.Tests.Integration/Api/SubscriptionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,40 +89,38 @@
}

[DefaultRetryFact]
public async Task CanCancelSubscription() {
public async Task CanUpdateSubscription() {
// Given
string customerId = await GetFirstCustomerWithValidMandate();
ListResponse<SubscriptionResponse> subscriptions = await _subscriptionClient.GetSubscriptionListAsync(customerId);
var activeSubscription = await GetActiveSubscription();

// When
SubscriptionResponse subscriptionToCancel = subscriptions.Items
.FirstOrDefault(s => s.Status != SubscriptionStatus.Canceled);
if (subscriptionToCancel != null) {
await _subscriptionClient.CancelSubscriptionAsync(customerId, subscriptionToCancel.Id);
SubscriptionResponse cancelledSubscription = await _subscriptionClient.GetSubscriptionAsync(customerId, subscriptionToCancel.Id);
if (activeSubscription != null) {
var customerId = activeSubscription.CustomerId;
SubscriptionUpdateRequest request = new SubscriptionUpdateRequest() {
Description = $"Updated subscription {Guid.NewGuid()}"
};
SubscriptionResponse response = await _subscriptionClient.UpdateSubscriptionAsync(customerId, activeSubscription.Id, request);

// Then
cancelledSubscription.Status.Should().Be(SubscriptionStatus.Canceled);
response.Description.Should().Be(request.Description);
}
}

[DefaultRetryFact]
public async Task CanUpdateSubscription() {
public async Task CanCancelSubscription() {
// Given
string customerId = await GetFirstCustomerWithValidMandate();
ListResponse<SubscriptionResponse> subscriptions = await _subscriptionClient.GetSubscriptionListAsync(customerId);

// When
SubscriptionResponse subscriptionToUpdate = subscriptions.Items
SubscriptionResponse subscriptionToCancel = subscriptions.Items
.FirstOrDefault(s => s.Status != SubscriptionStatus.Canceled);
if (subscriptionToUpdate != null) {
SubscriptionUpdateRequest request = new SubscriptionUpdateRequest() {
Description = $"Updated subscription {Guid.NewGuid()}"
};
SubscriptionResponse response = await _subscriptionClient.UpdateSubscriptionAsync(customerId, subscriptionToUpdate.Id, request);
if (subscriptionToCancel != null) {
await _subscriptionClient.CancelSubscriptionAsync(customerId, subscriptionToCancel.Id);
SubscriptionResponse cancelledSubscription = await _subscriptionClient.GetSubscriptionAsync(customerId, subscriptionToCancel.Id);

// Then
response.Description.Should().Be(request.Description);
cancelledSubscription.Status.Should().Be(SubscriptionStatus.Canceled);
}
}

Expand Down Expand Up @@ -163,6 +161,20 @@
return null;
}

private async Task<SubscriptionResponse?> GetActiveSubscription() {

Check warning on line 164 in tests/Mollie.Tests.Integration/Api/SubscriptionTests.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

Check warning on line 164 in tests/Mollie.Tests.Integration/Api/SubscriptionTests.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
ListResponse<CustomerResponse> customers = await _customerClient.GetCustomerListAsync();

foreach (CustomerResponse customer in customers.Items.OrderByDescending(x => x.CreatedAt)) {
ListResponse<SubscriptionResponse> subscriptions = await _subscriptionClient.GetSubscriptionListAsync(customer.Id);
var activeSubscription = subscriptions.Items.FirstOrDefault(x => x.Status == SubscriptionStatus.Active);
if (activeSubscription != null) {
return activeSubscription;
}
}

return null;
}

public void Dispose()
{
_subscriptionClient?.Dispose();
Expand Down
Loading