# Fortis Payment SDK
This SDK allows you to easily process payments and refunds through the Fortis payment gateway from within your iOS app.  It enables you to use both manual entry and mobile readers for taking payment and receiving feedback from our gateway to let you know if a payment has processed.  The SDK includes support for the ID Tech VP3300, and soon will also support the MagTek iDynamo.

##NOTE
The iOS SDK is now packaged with separate versions of the PaymentSDK.framework folder depending on which version of Swift you are using as well as which reader types you want to support.  Initially decide if you are developing with Xcode 14.2/Swift 5.7, Xcode 14.3/Swift 5.8, or Xcode 14.3.1/Swift 5.8.1.

The CocoaPod will always be for the most recent version of Swift and will be a full build including MagTek support.

## Mobile SDK Process Flow
To use the Mobile SDK, you will first need to ensure that Fortis' support team has sent you your appropriate credentials.  Then before beginning, analyze your codebase to determine the best location for handling the transaction flow.  For instance, you may want to add a new class to handle both the calls to the SDK and the callbacks from the SDK.  To determine where and how to best implement the integration, consider the following steps:

1. **Initialize:** Determine which class or module to implement the functionality.  In the initialization routines for that class:

* Create a RestServiceClient and setup whether the SDK should connect to our sandbox server or to our live one.

* Create a Dictionary/HashMap of parameters for the request headers required for a transaction.  These include your developer-id, user-id, and user-api-key.

* Set the Request Headers for the RestServiceClient using the object you created in step 2.

* Create a new EMVTransaction object passing in the RestServiceClient

2. **Search:** Start searching for a reader by calling the EMVTransaction's scanForDevices method.  Ensure that your reader is powered on and waiting for a connection.  If you are using a MagTek iDynamo, then the reader should be physically connected to your device.

3. **Connect:** Any ID Tech VP3300 readers that are found will generate a deviceScanResponse callback from the SDK.  When you receive that callback, take action to record the reader's information (name and id).  Once you are ready to initiate a connection call connectDeviceByName or connectDeviceByAddress to connect to the device.  The SDK will initiate the connection and then generate a deviceConnected callback.  *Note that for MagTek iDynamo readers the deviceScanResponse callback is not guaranteed.  The reader will immediately be connected to because it is physically connected to the device, and you will receive the deviceConnected callback.*

4. **Start Transaction**: When you're ready to initiate a transaction, create a Dictionary/HashMap of parameters for the transaction, including at minimum: action, payment_method, transaction_type, location_id, and transaction_amount.  Call performEMVSale to initiate the Transaction flow. 

5. **Display Results:** The transactionResponse callback will indicate the success or failure of the transaction as well as provide additional details to use.

## Using the Fortis Payment SDK
The Fortis Payment SDK can easily be imported into your project by using the following instructions: 

