Skip to content

Commit

Permalink
Added Integration-Example: Authorisation Adjustment (#91)
Browse files Browse the repository at this point in the history
* Initial commit - Authorisation Adjustment
* Modified solution to follow advanced-checkoutflow and use manual capture + preauth in additionalData to make a payment of 249.99
* Add incremental/decremental/extend adjustment services
* Added capture
* Added reversals
* Added styling, frontend bindings & respective views
* Updated build.yml and e2e.yml to ignore running tests when readme is updated
* Added GIF Authorisation Adjustment Card

---------

Co-authored-by: Kwok He Chu <>
  • Loading branch information
Kwok-he-Chu authored Aug 2, 2023
1 parent 18e42fa commit 025d54e
Show file tree
Hide file tree
Showing 74 changed files with 28,456 additions and 7 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,18 @@ name: .NET
on:
push:
branches: [ main ]
paths-ignore:
- '**/readme.md'
- .gitignore
- .gitpod.yml
- LICENSE
pull_request:
branches: [ main ]
paths-ignore:
- '**/readme.md'
- .gitignore
- .gitpod.yml
- LICENSE

jobs:
build:
Expand Down
24 changes: 23 additions & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,18 @@ on:
workflow_dispatch:
push:
branches: [ main ]
paths-ignore:
- '**/readme.md'
- .gitignore
- .gitpod.yml
- LICENSE
pull_request:
branches: [ main ]
paths-ignore:
- '**/readme.md'
- .gitignore
- .gitpod.yml
- LICENSE

jobs:
checkout:
Expand Down Expand Up @@ -66,4 +76,16 @@ jobs:
- name: Start paybylink-example container
run: docker run --rm -d --name paybylink-example-image -p 8080:80 -e ADYEN_API_KEY="${{ secrets.ADYEN_API_KEY }}" -e ADYEN_MERCHANT_ACCOUNT=${{ secrets.ADYEN_MERCHANT_ACCOUNT }} -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} paybylink-example-image:latest
- name: Run testing suite against paybylink-example-image
run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=paybylink --network host ghcr.io/adyen-examples/adyen-testing-suite:main
run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=paybylink --network host ghcr.io/adyen-examples/adyen-testing-suite:main

