diff --git a/force-app/main/default/classes/AdyenAuthorisationHelper.cls b/force-app/main/default/classes/AdyenAuthorisationHelper.cls index 70fa873..071d8a2 100644 --- a/force-app/main/default/classes/AdyenAuthorisationHelper.cls +++ b/force-app/main/default/classes/AdyenAuthorisationHelper.cls @@ -160,4 +160,19 @@ public with sharing class AdyenAuthorisationHelper { authReversalResponse.setGatewayMessage('[cancellation-received]'); return authReversalResponse; } + + public static CommercePayments.GatewayResponse createPostAuthResponse(CommercePayments.PostAuthorizationRequest postAuthRequest) { + CommercePayments.PostAuthorizationResponse postAuthorizationResponse = new CommercePayments.PostAuthorizationResponse(); + String pblId = postAuthRequest.additionalData?.get(AdyenOMSConstants.PBL_ID_KEY); + + postAuthorizationResponse.setAmount(postAuthRequest.amount); + postAuthorizationResponse.setGatewayResultCode(AdyenOMSConstants.GATEWAY_RESULT_SUCCESS); + postAuthorizationResponse.setGatewayResultCodeDescription(AdyenOMSConstants.GATEWAY_RESULT_SUCCESS_DESCRIPTION); + postAuthorizationResponse.setGatewayReferenceNumber(pblId); + postAuthorizationResponse.setSalesforceResultCodeInfo(AdyenConstants.SUCCESS_SALESFORCE_RESULT_CODE_INFO); + postAuthorizationResponse.setGatewayDate(System.now()); + postAuthorizationResponse.setAsync(true); + + return postAuthorizationResponse; + } } \ No newline at end of file diff --git a/force-app/main/default/classes/AdyenAuthorisationHelperTest.cls b/force-app/main/default/classes/AdyenAuthorisationHelperTest.cls index ada433e..7ce8fe0 100644 --- a/force-app/main/default/classes/AdyenAuthorisationHelperTest.cls +++ b/force-app/main/default/classes/AdyenAuthorisationHelperTest.cls @@ -153,4 +153,22 @@ private class AdyenAuthorisationHelperTest { Assert.areEqual(ex.getMessage(), String.format(AdyenAuthorisationHelper.AMOUNT_MISMATCH_ERROR, new List{price,availableToCapture})); } } + + @IsTest + static void createPostAuthResponseTest() { + // Given + Double price = 19.99; + CommercePayments.PostAuthorizationRequest postAuthRequest = new CommercePayments.PostAuthorizationRequest(price); + postAuthRequest.amount = 5000; + postAuthRequest.additionalData = new Map { + 'pblId' => 'testPblId123' + }; + + // When + CommercePayments.GatewayResponse response = AdyenAuthorisationHelper.createPostAuthResponse(postAuthRequest); + + // Then + Assert.isTrue(response.toString().contains('success')); + Assert.isTrue(response.toString().contains('testPblId123')); + } } \ No newline at end of file diff --git a/force-app/main/default/classes/AdyenOMSConstants.cls b/force-app/main/default/classes/AdyenOMSConstants.cls index fbfd5c6..89bdb6b 100644 --- a/force-app/main/default/classes/AdyenOMSConstants.cls +++ b/force-app/main/default/classes/AdyenOMSConstants.cls @@ -23,4 +23,10 @@ public with sharing class AdyenOMSConstants { AdyenConstants.NOTIFICATION_REQUEST_TYPE_REFUND_FAILED, AdyenConstants.NOTIFICATION_REQUEST_TYPE_CANCEL }; + + public static final String PBL_GATEWAY_TOKEN_DETAILS = 'PBL Id'; + public static final String PBL_PAYMENT_METHOD_NAME = 'pbl'; + public static final String PBL_ID_KEY = 'pblId'; + public static final String GATEWAY_RESULT_SUCCESS = 'success'; + public static final String GATEWAY_RESULT_SUCCESS_DESCRIPTION = 'Transaction Normal'; } \ No newline at end of file diff --git a/force-app/main/default/classes/AdyenPaymentHelper.cls b/force-app/main/default/classes/AdyenPaymentHelper.cls index 3286204..3c71085 100644 --- a/force-app/main/default/classes/AdyenPaymentHelper.cls +++ b/force-app/main/default/classes/AdyenPaymentHelper.cls @@ -14,6 +14,8 @@ public with sharing class AdyenPaymentHelper { if (paymentRequestType == CommercePayments.RequestType.Authorize) { return AdyenAuthorisationHelper.authorise((CommercePayments.AuthorizationRequest)paymentRequest); + } else if (paymentRequestType == CommercePayments.RequestType.PostAuth) { + return AdyenAuthorisationHelper.createPostAuthResponse((CommercePayments.PostAuthorizationRequest) paymentRequest); } else if (paymentRequestType == CommercePayments.RequestType.AuthorizationReversal) { return AdyenAuthorisationHelper.reverseAuth((CommercePayments.AuthorizationReversalRequest)paymentRequest); } else if (paymentRequestType == CommercePayments.RequestType.Capture) { @@ -120,4 +122,88 @@ public with sharing class AdyenPaymentHelper { return CommercePayments.NotificationClient.record(notification); } + + @InvocableMethod + public static List callPostAuthorize(List postAuthRequests) { + PBLPostAuthRequest postAuthRequestInput = postAuthRequests[0]; + Adyen_Adapter__mdt adyenAdapter = AdyenPaymentUtility.retrieveAdapterByDeveloperName(AdyenConstants.DEFAULT_ADAPTER_NAME); + + Amount amount = new Amount(); + amount.value = (postAuthRequestInput.amount * AdyenPaymentUtility.getAmountMultiplier(postAuthRequestInput.currencyIsoCode)).round(System.RoundingMode.HALF_UP); + amount.currency_x = postAuthRequestInput.currencyIsoCode; + + PaymentLinkRequest paymentLinkRequest = AdyenPBLHelper.buildPaymentLinkRequest(adyenAdapter, amount, postAuthRequestInput.accountId); + PaymentLinkResponse paymentLinkResponse = AdyenPBLHelper.generatePaymentLink(adyenAdapter, paymentLinkRequest); + + ConnectApi.PostAuthRequest postAuthRequest = new ConnectApi.PostAuthRequest(); + postAuthRequest.accountId = postAuthRequestInput.accountId; + postAuthRequest.amount = postAuthRequestInput.amount; + postAuthRequest.currencyIsoCode = postAuthRequestInput.currencyIsoCode; + postAuthRequest.effectiveDate = System.now(); + postAuthRequest.paymentGatewayId = postAuthRequestInput.paymentGatewayId; + postAuthRequest.paymentMethod = new ConnectApi.PostAuthApiPaymentMethodRequest(); + + ConnectApi.AlternativePaymentMethod apmRequest = new ConnectApi.AlternativePaymentMethod(); + apmRequest.gatewayToken = paymentLinkResponse.id; + apmRequest.gatewayTokenDetails = AdyenOMSConstants.PBL_GATEWAY_TOKEN_DETAILS; + postAuthRequest.paymentMethod.alternativePaymentMethod = apmRequest; + postAuthRequest.paymentMethod.alternativePaymentMethod.accountId = postAuthRequestInput.accountId; + postAuthRequest.paymentMethod.alternativePaymentMethod.name = AdyenOMSConstants.PBL_PAYMENT_METHOD_NAME; + + postAuthRequest.paymentGroup = new ConnectApi.PaymentGroupRequest(); + postAuthRequest.paymentGroup.createPaymentGroup = true; + postAuthRequest.paymentGroup.currencyIsoCode = postAuthRequestInput.currencyIsoCode; + + Map additionalData = new Map { + AdyenOMSConstants.PBL_ID_KEY => paymentLinkResponse.id + }; + postAuthRequest.additionalData = additionalData; + + ConnectApi.PostAuthorizationResponse postAuthorizationResponse = Test.isRunningTest() ? mockPostAuthResponse() : ConnectApi.Payments.postAuth(postAuthRequest); + + PBLPostAuthResponse postAuthResponse = new PBLPostAuthResponse(); + postAuthResponse.paymentMethodId = postAuthorizationResponse.paymentMethod.id; + postAuthResponse.paymentGroupId = postAuthorizationResponse.paymentGroup.id; + postAuthResponse.paymentLink = paymentLinkResponse.url; + postAuthResponse.linkExpiresAt = paymentLinkResponse.expiresAt; + return new List { postAuthResponse }; + } + + @TestVisible + private static ConnectApi.PostAuthorizationResponse mockPostAuthResponse() { + ConnectApi.PostAuthorizationResponse postAuthorizationResponse = new ConnectApi.PostAuthorizationResponse(); + postAuthorizationResponse.gatewayResponse = new ConnectApi.PostAuthGatewayResponse(); + postAuthorizationResponse.gatewayResponse.gatewayResultCode = AdyenOMSConstants.GATEWAY_RESULT_SUCCESS; + postAuthorizationResponse.paymentGroup = new ConnectApi.PaymentGroupResponse(); + postAuthorizationResponse.paymentMethod = new ConnectApi.PaymentMethodResponse(); + return postAuthorizationResponse; + } + + public class PBLPostAuthRequest { + @InvocableVariable(required=true) + public String paymentGatewayId; + + @InvocableVariable(required=true) + public String accountId; + + @InvocableVariable(required=true) + public String currencyIsoCode; + + @InvocableVariable(required=true) + public Decimal amount; + } + + public class PBLPostAuthResponse { + @InvocableVariable + public String paymentMethodId; + + @InvocableVariable + public String paymentGroupId; + + @InvocableVariable + public String paymentLink; + + @InvocableVariable + public String linkExpiresAt; + } } \ No newline at end of file diff --git a/force-app/main/default/classes/AdyenPaymentHelperTest.cls b/force-app/main/default/classes/AdyenPaymentHelperTest.cls index 502dfcd..01f3fbc 100644 --- a/force-app/main/default/classes/AdyenPaymentHelperTest.cls +++ b/force-app/main/default/classes/AdyenPaymentHelperTest.cls @@ -64,4 +64,30 @@ private class AdyenPaymentHelperTest { Assert.isInstanceOfType(ex, AdyenGatewayAdapter.GatewayException.class); } } -} + + @IsTest(SeeAllData=true) + static void callPostAuthorizeTest() { + // Given + Account testAccount = new Account(Name = 'Test Account'); + insert testAccount; + + AdyenPaymentHelper.PBLPostAuthRequest postAuthRequest = new AdyenPaymentHelper.PBLPostAuthRequest(); + postAuthRequest.paymentGatewayId = null; + postAuthRequest.accountId = testAccount.Id; + postAuthRequest.currencyIsoCode = 'EUR'; + postAuthRequest.amount = 55.55; + + List postAuthRequests = new List{ postAuthRequest }; + Test.startTest(); + Test.setMock(HttpCalloutMock.class, new TestDataFactory.PBLMockResponse()); + // when + List postAuthResponses = AdyenPaymentHelper.callPostAuthorize(postAuthRequests); + Test.stopTest(); + + // then + Assert.isTrue(postAuthResponses.size() == 1); + Assert.areEqual('https://test.payment.link', postAuthResponses[0].paymentLink); + Assert.areEqual('2024-01-01T12:00:00+00:00', postAuthResponses[0].linkExpiresAt); + + } +} \ No newline at end of file diff --git a/force-app/main/default/classes/AdyenPaymentUtility.cls b/force-app/main/default/classes/AdyenPaymentUtility.cls index 867076f..fe8fab4 100644 --- a/force-app/main/default/classes/AdyenPaymentUtility.cls +++ b/force-app/main/default/classes/AdyenPaymentUtility.cls @@ -65,6 +65,8 @@ public with sharing class AdyenPaymentUtility { private static Adyen_Adapter__mdt retrieveAdapter(String fieldName, String fieldValue, String errorMessage) { String query = 'SELECT DeveloperName, MasterLabel, Capture_Endpoint__c, Endpoint_Api_Version__c, ' + 'System_Integrator_Name__c, Endpoint_Path__c, Merchant_Account__c, Refund_Endpoint__c, ' + + 'Named_Credential__c, Package_Namespace__c, Payment_Link_Endpoint__c, ' + + 'Payment_Link_Return_Url__c, Payment_Link_Theme_Id__c, Payment_Link_Expiry_Duration__c, ' + 'Authorize_Endpoint__c, HMAC_Key__c, Cancel_Endpoint__c ' + 'FROM Adyen_Adapter__mdt WHERE ' + fieldName + ' = :fieldValue';