1. Initialize CocoaPods for your project by following the documentation at: [https://guides.cocoapods.org/using/using-cocoapods](https://guides.cocoapods.org/using/using-cocoapods "https://guides.cocoapods.org/using/using-cocoapods")

2. Open the Podfile in the Pods project in your workspace.  Add the following line inside the target’s block that you’re wanting to include the SDK in.

```
pod 'FortisPaymentSDK'
```
3. Clean your project and then build it.

4. In the class you would like to use the SDK in, add the following line at the top:

For Swift: 
```swift
      import PaymentSDK
```
For Objective-C:
```objective-c
      #import <PaymentSDK/PaymentSDK.h>
```

5. Determine which class you are implementing the functionality in and create an object of type RestServiceClient:

```swift
// apiHostname = either api.zeamster.com or api.sandbox.zeamster.com
// apiEndpointPath = /v2/transactions - full endpoint of the API
let restServiceClient = RestServiceClient(apiProtocol:"https", apiHostName:"api.sandbox.zeamster.com", apiEndpointPath:"/v2/transactions")
```
6. Create a dictionary with the developer credentials provided by Fortis for API access, and then call setRequestHeader with this dictionary. If additional headers are required, add them to this dictionary as well.

```swift
// Include header variables as necessary.  
var transactionHeaderDict : [String : String]!  = [:]
transactionHeaderDict["user-id"]="FortisAPIUserID"
transactionHeaderDict["user-api-key"]="FortisAPIUserAPIKey"
transactionHeaderDict["developer-id"]="FortisAPIDeveloperID"
```

7. Create another dictionary with all fields required for the POST to the API.  These will be included in the POST body.  Ensure that you include the appropriate Fortis Location ID, Action, and Transaction Amount.

```swift
// Include all relevant transaction parameters
var transactionParamDict : [String : String]!  = [:]
transactionParamDict["action"]="sale"   // or "refund"
transactionParamDict["payment_method"]="cc"
transactionParamDict["transaction_type"]="sale"
transactionParamDict["location_id"]="FortisLocationID"
transactionParamDict["transaction_amount"]="155.99"
```
8. Determine which type of transactions you want to support.  The SDK supports both Non EMV Transactions (card not present) and EMV transactions, which includes swipe, tap, or dip.

### Non EMV transactions
* Set the http request header details for the restServiceClient object.
```swift
restClientService.setHTTPRequestHeaders(headerParams: transactionHeaderDict as NSDictionary)
```
* Create an instance of the TransactionService class by passing the restServiceClient object created earlier. Then, call the processTransaction method and pass the arguments as shown below.
```swift
// transactionAction = one of the actions of TransactionAction Enum class as per requirement.
// paramMap = input parameters required by Transaction API for a type of action to be performed.
// transactionId = required, when the action is to be performed on an existing transaction such as a refund.
        let transactionService = TransactionService(restClient: restClientService)
        let transactionActionType = TransactionAction.Sale
        transactionService.processTransaction(transactionAction: transactionActionType, paramMap: (transactionParamDict as NSDictionary).mutableCopy() as! NSMutableDictionary,
                        transactionId: transactionId)
                        { (responseJSON) in
                            DispatchQueue.global().async(execute: {
                                DispatchQueue.main.sync {
                                    // Update the UI using  responseJSON
                                }
                            })
                        }
```
* Once the transaction completes with success or failure, the response will be returned in the processTransaction completion block.

### EMV transactions
* Create a RestClientService object with appropriate parameters and set the request header details.
* Create an instance of the EMVTransaction class by passing the restServiceClient object created earlier, ensuring you specify the correct reader type:
```swift
// apiHostname = either api.zeamster.com or api.sandbox.zeamster.com
// apiEndpointPath = /v2/transactions - full endpoint of the API
let restServiceClient = RestServiceClient(apiProtocol:"https", apiHostName:"api.sandbox.zeamster.com", apiEndpointPath:"/v2/transactions")
if (restClientService.setHTTPRequestHeaders(headerParams: transactionHeaderDict as NSDictionary)) {
            emvTransaction = EMVTransaction(restClient: restServiceClient, device: DeviceType.IDTECH_VP3300BT)
            emvTransaction.delegate = self
        }
```
* After creating the emvTransaction object, set its delegate to self and then set the device type as shown above.
* To perform an EMV transaction, implement the EMVUIDelegate methods on the class you are processing the EMV transaction in:

```swift
    func deviceMessage(message: String!) {
        DispatchQueue.main.async {
                //Add code to show reader LCD message
        }
    }
```
```swift
    func deviceScanResponse(deviceID: String!, deviceName: String!) {
        // Add code to hold the device that was found.

        // If you'd like to immediately connect, then you may do so here:
        emvTransaction.connectDeviceByName(name: deviceName)
    }
```
```swift
    func deviceConnected() {
        DispatchQueue.main.async {
            //Add code to show the device is connected.
        }
    }
```
```swift
    func deviceDisconnected() {
        DispatchQueue.main.async {
            //Add code to show device is disconnected.
        }
    }
```
```swift
    func outputLogs(logs: String!) {
        DispatchQueue.main.async {
            // Add code to show transaction output logs
        }
    }
```
```swift
    func transactionResponse(data: String!) {
        DispatchQueue.main.async {
            //Add code to show the transaction response.
            let jsonDictData = data.data(using: .utf8)!
            let txResponse = try? JSONSerialization.jsonObject(
                with: jsonDictData,
                options: []
            )
        }
    }
```
* Next call the scanForDevices() method to start a device scan:
```swift
emvTransaction.scanForDevices()
```
* Device scan responses are returned to the deviceScanResponse() callback. This method receives device name and ID, which you can use in other methods to connect to a specific device.  This method will be called multiple times for each device found, but will only be called once for each unique reader.
* Once your card reader is found, use the connectDeviceByName()  method of the emvTransaction instance to connect the device.  You can also use a separate method to connect using the device's ID instead if you do not want to connect via name.
* After the reader is connected successfully a response is sent to the deviceConnected() method you implemented.
* If the reader gets disconnected, the deviceDisconnected() method will be called.
* Initiate a transaction by calling PerformEMVSale with the appropriate payload that you assembled before:
```swift
emvTransaction.PerformEMVSale(jsonPayload: transactionParamDict)
```
*Note: The current SDK support two EMV transaction type : SALE and REFUND; In order to perform both transactions, we need to call the same PerformEMVSale() function with payload which should have the action field which is to be performed like ‘sale’ or ‘refund’. Payload inputs will be similar to non-EMV transactions. Details on what parameters should be sent can be found in the Zeamster Transaction API documentation (https://docs.zeamster.com/developers/api/endpoints/transactions)*
* The current status of a transaction will be reported to the deviceMessage() callback.
* All logs from processing the transaction will be reported to the outputLogs() callback.
* If you want to cancel a currently in progress transaction, call:
```swift
emvTransaction.CancelEMVSale();
```
* If you want to disconnect the currently connected reader, call:
```swift
emvTransaction.DisconnectDevice();
```
* Once you receive a response from the transaction processing, parse the passed in json string to determine the status of the transaction.  Refer to the Zeamster documentation linked above for additional information.