authorisation-adjustment:
runs-on: ubuntu-latest
steps:
- name: Authorisation Adjustment project
uses: actions/checkout@v3
- name: Build authorisation-adjustment-example image
run: docker build -t authorisation-adjustment-example-image:latest authorisation-adjustment-example
- name: Start authorisation-adjustment-example container
run: docker run --rm -d --name authorisation-adjustment-example-image -p 8080:80 -e ADYEN_API_KEY="${{ secrets.ADYEN_API_KEY }}" -e ADYEN_MERCHANT_ACCOUNT=${{ secrets.ADYEN_MERCHANT_ACCOUNT }} -e ADYEN_CLIENT_KEY=${{ secrets.ADYEN_CLIENT_KEY }} -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} authorisation-adjustment-example-image:latest
- name: Run testing suite against authorisation-adjustment-example-image
run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=authorisation-adjustment --network host ghcr.io/adyen-examples/adyen-testing-suite:main
8 changes: 8 additions & 0 deletions .gitpod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ tasks:
command: |
# Check if environment variables are set in https://gitpod.io/variables and run the application based on specified $path.
case "$path" in
"authorisation-adjustment-example")
if [ -z ${ADYEN_HMAC_KEY+x} ] || [[ -z ${ADYEN_API_KEY+x} ]] || [[ -z ${ADYEN_CLIENT_KEY+x} ]] || [[ -z ${ADYEN_MERCHANT_ACCOUNT+x} ]]; then
echo "Expected environment variables not found. Please set the ADYEN_HMAC_KEY, ADYEN_API_KEY, ADYEN_CLIENT_KEY, ADYEN_MERCHANT_ACCOUNT environment variables in https://gitpod.io/variables and restart."
exit 1
fi
dotnet run --project authorisation-adjustment-example
;;
"checkout-example")
if [ -z ${ADYEN_HMAC_KEY+x} ] || [[ -z ${ADYEN_API_KEY+x} ]] || [[ -z ${ADYEN_CLIENT_KEY+x} ]] || [[ -z ${ADYEN_MERCHANT_ACCOUNT+x} ]]; then
echo "Expected environment variables not found. Please set the ADYEN_HMAC_KEY, ADYEN_API_KEY, ADYEN_CLIENT_KEY, ADYEN_MERCHANT_ACCOUNT environment variables in https://gitpod.io/variables and restart."
Expand Down
11 changes: 10 additions & 1 deletion adyen-dotnet-online-payments.sln
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "adyen-dotnet-paybylink-exam
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "checkout-example-advanced", "checkout-example-advanced", "{B2582A34-631C-4130-B35D-838FA98297EA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "adyen-dotnet-checkout-example-advanced", "checkout-example-advanced\adyen-dotnet-checkout-example-advanced.csproj", "{26D67844-2033-4C06-A55A-5B50CFDEB0BC}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "adyen-dotnet-checkout-example-advanced", "checkout-example-advanced\adyen-dotnet-checkout-example-advanced.csproj", "{26D67844-2033-4C06-A55A-5B50CFDEB0BC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "authorisation-adjustment-example", "authorisation-adjustment-example", "{61BDBE25-C448-4640-A4C7-E6744FA2D44F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "adyen-dotnet-authorisation-adjustment-example", "authorisation-adjustment-example\adyen-dotnet-authorisation-adjustment-example.csproj", "{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -49,6 +53,10 @@ Global
{26D67844-2033-4C06-A55A-5B50CFDEB0BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26D67844-2033-4C06-A55A-5B50CFDEB0BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26D67844-2033-4C06-A55A-5B50CFDEB0BC}.Release|Any CPU.Build.0 = Release|Any CPU
{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -59,6 +67,7 @@ Global
{3972652A-783F-4114-B1C5-27BF754F2BA4} = {24558B77-0E04-4D15-90BC-05A57FCB5FE5}
{A4303B5C-301E-432F-B8AC-571096DF5273} = {F3A61AF3-5126-417B-9AB2-A0F99B119325}
{26D67844-2033-4C06-A55A-5B50CFDEB0BC} = {B2582A34-631C-4130-B35D-838FA98297EA}
{EC4006F7-EC06-4DBC-A9F7-2273AE677AC2} = {61BDBE25-C448-4640-A4C7-E6744FA2D44F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {777409BD-281D-419E-9F9B-BE609D4B6971}
Expand Down
25 changes: 25 additions & 0 deletions authorisation-adjustment-example/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
163 changes: 163 additions & 0 deletions authorisation-adjustment-example/Controllers/AdminController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
using Adyen.HttpClient;
using Adyen.Model.Checkout;
using Adyen.Service.Checkout;
using adyen_dotnet_authorisation_adjustment_example.Models;
using adyen_dotnet_authorisation_adjustment_example.Options;
using adyen_dotnet_authorisation_adjustment_example.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace adyen_dotnet_authorisation_adjustment_example.Controllers
{
public class AdminController : Controller
{
private readonly IPaymentRepository _repository;
private readonly IModificationsService _modificationsService;
private readonly ILogger<AdminController> _logger;
private readonly string _merchantAccount;

public AdminController(IPaymentRepository repository, IModificationsService modificationsService, IOptions<AdyenOptions> options, ILogger<AdminController> logger)
{
_repository = repository;
_merchantAccount = options.Value.ADYEN_MERCHANT_ACCOUNT;
_modificationsService = modificationsService;
_logger = logger;
}

[Route("admin")]
public IActionResult Index()
{
List<PaymentModel> payments = new List<PaymentModel>();
foreach (var kvp in _repository.Payments)
{
payments.Add(_repository.FindLatestPaymentByReference(kvp.Key));
}
ViewBag.Payments = payments;
return View();
}

[Route("admin/details/{reference}")]
public IActionResult Details(string reference)
{
// We fetch all payments (regardless whether its authorised/refused) that we have stored in our local repository and show it.
ViewBag.Payments = _repository.FindByReference(reference)
.OrderBy(x=> x.DateTime)
.ToList();
return View();
}

[HttpGet("admin/result/{status}/{reference}")]
public IActionResult Result(string reference, string status, [FromQuery(Name = "reason")] string refusalReason)
{
string msg;
string img;
switch (status)
{
case "received":
msg = $"Request received for Merchant Reference: {reference}. Wait a bit to receive the asynchronous webhook response.";
img = "success";
break;
default:
msg = $"Error! Refusal reason: {refusalReason}";
img = "failed";
break;
}
ViewBag.Status = status;
ViewBag.Msg = msg;
ViewBag.Img = img;
return View();
}

[HttpPost("admin/update-payment-amount")]
public async Task<ActionResult<PaymentAmountUpdateResource>> UpdatePaymentAmount([FromBody] UpdatePaymentAmountRequest request, CancellationToken cancellationToken = default)
{
PaymentModel payment = _repository.FindLatestPaymentByReference(request.Reference);

if (payment == null)
{
return NotFound();
}

try
{
var createPaymentAmountUpdateRequest = new CreatePaymentAmountUpdateRequest()
{
MerchantAccount = _merchantAccount, // Required
Amount = new Amount() { Value = request.Amount, Currency = payment.Currency },
Reference = payment.Reference,
IndustryUsage = CreatePaymentAmountUpdateRequest.IndustryUsageEnum.DelayedCharge,
};

var response = await _modificationsService.UpdateAuthorisedAmountAsync(payment.GetOriginalPspReference(), createPaymentAmountUpdateRequest, cancellationToken: cancellationToken);
return Ok(response);
}
catch (HttpClientException e)
{
_logger.LogError(e.ToString());
return BadRequest();
}
}

[HttpPost("admin/capture-payment")]
public async Task<ActionResult<PaymentCaptureResource>> CapturePayment([FromBody] CreateCapturePaymentRequest request, CancellationToken cancellationToken = default)
{
PaymentModel payment = _repository.FindLatestPaymentByReference(request.Reference);

if (payment == null)
{
return NotFound();
}

try
{
var createPaymentCaptureRequest = new CreatePaymentCaptureRequest()
{
MerchantAccount = _merchantAccount, // Required.
Amount = new Amount() { Value = payment.Amount, Currency = payment.Currency }, // Required.
Reference = payment.Reference
};

var response = await _modificationsService.CaptureAuthorisedPaymentAsync(payment.GetOriginalPspReference(), createPaymentCaptureRequest, cancellationToken: cancellationToken);
return Ok(response); // Note that the response will have a different PSPReference compared to the initial pre-authorisation.
}
catch (HttpClientException e)
{
_logger.LogError(e.ToString());
return BadRequest();
}
}

[HttpPost("admin/reversal-payment")]
public async Task<ActionResult<PaymentReversalResource>> ReversalPayment([FromBody] CreateReversalPaymentRequest request, CancellationToken cancellationToken = default)
{
PaymentModel payment = _repository.FindLatestPaymentByReference(request.Reference);

if (payment == null)
{
return NotFound();
}

try
{
var createPaymentReversalRequest = new CreatePaymentReversalRequest()
{
MerchantAccount = _merchantAccount, // Required.
Reference = payment.Reference
};

var response = await _modificationsService.RefundOrCancelPaymentAsync(payment.GetOriginalPspReference(), createPaymentReversalRequest, cancellationToken: cancellationToken);
return Ok(response);
}
catch (HttpClientException e)
{
_logger.LogError(e.ToString());
return BadRequest();
}
}
}
}
Loading

0 comments on commit 025d54e

Please sign in to comment.