NAV

App integration

Here's everything you require for integrating with the OderoPOS Android system, enabling your application to seamlessly interact with our devices for card payments and printing via a set of clearly defined APIs. Our tools simplify the integration process, ensuring ease and speed while minimizing the need for future adjustments on your end. OderoPOS, integrated into the Android system, is continuously maintained and updated, forming our robust ecosystem.

Launcher

In order to be recognized by Token Platform and be visible in the Launcher, please also add the following lines to AndroidManifest.xml file.

AndroidManifest.xml

<application>
    <!-- Other fields -->
    <!-- App Name should be started with LYL, thus Launcher can differentiate sale apps -->
    <meta-data android:name="app_name" android:value="LYL_APP_NAME" />
    <meta-data android:name="app_model_type" android:value="400TR" />
    <meta-data android:name="app_version" android:value="1" />
    <meta-data android:name="sale_activity_name" android:value="<internal_packages>.<activity_name>" />
</application>

Please ensure that sale_activity_name is the Activity that will be shown to the customers as the first screen.

<activity android:name=".activity.MyActivity"
            android:exported="true"></activity>
<!-- Example Usage -->
    <meta-data android:name="sale_activity_name" android:value=".android.MyActivity" />

PaymentGateway

Allows payment requests in a uniform way across all POS family.

The API is agnostic of the underlying payment procedures, which may involve banking, card reading, etc.

The PGW will take care of all the printing during a payment request. The caller does not need to handle it via the printer app.

!\[alt text\](Architecture)

Setup

In order to access the PGW app, the following pgw-launcher and common library should be included in the app. To do this add the following maven url to settings.gradle under dependencyResolutionManagement/repositories:

settings.gradle

maven {
    url 'https://ro-artifactory.devtokeninc.com/artifactory/PublicLibraries/'
}

And also in app/build.gradle the actual dependency should be added: implementation 'PaymentGateway:pgw-launcher:1.0.3'

build.gradle

dependencies {
implementation 'PaymentGateway:pgw-launcher:1.0.3'
}

Request payment

The payment request is done via an ActivityResultLauncher contract.

Obtaining the PGW contract

val paymentResultContract = PGWLauncher.getPGWContract(context)

Returns null if the PGW app is not installed on the device.

Payment request

import ro.odero.paymentgateway.common.data.CurrencyCode
import ro.odero.paymentgateway.common.data.PaymentOption
import ro.odero.paymentgateway.common.data.request.PaymentRequest
import ro.odero.paymentgateway.launcher.PGWLauncher

val pgwContract = PGWLauncher.getPGWContract(context)

if (pgwContract == null) {

}

val paymentLauncher = registerForActivityResult(pgwContract) {
paymentResponse : PaymentResponse ->
//payment response
}

paymentLauncher.launch(PaymentRequest(
                amount = 12345,
                paymentOptions = listOf(PaymentOption.Card),
                currencyCode = CurrencyCode.RON
            ))

According to the selected payment options PGW will handle the payment and printing. The amount will be internally translated as amount/100 to cover the currency decimal; in this case 12345 will internally converted to 123,45

Handling PaymentResponse

Check the PaymentResponse based on the payment options sent.

PaymentResponse handling

paymentResponse : PaymentResponse ->

if(paymentResponse is CardPaymentResponse)...

if(paymentResponse is CashPaymentResponse)...

Types of PaymentResponse

sealed class CardPaymentResponse : PaymentResponse {

    data class Success(
        val receiptNumber: String,
        val bankActivityResultCode: Int,
        val bankStatus: Int,
        val customerSlip: String,
        val merchantSlip: String,
    ) : CardPaymentResponse()

    data class Fail(
        val receiptNumber: String,
        val bankActivityResultCode: Int,
        val bankStatus: Int,
        val message: String,
    ) : CardPaymentResponse()
}


sealed class CashPaymentResponse : PaymentResponse {

    data class Success(
        val receiptNumber: String,
    ) : CashPaymentResponse()

    data class Fail(
        val receiptNumber: String,
        val message: String,
    ) : CashPaymentResponse()
}

Printer App

Allows printing in a uniform way across all POS family.

The API is agnostic of the underlying hardware but provides a set of well defined PrintCommands.

alt text

Setup

In order to access the Printer App, the following printer-launcher and common library should be included in the app. To do this add the following code into settings.gradle under dependencyResolutionManagement/repositories:

settings.gradle

maven {
    url 'https://ro-artifactory.devtokeninc.com/artifactory/PublicLibraries/'
}

Add in build.gradle the lib dependencies: implementation 'PrinterApp:printer-launcher:1.0.3' (the pgw-launcher should also add the common lib, if not please add the dependency implementation 'PrinterApp:common:1.0.3')

build.gradle

dependencies{
    implementation 'PrinterApp:printer-launcher:1.0.3'
}

Printing

There are two distinct flows that have to be implemented

When printer is ready print the receipts

val printerErrorCheck = registerForActivityResul(PrinterHealthResultContract()){
printerHealth: PrinterHealthResponse? ->

if(printerHealth.hasErrors.not()){
printReceipts()
}else
{
    //treat the error
}

}


