Get Started
Tailor-Made ItinerariesTour & Cruise ItinerariesFIT Package ItinerariesRole Guides
Kaptio AdminSupplier ContractingProduct Design/BuildProduct ContentTraining ManagerData ExpertsDevelopersKaptio Platform Architecture
Architecture OverviewDevelopment GuidelinesFunctional DecompositionPlatform FAQNew to Salesforce?Security & ComplianceManage your EnvironmentsData Import & ExportGlobal Platform Setup
Getting Started with Core ConfigurationManage Global SettingsConfigure ChannelsManaging Users, Roles & AccessUnderstanding Your Sample DataPIM: Supplier Contracting
Managing SuppliersSetup LocationsManaging ServicesConfigure PricesBulk Import Service DataManage InventoryPromotion & Discount SetupPIM: Tour & Package Design
Getting Started with PackagesUnderstanding Departure TypesManage Package PricingSetup Package ContentConfigure Package DefaultingCRM Module
Customizing Kaptio TravelManage Account Record TypesSetup Trip & Itinerary WorkflowManage Salesforce FeaturesCONNECT: Land & Air Connectivity
Getting Started with ConnectivityPNR Import Setup & UsageIntegrating Amadeus Hotel Connectivity Setup & UsageDOCS Module
Getting Started: ContentManaging Content & MediaSetup Document StagesSetup TemplatesBuilding Custom Content ComponentsBulk Import Content DataUsing the Document Starter KitUsing the ATOL Certificate Starter KitPersonalizing DocumentsGenerating DocumentsCustomer Access to DocumentsEmail Setup & UsageAdvanced Sample Email TemplateCRS: Training Guides
Getting Started: TrainingTraining Reservation TeamsTraining Finance TeamsPAY: Payment Gateway Integrations
Getting Started: PaymentsImplementing Braintree/PayPalIntegrating Your Own GatewayData Migration
Guide to Booking MigrationPeripheral Integration Guides
Accounting IntegrationData Warehouse IntegrationWebsite IntegrationThis guide provides instructions for integrating custom payment gateways using Apex code. It covers topics such as creating a payment gateway record, setting up payment settings, and developing a global payment handler class that implements the necessary KaptioTravel.IPaymentGateway methods. The guide also includes example code for authentication requests and responses, payment handler methods, and payment output. If you are looking to integrate a custom payment gateway into your Kaptio system, this guide is for you.
Payment Gateway Setup
First of all you need to create a Payment Gateway (KaptioTravel__PaymentGateway__c
) record. KaptioTravel__PaymentGateway__c
stores payment gateway settings and authentication parameters used when making callouts to a payment service. They can be found under the Payment Gateway tab. Fields on this object are:
ApexClass__c
– Name of the apex class that implements the KaptioTravel global interface for handling payment requests, response and callbacks.CallbackPage__c
– The Visualforce Page that handles the callback once payment attempt has been made.PaymentPage__c
– Name of the Visualforce page that displays and processes user inputs (address, credit card, user info, etc.). Leave this field empty if you do not need to customize.PropertiesJSON__c
– Properties, authentication and other variables used for payment engine integration. Each payment engine has different authentication and properties, therefore we use a flexible data storage mechanism (i.e JSON).
Payment Settings Setup
- Go to the Channel details page -> Payment Settings → New
- Select visibility, set the type to payment gateway, select Payment Gateway and choose the gateway you have defined.
- Set Require Payer’s Address to true if you want to display the billing address inputs on the payment page.
IPaymentGateway Interface
For implementation of the new Payment Gateway you need to develop a global payment handler class which should implement the following KaptioTravel.IPaymentGateway methods:
/**
* @author Ragnar
* @date 2016/08/01
* @description Interface (i.e. contract) for Payment Gateway implementation
*/
global interface IPaymentGateway {
/**
* @description Returns a HttpRequest for the paymentRequestId
* @param p_stagingRecord - PaymentRequest__c record
* @param p_orderInfo - Map<String, Object> of additional payment params
* @return HttpRequest instance.
**/
HttpRequest makeRequest(PaymentRequest__c p_stagingRecord, Map<String, Object> p_orderInfo);
/**
* @description Returns the redirctURL provided by the payment gateway for so the customer can proceed with his payment.
* @return String - Redirect page Url.
**/
String getRedirectURL();
/**
* @description populates PaymentRequest__c record with additional params needed in next steps
* @param p_paymentRequest - PaymentRequest__c record
* @return PaymentRequest__c.
**/
PaymentRequest__c populatePaymentRequest(PaymentRequest__c p_paymentRequest);
/**
* @description Allows the consumer to populate information about the paymnet into the transaction logged in Kaptio using the callbackPage as as source.
* @param p_payment - Transaction__c record
* @return Transaction__c - Transaction__c record
**/
Transaction__c populatePayment(Transaction__c p_payment);
/**
* @description Parse information about the paymnet into and saves it in inner vars.
* @param p_callbackResponse - response from payment service
* @return void
**/
void parseResponse(String p_callbackResponse);
/**
* @description Checks the status of transaction.
* @param p_callbackResponse - response from payment service
* @return Boolean - success/failer
**/
Boolean isSuccess();
/**
* @description Returns Payment error message
* @return String - error maethod
**/
String getErrorMessage();
/**
* @description returns the name of payment gateway
* @return String.
**/
String getGatewayName();
}
Payment Handler Class
Note: Payment handler class should have default constructor without parameters. In example ResponseDto
- is a wrapper class for payment service response properties
/**
* @description default constructor, used in payment process
**/
public PaymentHandlerController() {
response = new ResponseDto();
}
Payment handler methods are used in CustomerPaymentRequestDto
and CustomerPaymentResponseDto
global classes. Please be aware of the following suggestions:
- Use
KaptioTravel.CustomerPaymentRequestDto
global helper class for working with theKaptioTravel__PaymentRequest__c
sObject record. This object contains all information about request/ response from the payment service. - You can retrieve
KaptioTravel__PaymentGateway__c
in the payment handler byp_stagingRecord.KaptioTravel__PaymentGateway__c
. - You can store any information to
p_orderInfo
. This map will be serialized and saved toKaptioTravel__PaymentRequest__c
. - The
p_orderInfo
map contains all information related to the user selection on previous payment steps.(see ex.)
Authentication Request
The below example uses the Altapay Hosted Payments API. The MakeRequest method should prepare the HttpRequest instance with required properties for the authentication request to the payment service.
public HttpRequest makeRequest(KaptioTravel__PaymentRequest__c p_stagingRecord, Map < String, Object > p_orderInfo) {
paymentRequest = new KaptioTravel.CustomerPaymentRequestDto(p_stagingRecord);
itineraryRecord = KtTemplateController.queryItineraryRecord(p_stagingRecord.KaptioTravel__itinerary__c);
List < KaptioTravel__Transaction__c > itineraryTransactions = [select Id from KaptioTravel__Transaction__c where KaptioTravel__Itinerary__c =: itineraryRecord.Id];
// Payment is pre-auth compatible if no payment has been taken and itinerary PaymentCaptureType__c field is set to pre-auth value.
Boolean preAuthCompatible = itineraryTransactions.isEmpty() && itineraryRecord.PaymentCaptureType__c.equals('Pre-Authorise Payment');
HttpRequest req = new HttpRequest();
KaptioTravel__PaymentGateway__c paymentGateway = [SELECT Id, KaptioTravel__PropertiesJSON__c FROM KaptioTravel__PaymentGateway__c WHERE Id =: p_stagingRecord.KaptioTravel__PaymentGateway__c];
PropertiesDto properties = (PropertiesDto) JSON.deserialize(paymentGateway.KaptioTravel__PropertiesJSON__c, PropertiesDto.class);
PageReference pref = new PageReference('https://' + properties.merchant_domain + '.altapaysecure.com/merchant/API/createPaymentRequest';);
Map < String, String > paramsMap = new Map < String, String > ();
PageReference callbackSuccess = paymentRequest.getCallbackSuccessURL();
PageReference callbackFailure = paymentRequest.getCallbackFailureURL();
Id paymentRequestId = (Id) callbackSuccess.getParameters().get('id');
Id sobjId = ApexPages.currentPage().getParameters().get('id');
//check if it's itinerary - redirect to package page due to custom page requires contentId
if (sobjId.getSobjectType() == KaptioTravel__Itinerary__c.getSobjectType()) {
callbackSuccess = new PageReference(URL.getSalesforceBaseUrl().toExternalForm() + Page.KaptioTravel__CustomerPaymentResult.getUrl());
callbackSuccess.getParameters().put('request', paymentRequest.encryptedRequestKey);
callbackSuccess.getParameters().put('id', paymentRequestId);
callbackFailure = callbackSuccess;
} else {
callbackSuccess.getParameters().put('prId', paymentRequestId);
callbackSuccess.getParameters().put('id', sobjId);
callbackFailure.getParameters().put('prId', paymentRequestId);
callbackFailure.getParameters().put('id', sobjId);
}
putParamToRequestMap(paramsMap, 'terminal', properties.terminal_name);
putParamToRequestMap(paramsMap, 'shop_orderid', itineraryRecord.KaptioTravel__Itinerary_No__c);
putParamToRequestMap(paramsMap, 'transaction_info[0]', EncodingUtil.base64Encode(Blob.valueOf(itineraryRecord.Id)));
putParamToRequestMap(paramsMap, 'amount', String.valueOf(p_stagingRecord.KaptioTravel__Amount__c));
putParamToRequestMap(paramsMap, 'currency', p_stagingRecord.CurrencyIsoCode);
putParamToRequestMap(paramsMap, 'language', itineraryRecord.KaptioTravel__Channel__r.KaptioTravel__LanguageCode__c);
String paymentType = preAuthCompatible ? 'payment' : 'paymentAndCapture';
putParamToRequestMap(paramsMap, 'type', paymentType);
putParamToRequestMap(paramsMap, 'config[callback_form]', getCallbackFormURL(p_stagingRecord.Id));
putParamToRequestMap(paramsMap, 'config[callback_ok]', callbackSuccess.getURL() + '&sid=' + UserInfo.getSessionId());
putParamToRequestMap(paramsMap, 'config[callback_fail]', callbackFailure.getURL() + '&sid=' + UserInfo.getSessionId());
//push order items to request if it defined
if (p_orderInfo.get('orderItems') != NULL) {
Integer n = 0;
for (Object orderItemObj: (List < Object > ) p_orderInfo.get('orderItems')) {
Map < String, Object > orderItem = (Map < String, Object > ) orderItemObj;
// pre auth textual handling to show the user that it will be a preauth payment.
String additionalDescription = preAuthCompatible ? 'Pre-Authorised ' : '';
orderItem.put('itemName', additionalDescription + orderItem.get('itemName'));
putParamToRequestMap(paramsMap, 'orderLines[' + n + '][itemId]', p_stagingRecord.Id + String.valueOf(n));
putParamToRequestMap(paramsMap, 'orderLines[' + n + '][description]', orderItem.get('itemDescription'));
putParamToRequestMap(paramsMap, 'orderLines[' + n + '][unitPrice]', orderItem.get('amount'));
putParamToRequestMap(paramsMap, 'orderLines[' + n + '][quantity]', orderItem.get('quantity'));
n++;
}
}
//push billing information to request from user inputs
if (p_orderInfo.get('billingInfo') != NULL) {
Map < String, Object > billingInfo = (Map < String, Object > ) p_orderInfo.get('billingInfo');
String billingAddress;
if (billingInfo.get('address') != null)
billingAddress = String.valueOf(billingInfo.get('address')).length() > 30 ? String.valueOf(billingInfo.get('address')).left(30) : String.valueOf(billingInfo.get('address'));
putParamToRequestMap(paramsMap, 'customer_info[billing_address]', billingAddress);
putParamToRequestMap(paramsMap, 'customer_info[billing_firstname]', billingInfo.get('firstname'));
putParamToRequestMap(paramsMap, 'customer_info[billing_lastname]', billingInfo.get('lastname'));
putParamToRequestMap(paramsMap, 'customer_info[billing_postal]', billingInfo.get('postalCode'));
putParamToRequestMap(paramsMap, 'customer_info[billing_city]', billingInfo.get('city'));
putParamToRequestMap(paramsMap, 'customer_info[billing_country]', billingInfo.get('country'));
putParamToRequestMap(paramsMap, 'customer_info[email]', billingInfo.get('email'));
}
pref.getParameters().putAll(paramsMap);
Blob headerValue = Blob.valueOf(properties.username + ':' + properties.password);
String authorizationHeader = 'Basic ' + EncodingUtil.base64Encode(headerValue);
req.setEndpoint(pref.getURL());
req.setHeader('Authorization', authorizationHeader);
req.setMethod('POST');
system.debug('param:' + paramsMap);
return req;
}
Authentication Response
After the authentication response is returned from the payment service, the following methods will run:
- ParseResponse(String responseBody) — response should be parsed and saved to the local properties (will be used in the next functions)
- isSuccess() – returns true/ false based on payment service response
- GetErrorMessage() – returns error message from response
- GetRedirectURL() – returns url to the payment form of the payment service.
- PopulatePaymentRequest(PaymentRequest__c stagingRecord) – Here the PaymentRequest__c default values can be overridden.
After that, the PaymentRequest__c record will be updated (by kaptio inner classes).
Next, the user will be redirected to the payment service payment page. After the user makes a payment, he will be redirected to the callbackUrl.
Payment Response
We have CustomerPaymentResponseDto.cls as the process response:
KaptioTravel.CustomerPaymentResponseDto cp_response = new KaptioTravel.CustomerPaymentResponseDto(paymentRequestId, ktkey, ApexPages.currentPage().getURL());
if (cp_response.isSuccess) {
//show success block
//Use created Transaction__c record for output all information related to payment
cp_response.payment.KaptioTravel__Amount__c,
cp_response.payment.KaptioTravel__PaymentInfo__c,
cp_response.payment.KaptioTravel__PayerName__c,
cp_response.payment.KaptioTravel__PayerEmail__c,
....
} else {
//show error message
cp_response.errorMessage
Calls the following handler’s methods:
- ParseResponse(String responseBody) — response should be parsed and saved to the local properties (will be used in next functions)
- isSuccess() – returns true/ false based on the payment service response
- GetErrorMessage() – returns error message from the response
- PopulatePayment(
KaptioTravel__Transaction__c
payment) – Payment gateway specific data can be populated
Example code:
public KaptioTravel__Transaction__c populatePayment(KaptioTravel__Transaction__c p_payment) {
p_payment.CardType__c = response.paymentScheme;
p_payment.KaptioTravel__PaymentInfo__c = String.format(
' Paid via WorldPay\n Transaction ID: {0}\n Payment ID: {1}\n \n Credit Card: {3}',
new List < String > {
response.transactionId,
response.paymentId,
response.paymentStatus,
response.maskedCreditCard
});
if (response.surchargeAmount != NULL) {
p_payment.KaptioTravel__Surcharge__c = response.surchargeAmount;
}
return p_payment;
}
Payment Output
We use the CustomerPayments.component for payment outputs. The CustomerPayments component displays a table of PaymentSchedule__c records and provides select options with amounts based on itinerary guest groups (or Group Size). We also build available payment methods based on Channel settings.
How to Useturned_in
You need to include kaptio CustomerPaymens.component to your custom page and configure Channel payment schedules and payment settings.
<KaptioTravel:CustomerPayments itineraryId="{!
itineraryRecord.Id
}" isExternalPage="true" saveRetUrl="{!$Page.PaymentHandler}?Id={!$
CurrentPage.parameters.id
}" showTransactions="true" />
CustomerPayments
parameters
- itineraryId(required) – Id of
KaptioTravel__Itinerary__c
record. - redirectIdValue – Id of sObject that would be posted in get params(used in “redirect to custom Vf page ” payment method)
- cancelUrl – retUrl for cancel action
- showTransactions – show/hide transactions
- showCreditCardInputSection – Display Credit Card inputs (can be overridden on the channel level)
- showAddressInputSection– Display Billing Address inputs (can be overridden on the channel level)
- amountCurrencySymbol – Symbol which will be displayed instead of CurrencyIsoCode
- isExternalPage – Set to true for external site pages. Used in building of available payment methods.
Payment Result Page (for payment gateway payment method)
We do not have any global component for the output of payment result. If you do not want to customize it, you can use the kaptio default “CustomerPaymentResult.page”. Otherwise you need to implement a custom page and use the Kaptio CustomerPaymentResponseDto global class.