Performing an EMV Sale

Step 1 - Create Transaction Object

Create the Transaction object for the particular gateway you want to use:

final EmvTransaction transaction = new AnyPayTransaction();
transaction.setTransactionType(TransactionType.SALE);

// Currency is required
transaction.setCurrency("USD");
initWithType:ANPTransactionType_SALE];

transaction.currency = @"USD";

Step 2 - Set the Amount

The simple method is to set the amount as follows.

transaction.setTotalAmount(new Amount("10.00"));
transaction.totalAmount = [ANPAmount amountWithDouble:(double)10.00];
// with string:
// transaction.totalAmount = [ANPAmount amountWithString:self.textField.text];

Otherwise, the total may be derived via a more complex arrangement (subtotal + taxes + tips) etc..

OPTIONAL: To add tax, a tip, or a convenience fee, just set a subtotal and invoke the corresponding Add methods for the type of surcharge. You can add as many as you like (though you can only add one tip)

transaction.setSubtotal(new Amount("10.00"));

transaction.addTax(new TaxLineItem("GST", "5.00%"));
transaction.addTax(new TaxLineItem("PST", "6.00%"));
transaction.setTip(new TipLineItem("15.00%"));                            // Accepts percentages or fixed values (e.g. $1.50).
transaction.addFee(new FeeLineItem("Convenience Fee", "3.00%"));    // Accepts percentages or fixed values (e.g. $1.50).

// Note:  With some gateways, it is possible to create a split-funding fee, which will settle to a different account.
// To make this happen, just make the fee an instance of a SplitFundingFeeLineItem.

transaction.addFee(new SplitFundingFeeLineItem("Processor Fee", "2.50%", "1234567"));

// Once a subtotal has been set, you can automatically calculate the taxes, tips, fees, and total amount by using the calculateAmounts() helper
// method. It will calculate the relevant tax, tip, and fee amounts, and the final total.

transaction.calculateAmounts();

String taxAmount = transaction.getTax("GST").getAmount().toLocalizedCurrencyString();               // should be "0.50" (5.00% of $10.00 subtotal)
String tipAmount = transaction.getTip().getAmount().toLocalizedCurrencyString();                          // should be "1.50" (15% of $10.00 subtotal)
String feeAmount = transaction.getFee("Convenience Fee").getAmount().toLocalizedCurrencyString();   // should be "0.30" (3.00% of $10.00 subtotal)
String totalAmount = transaction.getTotalAmount().toLocalizedCurrencyString();                            // Should be "13.15" ($10 subtotal + 5% GST, 6% PST + 3% fee + 2.5% fee + 15% tip)

// SIDEBAR:  The calculateAmounts() method will always calculate everything against the subtotal.
//           If you need something more advanced (such as calculating tips on the total after taxes),
//           you can calculate the amounts yourself.  To do this, simply call the calculateOn method
//           with the value you want to calculate against.

// Example:
String tipOnTotalAmount = transaction.getTip().calculateOn(transaction.getTotalAmount()).toLocalizedCurrencyString();
transaction.subtotal = [ANPAmount amountWithString:self.textField.text];
    
ANPTaxLineItem *taxItem = [[ANPTaxLineItem alloc] initWithName:@"TAX1" rate:[ANPAmount amountWithString:@"11"] surchargeCalculationMethod:ANPSurchargeCalculationMethod_PERCENTAGE_SUBTOTAL];
[transaction addTaxItem:taxItem];

ANPFeeLineItem *feeItem = [[ANPFeeLineItem alloc] initWithName:@"FEE1" rate:[ANPAmount amountWithString:@"10"] surchargeCalculationMethod:ANPSurchargeCalculationMethod_FLAT_RATE];
[transaction addFeeItem:feeItem];
    
[transaction calculateAmounts];

Step 3 - Set any desired optional fields

Any of the fields below can be added to the transaction, but are not required:

transaction.setGeolocationData(GeolocationController.getLastKnownPosition());

transaction.setOperator(Session.getInstance().user.getUsername());

transaction.setCurrency("USD");                        // The default currency will typically be specified by the gateway.  Use this method to override it.

transaction.setPaymentMethod(PaymentMethod.CREDIT);    // The payment method type (i.e. CASH, CREDIT, DEBIT, CRYPTO, etc..)

transaction.setKeywords("Shirt Cotton Blue Sweater");  // Keywords that can be used in a future search to find the transaction quickly.  Separated by spaces

transaction.setNotes("This purchase is a gift");       // Freeform text field

transaction.addCustomField("yourCustomFieldName", "yourCustomFieldValue");  // You can add as many of these as you wish.
// The default currency will typically be specified by the gateway.
// Use this method to override it.
[transaction setCurrency:@"USD"];

[transaction setNotes:@"This purchase is a gift"];       // Freeform text field

Step 4 - Attach a Card Reader (Android)

This step may be skipped for keyed transactions.

For card-present transactions the following line tells the transaction that it should receive card information from the associated reader.
When transaction.execute() is called, it will automatically invoke the reader and submit the transaction to the endpoint server when the user swipes/dips/taps the card.