Actual printing contract that is used to start the PrinterApp

val printerLauncher = registerForActivityResult(PrinterResultContract()) {
printerResponse: PrinterResponse? ->
//treat printer response
}

Receipts example

 val customerReceipt = listOf(
        PrintCommand.PrintSpace,
        PrintCommand.PrintImage(image), PrintCommand.PrintSpace,
        PrintCommand.PrintWithBold(true),
        PrintCommand.PrintText(
            "Test SRL",
            TextAlignment.Left,
        ),
        PrintCommand.PrintWithBold(false),
        PrintCommand.PrintSpace,
        PrintCommand.PrintText(
            "Data:10.03.2023",
            TextAlignment.Left,
        ),
        PrintCommand.PrintText(
            "Ora:10:00",
            TextAlignment.Right,
        ),
        PrintCommand.PrintText(
            "TID:0 MID:0",
            TextAlignment.Left,
        ),
        PrintCommand.PrintSpace,
        PrintCommand.PrintSpace,
        PrintCommand.PrintText(
            "AID:00000",
            TextAlignment.Right,
        ),
        PrintCommand.PrintText(
            "0000000000",
            TextAlignment.Left,
        ),
        PrintCommand.PrintFontSize(FontSize.Small),
        PrintCommand.PrintColumns(arrayOf("BATCH:000001", "BON:000001")),
        PrintCommand.PrintColumns(arrayOf("RRN:00123456789", "RC: 00")),
        PrintCommand.PrintColumns(arrayOf("AUTH:775040", "STAN:012345")),
        PrintCommand.PrintLine, PrintCommand.PrintWithBold(true),
        PrintCommand.PrintFontSize(FontSize.Large),
        PrintCommand.PrintColumns(arrayOf("SUMA:", "50")),
        PrintCommand.PrintWithBold(false), PrintCommand.PrintSpace,
        PrintCommand.PrintText("APPROVED", TextAlignment.Left),
        PrintCommand.PrintFontSize(FontSize.Medium),
        PrintCommand.PrintText("EXEMPLAR CLIENT", TextAlignment.Left),
        PrintCommand.PrintLine, PrintCommand.PrintSpace,
        PrintCommand.PrintSpace,
    )

    val merchantReceipt = listOf(
        PrintCommand.PrintSpace,
        PrintCommand.PrintImage(image), PrintCommand.PrintSpace,
        PrintCommand.PrintWithBold(true),
        PrintCommand.PrintText(
            "Test SRL",
            TextAlignment.Left,
        ),
        PrintCommand.PrintWithBold(false),
        PrintCommand.PrintSpace,
        PrintCommand.PrintText(
            "Data:10.03.2023",
            TextAlignment.Left,
        ),
        PrintCommand.PrintText(
            "Ora:10:00",
            TextAlignment.Right,
        ),
        PrintCommand.PrintText(
            "TID:0 MID:0",
            TextAlignment.Center,
        ),
        PrintCommand.PrintSpace,
        PrintCommand.PrintSpace,
        PrintCommand.PrintText(
            "AID:00000",
            TextAlignment.Right,
        ),
        PrintCommand.PrintText(
            "0000000000", // cardno
            TextAlignment.Left,
        ),
        PrintCommand.PrintFontSize(FontSize.Small),
        PrintCommand.PrintColumns(arrayOf("BATCH:000001", "BON:000001")),
        PrintCommand.PrintColumns(arrayOf("RRN:00123456789", "RC: 00")),
        PrintCommand.PrintColumns(arrayOf("AUTH:775040", "STAN:012345")),
        PrintCommand.PrintLine, PrintCommand.PrintWithBold(true),
        PrintCommand.PrintFontSize(FontSize.Large),
        PrintCommand.PrintColumns(arrayOf("SUMA:", "50")),
        PrintCommand.PrintWithBold(false), PrintCommand.PrintSpace,
        PrintCommand.PrintText("APPROVED", TextAlignment.Left),
        PrintCommand.PrintFontSize(FontSize.Medium),
        PrintCommand.PrintText("EXEMPLAR VANZATOR", TextAlignment.Center),
        PrintCommand.PrintLine, PrintCommand.PrintSpace,
        PrintCommand.PrintSpace,
    )

Printing

fun printReceipts(){

printerLauncher.launch(
            PrinterRequest(
                listOf(
                    PrintDocument(
                        clientReceipt,
                        "Chitanta client",
                    ),
                    PrintDocument(merchantReceipt, "Chitanta vanzator"),
                ),
                PrintRequestType.PrintWithDialog, // will show a dialog between each print
                // document
                // PrintRequestType.SimplePrint //will print each document back-to-back - useful
                // for setlements, reports, etc
            )),
}

PrinterResponse structure

data class PrinterResponse(
    val status: Status,
    val message: String,
    val data: List<DocumentData>,
) {

    enum class Status {
        SUCCESS,
        ERROR,
    }
}

OPIT

Odero POS Integration Toolkit for Developers

