Print Receipts

This method integrates receipt printing into your application.

In this topic:

Receipt Properties

Commerce SDK comes with the ability to print an EMV compliant receipt utilizing the integration with Star Micronics printers. If this integration is not utilized, it is the integrator’s responsibility to generate the appropriate receipt for both the consumer and the merchant. An appropriate receipt is dependent on items such as industry, card present vs. card not present and card entry method.

Below are data elements that must be included on a receipt for an EMV transaction in order to have an EMV compliant receipt. These data elements are returned to the integrator for use in generating an EMV compliant receipt. The following are data elements that should be included on a transaction receipt:

Data ElementDescription
Merchant NameName of business that would be recognized by the cardholder (and Merchant ID for UnionPay only).
Merchant LocationIncluding place of business (street address) city and state/province.
Transaction Receipt TypePurchase, Credit, Cash Back, Cash Disbursement, Refund
Transaction AmountTotal of all goods/services sold and any tips, taxes, fees, surcharges, adjustments, credits, cash back.
Transaction CurrencyIf not included, it is the local currency of the transaction country.
Transaction DateActual day which the products/services were exchanged.
Item DescriptionDescription of each product or service purchased. 
Authorization CodeComplete authorization code, provided by the Card issuing bank.
Card Network NameExamples: American Express, Discover, MasterCard, UnionPay or Visa
Account NumberSuppressed/truncated PAN or token (card expiration date must be omitted). 
Cardholder NameAs it appears on the Card if present – Discover Cards only (not required in Canada). 
Cardholder SignatureMerchants must retain a copy of a signed receipt for those that require signature.
Return PolicySpecific information regarding merchant’s return policy (refer to refund policy FAQ below).

Additionally, these data elements should be included on the receipt for an EMV transaction:

Transaction TagExamples/Values
Transaction Status Information (TSI)E800 (Offline Data Auth; CVM; Card Risk Mgmt; Terminal Risk Mgmt)
Terminal Verification Results (TVR)0200008000 (SDA; Floor Limit Exceeded)
Authorization Response Code (ARC)- 00 (Online Approval)
- 05 (Online Decline)
- Z3 (Unable to Online;Offline Declined)
Application ID (AID)- A0000000041010 (Mastercard)
- A00000002501 (Amex)
Application Counter (AC)0E9E8197FF2B672A

Cardholder Verification Method (CVM)

The CVM performed must be identified on the transaction receipt (even if no CVM was performed).  Possible values include:

Test/ValueDescription
No CVM RequiredAppears in the case where neither PIN nor Signature was required (i.e. NO CVM)
Verified by PINCardholder entered PIN on terminal
Verified by SignatureEither signature capture is performed on the terminal, or a signature line is printed on the receipt (to be signed)
Verified by PIN and SignatureAppears in the case where both PIN and Signature were required

Application Name

When possible, the Application Preferred Name should be rendered on any receipt.  If the Preferred Name cannot be rendered on the receipt, the Application Name should be used.

Code Samples

CWS

Request

PropertyDescription
method
string | required
printReceipt
requestId
string | required
Transaction Request ID
targetType
string | required
paymentGatewayConverge
parameters
JSONObject | required
All relevant parameters for printing receipts.
paymentGatewayId
string | required
Payment Gateway ID
Unique payment gateway identifier as returned in the openPaymentGateway transaction response.
transactionId
string | optional
Transaction ID
Unique transaction identifier of the approved transaction.
Note: Set the value to null (default) to print the last successful transaction.
receiptTerms
JSONObject | optional
Terms Map
A map of terms to be printed on the receipt.
“receiptTerms” : { “CARD” : “CreditCard”, “START” : “Start”, “EXPIRY” : “Expire”, “SALE” : “Sale”, “REFUND” : “Refundent”, “CASH” : “Cashless”, “CHECK” : “Checkered”, “GRATUITY” : “Tipsy”, “TOTAL” : “Totality”, “SUBTOTAL” : “not the whole amount”, “DISCOUNT” : “Discounted”, “TAX” : “Taxi” },
accountInfo
JSONObject | optional
Account Information
Alternate description of the business.
“accountInfo” : { “name” : “Pete’s Northside Dive”, “businessEmail” : “support@elavon.com”, “address1” : “8985 Ridgestone Ct”, “city” : “Roswell”, “stateProvince” : “GA”, “postalCode” : “30076” },

