diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 6008b0c..d767738 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -131,3 +131,26 @@ jobs: run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=giving -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} --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: Setup java + uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: 17 + - name: Grant execute permission for gradlew + run: chmod +x authorisation-adjustment-example/gradlew + - name: Build authorisation-adjustment-example with Gradle + run: cd authorisation-adjustment-example; ./gradlew build + - name: Build authorisation-adjustment-example image + run: docker build -t authorisation-adjustment-example:latest authorisation-adjustment + - name: Start authorisation-adjustment container + run: docker run --rm -d --name authorisation-adjustment-example -p 8080:8080 -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:latest + - name: Run testing suite + run: docker run --rm --name adyen-testing-suite -e PLAYWRIGHT_FOLDERNAME=authorisation-adjustment -e ADYEN_HMAC_KEY=${{ secrets.ADYEN_HMAC_KEY }} --network host ghcr.io/adyen-examples/adyen-testing-suite:main + + diff --git a/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/ApiController.java b/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/ApiController.java index 9c32117..c968a86 100644 --- a/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/ApiController.java +++ b/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/ApiController.java @@ -23,7 +23,7 @@ import com.adyen.service.exception.ApiException; /** - * REST controller for using Adyen checkout API + * REST controller for using Adyen Payments API */ @RestController @RequestMapping("/api") diff --git a/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/WebhookController.java b/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/WebhookController.java index 954dc96..ecfecc1 100644 --- a/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/WebhookController.java +++ b/authorisation-adjustment-example/src/main/java/com/adyen/checkout/api/WebhookController.java @@ -1,6 +1,8 @@ package com.adyen.checkout.api; import com.adyen.checkout.ApplicationProperty; +import com.adyen.checkout.model.PaymentDetailsModel; +import com.adyen.checkout.util.Storage; import com.adyen.model.notification.NotificationRequest; import com.adyen.model.notification.NotificationRequestItem; import com.adyen.util.HMACValidator; @@ -16,6 +18,7 @@ import java.io.IOException; import java.security.SignatureException; +import java.time.LocalDateTime; /** * REST controller for receiving Adyen webhook notifications @@ -46,7 +49,6 @@ public WebhookController(ApplicationProperty applicationProperty) { */ @PostMapping("/webhooks/notifications") public ResponseEntity webhooks(@RequestBody String json) throws IOException { - // from JSON string to object var notificationRequest = NotificationRequest.fromJson(json); @@ -54,17 +56,16 @@ public ResponseEntity webhooks(@RequestBody String json) throws IOExcept var notificationRequestItem = notificationRequest.getNotificationItems().stream().findFirst(); if (notificationRequestItem.isPresent()) { - var item = notificationRequestItem.get(); try { if (getHmacValidator().validateHMAC(item, this.applicationProperty.getHmacKey())) { log.info(""" - Received webhook with event {} :\s - Merchant Reference: {} - Alias : {} - PSP reference : {}""" - , item.getEventCode(), item.getMerchantReference(), item.getAdditionalData().get("alias"), item.getPspReference()); + Received webhook with event {} :\s + Merchant Reference: {} + Alias : {} + PSP reference : {}""" + , item.getEventCode(), item.getMerchantReference(), item.getAdditionalData().get("alias"), item.getPspReference()); // consume event asynchronously consumeEvent(item); @@ -89,19 +90,72 @@ public ResponseEntity webhooks(@RequestBody String json) throws IOExcept } // process payload asynchronously - void consumeEvent(NotificationRequestItem item) { - // add item to DB, queue or different thread - - // example: send to Kafka consumer - - // producer.send(producerRecord); - // producer.flush(); - // producer.close(); + private void consumeEvent(NotificationRequestItem notification) { + switch (notification.getEventCode()) { + case "AUTHORISATION": + log.info("Payment authorised - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + case "AUTHORISATION_ADJUSTMENT": + log.info("Authorisation adjustment - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + if (notification.isSuccess()) { + // see documentation for the different expiry dates per card scheme: https://docs.adyen.com/online-payments/adjust-authorisation/#validity + var expiryDate = LocalDateTime.now().plusDays(28); + Storage.updatePayment(notification.getMerchantReference(), notification.getAmount().getValue(), expiryDate); + } + break; + + case "CAPTURE": + log.info("Payment capture - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + case "CAPTURE_FAILED": + log.info("Payment capture failed - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + case "CANCEL_OR_REFUND": + log.info("Payment cancel_or_refund - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + case "REFUND_FAILED": + log.info("Payment refund failed - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + case "REFUNDED_REVERSED": + log.info("Payment refund reversed - pspReference: {} eventCode: {}", notification.getPspReference(), notification.getEventCode()); + savePayment(notification); + break; + + default: + log.warn("Unexpected eventCode: {}", notification.getEventCode()); + break; + } + } + private void savePayment(NotificationRequestItem notification) { + PaymentDetailsModel paymentDetails = new PaymentDetailsModel( + notification.getMerchantReference(), + notification.getPspReference(), + notification.getOriginalReference(), + notification.getAmount().getValue(), + notification.getAmount().getCurrency(), + LocalDateTime.now(), + notification.getEventCode(), + notification.getReason(), + notification.getPaymentMethod(), + notification.isSuccess() + ); + Storage.addPaymentToHistory(paymentDetails); } @Bean public HMACValidator getHmacValidator() { return new HMACValidator(); } -} +} \ No newline at end of file