transaction.useCardReader(reader);

Step 5 - Register Callbacks (Android)

The following method sets the callback that will get invoked if the transaction requires a signature (i.e. chip and signature transaction). Required for chip and signature transactions and swiped transactions.

transaction.setOnSignatureRequiredListener(new GenericEventListener() {
  @Override
  public void onEvent() {
    // ?TODO? - Capture signature, assign it to the transaciton, then call the "proceed()" method.

    // Please be sure to capture the signature in the format required by the endpoint.
    // For now, we'll just send an empty signature.
    CoreSignature s = new CoreSignature(); // This is the signature format required for this demo.
    transaction.setSignature(s);

    // The transaction is blocked until the signature is captured, so be sure to call proceed() when done to resume the transaction.
    transaction.proceed();
  }
});

// OPTIONAL:  The following method sets the callback that will get invoked if the transaction requires account selection (i.e. choosing between CHECKING and SAVINGS transactions)
//            This typically would only be fired if you support bank debit cards.

transaction.setOnAccountSelectionRequiredListener(new GenericEventListener() {
  @Override
  public void onEvent() {
    // TODO - You can display a user interface to allow the user to select the account type.

    // For this example, we'll just default to CHECKING.
    transaction.setAccountType(AccountType.CHECKING);
    // The transaction is blocked until the account is selected, so be sure to call proceed() when done to resume the transaction.
    transaction.proceed();
  }
});

// OPTIONAL:  If you want to receive notification of card reader events, such as CARD_INSERTED, uncomment the following lines:
/*
// Update:  This was removed in 0.9 beta.  Kept here for backward compatibility
transaction.subscribeCardReaderEvents(new MeaningfulMessageListener() {
  @Override
  public void onMessage(MeaningfulMessage message) {
    // Generally speaking, notification events have no functional value other
    // than human interface considerations and shouldn't require any special logic.

    // TODO - Update UI or other trivial operation.
  }
});
*/

// OPTIONAL:  If you want to receive notification of warnings (i.e. non-fatal but unexpected events) that occurred during a transaction,
//            uncomment the following lines:
/*
transaction.setOnWarningListener(new MeaningfulMessageListener() {
	@Override
  public void onMessage(MeaningfulMessage message) {
    // Something unexpected happened, but the transaction will continue.

    // TODO - Notify user to take some custom action.
  }
});
*/

Step 6 - Execute the Transaction

This will activate the specified card reader and send the data to the server.

transaction.execute(new CardTransactionListener() {
  @Override
  public void onCardReaderEvent(MeaningfulMessage meaningfulMessage) {
    // This event will fire to inform you of the card reader events
    transactionListener.onCardReaderEvent(meaningfulMessage);
  }

  @Override
  public void onTransactionCompleted() {
    // The transaction completed (i.e. received a valid response from the server).
    // This does NOT mean the transaction was approved.

    if ( transaction.isPartiallyApproved() )
    {
    // Transaction was approved, but not for the full amount.  Check the ApprovedAmount field
    // to see how much was actually approved.
    }
    else if ( transaction.isApproved() )
    {
    // Transaction approved for the full amount requested
    }
    else
    {
    // Transaction declined.  Check the response for details.
    GatewayResponse response = transaction.getGatewayResponse();
    String reasonForDecline = response.getResponseText();
    }

    // Notify the user
    transactionListener.onTransactionCompleted();
  }

  @Override
    public void onTransactionFailed(MeaningfulError reason) {
      // Something went wrong and a valid response was not received from the server.

      // Reverse the transaction to ensure consistency.
      // The cancel method will queue the transaction for reversal when an internet
      // connection is present again.
      transaction.cancel();

      transactionListener.onTransactionFailed(reason);
    }
  });
}
[transaction execute:^(ANPTransactionStatus status, ANPMeaningfulError * _Nullable error) {
        if (status == ANPTransactionStatus_APPROVED) {
            NSLog(@"Ref Transaction APPROVED");
            [self appendText:[NSString stringWithFormat:@"\n\n EMV Sale Transaction Approved."]];
            
            ANPPropayTransaction *tr = [ANPDatabase getTransactionWithId:transaction.internalID];
            NSLog(@"Fetched Tranasction %@", tr.externalID);
            
            
            //[self appendText:[NSString stringWithFormat:@"\n\n Signature Required."]];
            
            //[self performSegueWithIdentifier:@"PresentSignatureViewController" sender:nil];
          });
        }
        else if (status == ANPTransactionStatus_DECLINED) {
            NSLog(@"Ref Transaction DECLINED");
            [self appendText:[NSString stringWithFormat:@"\n\n EMV Sale Transaction DECLINED"]];
        }
        else {
            NSLog(@"Ref Transaction Failed");
            [self appendText:[NSString stringWithFormat:@"\n\n EMV Sale Transaction Failed -- %@", error.message]];
        }
    } cardReaderEvent:^(ANPMeaningfulMessage * _Nullable message) {
        NSLog(@"On Card Reader Event");
        [self appendText:[NSString stringWithFormat:@"\n\n %@", message.message]];
    }];