Пример интеграции POS терминала в Android приложение

Первые шаги

Приступим к интеграции IKKM в вашем Android приложение. Мы рассмотрим простейший случай, когда в приложении имеется Activity, содержащая таблицу товаров. Для этого воспользуемся библиотеками okhttp3, которая упрощает работу с http запросами и gson.

Для начала добавим в файл app/build.gradle зависимость.

dependencies {
...
    implementation 'com.squareup.okhttp3:okhttp:4.2.2'
    implementation 'com.squareup.okhttp3:okhttp-urlconnection:4.2.2'
    implementation 'com.google.code.gson:gson:2.8.6'
}

Параметры подключения для работы с устройством
public class IkkmHelper {

    private SharedPreferences sharedPreferences; // где будем хранить config параметры
    private Context m_context; // передаем с какого Activity работаем

    private String ip_ikkm; // ip адрес устройства (192.168.0.100)
    private String key_ikkm; // при каждом фискальном чеке меняется ключ доступа (токенизация, малая безопасность в локальной сети), в остальных случаях ключ не меняется 
    private int trackdocument_ikkm; // номер текущего фискального чека в аппарате, нужен для банковской операции, возможен другой алгоритм с использованием timestamp
    private boolean ikkm_is_present; // метка проверки доступности терминала по сети 
    private boolean check_is_payed; // метка оплаты чека картой за номером trackdocument_ikkm+1
    private String errorIKKM;  // текущая ошибка 

    private OkHttpClient client; // для http запросов

    private HashMap<String,String> errorMap= new HashMap<>(); // если требуется расшифровка ошибки от устройства  

    IkkmHelper(Context context) {

        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        m_context = context;

        ip_ikkm            = sharedPreferences.getString("ip_address_ikkm", "192.168.0.100"); // спросим актуальный ip адрес устройства 
        key_ikkm           = sharedPreferences.getString("api_key_ikkm", "12345678"); // токен для API 
        ikkm_is_present    = false;
        check_is_payed     = false;
        trackdocument_ikkm = 0;
        errorIKKM          = "no connect to ikkm"; // не найдено устройство в сети

        client = new OkHttpClient(); 

        //Beep for service and get check number for track number
        doApiCheckBeep(true); // just checking ikkm and take current number of check(bill). if(false) - no signal beep.

        // if need extended answer error
        //loadErrorMap();


    }

Используем AsyncTask для организации взаимодействия с IKKM

