Skip to content

Commit

Permalink
[ACL-96] Add cancel payment endpoint (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
tl-luca-baggi authored Sep 30, 2024
1 parent 1c05046 commit 2e87fcc
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/TrueLayer/Payments/IPaymentsApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,17 @@ Task<ApiResponse<ListPaymentRefundsResponse>> ListPaymentRefunds(string paymentI
Task<ApiResponse<RefundUnion>> GetPaymentRefund(string paymentId,
string refundId,
CancellationToken cancellationToken = default);

/// <summary>
/// Cancel a payment.
/// </summary>
/// <param name="paymentId">The payment identifier</param>
/// <param name="idempotencyKey">
/// An idempotency key to allow safe retrying without the operation being performed multiple times.
/// The value should be unique for each operation, e.g. a UUID, with the same key being sent on a retry of the same request.
/// </param>
/// <param name="cancellationToken">The cancellation token to cancel the operation</param>
/// <returns>HTTP 202 Accepted if successful, otherwise problem details.</returns>
Task<ApiResponse> CancelPayment(string paymentId, string idempotencyKey, CancellationToken cancellationToken = default);
}
}
21 changes: 21 additions & 0 deletions src/TrueLayer/Payments/PaymentsApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -198,5 +198,26 @@ public async Task<ApiResponse<RefundUnion>> GetPaymentRefund(string paymentId,
cancellationToken: cancellationToken
);
}

public async Task<ApiResponse> CancelPayment(string paymentId, string idempotencyKey, CancellationToken cancellationToken = default)
{
paymentId.NotNullOrWhiteSpace(nameof(paymentId));
idempotencyKey.NotNullOrWhiteSpace(nameof(idempotencyKey));

ApiResponse<GetAuthTokenResponse> authResponse = await _auth.GetAuthToken(
new GetAuthTokenRequest("payments"), cancellationToken);

if (!authResponse.IsSuccessful)
{
return new ApiResponse(authResponse.StatusCode, authResponse.TraceId);
}

return await _apiClient.PostAsync(
_baseUri.Append(paymentId).Append("/actions/cancel"),
idempotencyKey: idempotencyKey,
accessToken: authResponse.Data!.AccessToken,
signingKey: _options.Payments!.SigningKey,
cancellationToken: cancellationToken);
}
}
}
26 changes: 26 additions & 0 deletions test/TrueLayer.AcceptanceTests/PaymentTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,32 @@ public async Task Can_create_and_list_payment_refunds()
listPaymentRefundsResponse.Data!.Items.Count.ShouldBe(1);
}

[Fact]
public async Task Can_cancel_a_payment()
{
// arrange
var paymentRequest = CreateTestPaymentRequest();
var payment = await _fixture.Client.Payments.CreatePayment(
paymentRequest, idempotencyKey: Guid.NewGuid().ToString());

payment.IsSuccessful.ShouldBeTrue();
var paymentId = payment.Data.AsT0.Id;

// act
var cancelPaymentResponse = await _fixture.Client.Payments.CancelPayment(
paymentId,
idempotencyKey: Guid.NewGuid().ToString());

var getPaymentResponse = await _fixture.Client.Payments.GetPayment(paymentId);

// assert
cancelPaymentResponse.IsSuccessful.ShouldBeTrue();
cancelPaymentResponse.StatusCode.ShouldBe(HttpStatusCode.Accepted);
getPaymentResponse.IsSuccessful.ShouldBeTrue();
getPaymentResponse.Data.AsT5.ShouldNotBeNull();
getPaymentResponse.Data.AsT5.FailureReason.ShouldBe("canceled");
}

private static void AssertSchemeSelection(
PaymentsSchemeSelectionUnion? actualSchemeSelection,
PaymentsSchemeSelectionUnion? expectedSchemeSelection,
Expand Down

0 comments on commit 2e87fcc

Please sign in to comment.