Welcome to OPit, the Odero POS Integration Toolkit designed to streamline and enhance the communication between a Windows device (PC, laptop) and an Odero POS terminal. OPit enables developers to send commands such as Payment Requests, Settlements, Reports, and more, directly to the Odero POS terminal over a TCP/IP socket connection. By leveraging this powerful toolkit, developers can seamlessly integrate their Windows applications with Odero POS, unlocking new possibilities for efficient and secure payment processing.

At its core, OPit provides a reliable and secure channel for data exchange between the Windows device and the Odero POS terminal. This communication is facilitated through TCP/IP sockets, allowing for real-time, bidirectional communication over a local network. To ensure a seamless connection, both the Windows device and the Odero POS terminal must be connected to the same router or Wi-Fi network.

With OPit, developers gain full control over the payment flow, enabling them to initiate payment requests from their Windows applications and receive responses from the Odero POS terminal. This integration empowers developers to create custom workflows, tailor the user experience, and incorporate Odero POS functionality seamlessly into their existing applications. Whether you're building a point-of-sale system, a payment gateway, or any other payment-related application, OPit provides the tools you need to connect and communicate effortlessly with Odero POS.

By leveraging the power of OPit, developers can harness the extensive capabilities of Odero POS, such as processing transactions, generating reports, performing settlements, and more, directly from their Windows applications. This seamless integration ensures a cohesive experience for users and eliminates the need for manual data entry or redundant workflows. With OPit, you can empower your users with a unified and efficient payment processing solution, offering a streamlined experience that enhances productivity and accuracy.

In this developer documentation, we will provide you with comprehensive guidance on utilizing OPit to integrate your Windows applications with Odero POS. You'll find detailed instructions, sample code snippets, and best practices to help you make the most of this powerful toolkit. Whether you're a seasoned developer or just getting started, this documentation will serve as your roadmap to successfully integrating OPit and unlocking the full potential of Odero POS in your applications.

We're excited to have you embark on this journey with OPit, and we look forward to witnessing the innovative solutions you'll build with the power of seamless communication between Windows devices and Odero POS terminals. Let's dive in and get started!

Introduction

OPit Lan for Windows is a C++ library which allows for a Windows device (PC, laptop) to send commands (Payment Request, Settlement, Reports etc) to an Odero Pos terminal.
The communication between the two devices is performed through TCP/IP sockets.
Both devices have to be connected to the same router / wifi network.

Please follow the below instructions for setup:

  1. To use OPIT Lan you will need to use static ips for both devices, on the client tablet and the Odero POS terminal, and to have a dedicated router with - potentially - DHCP off (depends on the router)
    Tutorial on how to set up static ip on Windows can be found here
  2. Connect to wifi on the dedicated router on both devices.
  3. The Odero POS terminal must have the ip 192.168.1.1 this is the ip where the client device expects to find the host.
  4. Install app-lan-host-release.apk on the Odero POS terminal and OpitDesktopSampleApp on the Windows device.
  5. Start the OPIT Lan app on the Odero POS terminal.
  6. Start Sample app on windows.
  7. Send payment request.


Below you can find the OPit Lan for Windows diagram.

  1. OPit lan host on Odero POS terminal is started and the socket server is booted up.
  2. Client app (that implement OPit library) starts on windows device and connects to the socket server from the Odero POS terminal.
  3. Client app receives onConnected callback.
  4. Client app sends payment request via opened tcp/ip socket and is received on the Odero POS terminal.
  5. Client app terminates the socket connection.
  6. Client app receives onDisconnected callback.
  7. Odero POS terminal switchs from wifi to gsm data as required by the bank app in order to perform the transaction on secure connection. Also the host socket server is shut down.
  8. Odero POS terminal host awaits for response from the bank app.
  9. Client app sends connnection ping requests attempting to connect to the socket server on the host device. These attempts fail at this point because the socket server is shut down as described in previous step.
  10. Host app receives response from the bank app, network switch from gsm to wifi occurs and the socket server is started.
  11. Client app connection request is successful.
  12. Host app on Odero POS terminal sends the response from the bank app and is received on the client app (windows)

The client app side implementation is rather simple, only step 4 is required to be perfomed, all other steps on the client side are performed under the hood inside the library.

Setup

  1. Download the latest OPIT Lan for Windows release and unzip the archive.
  2. Copy archive contents inside the sample project folder.
  3. Open the sample app project solution with Microsoft Visual Studio (make sure C++ module is installed).
  4. In Microsoft Visual Studio go to Project -> Properties -> C/C++ -> Command Line -> Additional Options -> add text: /std:c++latest

  5. C/C++ -> General -> Additional Include Directories -> click on the dropdown -> Edit -> in the popup press the 3 dots (...) button from the right -> Choose headers folder from the opit-desktop project -> Ok

  6. Linker -> Input -> Additional Dependencies -> click on the dropdown -> Edit -> add text: OpitDesktop.lib -> Ok

  7. Linker -> General -> Additional Library Directories -> click on the dropdown -> Edit -> in the popup press the 3 dots (...) button from the right -> select the folder where the OpitDesktop.lib file is located -> Ok

  8. That's it! The solution should now build.