Example

Request
{
  "method" : "printReceipt",
  "requestId" : "1581202618",
  "targetType" : "paymentGatewayConverge",
  "version" : "1.0",
  "parameters" : {
    "receiptTerms" : {
      "CARD" : "CreditCard",
      "START" : "Start",
      "EXPIRY" : "Expire",
      "SALE" : "Sale",
      "REFUND" : "Refundent",
      "CASH" : "Cashless",
      "CHECK" : "Checkered",
      "GRATUITY" : "Tipsy",
      "TOTAL" : "Totality",
      "SUBTOTAL" : "not the whole amount",
      "DISCOUNT" : "Discounted",
      "TAX" : "Taxi"
    },
    "transactionId" : null,                    /* null implies last successful transaction */
    "localeLanguage" : "en",
    "localeCountry" : "US",
    "utcDate" : null,
    "paymentGatewayId" : "5af70b73-1c44-40c4-9cef-b0b4af0265b5",
    "accountInfo" : {
      "name" : "Pete's Northside Dive",
      "currencyCode" : "USD",
      "businessEmail" : "support@elavon.com",
      "address1" : "8985 Ridgestone Ct",
      "city" : "Roswell",
      "stateProvince" : "GA",
      "postalCode" : "30076",
      "isGratuitySupported" : false,
      "marketSegment" : null
    },
    "currencyFormatPattern" : "###,###.## USD",
    "receiptRequestor" : "CUSTOMER",
    "languageInformation" : {
        "languageCode" : "EN",
        "countryCode" : "US"
    }
  }
}
/* Reprint a receipt */
 
{
  "method" : "printReceipt",
  "requestId" : "1327657496",
  "targetType" : "paymentGatewayConverge",
  "version" : "1.0",
  "parameters" : {
    "receiptTerms" : {
      "CARD" : "CreditCard",
      "START" : "Start",
      "EXPIRY" : "Expire",
      "SALE" : "Sale",
      "REFUND" : "Refundent",
      "CASH" : "Cashless",
      "CHECK" : "Checkered",
      "GRATUITY" : "Tipsy",
      "TOTAL" : "Totality",
      "SUBTOTAL" : "not the whole amount",
      "DISCOUNT" : "Discounted",
      "TAX" : "Taxi"
    },
    "transactionId" : "070316A15-E4D15565-86A8-490F-A5F1-F9996C062800",   /* This transaction id */
    "localeLanguage" : "en",
    "localeCountry" : "US",
    "utcDate" : "2016/03/07 11:04:21",       /* On this date */
    "paymentGatewayId" : "2cdfef04-b699-4880-a294-ef8da0baaee7",
    "accountInfo" : {
      "name" : "Pete's Northside Dive",
      "currencyCode" : "USD",
      "businessEmail" : "support@elavon.com",
      "address1" : "8985 Ridgestone Ct",
      "city" : "Roswell",
      "stateProvince" : "GA",
      "postalCode" : "30076",
      "isGratuitySupported" : false,
      "marketSegment" : null
    },
    "currencyFormatPattern" : "###,###.## USD",
    "receiptRequestor" : "CUSTOMER",
    "languageInformation" : {
        "languageCode" : "EN",
        "countryCode" : "US"
    }
  }
}

Java

You will need to keep ECLTransaction, ECLTender and ECLOutcome from a completed transaction in order to print the last transaction, get the printer to us, and then tell ECLReceiptProcessor to send the receipt to that printer.