    private void sendPOST_to_ikkm(final String api_url){
        //async request
        @SuppressLint("StaticFieldLeak")
        class GetAPI_Result extends AsyncTask<Void, String, String> {
.....
            @Override
            protected void onPreExecute()
            {
.....
            }
            @Override
            protected String doInBackground(Void... params) {


                String Answer_from_ikkm = "not found ikkm";

                RequestBody formBody = new FormBody.Builder()
                        .add("key", key_ikkm)
                        .build();


                Request request = new Request.Builder()
                        .url("http://" + ip_ikkm + ":8080" + api_url)
                        .post(formBody)
                        .build();

                try (Response response = client.newCall(request).execute()) {


                    publishProgress("Receiving...");

                    String apiResult  = Objects.requireNonNull(response.body()).string().trim();
                    String apiMessage = response.message().trim();
                    if (response.isSuccessful()){
...
                    return Answer_from_ikkm;
            }

            @Override
            protected void onProgressUpdate(String... progress) {
                super.onProgressUpdate(progress);
                tvText.setText(progress[0]);
            }

            @Override
            protected void onPostExecute(String answer) {
                super.onPostExecute(answer);
                if(answer.equals("Ok")) {
                    if (dialog != null )dialog.dismiss();
                }else {

В конструктор ItemData мы передаем строчку из табличной части

public class ItemData {
    private String name;
    private String price;
    private String qty;
    private String sum;
    private String taxid; // код налога в ikkm ( пример: 1 - безНДС, 2 - НДС)
    public ItemData(String name, String price, String qty, String sum, String taxid) {
        this.name = name;
        this.price = price;
        this.qty = qty;
        this.sum = sum;
        this.taxid = taxid;
    }

Создаем Array (табличная часть чека с наименованием, ценой, кол-вом, суммой и кодом налога) и передаем в JSON 
печатаем фискальный чек!

public void testPrintFiscalCheck() {

        ArrayList<ItemData> ItemList = new ArrayList<ItemData>();

        ItemList.add(0,new ItemData("чай","200","2","400", "7"));
        ItemList.add(1,new ItemData("булка","1600","1","1600", "8"));

        doFiscal(0,2000.00, 1200.00, 800.00, 0,0, new Gson().toJson(ItemList)); // пригодился gson
    }
    
public void doFiscal(int docType, double total, double cash, double bank, double tara, double credit, String OfdItemDataJSON) {
        String _docType = "sale";
        if (docType == 2) _docType = "saleReturn";
        if (docType == 3) _docType = "buy";
        if (docType == 4) _docType = "buyReturn";
        String api_url = "/api/?" + _docType + "=" + String.format(Locale.US,"%.2f",total);
        if (cash > 0){
            api_url += "&cash="   + String.format(Locale.US,"%.2f",cash);  // сколько дали наличности
        }
        if (bank > 0){
            api_url += "&bank="   + String.format(Locale.US,"%.2f",bank); // сколько прошло по банковской карте
        }
        if (tara > 0) {
            api_url += "&tara="   + String.format(Locale.US, "%.2f", tara); // иногда используют как подарочный сертификат 
        }
        if (credit > 0) {
            api_url += "&credit=" + String.format(Locale.US, "%.2f", credit); // для регистрации отпуска в кредит ( например: отпуск товара с доставкой, оплата потом)    
        }
        api_url += "&itemdata=" + OfdItemDataJSON;
        sendPOST_to_ikkm(api_url); // отправили http запрос в ikkm
    }

Требование о закрытии фискальной смены (после 24 часов работы), реализуется командой

    public void doReportZX(int repType){ // repType = 0 - x отчет, любые цифры -  z-отчет(закрытие смены)
        String url =  "/apizreport";
        if (repType == 0)
            url =  "/apixreport";
        sendPOST_to_ikkm(url);
    }
Запрос на печать последнего  зарегистрированного чека, бывают разные ситуации, бумага закончилась в момент печати и т.п. Дубликаты других документов (Z отчет, чек и т.д.) можно распечатать используя интерфейс  на самом аппарате.
public void doPrintLastCheque() {
        sendPOST_to_ikkm("/apicheck/printLastDocument"); 
// запрос на печать дубликата чека.
}


Разберем работу с банковской частью ikkm
public void startBank(double bankAmount) {
        String amount = String.format(Locale.US, "%.2f", bankAmount); // сколько хотим принять на терминале, сумма! 
// перед данным запросом запускаем doApiCheckBeep(boolean beep) - узнаем состояние устройства (доступно, какой номер последнего чека)        
if(ikkm_is_present){
            callBackFromBank_ikkm();   // может данный чек оплачен? check_is_payed                                                            
            if (!check_is_payed) {
                String _trackdocument_ikkm = String.valueOf(trackdocument_ikkm);
                sendPOST_to_ikkm("/apibank/?message=purchase&amount=" + amount + "&trackdocument=" + _trackdocument_ikkm);
            }else {
                Toast.makeText(m_context, "Check #"+trackdocument_ikkm + " is Payed", Toast.LENGTH_SHORT).show();
            }
        }else{
            Toast.makeText(m_context, errorIKKM, Toast.LENGTH_SHORT).show();
        }
    }

Подготовим разметку

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    tools:context=".tools.IKKM.IkkmHelperActivity">

    <Button
        android:id="@+id/check_ikkm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Check"
        app:layout_constraintBottom_toTopOf="@+id/z_report_ikkm"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/z_report_ikkm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Z Report"
        app:layout_constraintBottom_toTopOf="@+id/bank_ikkm"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/check_ikkm"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/bank_ikkm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Bank"
        app:layout_constraintBottom_toBottomOf="@id/z_report_ikkm"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/beep_ikkm"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/beep_ikkm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Beep"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/bank_ikkm"
        tools:ignore="MissingConstraints" />


</androidx.constraintlayout.widget.ConstraintLayout>
Activity

import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

import kz.isoft.orangekassa.R;

public class IkkmHelperActivity extends AppCompatActivity {


    private IkkmHelper ikkmHelper;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.ikkm_activity);


        ikkmHelper = new IkkmHelper(IkkmHelperActivity.this);

        Button button_beep = findViewById(R.id.beep_ikkm);
        button_beep.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    ikkmHelper.doApiCheckBeep(true);
            }
        });

        Button button_z_report = findViewById(R.id.z_report_ikkm);
        button_z_report.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    ikkmHelper.doReportZX(1);
            }
        });

        Button button_check_report = findViewById(R.id.check_ikkm);
        button_check_report.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                    ikkmHelper.testPrintFiscalCheck();
            }
        });

        Button button_bank = findViewById(R.id.bank_ikkm);
        button_bank.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                ikkmHelper.startBank(1005);
            }
        });


    }


