Get Started

Tailor-Made Itineraries

Tour & Cruise Itineraries

FIT Package Itineraries

Role Guides

Kaptio Admin

Supplier Contracting

Product Design/Build

Product Content

Training Manager

Data Experts

Developers

Kaptio Platform Architecture

Architecture Overview

Development Guidelines

Functional Decomposition

Platform FAQ

New to Salesforce?

Security & Compliance

Manage your Environments

Data Import & Export

Global Platform Setup

Getting Started with Core Configuration

Manage Global Settings

Configure Channels

Managing Users, Roles & Access

Understanding Your Sample Data

PIM: Supplier Contracting

Managing Suppliers

Setup Locations

Managing Services

Configure Prices

Bulk Import Service Data

Manage Inventory

Promotion & Discount Setup

PIM: Tour & Package Design

Getting Started with Packages

Understanding Departure Types

Manage Package Pricing

Setup Package Content

Configure Package Defaulting

CRM Module

Customizing Kaptio Travel

Manage Account Record Types

Setup Trip & Itinerary Workflow

Manage Salesforce Features

CONNECT: Land & Air Connectivity

Getting Started with Connectivity

PNR Import Setup & Usage

Integrating Amadeus

Hotel Connectivity Setup & Usage

DOCS Module

Getting Started: Content

Managing Content & Media

Setup Document Stages

Setup Templates

Building Custom Content Components

Bulk Import Content Data

Using the Document Starter Kit

Using the ATOL Certificate Starter Kit

Personalizing Documents

Generating Documents

Customer Access to Documents

Email Setup & Usage

Advanced Sample Email Template

CRS: Training Guides

Getting Started: Training

Training Reservation Teams

Training Finance Teams

PAY: Payment Gateway Integrations

Getting Started: Payments

Implementing Braintree/PayPal

Integrating Your Own Gateway

Data Migration

Guide to Booking Migration

Peripheral Integration Guides

Accounting Integration

Data Warehouse Integration

Website Integration

This 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:

Payment Settings Setup

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:

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;
}