/* Create receipt using last transaction, tender, and outcome. Specify no account information override, customer as requestor, and no language override. */
final ECLReceiptProcessorInterface receiptProcessor = account.getReceiptProcessor();
ECLReceiptInterface receipt = receiptProcessor.createReceiptForCurrentTransaction(lastCompletedTransaction, lastCompletedTender, lastOutcome,
    null, ECLReceiptRequestor.CUSTOMER, null);

/* Create receipt processing listener for receipt processor callbacks */
ECLReceiptProcessingListener receiptProcessingListener = new ECLReceiptProcessingListener() {

    @Override
    public void receiptDidSucceed(ECLReceiptInterface eclReceiptInterface, ECLReceiptOutputType eclReceiptOutputType) {
    }

    @Override
    public void receiptDidFail(ECLReceiptInterface eclReceiptInterface, ECLReceiptOutputType eclReceiptOutputType, ECCError eccError) {
    }

    @Override
    public String receiptShouldProvideLocalizedText(ECLReceiptInterface eclReceiptInterface, ECLReceiptTextIdentifier eclReceiptTextIdentifier) {
        return null;
    }

    @Override
    public String receiptShouldProvideLocalizedMoneyText(ECLReceiptInterface eclReceiptInterface, ECLMoney eclMoney) {
        return null;
    }

    @Override
    public String receiptShouldProvideLocalizedPercentageText(ECLReceiptInterface eclReceiptInterface, BigDecimal bigDecimal) {
        return null;
    }
};

/* Search for a printer to use */
ECCError error = account.getPrinters().findDevices(new ECLDevicesSearchingListener() {
    /* This will be called during the search each time a printer is found. The deviceSearchDone will be called when searching is completed */
    @Override
    public void devicesSearchFound(String name, ECLDeviceConnectionType connection)
    {
    }

    /* This method is called when searching is completed */
    @Override                    
    public void devicesSearchDone(List<ECLDeviceSearchResult> deviceSearchResults)                    
    {                        
        if (deviceSearchResults.size() == 0)                    
        {
            /* No printers found. Need to tell user to connect a printer */
            return;
        }
        /* If there are multiple printers, you could show UI to let user choose which one to use. Here we will just use the first one */
        ECLDeviceSearchResult result = deviceSearchResults.get(0);
        ECLPrinterInterface printer = account.getPrinters().setDeviceToUse(result.getName(), result.getConnectionTypes());      
        receiptProcessor.printReceipt(receipt, printer, receiptProcessingListener);
    }                
}, ECLDeviceConnectionType.enumSetForAll(), FIND_DEVICES_TIMEOUT_IN_SECONDS);

if (error != null) 
{
    /* There was a problem starting the search. Show UI for error */
}

Objective-C

ECLReceiptProtocol

First you will need to implement the ECLDevicesSearchingDelegate which you will use to search for a printer and then print the receipt. We will also use the same class for aECLReceiptProcessingDelegate that we pass when printing the receipt.

/* In your header */
#import <Commerce-Converge/ECLReceiptProcessingDelegate.h>
#import <Commerce-Converge/ECLDevicesSearchingDelegate.h>


@interface ReceiptPrint : NSObject<ECLReceiptProcessingDelegate,ECLDevicesSearchingDelegate>

@property (readonly) id<ECLReceiptProcotol>)receipt;

+ (id)initWithReceipt:(id<ECLReceiptProcotol>)receipt;
@end

/* In your m file */

@implementation ReceiptPrint

+ (id)initWithReceipt:(id<ECLReceiptProcotol>)receiptParam {
    self = [super init];
    if (self) {
        _receipt = receiptParam;
    }
    return self;
}

+ (void)deviceSearchFound:(id<ECLDevicesProtocol>)devices name:(NSString *)name connection:(ECLDeviceConnectionType)connection {
    /* printer was found but lets wait until the search is done.
       We could show some progress to the user if we wanted. */
}