начнем 

import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

import androidx.preference.PreferenceManager;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Locale;
import java.util.Objects;

import kz.isoft.orangekassa.data.model.ItemData;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class IkkmHelper {

    private SharedPreferences sharedPreferences;
    private Context m_context;

    private String ip_ikkm;
    private String key_ikkm;
    private int trackdocument_ikkm;
    private boolean ikkm_is_present;
    private boolean check_is_payed;
    private String errorIKKM;

    private OkHttpClient client;

    private HashMap<String,String> errorMap= new HashMap<>();

    IkkmHelper(Context context) {

        sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
        m_context = context;

        ip_ikkm            = sharedPreferences.getString("ip_address_ikkm", "");
        key_ikkm           = sharedPreferences.getString("api_key_ikkm", "12345678");
        ikkm_is_present    = false;
        check_is_payed     = false;
        trackdocument_ikkm = 0;
        errorIKKM          = "no connect to ikkm"; //
        client = new OkHttpClient();


        //Beep for service and get check number for track number
        doApiCheckBeep(true); // just checking ikkm and take current number of check(bill). if(false) - no signal beep.

        //if need extended
        //loadErrorMap();


    }

    void doApiCheckBeep(boolean beep) {

        if(beep) {
            sendPOST_to_ikkm("/apicheck/?beep=true");
        }else{
            sendPOST_to_ikkm("/apicheck/");
        }
    }

    public void doReportZX(int repType){

        String url =  "/apizreport";

        if (repType == 0)
            url =  "/apixreport";

        sendPOST_to_ikkm(url);
    }

    public void doPrintLastCheque() {

        sendPOST_to_ikkm("/apicheck/printLastDocument");

    }



    public void startBank(double bankAmount) {

        String amount = String.format(Locale.US, "%.2f", bankAmount);
        if(ikkm_is_present){

            callBackFromBank_ikkm();

            if (!check_is_payed) {

                String _trackdocument_ikkm = String.valueOf(trackdocument_ikkm);

                sendPOST_to_ikkm("/apibank/?message=purchase&amount=" + amount + "&trackdocument=" + _trackdocument_ikkm);

            }else {
                Toast.makeText(m_context, "Check #"+trackdocument_ikkm + " is Payed", Toast.LENGTH_SHORT).show();
            }
        }else{
            Toast.makeText(m_context, errorIKKM, Toast.LENGTH_SHORT).show();
        }
    }

    // HTTP POST request

    //Example FiscalCheck

    public void testPrintFiscalCheck() {

        ArrayList<ItemData> ItemList = new ArrayList<ItemData>();

        ItemList.add(0,new ItemData("чай","200","2","400", "7"));
        ItemList.add(1,new ItemData("булка","1600","1","1600", "8"));

        doFiscal(0,2000.00, 1200.00, 800.00, 0,0, new Gson().toJson(ItemList));

    }

    public void doFiscal(int docType, double total, double cash, double bank, double tara, double credit, String OfdItemDataJSON) {


        String _docType = "sale";
        if (docType == 2) _docType = "saleReturn";
        if (docType == 3) _docType = "buy";
        if (docType == 4) _docType = "buyReturn";

        String api_url = "/api/?" + _docType + "=" + String.format(Locale.US,"%.2f",total);

        if (cash > 0){
            api_url += "&cash="   + String.format(Locale.US,"%.2f",cash);
        }
        if (bank > 0){
            api_url += "&bank="   + String.format(Locale.US,"%.2f",bank);
        }
        if (tara > 0) {
            api_url += "&tara="   + String.format(Locale.US, "%.2f", tara);
        }
        if (credit > 0) {
            api_url += "&credit=" + String.format(Locale.US, "%.2f", credit);
        }


        api_url += "&itemdata=" + OfdItemDataJSON;

        sendPOST_to_ikkm(api_url);

    }




    private void callBackFromBank_ikkm(){


        final String _trackdocument_ikkm = String.valueOf(trackdocument_ikkm);

        @SuppressLint("StaticFieldLeak")
        class GetCallBack_ResultBank extends AsyncTask<Void, String, String> {


            @Override
            protected String doInBackground(Void... params) {


                String Answer_from_ikkm = "not found ikkm?";

                RequestBody formBody = new FormBody.Builder()
                        .add("key", key_ikkm)
                        .build();


                Request request = new Request.Builder()
                        .url("http://" + ip_ikkm + ":8080/dump/bank/" + _trackdocument_ikkm +"/trackdocument")
                        .post(formBody)
                        .build();

                try (Response response = client.newCall(request).execute()) {

                    if (response.isSuccessful()) {

                        switch (response.code()) {

                            case 200:

                                String jsonRespon = Objects.requireNonNull(response.body()).string();
                                try {

                                    JSONObject jsonObject = new JSONObject(jsonRespon);
                                    Answer_from_ikkm = jsonObject.getString("transactionResult");

                                } catch (final JSONException e) {
                                    Answer_from_ikkm = "error parse json";
                                }

                                break;
                            case 203:
                                Answer_from_ikkm = "duplicate request!";
                                break;
                            case 202:
                                Answer_from_ikkm = "check mode!";
                                break;
                            default:
                                Answer_from_ikkm = "Error answer";
                                break;
                        }

                    }else {
                        if (response.code() == 400){
                            //error from ikkm
                            Answer_from_ikkm =  "Error " + response.message();
                        }
                        throw new IOException("Unexpected code " + response);
                    }



                } catch (IOException e) {
                    e.printStackTrace();
                }

                return Answer_from_ikkm;
            }

            @Override
            protected void onPostExecute(String answer) {
                super.onPostExecute(answer);
                if(answer.equals("success")) {

                    check_is_payed = true;
                }else {
                    check_is_payed = false;
                }
//                Toast.makeText(m_context, Answer_from_ikkm_body, Toast.LENGTH_SHORT).show();
            }
        }

        GetCallBack_ResultBank gTask = new GetCallBack_ResultBank();
        gTask.execute();

    }


    private void sendPOST_to_ikkm(final String api_url){
        //async request
        @SuppressLint("StaticFieldLeak")
        class GetAPI_Result extends AsyncTask<Void, String, String> {


            private LinearLayout ll = new LinearLayout(m_context);
            private ProgressBar progressBar = new ProgressBar(m_context);
            private TextView tvText = new TextView(m_context);


            private AlertDialog.Builder builder = new AlertDialog.Builder(m_context);
            private AlertDialog dialog;

            @Override
            protected void onPreExecute()
            {

                ll.setOrientation(LinearLayout.HORIZONTAL);
                int llPadding = 30;
                ll.setPadding(llPadding, llPadding, llPadding, llPadding);
                ll.setGravity(Gravity.CENTER);
                LinearLayout.LayoutParams llParam = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        LinearLayout.LayoutParams.WRAP_CONTENT);
                llParam.gravity = Gravity.CENTER;
                ll.setLayoutParams(llParam);

                progressBar.setIndeterminate(true);
                progressBar.setPadding(0, 0, llPadding, 0);
                progressBar.setLayoutParams(llParam);

                llParam = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                        ViewGroup.LayoutParams.WRAP_CONTENT);
                llParam.gravity = Gravity.CENTER;
                tvText.setText("Starting ...");
                tvText.setTextColor(Color.parseColor("#000000"));
                tvText.setTextSize(20);
                tvText.setLayoutParams(llParam);

                ll.addView(progressBar);
                ll.addView(tvText);

                builder.setCancelable(true);
                builder.setView(ll);

                dialog = builder.create();
                dialog.show();
//                Window window = dialog.getWindow();
//                if (window != null) {
//                    WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
//                    layoutParams.copyFrom(dialog.getWindow().getAttributes());
//                    layoutParams.width = LinearLayout.LayoutParams.WRAP_CONTENT;
//                    layoutParams.height = LinearLayout.LayoutParams.WRAP_CONTENT;
//                    dialog.getWindow().setAttributes(layoutParams);
//                }
            }


            @Override
            protected String doInBackground(Void... params) {


                String Answer_from_ikkm = "not found ikkm";

                RequestBody formBody = new FormBody.Builder()
                        .add("key", key_ikkm)
                        .build();


                Request request = new Request.Builder()
                        .url("http://" + ip_ikkm + ":8080" + api_url)
                        .post(formBody)
                        .build();

                try (Response response = client.newCall(request).execute()) {


                    publishProgress("Receiving...");

                    String apiResult  = Objects.requireNonNull(response.body()).string().trim();
                    String apiMessage = response.message().trim();
                    if (response.isSuccessful()){


                        switch (response.code()){

                            case 200:

                            if (isInteger(apiMessage)){
                                Answer_from_ikkm =  "Ok";

                                // Take number of check
                                trackdocument_ikkm = Integer.parseInt(apiMessage)+1;
                                ikkm_is_present = true;
                                //safe api_key to setting
                                if (apiResult.length() == 8) {
                                    Answer_from_ikkm = "Ok";
                                    SharedPreferences.Editor edit = sharedPreferences.edit();
                                    edit.putString("api_key_ikkm", apiResult);
                                    edit.apply();
                                }

                            }else{

                                switch (apiMessage){


                                    case "bank-is-opened":

                                        Answer_from_ikkm = "Error check #"+trackdocument_ikkm+" not payed";

                                        for(int i = 0; i < 3; i++) {
                                            // Ваш код
                                            publishProgress("Wait card..." + String.valueOf(i)+"0 sec (30 sec)");
                                            try {
                                                Thread.sleep(8000);
                                            } catch(InterruptedException e) {
                                                e.printStackTrace();
                                            }
                                            callBackFromBank_ikkm();
                                            if(check_is_payed){
                                                Answer_from_ikkm = "Check #"+trackdocument_ikkm+" is payed, OK!";
                                                break;
                                            }
                                        }



                                        break;
                                    case "z-report-started":
                                        Answer_from_ikkm =  "ZX-report-started";
                                        break;
                                    case "ikkm-busy":
                                        Answer_from_ikkm =  "ikkm-busy";
                                        break;
                                    default:
                                        break;

                                }

                            }
                                break;
                            case 203:
                                Answer_from_ikkm =  "duplicate request!";
                                break;
                            case 202:
                                Answer_from_ikkm =  "check mode!";
                                break;
                            default:
                                Answer_from_ikkm =  "Error answer";
                                break;
                        }

                    }else {

                        if (response.code() == 400){
                            //error from ikkm
                            Answer_from_ikkm =  "Error " + apiMessage;
                        }

                        throw new IOException("Unexpected code " + response);
                    }


                } catch (IOException e) {
                    e.printStackTrace();
                }


                return Answer_from_ikkm;
            }

            @Override
            protected void onProgressUpdate(String... progress) {
                super.onProgressUpdate(progress);
                tvText.setText(progress[0]);
            }

            @Override
            protected void onPostExecute(String answer) {
                super.onPostExecute(answer);
                if(answer.equals("Ok")) {
                    if (dialog != null )dialog.dismiss();
                }else {
                    progressBar.setVisibility(View.GONE);
                    tvText.setText(answer);
                    errorIKKM = answer;
//                    if (dialog != null )dialog.dismiss();
                }
            }
        }

        GetAPI_Result gTask = new GetAPI_Result();
        gTask.execute();

    }


    private String getErrorText(String code){
        if (errorMap.containsKey(code)) return errorMap.get(code);
        return "неизвестная ошибка iKKM "+code;
    }

    private void loadErrorMap(){
        errorMap.put("no-web-api-key-provided","-7 Не передан web-api ключ");
        errorMap.put("incorrect-web-api-key","-1 Не верный web-api ключ");
        errorMap.put("ikkm-is-blocked","-100 ОФД заблокировал iKKM");
        errorMap.put("check-external-printer","-6 Нет связи с внешним принтером");
        errorMap.put("check-printer-or-batt","-6 Нет бумаги или низкий заряд батареи");
        errorMap.put("sale-param-error","-9 Ошибка передачи параметра");
        errorMap.put("buy-param-error","-9 Ошибка передачи параметра");
        errorMap.put("saleRet-param-error","-9 Ошибка передачи параметра");
        errorMap.put("buyRet-param-error","-9 Ошибка передачи параметра");
        errorMap.put("check-all-params","-7 Проверьте все параметры");
        errorMap.put("payment-params-missed","-7 Параметры оплаты отсутствуют");
        errorMap.put("cache-param-error","-7 Ошибка передачи параметра");
        errorMap.put("bank-param-error","-7 Ошибка передачи параметра");
        errorMap.put("tara-param-error","-7 Ошибка передачи параметра");
        errorMap.put("credit-param-error","-7 Ошибка передачи параметра");
        errorMap.put("cache-not-in-range","-7 Параметр за пределами значений");
        errorMap.put("bank-not-in-range","-7 Параметр за пределами значений");
        errorMap.put("tara-not-in-range","-7 Параметр за пределами значений");
        errorMap.put("credit-not-in-range","-7 Параметр за пределами значений");
        errorMap.put("sale-lq-one","-7 Значение меньше 1");
        errorMap.put("sale-hq-20mil","-7 Значение больше 20000000");
        errorMap.put("cash-lq-sale","-10 Наличность меньше суммы чека");
        errorMap.put("bank-hq-sale","-10 Оплата по банку должна быть равна сумме продажи");
        errorMap.put("tara-hq-sale","-10 Значение меньше 1");
        errorMap.put("credit-hq-sale","-10 Значение меньше 1");
        errorMap.put("bank-tara-credit-hq-sale","-13 Оплата безналом больше чем сумма чека");
        errorMap.put("no-cache-hq-sale","-13 Чек оплачен безналом, наличность запрещена");
        errorMap.put("no-mixed-payment-allowed","-13 Смешанный вид оплаты выключен в настройках");
        errorMap.put("change-not-allowed","-13 Сдача запрещена в данной операции");
        errorMap.put("tax-invlid-num","-14 Неправильный код налога");
        errorMap.put("tax-not-found","-14 Код налога не найден");
        errorMap.put("cash-lq-tax","-12 Сумма чека (с налогом) больше принятой оплаты");
        errorMap.put("no-cash-in-pos","-15 Нет наличности в кассе");
        errorMap.put("internal-error","-99 Внутренняя ошибка кассы (повреждена БД)");
        errorMap.put("wrong-cashier","-11 Смену открыл другой кассир");
        errorMap.put("shift-gt-24h","-3 Смена отрыта более 24 часов");
        errorMap.put("no-last-document","-7 Нет последнего документа");
        errorMap.put("print-lines-parse-error","-7 Ошибка парсинга параметра print");
        errorMap.put("only-master-cashier","-16 Операцию может провести только старший кассир");
        errorMap.put("shift-gt-7days","-3 Смена открыта более 7 дней");
        errorMap.put("incorrect-method","-8 Неправильно указан метод");
        errorMap.put("ikkm-need-update","-19 прошивка iKKM не совместима, обновите iKKM");
        errorMap.put("check-printer","Ошибка принтера iKKM");
        errorMap.put("unknown-error","-99 Неизвестная ошибка");
    }

    private static String toJSON(Object object) throws JSONException, IllegalAccessException {
        String str = "";
        Class c = object.getClass();
        JSONObject jsonObject = new JSONObject();
        for (Field field : c.getDeclaredFields()) {
            field.setAccessible(true);
            String name = field.getName();
            String value = String.valueOf(field.get(object));
            jsonObject.put(name, value);
        }
//        System.out.println(jsonObject.toString());
        return jsonObject.toString();
    }

    private static boolean isInteger(String s) {
        try {
            Integer.parseInt(s);
        } catch(NumberFormatException e) {
            return false;
        } catch(NullPointerException e) {
            return false;
        }
        // only got here if we didn't return false
        return true;
    }

Ваша проблема решена?