/* searchResults array contains ECLDeviceSearchResult */
+ (void)deviceSearchDone:(id<ECLDevicesProtocol>)devices searchResults:(NSArray *)searchResults {
    if ([searchResults count] == 0) {
        /* no printers. show UI to tell user to connect printer */
        return;
    }
    /* If there are multiple printers available we could show UI to let user choose. Here we will just use the first one to print the receipt . */
    ECLDeviceSearchResult *result = searchResults[0];
    id<ECLPrinterProtocol> printer = (id<ECLPrinterProtocol>)[account.printers setDeviceToUse:result.name connection:result.connectionTypes];
    [account.receiptProcessor printReceipt:_receipt printer:printer delegate:self];
}

/* This will be called when the receipt was successfully printer, emailed, etc. */
+ (void)receiptDidSucceed:(id<ECLReceiptProtocol>)receipt output:(ECLReceiptOutputType)output {
}

/* This will be called when the receipt failed to go to printer, email, etc. */
+ (void)receiptDidFail:(id<ECLReceiptProtocol>)receipt output:(ECLReceiptOutputType)output error:(NSError *)error {
}

/* Commerce does not provide localization so you need to provide the localized text for each of the following methods */

+ (NSString *)receiptShouldProvideLocalizedText:(id<ECLReceiptProtocol>)receipt for:(ECLReceiptTextIdentifier)textIdentifier {
    /* return localized text for the ID */
}

+ (NSString *)receiptShouldProvideLocalizedMoneyText:(id<ECLReceiptProtocol>)receipt amount:(ECLMoney *)amount {
    /* You can use our provided methods for this */
    return [ECLMoneyUtil stringFromMoney:amount withSymbol:NO withSeparators:NO];
}

+ (NSString *)receiptShouldProvideLocalizedPercentageText:(id<ECLReceiptProtocol>)receipt for:(NSNumber *)percentage {
    /* return localized text for the percentage */
}

+ (NSString *)receiptShouldProvideLocalizedText:(id<ECLReceiptProtocol>)receipt forTransactionResult:(ECLTransactionResult)result {
    /* return localized text for the transaction result */
}

+ (NSString *)receiptShouldProvideLocalizedText:(id<ECLReceiptProtocol>)receipt forCardScheme:(ECLCardTenderScheme)cardScheme {
    /* return localized text for the card scheme */
}
@end

Now that we have our printer search delegate and a receipt processing delegate we can print the receipt.

/* Create receipt using last transaction, tender, and outcome. Specify no account information override, customer as requestor, and no language override. */
id<ECLReceiptProcessorProtocol> receiptProcessor = account.receiptProcessor;
id<ECLReceiptProtocol> receipt = [receiptProcessor createReceiptForCurrentTransaction:lastCompletedTransaction using:lastCompletedTender withOutcome:lastOutcome
    accountInformation:nil requestor:ECLReceiptRequestor_Customer languageInformation:nil];

/* Search for a printer to use and then our delegate will print the receipt */
NSError *error = [account.printers findDevices:[[ReceiptPrint alloc] initWithReceipt:receipt] connection:allDeviceConnectionsTypes()  timeoutInSecond:30];

if (error != nil) {
    /* error starting search. Show UI */
    return;
}

C#

PrintBackEndArgs

m_PrintPaymentArgs = new PrintPaymentArgs();
m_PrintPaymentArgs.paymentGatewayId = m_PaymentGatewayId;
m_PrintPaymentArgs.accountInfo = null;
m_PrintPaymentArgs.receiptRequestor = ReceiptRequestor.CUSTOMER.ToString();
m_PrintPaymentArgs.languageInformation = null;
 
m_PrintPaymentArgs.transactionId = null;
m_CWS.StartPrintPaymentReceipt(m_PrintPaymentArgs, MyNotifyCWSEvent, MyPaymentComplete);
 
/* To reprint */
 
m_PrintPaymentArgs.transactionId = origTransId;
m_PrintPaymentArgs.utcDate = origDate;
m_CWS.StartPrintPaymentReceipt(m_PrintPaymentArgs, MyNotifyCWSEvent, MyPaymentComplete);