diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/src/main/aidl/ru/evotor/tspiot/ITsPioTService.aidl b/src/main/aidl/ru/evotor/tspiot/ITsPioTService.aidl new file mode 100644 index 0000000000..b654ddd95f --- /dev/null +++ b/src/main/aidl/ru/evotor/tspiot/ITsPioTService.aidl @@ -0,0 +1,10 @@ +package ru.evotor.tspiot; + +import ru.evotor.tspiot.model.MarkingCode; +import ru.evotor.tspiot.result.TsPioTResult; + +interface ITsPioTService { + TsPioTResult getKktInfo(); + + TsPioTResult getMarkedProductsInfo(in List codes, in String userUuid); +} \ No newline at end of file diff --git a/src/main/aidl/ru/evotor/tspiot/model/MarkingCode.aidl b/src/main/aidl/ru/evotor/tspiot/model/MarkingCode.aidl new file mode 100644 index 0000000000..487b3f17a5 --- /dev/null +++ b/src/main/aidl/ru/evotor/tspiot/model/MarkingCode.aidl @@ -0,0 +1,3 @@ +package ru.evotor.tspiot.model; + +parcelable MarkingCode; \ No newline at end of file diff --git a/src/main/aidl/ru/evotor/tspiot/result/TsPioTResult.aidl b/src/main/aidl/ru/evotor/tspiot/result/TsPioTResult.aidl new file mode 100644 index 0000000000..65c890c8fd --- /dev/null +++ b/src/main/aidl/ru/evotor/tspiot/result/TsPioTResult.aidl @@ -0,0 +1,3 @@ +package ru.evotor.tspiot.result; + +parcelable TsPioTResult; \ No newline at end of file diff --git a/src/main/java/ru/evotor/tspiot/TsPioTServiceConnector.java b/src/main/java/ru/evotor/tspiot/TsPioTServiceConnector.java new file mode 100644 index 0000000000..8bddbaa9c4 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/TsPioTServiceConnector.java @@ -0,0 +1,64 @@ +package ru.evotor.tspiot; + +import android.content.Context; +import android.os.DeadObjectException; +import java.util.concurrent.CopyOnWriteArrayList; +import ru.evotor.tspiot.exceptions.ServiceNotConnectedException; +import ru.evotor.tspiot.exceptions.TsPioTServiceOperationOnMainThreadException; +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; +import ru.evotor.tspiot.exceptions.TsPioTServiceRuntimeException; +import ru.evotor.tspiot.service.ITsPioTConnectionWrapper; +import ru.evotor.tspiot.service.ITsPioTServiceWrapper; +import ru.evotor.tspiot.service.TsPioTService; + +public class TsPioTServiceConnector { + + protected static final String TAG = "TsPioTServiceConnector"; + + public static final String ACTION_TSPIOT_SERVICE = "evotor.intent.action.TSPIOT_SERVICE"; + public static final String TARGET_PACKAGE = "ru.esp.umesm"; + public static final String TARGET_CLASS_NAME = "ru.esp.worker.worker.IntegrationMarksCheckService"; + + protected final static TsPioTService tsPioTService = new TsPioTService(); + + protected final static CopyOnWriteArrayList connectionWrappers = new CopyOnWriteArrayList<>(); + + public static CopyOnWriteArrayList getConnectionWrappers() { + return connectionWrappers; + } + + public static void addConnectionWrapper(ITsPioTConnectionWrapper connectionWrapper) { + connectionWrappers.add(connectionWrapper); + } + + public static void removeConnectionWrapper(ITsPioTConnectionWrapper connectionWrapper) { + connectionWrappers.remove(connectionWrapper); + } + + public static void clearConnectionWrappers() { + connectionWrappers.clear(); + } + + public static ITsPioTServiceWrapper connectTsPioTService(Context context) throws TsPioTServiceException { + TsPioTServiceOperationOnMainThreadException.throwIfMainThread(); + + tsPioTService.connectService(context, false); + return tsPioTService; + } + + public static void disconnectTsPioTService() throws TsPioTServiceException { + TsPioTServiceOperationOnMainThreadException.throwIfMainThread(); + + tsPioTService.disconnectService(); + } + + public static void processException(Exception exc) throws TsPioTServiceException { + if (exc instanceof DeadObjectException) { + tsPioTService.reconnectService(); + throw new ServiceNotConnectedException(exc); + } else if (exc instanceof RuntimeException) { + throw new TsPioTServiceRuntimeException(exc); + } + exc.printStackTrace(); + } +} diff --git a/src/main/java/ru/evotor/tspiot/Utils.java b/src/main/java/ru/evotor/tspiot/Utils.java new file mode 100644 index 0000000000..edcf42ca88 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/Utils.java @@ -0,0 +1,104 @@ +package ru.evotor.tspiot; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import java.io.Serializable; + +public final class Utils { + + @Nullable + public static Integer readInteger(Parcel parcel) { + try { + return (Integer) parcel.readValue(Integer.class.getClassLoader()); + } catch (Exception ex) { + return null; + } + } + + @Nullable + public static Boolean readBoolean(Parcel parcel) { + try { + return (Boolean) parcel.readValue(Boolean.class.getClassLoader()); + } catch (Exception ex) { + return null; + } + } + + @SuppressWarnings("unchecked") + @Nullable + public static Class readClass(Parcel parcel) { + Serializable serializable = parcel.readSerializable(); + + if (serializable == null) { + return null; + } + + try { + return (Class) serializable; + } catch (Exception exception) { + return null; + } + } + + @Nullable + public static T readData(Class classType, Parcel parcel) { + try { + if (classType == null) { + return parcel.readParcelable(null); + } + + return parcel.readParcelable(classType.getClassLoader()); + } catch (Exception exception) { + return null; + } + } + + public static String toString(@Nullable Object object) { + return object == null ? "null" : object.toString(); + } + + public static String toString(@Nullable int[] ints) { + if (ints == null) { + return "null"; + } else if (ints.length == 0) { + return "[]"; + } else { + StringBuilder sb = new StringBuilder(); + + sb.append("["); + for (int i = 0; i < ints.length; i++) { + sb.append(ints[i]); + + if (i != ints.length - 1) { + sb.append(", "); + } + } + sb.append("]"); + + return sb.toString(); + } + } + + public static String toString(@Nullable Object[] objects) { + if (objects == null) { + return "null"; + } else if (objects.length == 0) { + return "[]"; + } else { + StringBuilder sb = new StringBuilder(); + + sb.append("["); + for (int i = 0; i < objects.length; i++) { + sb.append(objects[i]); + + if (i != objects.length - 1) { + sb.append(", "); + } + } + sb.append("]"); + + return sb.toString(); + } + } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/NullContextException.java b/src/main/java/ru/evotor/tspiot/exceptions/NullContextException.java new file mode 100644 index 0000000000..d027ead12a --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/NullContextException.java @@ -0,0 +1,5 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class NullContextException extends TsPioTServiceException { } diff --git a/src/main/java/ru/evotor/tspiot/exceptions/ServiceAlreadyConnectedException.java b/src/main/java/ru/evotor/tspiot/exceptions/ServiceAlreadyConnectedException.java new file mode 100644 index 0000000000..cb8829c7f1 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/ServiceAlreadyConnectedException.java @@ -0,0 +1,5 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class ServiceAlreadyConnectedException extends TsPioTServiceException { } diff --git a/src/main/java/ru/evotor/tspiot/exceptions/ServiceNotConnectedException.java b/src/main/java/ru/evotor/tspiot/exceptions/ServiceNotConnectedException.java new file mode 100644 index 0000000000..93d8812b78 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/ServiceNotConnectedException.java @@ -0,0 +1,8 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class ServiceNotConnectedException extends TsPioTServiceException { + + public ServiceNotConnectedException(Exception ex) { super(ex); } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/TsPioTErrorHolderException.java b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTErrorHolderException.java new file mode 100644 index 0000000000..6f76af0da5 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTErrorHolderException.java @@ -0,0 +1,16 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; +import ru.evotor.tspiot.result.model.base.ErrorDescription; +import ru.evotor.tspiot.result.model.errors.TsPioTErrorsDescriptionWrapper; + +/** Исключение обёртка для передачи ошибок от драйвера ТС ПИоТ */ +public class TsPioTErrorHolderException extends TsPioTServiceException { + + public final TsPioTErrorsDescriptionWrapper errorDescriptionWrapper; + + public TsPioTErrorHolderException(TsPioTErrorsDescriptionWrapper errorDescriptionWrapper) { + super(); + this.errorDescriptionWrapper = errorDescriptionWrapper; + } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceOperationOnMainThreadException.java b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceOperationOnMainThreadException.java new file mode 100644 index 0000000000..7641883b55 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceOperationOnMainThreadException.java @@ -0,0 +1,16 @@ +package ru.evotor.tspiot.exceptions; + +import android.os.Looper; +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class TsPioTServiceOperationOnMainThreadException extends TsPioTServiceException { + public TsPioTServiceOperationOnMainThreadException() { + super("It is forbidden to perform operations with TS PIoT service in the main thread, it can be time-consuming"); + } + + public static void throwIfMainThread() throws TsPioTServiceOperationOnMainThreadException { + if (Looper.getMainLooper() == Looper.myLooper()) { + throw new TsPioTServiceOperationOnMainThreadException(); + } + } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceRuntimeException.java b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceRuntimeException.java new file mode 100644 index 0000000000..f7d3b3a681 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/TsPioTServiceRuntimeException.java @@ -0,0 +1,8 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class TsPioTServiceRuntimeException extends TsPioTServiceException { + + public TsPioTServiceRuntimeException(Exception ex) { super(ex); } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/UnknownException.java b/src/main/java/ru/evotor/tspiot/exceptions/UnknownException.java new file mode 100644 index 0000000000..f89bf1b1f3 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/UnknownException.java @@ -0,0 +1,8 @@ +package ru.evotor.tspiot.exceptions; + +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; + +public class UnknownException extends TsPioTServiceException { + + public UnknownException(String message) { super(message); } +} diff --git a/src/main/java/ru/evotor/tspiot/exceptions/base/TsPioTServiceException.java b/src/main/java/ru/evotor/tspiot/exceptions/base/TsPioTServiceException.java new file mode 100644 index 0000000000..f892280bae --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/exceptions/base/TsPioTServiceException.java @@ -0,0 +1,17 @@ +package ru.evotor.tspiot.exceptions.base; + +/** Базовый класс для исключений, которые могу возникнуть на стороне клиента ТС ПИоТ*/ +public class TsPioTServiceException extends Exception { + + public TsPioTServiceException() { + super(); + } + + public TsPioTServiceException(String message) { + super(message); + } + + public TsPioTServiceException(Exception e) { + super(e); + } +} diff --git a/src/main/java/ru/evotor/tspiot/model/MarkingCode.java b/src/main/java/ru/evotor/tspiot/model/MarkingCode.java new file mode 100644 index 0000000000..88bbd82222 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/model/MarkingCode.java @@ -0,0 +1,59 @@ +package ru.evotor.tspiot.model; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import org.jetbrains.annotations.NotNull; +import java.util.Objects; +import ru.evotor.tspiot.Utils; + +public class MarkingCode implements Parcelable { + + /** Версия MarkingCode */ + private static final int VERSION = 1; + + /** Код маркировки */ + @NotNull private final String cis; + + /** Опциональный параметр идентификатора товарной группы */ + @Nullable private final Integer productType; + + public MarkingCode(@NotNull String cis, @Nullable Integer productType) { + this.cis = cis; + this.productType = productType; + } + + private MarkingCode(Parcel parcel) { + int version = parcel.readInt(); + this.cis = Objects.requireNonNull(parcel.readString()); + this.productType = Utils.readInteger(parcel); + } + + @NotNull + public String getCis() { return cis; } + + @Nullable + public Integer getProductType() { return productType; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(VERSION); + parcel.writeString(cis); + parcel.writeValue(productType); + } + + public static Creator CREATOR = new Creator<>() { + @Override + public MarkingCode createFromParcel(Parcel parcel) { + return new MarkingCode(parcel); + } + + @Override + public MarkingCode[] newArray(int i) { + return new MarkingCode[i]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/TsPioTError.java b/src/main/java/ru/evotor/tspiot/result/TsPioTError.java new file mode 100644 index 0000000000..f74c2afc82 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/TsPioTError.java @@ -0,0 +1,54 @@ +package ru.evotor.tspiot.result; + +import android.os.Parcel; +import android.os.Parcelable; +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.ErrorDescription; +import ru.evotor.tspiot.result.model.errors.TsPioTErrorsDescriptionWrapper; + +public class TsPioTError implements Parcelable { + + /** Версия TsPioTError */ + private final static int VERSION = 1; + + /** Описание ошибки */ + private final TsPioTErrorsDescriptionWrapper error; + + private final Class> errorType; + + private TsPioTError(Parcel parcel) { + int version = parcel.readInt(); + errorType = Utils.readClass(parcel); + error = Utils.readData(errorType, parcel); + } + + @SuppressWarnings("unchecked") + public TsPioTError(TsPioTErrorsDescriptionWrapper error) { + this.error = error; + this.errorType = (Class>) error.getClass(); + } + + public TsPioTErrorsDescriptionWrapper getError() { return error; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeSerializable(errorType); + parcel.writeParcelable(error, flags); + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public TsPioTError createFromParcel(Parcel parcel) { + return new TsPioTError(parcel); + } + + @Override + public TsPioTError[] newArray(int size) { + return new TsPioTError[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/TsPioTResult.java b/src/main/java/ru/evotor/tspiot/result/TsPioTResult.java new file mode 100644 index 0000000000..10a4cb963e --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/TsPioTResult.java @@ -0,0 +1,69 @@ +package ru.evotor.tspiot.result; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import ru.evotor.tspiot.Utils; + +public class TsPioTResult implements Parcelable { + + /** Версия TsPioTResult */ + private final static int VERSION = 1; + + @Nullable + private final Class classType; + + @Nullable private final TsPioTError error; + + @Nullable private final T data; + + private TsPioTResult(Parcel parcel) { + int version = parcel.readInt(); + this.classType = Utils.readClass(parcel); + this.data = Utils.readData(classType, parcel); + this.error = parcel.readParcelable(TsPioTError.class.getClassLoader()); + } + + @SuppressWarnings("unchecked") + public TsPioTResult(T data) { + this.classType = (Class) data.getClass(); + this.data = data; + this.error = null; + } + + public TsPioTResult(@NonNull TsPioTError error) { + this.classType = null; + this.data = null; + this.error = error; + } + + @Nullable + public T getData() { return data; } + + @Nullable + public TsPioTError getError() { return error; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeSerializable(classType); + parcel.writeParcelable(data, flags); + parcel.writeParcelable(error, flags); + } + + public static final Creator> CREATOR = new Creator<>() { + @Override + public TsPioTResult createFromParcel(Parcel parcel) { + return new TsPioTResult<>(parcel); + } + + @Override + public TsPioTResult[] newArray(int size) { + return new TsPioTResult[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/CodesCheckResult.java b/src/main/java/ru/evotor/tspiot/result/model/CodesCheckResult.java new file mode 100644 index 0000000000..900589fbcc --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/CodesCheckResult.java @@ -0,0 +1,57 @@ +package ru.evotor.tspiot.result.model; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import java.util.List; +import ru.evotor.tspiot.result.model.offline.OfflineCodesCheck; +import ru.evotor.tspiot.result.model.online.OnlineCodesCheck; + +public class CodesCheckResult implements Parcelable { + + /** Версия CodesCheckResult */ + private final static int VERSION = 1; + + @Nullable private final List onlineCodesChecks; + + @Nullable private final List offlineCodesChecks; + + private CodesCheckResult(Parcel parcel) { + int version = parcel.readInt(); + this.onlineCodesChecks = parcel.createTypedArrayList(OnlineCodesCheck.CREATOR); + this.offlineCodesChecks = parcel.createTypedArrayList(OfflineCodesCheck.CREATOR); + } + + public CodesCheckResult(@Nullable List onlineCodesChecks, @Nullable List offlineCodesChecks) { + this.onlineCodesChecks = onlineCodesChecks; + this.offlineCodesChecks = offlineCodesChecks; + } + + @Nullable + public List getOnlineCodesChecks() { return onlineCodesChecks; } + + @Nullable + public List getOfflineCodesChecks() { return offlineCodesChecks; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeTypedList(onlineCodesChecks); + parcel.writeTypedList(offlineCodesChecks); + } + + public static Creator CREATOR = new Creator<>() { + @Override + public CodesCheckResult createFromParcel(Parcel parcel) { + return new CodesCheckResult(parcel); + } + + @Override + public CodesCheckResult[] newArray(int size) { + return new CodesCheckResult[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/KktInfo.java b/src/main/java/ru/evotor/tspiot/result/model/KktInfo.java new file mode 100644 index 0000000000..15f01b657d --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/KktInfo.java @@ -0,0 +1,106 @@ +package ru.evotor.tspiot.result.model; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import ru.evotor.tspiot.Utils; + +public class KktInfo implements Parcelable { + + /** Версия KktInfo */ + private final static int VERSION = 1; + + /** Идентификатор ТС ПИоТ */ + private final String tspiotId; + + /** ЗН ККТ */ + private final String kktSerial; + + /** ЗН ФН */ + private final String fnSerial; + + /** ИНН ККТ */ + private final String kktInn; + + /** Время проверки кода в ТС ПИоТ (В миллисекундах) */ + private final int codesCheckTimeOut; + + @Nullable private final LmChzInfo lmChzInfo; + + public KktInfo( + String tspiotId, + String kktSerial, + String fnSerial, + String kktInn, + int codesCheckTimeOut, + @Nullable LmChzInfo lmChzInfo + ) { + this.tspiotId = tspiotId; + this.kktSerial = kktSerial; + this.fnSerial = fnSerial; + this.kktInn = kktInn; + this.codesCheckTimeOut = codesCheckTimeOut; + this.lmChzInfo = lmChzInfo; + } + + private KktInfo(Parcel parcel) { + int version = parcel.readInt(); + this.tspiotId = parcel.readString(); + this.kktSerial = parcel.readString(); + this.fnSerial = parcel.readString(); + this.kktInn = parcel.readString(); + this.codesCheckTimeOut = parcel.readInt(); + this.lmChzInfo = parcel.readTypedObject(LmChzInfo.CREATOR); + } + + public String getTspiotId() { return tspiotId; } + + public String getKktSerial() {return kktSerial; } + + public String getFnSerial() { return fnSerial; } + + public String getKktInn() { return kktInn; } + + public int getCodesCheckTimeOut() { return codesCheckTimeOut; } + + @Nullable + public LmChzInfo getLmChzInfo() { return lmChzInfo; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeString(tspiotId); + parcel.writeString(kktSerial); + parcel.writeString(fnSerial); + parcel.writeString(kktInn); + parcel.writeInt(codesCheckTimeOut); + parcel.writeTypedObject(lmChzInfo, flags); + } + + public static final Creator CREATOR = new Creator<>() { + + public KktInfo createFromParcel(Parcel in) { + return new KktInfo(in); + } + + public KktInfo[] newArray(int size) { + return new KktInfo[size]; + } + }; + + @NonNull + @Override + public String toString() { + return "TsPioTId: " + Utils.toString(tspiotId) + "\n" + + "KktSerial: " + Utils.toString(kktSerial) + "\n" + + "FnSerial: " + Utils.toString(fnSerial) + "\n" + + "KktInn: " + Utils.toString(kktInn) + "\n" + + "CodesCheckTimeout: " + Utils.toString(codesCheckTimeOut) + "\n" + + "LmChzInfo: " + Utils.toString(lmChzInfo); + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/LmChzInfo.java b/src/main/java/ru/evotor/tspiot/result/model/LmChzInfo.java new file mode 100644 index 0000000000..b429d2459b --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/LmChzInfo.java @@ -0,0 +1,179 @@ +package ru.evotor.tspiot.result.model; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.NonNull; + +import ru.evotor.tspiot.Utils; + +public class LmChzInfo implements Parcelable { + + private final static String VERSION_DEFAULT = ""; + private final static String STATUS_DEFAULT = ""; + private final static String TOKEN_DEFAULT = ""; + private final static String EXP_DATE_DEFAULT = ""; + private final static String IP_DEFAULT = ""; + private final static String LOGIN_DEFAULT = ""; + private final static String PASS_DEFAULT = ""; + + /** Версия LmChzInfo */ + private final static int VERSION = 1; + + /** Версия СПО «Локальный модуль» «Честный ЗНАК» */ + @NonNull private final String version; + + /** + *
    + * Возможные значения: + *
      + *
    • not_configured – не отконфигурирован;
    • + *
    • initialization – инициализация;
    • + *
    • ready – готов к работе;
    • + *
    • sync_error – ошибка синхронизации.
    • + *
    + *
+ */ + @NonNull private final String status; + + /** + * Дата и время последней синхронизации по всем базам данных. + * Если система не была инициализирована, то значение по умолчанию равно нулю. UnixTime в (мс) + */ + private final long lastSync; + + /** Токен ЛМ ЧЗ. */ + @NonNull private final String token; + + /** + * Дата и время истечения срока действия токена в формате ISO 8601 + * (например, 2025-03- 22T10:30:00Z). Время указано в UTC. + */ + @NonNull private final String expDate; + + /** IP-адрес установки ЛМ ЧЗ */ + @NonNull private final String ip; + + /** Порт ЛМ ЧЗ */ + private final int port; + + /** Логин для авторизации в ЛМ ЧЗ */ + @NonNull private final String login; + + /** Пароль для авторизации в ЛМ ЧЗ */ + @NonNull private final String pass; + + private LmChzInfo(@NonNull Parcel parcel) { + int classVersion = parcel.readInt(); + version = readParcelString(parcel, VERSION_DEFAULT); + status = readParcelString(parcel, STATUS_DEFAULT); + lastSync = parcel.readLong(); + token = readParcelString(parcel, TOKEN_DEFAULT); + expDate = readParcelString(parcel, EXP_DATE_DEFAULT); + ip = readParcelString(parcel, IP_DEFAULT); + port = parcel.readInt(); + login = readParcelString(parcel, LOGIN_DEFAULT); + pass = readParcelString(parcel, PASS_DEFAULT); + } + + private @NonNull String readParcelString(@NonNull Parcel parcel, @NonNull String defaultString) { + String parcelString = parcel.readString(); + return parcelString == null ? defaultString : parcelString; + } + + public LmChzInfo( + @NonNull + String version, + @NonNull + String status, + long lastSync, + @NonNull + String token, + @NonNull + String expDate, + @NonNull + String ip, + int port, + @NonNull + String login, + @NonNull + String pass + ) { + this.version = version; + this.status = status; + this.lastSync = lastSync; + this.token = token; + this.expDate = expDate; + this.ip = ip; + this.port = port; + this.login = login; + this.pass = pass; + } + + public int getPort() { return port; } + + public long getLastSync() { return lastSync; } + + @NonNull + public String getExpDate() { return expDate; } + + @NonNull + public String getIp() { return ip; } + + @NonNull + public String getLogin() { return login; } + + @NonNull + public String getPass() { return pass; } + + @NonNull + public String getStatus() { return status; } + + @NonNull + public String getToken() { return token; } + + @NonNull + public String getVersion() { return version; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(@NonNull Parcel parcel, int i) { + parcel.writeInt(VERSION); + parcel.writeString(version); + parcel.writeString(status); + parcel.writeLong(lastSync); + parcel.writeString(token); + parcel.writeString(expDate); + parcel.writeString(ip); + parcel.writeInt(port); + parcel.writeString(login); + parcel.writeString(pass); + } + + @NonNull + @Override + public String toString() { + return "Version: " + Utils.toString(version) + "\n" + + "Status : " + Utils.toString(status) + "\n" + + "Last sync: " + Utils.toString(lastSync) + "\n" + + "Token: " + Utils.toString(token) + "\n" + + "Exp date: " + Utils.toString(expDate) + "\n" + + "Ip: " + Utils.toString(ip) + "\n" + + "Port: " + Utils.toString(port) + "\n" + + "Login: " + Utils.toString(login) + "\n" + + "Pass: " + Utils.toString(pass); + } + + public final static Creator CREATOR = new Creator<>() { + @Override + public LmChzInfo createFromParcel(Parcel parcel) { + return new LmChzInfo(parcel); + } + + @Override + public LmChzInfo[] newArray(int size) { + return new LmChzInfo[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/VariableExpiration.java b/src/main/java/ru/evotor/tspiot/result/model/VariableExpiration.java new file mode 100644 index 0000000000..8d8d9aa628 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/VariableExpiration.java @@ -0,0 +1,62 @@ +package ru.evotor.tspiot.result.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import ru.evotor.tspiot.Utils; + +public class VariableExpiration implements Parcelable { + + /** Версия VariableExpiration */ + private final static int VERSION = 1; + + private final int degrees; + + private final String date; + + private VariableExpiration(Parcel parcel) { + int version = parcel.readInt(); + this.degrees = parcel.readInt(); + this.date = parcel.readString(); + } + + public VariableExpiration(int degrees, String date) { + this.degrees = degrees; + this.date = date; + } + + public int getDegrees() { return degrees; } + + public String getDate() { return date; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(VERSION); + parcel.writeInt(degrees); + parcel.writeString(date); + } + + public static final Creator CREATOR = new Creator() { + @Override + public VariableExpiration createFromParcel(Parcel parcel) { + return new VariableExpiration(parcel); + } + + @Override + public VariableExpiration[] newArray(int i) { + return new VariableExpiration[i]; + } + }; + + @NonNull + @Override + public String toString() { + return "Degrees: " + Utils.toString(degrees) + "\n" + + "Date: " + Utils.toString(date); + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/VariableExpirations.java b/src/main/java/ru/evotor/tspiot/result/model/VariableExpirations.java new file mode 100644 index 0000000000..5dd6491d59 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/VariableExpirations.java @@ -0,0 +1,55 @@ +package ru.evotor.tspiot.result.model; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; + +import ru.evotor.tspiot.Utils; + +/** Вариативный срок годности */ +public class VariableExpirations implements Parcelable { + + /** Версия VariableExpirations */ + private final static int VERSION = 1; + + private VariableExpiration[] expirations; + + private VariableExpirations(Parcel parcel) { + int version = parcel.readInt(); + parcel.readTypedArray(expirations, VariableExpiration.CREATOR); + } + + public VariableExpirations(VariableExpiration[] expirations) { + this.expirations = expirations; + } + + public VariableExpiration[] getExpirations() { return expirations; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeTypedArray(expirations, flags); + } + + public static Creator CREATOR = new Creator() { + @Override + public VariableExpirations createFromParcel(Parcel parcel) { + return new VariableExpirations(parcel); + } + + @Override + public VariableExpirations[] newArray(int i) { + return new VariableExpirations[i]; + } + }; + + @NonNull + @Override + public String toString() { + return "VariableExpirations: " + Utils.toString(expirations); + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodeCheck.java b/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodeCheck.java new file mode 100644 index 0000000000..fb2052b4ee --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodeCheck.java @@ -0,0 +1,272 @@ +package ru.evotor.tspiot.result.model.base; + +import android.os.Parcel; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.VariableExpirations; + +public abstract class BaseCodeCheck { + + /** + * Версия BaseCodeCheck + */ + private final static int VERSION = 1; + + /** + * КИ / КиЗ из запроса + */ + protected final String cis; + + /** + * Признак наличия кода в ГИС МТ + */ + @Nullable + protected final Boolean found; + + /** + * Результат проверки валидности структуры КИ / КиЗ + */ + @Nullable + protected final Boolean valid; + + /** + * КИ без крипто-подписи / КиЗ + */ + @Nullable + protected final String printView; + + /** + * Код товара + */ + @Nullable + protected final String gtin; + + /** + * Массив идентификаторов товарных групп + */ + @Nullable + protected final int[] groupIds; + + /** + * Результат проверки крипто-подписи КМ + */ + @Nullable + protected final Boolean verified; + + /** + * Признак возможности реализации КИ / КиЗ + */ + @Nullable + protected final Boolean realizable; + + /** + * Признак нанесения КИ / КиЗ на упаковку + */ + @Nullable + protected final Boolean utilized; + + /** + * Информация о вариативном сроке годности + */ + @Nullable + protected final VariableExpirations variableExpirations; + + /** + * Признак того, что розничная продажа продукции заблокирована по решению ОГВ + */ + @Nullable + protected final Boolean isBlocked; + + /** + * Органы государственной власти, установившие блокировку на КИ + */ + @Nullable + protected final String[] ogvs; + + /** + * Признак продажи товара + */ + @Nullable + protected final Boolean sold; + + /** + * Максимальная розничная цена + */ + @Nullable + protected final Integer mrp; + + /** + * Единая минимальная цена (ЕМЦ) + */ + @Nullable + protected final Integer smp; + + protected BaseCodeCheck(Parcel parcel) { + int version = parcel.readInt(); + this.cis = parcel.readString(); + this.found = Utils.readBoolean(parcel); + this.valid = Utils.readBoolean(parcel); + this.printView = parcel.readString(); + this.gtin = parcel.readString(); + this.groupIds = parcel.createIntArray(); + this.verified = Utils.readBoolean(parcel); + this.realizable = Utils.readBoolean(parcel); + this.utilized = Utils.readBoolean(parcel); + this.variableExpirations = parcel.readTypedObject(VariableExpirations.CREATOR); + this.isBlocked = Utils.readBoolean(parcel); + this.ogvs = parcel.createStringArray(); + this.sold = Utils.readBoolean(parcel); + this.mrp = Utils.readInteger(parcel); + this.smp = Utils.readInteger(parcel); + } + + public BaseCodeCheck( + String cis, + @Nullable Boolean found, + @Nullable Boolean valid, + @Nullable String printView, + @Nullable String gtin, + @Nullable int[] groupIds, + @Nullable Boolean verified, + @Nullable Boolean realizable, + @Nullable Boolean utilized, + @Nullable VariableExpirations variableExpirations, + @Nullable Boolean isBlocked, + @Nullable String[] ogvs, + @Nullable Boolean sold, + @Nullable Integer mrp, + @Nullable Integer smp + ) { + this.cis = cis; + this.found = found; + this.valid = valid; + this.printView = printView; + this.gtin = gtin; + this.groupIds = groupIds; + this.verified = verified; + this.realizable = realizable; + this.utilized = utilized; + this.variableExpirations = variableExpirations; + this.isBlocked = isBlocked; + this.ogvs = ogvs; + this.sold = sold; + this.mrp = mrp; + this.smp = smp; + } + + protected void write(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeString(cis); + parcel.writeValue(found); + parcel.writeValue(valid); + parcel.writeString(printView); + parcel.writeString(gtin); + parcel.writeIntArray(groupIds); + parcel.writeValue(verified); + parcel.writeValue(realizable); + parcel.writeValue(utilized); + parcel.writeTypedObject(this.variableExpirations, flags); + parcel.writeValue(isBlocked); + parcel.writeStringArray(ogvs); + parcel.writeValue(sold); + parcel.writeValue(mrp); + parcel.writeValue(smp); + } + + @Nullable + public Boolean getBlocked() { + return isBlocked; + } + + @Nullable + public Boolean isFound() { + return found; + } + + @Nullable + public Boolean isRealizable() { + return realizable; + } + + @Nullable + public Boolean isSold() { + return sold; + } + + @Nullable + public Boolean isUtilized() { + return utilized; + } + + @Nullable + public Boolean isValid() { + return valid; + } + + @Nullable + public Boolean isVerified() { + return verified; + } + + @Nullable + public int[] getGroupIds() { + return groupIds; + } + + @Nullable + public Integer getMrp() { + return mrp; + } + + @Nullable + public Integer getSmp() { + return smp; + } + + public String getCis() { + return cis; + } + + @Nullable + public String getGtin() { + return gtin; + } + + @Nullable + public String getPrintView() { + return printView; + } + + @Nullable + public String[] getOgvs() { + return ogvs; + } + + @Nullable + public VariableExpirations getVariableExpirations() { + return variableExpirations; + } + + @NonNull + @Override + public String toString() { + return "Cis: " + Utils.toString(cis) + "\n" + + "IsFound: " + Utils.toString(found) + "\n" + + "IsValid: " + Utils.toString(valid) + "\n" + + "PrintView: " + Utils.toString(printView) + "\n" + + "Gtin: " + Utils.toString(gtin) + "\n" + + "GroupIds: " + Utils.toString(groupIds) + "\n" + + "IsVerified: " + Utils.toString(verified) + "\n" + + "IsRealizable: " + Utils.toString(realizable) + "\n" + + "IsUtilized: " + Utils.toString(utilized) + "\n" + + "VariableExpirations: " + Utils.toString(variableExpirations) + "\n" + + "IsBlocked: " + Utils.toString(isBlocked) + "\n" + + "Ogvs: " + Utils.toString(ogvs) + "\n" + + "IsSold: " + Utils.toString(sold) + "\n" + + "Mrp: " + Utils.toString(mrp) + "\n" + + "Smp: " + Utils.toString(smp) + "\n"; + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodesCheck.java b/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodesCheck.java new file mode 100644 index 0000000000..cdd703f3b0 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/base/BaseCodesCheck.java @@ -0,0 +1,59 @@ +package ru.evotor.tspiot.result.model.base; + +import android.os.Parcel; + +import androidx.annotation.NonNull; + +import ru.evotor.tspiot.Utils; + +public abstract class BaseCodesCheck { + + /** Версия BaseCodesCheck */ + private final static int VERSION = 1; + + protected final int code; + + /** Уникальный идентификатор запроса */ + protected final String reqId; + + /** Дата и время формирования запроса (в UTC) */ + protected final long reqTimestamp; + + protected BaseCodesCheck(Parcel parcel) { + int version = parcel.readInt(); + this.code = parcel.readInt(); + this.reqId = parcel.readString(); + this.reqTimestamp = parcel.readLong(); + } + + public BaseCodesCheck( + int code, + String reqId, + long reqTimestamp + ) { + this.code = code; + this.reqId = reqId; + this.reqTimestamp = reqTimestamp; + } + + protected final void write(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeInt(code); + parcel.writeString(reqId); + parcel.writeLong(reqTimestamp); + } + + public int getCode() { return code; } + + public String getReqId() { return reqId; } + + public long getReqTimestamp() { return reqTimestamp; } + + @NonNull + @Override + public String toString() { + return "Code: " + Utils.toString(code) + "\n" + + "ReqId: " + Utils.toString(reqId) + "\n" + + "ReqTimestamp: " + Utils.toString(reqTimestamp) + "\n"; + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/base/ErrorDescription.java b/src/main/java/ru/evotor/tspiot/result/model/base/ErrorDescription.java new file mode 100644 index 0000000000..7211f4e4cc --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/base/ErrorDescription.java @@ -0,0 +1,5 @@ +package ru.evotor.tspiot.result.model.base; + +import android.os.Parcelable; + +public interface ErrorDescription extends Parcelable { } diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/CheckServiceAreUnavailable.java b/src/main/java/ru/evotor/tspiot/result/model/errors/CheckServiceAreUnavailable.java new file mode 100644 index 0000000000..efbe6dd5a9 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/CheckServiceAreUnavailable.java @@ -0,0 +1,33 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; + +/** + * ТС ПИоТ не смог получить ответ ни от ГИС МТ, ни от ЛМ ЧЗ. + * Сервисы ЧЗ недоступны, имеет смысл повторить запрос позже. + */ +public final class CheckServiceAreUnavailable extends TsPioTErrorsDescriptionWrapper { + private final CodesCheckErrorDescription errorDescription; + + public CheckServiceAreUnavailable(CodesCheckErrorDescription errorDescription) { + this.errorDescription = errorDescription; + } + + private CheckServiceAreUnavailable(Parcel parcel) { + super(parcel); + this.errorDescription = parcel.readParcelable(CodesCheckErrorDescription.class.getClassLoader()); + } + + @Override + public CodesCheckErrorDescription getErrorDescription() { return errorDescription; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(errorDescription, flags); + } + + public static final Creator CREATOR = new BaseCreator<>(CheckServiceAreUnavailable.class); +} \ No newline at end of file diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescription.java b/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescription.java new file mode 100644 index 0000000000..b3d8ab9aed --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescription.java @@ -0,0 +1,64 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; + +import androidx.annotation.NonNull; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.ErrorDescription; + +public class CodeMessageErrorDescription implements ErrorDescription { + + /** Версия CommonErrorDescription */ + private final static int VERSION = 1; + + /** Код ошибки */ + private final int errorCode; + + /** Описание ошибки */ + private final String message; + + private CodeMessageErrorDescription(Parcel parcel) { + int version = parcel.readInt(); + this.errorCode = parcel.readInt(); + this.message = parcel.readString(); + } + + public CodeMessageErrorDescription(int errorCode, String message) { + this.errorCode = errorCode; + this.message = message; + } + + public int getErrorCode() { return errorCode; } + + public String getMessage() { return message; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(VERSION); + parcel.writeInt(errorCode); + parcel.writeString(message); + } + + @NonNull + @Override + public String toString() { + return "ErrorCode: " + Utils.toString(errorCode) + "\n" + + "Message: " + Utils.toString(message) + "\n"; + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public CodeMessageErrorDescription createFromParcel(Parcel parcel) { + return new CodeMessageErrorDescription(parcel); + } + + @Override + public CodeMessageErrorDescription[] newArray(int size) { + return new CodeMessageErrorDescription[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescriptionWrapper.java b/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescriptionWrapper.java new file mode 100644 index 0000000000..fbe962ffd0 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/CodeMessageErrorDescriptionWrapper.java @@ -0,0 +1,74 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; + +public sealed abstract class CodeMessageErrorDescriptionWrapper extends TsPioTErrorsDescriptionWrapper { + protected final CodeMessageErrorDescription errorDescription; + + protected CodeMessageErrorDescriptionWrapper(Parcel parcel) { + super(parcel); + this.errorDescription = parcel.readParcelable(CodeMessageErrorDescription.class.getClassLoader()); + } + + public CodeMessageErrorDescriptionWrapper(CodeMessageErrorDescription errorDescription) { + this.errorDescription = errorDescription; + } + + @Override + public CodeMessageErrorDescription getErrorDescription() { return errorDescription; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(errorDescription, flags); + } + + /** Ошибка на стороне ККМ */ + public static final class KkmError extends CodeMessageErrorDescriptionWrapper { + private KkmError(Parcel parcel) { super(parcel); } + + public KkmError(CodeMessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(KkmError.class); + } + + /** Ошибка на стороне локального модуля */ + public static final class LocalModuleError extends CodeMessageErrorDescriptionWrapper { + private LocalModuleError(Parcel parcel) { super(parcel); } + + public LocalModuleError(CodeMessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(LocalModuleError.class); + } + + /** Не удалось получить fnSid (Не удалось установить доверенный канал) */ + public static final class FnSidError extends CodeMessageErrorDescriptionWrapper { + private FnSidError(Parcel parcel) { super(parcel); } + + public FnSidError(CodeMessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(FnSidError.class); + } + + /** + * Аварийный режим. Продажа товара разрешена без проверки, + * действуют ограничения аварийного режима + */ + public static final class EmergencyMode extends CodeMessageErrorDescriptionWrapper { + private EmergencyMode(Parcel parcel) { super(parcel); } + + public EmergencyMode(CodeMessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(EmergencyMode.class); + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/CodesCheckErrorDescription.java b/src/main/java/ru/evotor/tspiot/result/model/errors/CodesCheckErrorDescription.java new file mode 100644 index 0000000000..9f65924237 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/CodesCheckErrorDescription.java @@ -0,0 +1,77 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; +import androidx.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.ErrorDescription; + +public class CodesCheckErrorDescription implements ErrorDescription { + + /** Версия CodesCheckErrorDescription */ + private final static int VERSION = 1; + + @Nullable private final Class onlineErrorClass; + + @Nullable private final Class offlineErrorClass; + + /** Ошибка онлайн проверки */ + @Nullable private final ErrorDescription onlineError; + + /** Ошибка офлайн проверки */ + @Nullable private final ErrorDescription offlineError; + + private CodesCheckErrorDescription(Parcel parcel) { + int version = parcel.readInt(); + this.onlineErrorClass = Utils.readClass(parcel); + this.offlineErrorClass = Utils.readClass(parcel); + this.onlineError = Utils.readData(onlineErrorClass, parcel); + this.offlineError = Utils.readData(offlineErrorClass, parcel); + } + + public CodesCheckErrorDescription(@Nullable ErrorDescription onlineError, @Nullable ErrorDescription offlineError) { + this.onlineErrorClass = onlineError != null ? onlineError.getClass() : null; + this.offlineErrorClass = offlineError != null ? offlineError.getClass() : null; + this.onlineError = onlineError; + this.offlineError = offlineError; + } + + @Nullable + public ErrorDescription getOnlineError() { return onlineError; } + + @Nullable + public ErrorDescription getOfflineError() { return offlineError; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeInt(VERSION); + parcel.writeSerializable(onlineErrorClass); + parcel.writeSerializable(offlineErrorClass); + parcel.writeParcelable(onlineError, flags); + parcel.writeParcelable(offlineError, flags); + } + + @NotNull + @Override + public String toString() { + return "OnlineError:\n" + Utils.toString(onlineError) + "\n" + + "OfflineError:\n" + Utils.toString(offlineError) + "\n"; + } + + public static final Creator CREATOR = new Creator<>() { + @Override + public CodesCheckErrorDescription createFromParcel(Parcel parcel) { + return new CodesCheckErrorDescription(parcel); + } + + @Override + public CodesCheckErrorDescription[] newArray(int size) { + return new CodesCheckErrorDescription[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescription.java b/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescription.java new file mode 100644 index 0000000000..b91b65619d --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescription.java @@ -0,0 +1,55 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; + +import org.jetbrains.annotations.NotNull; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.ErrorDescription; + +public class MessageErrorDescription implements ErrorDescription { + + /** Версия MessageErrorDescription */ + private final static int VERSION = 1; + + /** Описание ошибки */ + private final String message; + + private MessageErrorDescription(Parcel parcel) { + int version = parcel.readInt(); + this.message = parcel.readString(); + } + + public MessageErrorDescription(String message) { + this.message = message; + } + + public String getMessage() { return message; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int i) { + parcel.writeInt(VERSION); + parcel.writeString(message); + } + + @NotNull + @Override + public String toString() { + return "Message: " + Utils.toString(message) + "\n"; + } + + public static final Creator CREATOR = new Creator() { + @Override + public MessageErrorDescription createFromParcel(Parcel parcel) { + return new MessageErrorDescription(parcel); + } + + @Override + public MessageErrorDescription[] newArray(int size) { + return new MessageErrorDescription[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescriptionWrapper.java b/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescriptionWrapper.java new file mode 100644 index 0000000000..1bc90387a8 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/MessageErrorDescriptionWrapper.java @@ -0,0 +1,126 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; + +public sealed abstract class MessageErrorDescriptionWrapper extends TsPioTErrorsDescriptionWrapper { + final protected MessageErrorDescription errorDescription; + + protected MessageErrorDescriptionWrapper(Parcel parcel) { + super(parcel); + this.errorDescription = parcel.readParcelable(MessageErrorDescription.class.getClassLoader()); + } + + public MessageErrorDescriptionWrapper(MessageErrorDescription errorDescription) { + this.errorDescription = errorDescription; + } + + @Override + public MessageErrorDescription getErrorDescription() { return errorDescription; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + parcel.writeParcelable(errorDescription, flags); + } + + /** Нет доступных CDN для онлайн проверки */ + public static final class CdnNotFoundError extends MessageErrorDescriptionWrapper { + private CdnNotFoundError(Parcel parcel) { super(parcel); } + + public CdnNotFoundError(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(CdnNotFoundError.class); + } + + /** ТСПиОТ не зарегистрирован */ + public static final class NotRegistered extends MessageErrorDescriptionWrapper { + private NotRegistered(Parcel parcel) { super(parcel); } + + public NotRegistered(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(NotRegistered.class); + } + + /** Не получена конфигурация ТСПиОТ */ + public static final class NotConfigured extends MessageErrorDescriptionWrapper { + private NotConfigured(Parcel parcel) { super(parcel); } + + public NotConfigured(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(NotConfigured.class); + } + + /** Отсутствует пермишн PMSR в манифесте приложения */ + public static final class NotFoundPermission extends MessageErrorDescriptionWrapper { + private NotFoundPermission(Parcel parcel) { super(parcel); } + + public NotFoundPermission(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(NotFoundPermission.class); + } + + /** Отсутствует PMSR_ID в манифесте приложения */ + public static final class NotFoundPmsrId extends MessageErrorDescriptionWrapper { + private NotFoundPmsrId(Parcel parcel) { super(parcel); } + + public NotFoundPmsrId(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(NotFoundPmsrId.class); + } + + /** Отсутствует PMSR_TOKEN в манифесте приложения */ + public static final class NotFoundPmsrToken extends MessageErrorDescriptionWrapper { + private NotFoundPmsrToken(Parcel parcel) { super(parcel); } + + public NotFoundPmsrToken(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(NotFoundPmsrToken.class); + } + + /** Не удалось получить appName вызывающего приложения */ + public static final class FailedGetAppName extends MessageErrorDescriptionWrapper { + private FailedGetAppName(Parcel parcel) { super(parcel); } + + public FailedGetAppName(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(FailedGetAppName.class); + } + + /** Не удалось получить версию вызывающего приложения */ + public static final class FailedGetAppVersion extends MessageErrorDescriptionWrapper { + private FailedGetAppVersion(Parcel parcel) { super(parcel); } + + public FailedGetAppVersion(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(FailedGetAppVersion.class); + } + + /** Неизвестная ошибка */ + public static final class UnknownError extends MessageErrorDescriptionWrapper { + private UnknownError(Parcel parcel) { super(parcel); } + + public UnknownError(MessageErrorDescription errorDescription) { + super(errorDescription); + } + + public static final Creator CREATOR = new BaseCreator<>(UnknownError.class); + } +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/errors/TsPioTErrorsDescriptionWrapper.java b/src/main/java/ru/evotor/tspiot/result/model/errors/TsPioTErrorsDescriptionWrapper.java new file mode 100644 index 0000000000..7c50b7b638 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/errors/TsPioTErrorsDescriptionWrapper.java @@ -0,0 +1,37 @@ +package ru.evotor.tspiot.result.model.errors; + +import android.os.Parcel; +import android.os.Parcelable; +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import ru.evotor.tspiot.result.model.base.ErrorDescription; + +public abstract sealed class TsPioTErrorsDescriptionWrapper implements Parcelable permits CheckServiceAreUnavailable, CodeMessageErrorDescriptionWrapper, MessageErrorDescriptionWrapper { + abstract public T getErrorDescription(); + + protected TsPioTErrorsDescriptionWrapper() { } + + protected TsPioTErrorsDescriptionWrapper(Parcel parcel) { } + + public static class BaseCreator> implements Creator { + private final Class clazz; + + public BaseCreator(Class clazz) { this.clazz = clazz; } + + @SuppressWarnings("unchecked") + @Override + public I createFromParcel(Parcel in) { + try { + Constructor constructor = clazz.getDeclaredConstructor(Parcel.class); + constructor.setAccessible(true); + return constructor.newInstance(in); + } catch (Exception e) { + throw new RuntimeException("Cannot create " + clazz.getSimpleName(), e); + } + } + + @SuppressWarnings("unchecked") + @Override + public I[] newArray(int size) { return (I[]) Array.newInstance(clazz, size); } + } +} \ No newline at end of file diff --git a/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodeCheck.java b/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodeCheck.java new file mode 100644 index 0000000000..d9267a105d --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodeCheck.java @@ -0,0 +1,66 @@ +package ru.evotor.tspiot.result.model.offline; + +import android.os.Parcel; +import android.os.Parcelable; +import androidx.annotation.Nullable; +import ru.evotor.tspiot.result.model.VariableExpirations; +import ru.evotor.tspiot.result.model.base.BaseCodeCheck; + +public class OfflineCodeCheck extends BaseCodeCheck implements Parcelable { + + private OfflineCodeCheck(Parcel parcel) { + super(parcel); + } + + public OfflineCodeCheck( + String cis, + @Nullable Boolean found, + @Nullable Boolean valid, + @Nullable String printView, + @Nullable String gtin, + @Nullable Boolean verified, + @Nullable Boolean realizable, + @Nullable Boolean utilized, + @Nullable VariableExpirations variableExpirations, + @Nullable Boolean isBlocked, + @Nullable Boolean sold, + @Nullable Integer mrp, + @Nullable Integer smp + ) { + super( + cis, + found, + valid, + printView, + gtin, + null, + verified, + realizable, + utilized, + variableExpirations, + isBlocked, + null, + sold, + mrp, + smp + ); + } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { super.write(parcel, flags); } + + public final static Creator CREATOR = new Creator() { + @Override + public OfflineCodeCheck createFromParcel(Parcel parcel) { + return new OfflineCodeCheck(parcel); + } + + @Override + public OfflineCodeCheck[] newArray(int size) { + return new OfflineCodeCheck[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodesCheck.java b/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodesCheck.java new file mode 100644 index 0000000000..46a8c92b42 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/offline/OfflineCodesCheck.java @@ -0,0 +1,95 @@ +package ru.evotor.tspiot.result.model.offline; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.List; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.BaseCodesCheck; + +public class OfflineCodesCheck extends BaseCodesCheck implements Parcelable { + + /** Версия OfflineCodesCheck */ + private final static int VERSION = 1; + + /** Версия базы "чёрного списка", на которой выполнялась проверка КИ */ + private final String version; + + /** Идентификатор экземпляра ПО ЛМ ЧЗ */ + private final String inst; + + /** Результат проверки марок*/ + private final List codes; + + private OfflineCodesCheck(Parcel parcel) { + super(parcel); + + int classVersion = parcel.readInt(); + this.version = parcel.readString(); + this.inst = parcel.readString(); + this.codes = parcel.createTypedArrayList(OfflineCodeCheck.CREATOR); + } + + public OfflineCodesCheck( + int code, + String reqId, + long reqTimestamp, + String version, + String inst, + List codes + ) { + super(code, reqId, reqTimestamp); + + this.version = version; + this.inst = inst; + this.codes = codes; + } + + public String getInst() { return inst; } + + public String getVersion() { return version; } + + public List getCodes() { return codes; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + super.write(parcel, flags); + + parcel.writeInt(VERSION); + parcel.writeString(version); + parcel.writeString(inst); + parcel.writeTypedList(codes); + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = new StringBuilder(super.toString()); + + builder.append("Version: ").append(Utils.toString(version)).append("\n"); + builder.append("Inst: ").append(Utils.toString(inst)).append("\n"); + codes.forEach(offlineCodeCheck -> { + builder.append("OfflineCodeCheck: ").append(offlineCodeCheck).append("\n"); + }); + + return builder.toString(); + } + + public final static Creator CREATOR = new Creator<>() { + @Override + public OfflineCodesCheck createFromParcel(Parcel parcel) { + return new OfflineCodesCheck(parcel); + } + + @Override + public OfflineCodesCheck[] newArray(int size) { + return new OfflineCodesCheck[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodeCheck.java b/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodeCheck.java new file mode 100644 index 0000000000..a3bd2e9225 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodeCheck.java @@ -0,0 +1,414 @@ +package ru.evotor.tspiot.result.model.online; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.Date; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.VariableExpirations; +import ru.evotor.tspiot.result.model.base.BaseCodeCheck; + +public class OnlineCodeCheck extends BaseCodeCheck implements Parcelable { + + /** + * Версия OnlineCodeCheck + */ + private final static int VERSION = 1; + + /** + * Дата и время истечения срока годности + */ + @Nullable + private final Date expireDate; + + /** + * Дата производства продукции + */ + @Nullable + private final Date productionDate; + + /** + * Переменный вес продукции (в граммах) + */ + @Nullable + private final Integer productWeight; + + /** + * Производственный ветеринарный сопроводительный документ + */ + @Nullable + private final String prVetDocument; + + /** + * Признак, определяющий, что запрос направлен владельцем кода (определяется по аутентификационному токену) + */ + @Nullable + private final Boolean isOwner; + + /** + * Сообщение об ошибке + */ + @Nullable + private final String message; + + /** + * Код ошибки + *
    + * Возможные значения: + *
      + *
    • 0 — ошибки отсутствуют
    • + *
    • 1 — ошибка валидации КМ
    • + *
    • 2 — КМ не содержит GTIN
    • + *
    • 3 — КМ не содержит серийный номер
    • + *
    • 4 — КМ содержит недопустимые символы
    • + *
    • 5 — ошибка верификации крипто-подписи КМ (формат крипто-подписи не соответствует типу КМ)
    • + *
    • 6 — ошибка верификации крипто-подписи КМ (криптоподпись невалидная)
    • + *
    • 7 — ошибка верификации крипто-подписи КМ (крипто-ключ не валиден)
    • + *
    • 8 — КМ не прошел верификацию в стране эмитента
    • + *
    • 9 — Найденные AI в КМ не поддерживаются
    • + *
    • 10 — КМ не найден в ГИС МТ
    • + *
    • 11 — КМ не найден в трансгране
    • + *
    + *
+ */ + @Nullable + private final Integer errorCode; + + /** + * Признак контроля прослеживаемости в товарной группе + */ + @Nullable + private final Boolean isTracking; + + /** + * Признак использования причин выбытия, разрешающих продажу КМ + */ + @Nullable + private final Integer eliminationState; + + /** + * Признак принадлежности табачной продукции к «серой зоне» + */ + @Nullable + private final Boolean grayZone; + + /** + * Количество единиц товара в потребительской упаковке / Фактический объём / Фактический вес + */ + @Nullable + private final Integer innerUnitCount; + + /** + * Счётчик проданного и возвращённого товара + */ + @Nullable + private final Integer soldUnitCount; + + /** + * Тип упаковки + */ + @Nullable + private final String packageType; + + /** + * КИ агрегата + */ + @Nullable + private final String parent; + + /** + * ИНН производителя + */ + @Nullable + private final String producerInn; + + /** + * Номер производственной серии + */ + @Nullable + private final String productionSerialNumber; + + /** + * Номер производственной партии + */ + @Nullable + private final String productionBatchNumber; + + /** + * Заводской серийный номер + */ + @Nullable + private final String factorySerialNumber; + + /** + * Ёмкость КИГУ + */ + @Nullable + private final Integer packageQuantity; + + private OnlineCodeCheck(Parcel parcel) { + super(parcel); + + int version = parcel.readInt(); + this.expireDate = (Date) parcel.readSerializable(); + this.productionDate = (Date) parcel.readSerializable(); + this.productWeight = Utils.readInteger(parcel); + this.prVetDocument = parcel.readString(); + this.isOwner = Utils.readBoolean(parcel); + this.message = parcel.readString(); + this.errorCode = Utils.readInteger(parcel); + this.isTracking = parcel.readInt() == 1; + this.eliminationState = Utils.readInteger(parcel); + this.grayZone = Utils.readBoolean(parcel); + this.innerUnitCount = Utils.readInteger(parcel); + this.soldUnitCount = Utils.readInteger(parcel); + this.packageType = parcel.readString(); + this.parent = parcel.readString(); + this.producerInn = parcel.readString(); + this.productionSerialNumber = parcel.readString(); + this.productionBatchNumber = parcel.readString(); + this.factorySerialNumber = parcel.readString(); + this.packageQuantity = Utils.readInteger(parcel); + } + + public OnlineCodeCheck( + String cis, + @Nullable Boolean found, + @Nullable Boolean valid, + @Nullable String printView, + @Nullable String gtin, + @Nullable int[] groupIds, + @Nullable Boolean verified, + @Nullable Boolean realizable, + @Nullable Boolean utilized, + @Nullable Date expireDate, + @Nullable VariableExpirations variableExpirations, + @Nullable Date productionDate, + @Nullable Integer productWeight, + @Nullable String prVetDocument, + @Nullable Boolean isOwner, + @Nullable Boolean isBlocked, + @Nullable String[] ogvs, + @Nullable String message, + @Nullable Integer errorCode, + @Nullable Boolean isTracking, + @Nullable Boolean sold, + @Nullable Integer eliminationState, + @Nullable Integer mrp, + @Nullable Integer smp, + @Nullable Boolean grayZone, + @Nullable Integer innerUnitCount, + @Nullable Integer soldUnitCount, + @Nullable String packageType, + @Nullable String parent, + @Nullable String producerInn, + @Nullable String productionSerialNumber, + @Nullable String productionBatchNumber, + @Nullable String factorySerialNumber, + @Nullable Integer packageQuantity + ) { + super( + cis, + found, + valid, + printView, + gtin, + groupIds, + verified, + realizable, + utilized, + variableExpirations, + isBlocked, + ogvs, + sold, + mrp, + smp + ); + + this.expireDate = expireDate; + this.productionDate = productionDate; + this.productWeight = productWeight; + this.prVetDocument = prVetDocument; + this.isOwner = isOwner; + this.message = message; + this.errorCode = errorCode; + this.isTracking = isTracking; + this.eliminationState = eliminationState; + this.grayZone = grayZone; + this.innerUnitCount = innerUnitCount; + this.soldUnitCount = soldUnitCount; + this.packageType = packageType; + this.parent = parent; + this.producerInn = producerInn; + this.productionSerialNumber = productionSerialNumber; + this.productionBatchNumber = productionBatchNumber; + this.factorySerialNumber = factorySerialNumber; + this.packageQuantity = packageQuantity; + } + + @Nullable + public Boolean getGrayZone() { + return grayZone; + } + + @Nullable + public Boolean getOwner() { + return isOwner; + } + + @Nullable + public Boolean isTracking() { + return isTracking; + } + + @Nullable + public Date getExpireDate() { + return expireDate; + } + + @Nullable + public Date getProductionDate() { + return productionDate; + } + + @Nullable + public Integer getEliminationState() { + return eliminationState; + } + + @Nullable + public Integer getErrorCode() { + return errorCode; + } + + @Nullable + public Integer getInnerUnitCount() { + return innerUnitCount; + } + + @Nullable + public Integer getPackageQuantity() { + return packageQuantity; + } + + @Nullable + public Integer getProductWeight() { + return productWeight; + } + + @Nullable + public Integer getSoldUnitCount() { + return soldUnitCount; + } + + @Nullable + public String getFactorySerialNumber() { + return factorySerialNumber; + } + + @Nullable + public String getMessage() { + return message; + } + + @Nullable + public String getPackageType() { + return packageType; + } + + @Nullable + public String getParent() { + return parent; + } + + @Nullable + public String getProducerInn() { + return producerInn; + } + + @Nullable + public String getProductionBatchNumber() { + return productionBatchNumber; + } + + @Nullable + public String getProductionSerialNumber() { + return productionSerialNumber; + } + + @Nullable + public String getPrVetDocument() { + return prVetDocument; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + super.write(parcel, flags); + + parcel.writeInt(VERSION); + parcel.writeSerializable(expireDate); + parcel.writeSerializable(productionDate); + parcel.writeValue(productWeight); + parcel.writeString(prVetDocument); + parcel.writeValue(isOwner); + parcel.writeString(message); + parcel.writeValue(errorCode); + parcel.writeValue(isTracking); + parcel.writeValue(eliminationState); + parcel.writeValue(grayZone); + parcel.writeValue(innerUnitCount); + parcel.writeValue(soldUnitCount); + parcel.writeString(packageType); + parcel.writeString(parent); + parcel.writeString(producerInn); + parcel.writeString(productionSerialNumber); + parcel.writeString(productionBatchNumber); + parcel.writeString(factorySerialNumber); + parcel.writeValue(packageQuantity); + } + + @NonNull + @Override + public String toString() { + return super.toString() + "ExpireDate: " + Utils.toString(expireDate) + "\n" + + "ProductionDate: " + Utils.toString(productionDate) + "\n" + + "ProductWeight: " + Utils.toString(productWeight) + "\n" + + "PrVetDocument: " + Utils.toString(prVetDocument) + "\n" + + "IsOwner: " + Utils.toString(isOwner) + "\n" + + "Message: " + Utils.toString(message) + "\n" + + "ErrorCode: " + Utils.toString(errorCode) + "\n" + + "IsTracking: " + Utils.toString(isTracking) + "\n" + + "EliminationState: " + Utils.toString(eliminationState) + "\n" + + "IsGrayZone: " + Utils.toString(grayZone) + "\n" + + "InnerUnitCount: " + Utils.toString(innerUnitCount) + "\n" + + "SoldUnitCount: " + Utils.toString(soldUnitCount) + "\n" + + "PackageType: " + Utils.toString(packageType) + "\n" + + "Parent: " + Utils.toString(parent) + "\n" + + "ProducerInn: " + Utils.toString(producerInn) + "\n" + + "ProductionSerialNumber: " + Utils.toString(productionSerialNumber) + "\n" + + "ProductionBatchNumber: " + Utils.toString(productionBatchNumber) + "\n" + + "FactorySerialNumber: " + Utils.toString(factorySerialNumber) + "\n" + + "PackageQuantity: " + Utils.toString(packageQuantity) + "\n"; + } + + public final static Creator CREATOR = new Creator<>() { + @Override + public OnlineCodeCheck createFromParcel(Parcel parcel) { + return new OnlineCodeCheck(parcel); + } + + @Override + public OnlineCodeCheck[] newArray(int size) { + return new OnlineCodeCheck[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodesCheck.java b/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodesCheck.java new file mode 100644 index 0000000000..5edd7f159e --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/result/model/online/OnlineCodesCheck.java @@ -0,0 +1,87 @@ +package ru.evotor.tspiot.result.model.online; + +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import java.util.List; + +import ru.evotor.tspiot.Utils; +import ru.evotor.tspiot.result.model.base.BaseCodesCheck; + +public class OnlineCodesCheck extends BaseCodesCheck implements Parcelable { + + /** Версия OnlineCodesCheck */ + private final static int VERSION = 1; + + /** Текстовое описание результата выполнения метода */ + @Nullable + private final String description; + + /** Результат проверки марок*/ + private final List codes; + + private OnlineCodesCheck(Parcel parcel) { + super(parcel); + + int version = parcel.readInt(); + this.description = parcel.readString(); + this.codes = parcel.createTypedArrayList(OnlineCodeCheck.CREATOR); + } + + public OnlineCodesCheck( + int code, + @Nullable String description, + List codes, + String reqId, + long reqTimestamp + ) { + super(code, reqId, reqTimestamp); + + this.description = description; + this.codes = codes; + } + + @Nullable + public String getDescription() { return description; } + + public List getCodes() { return codes; } + + @Override + public int describeContents() { return 0; } + + @Override + public void writeToParcel(Parcel parcel, int flags) { + super.write(parcel, flags); + + parcel.writeInt(VERSION); + parcel.writeString(description); + parcel.writeTypedList(codes); + } + + @NonNull + @Override + public String toString() { + StringBuilder builder = new StringBuilder(super.toString()); + + builder.append("Description: ").append(Utils.toString(description)).append("\n"); + codes.forEach(onlineCodeCheck -> { + builder.append("OnlineCodeCheck: ").append(onlineCodeCheck).append("\n"); + }); + + return builder.toString(); + } + + public final static Creator CREATOR = new Creator<>() { + @Override + public OnlineCodesCheck createFromParcel(Parcel parcel) { + return new OnlineCodesCheck(parcel); + } + + @Override + public OnlineCodesCheck[] newArray(int size) { + return new OnlineCodesCheck[size]; + } + }; +} diff --git a/src/main/java/ru/evotor/tspiot/service/ITsPioTConnectionWrapper.java b/src/main/java/ru/evotor/tspiot/service/ITsPioTConnectionWrapper.java new file mode 100644 index 0000000000..95bdc90bb7 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/service/ITsPioTConnectionWrapper.java @@ -0,0 +1,7 @@ +package ru.evotor.tspiot.service; + +public interface ITsPioTConnectionWrapper { + void onTsPioTServiceConnected(ITsPioTServiceWrapper tsPioTService); + + void onTsPioTServiceDisconnected(); +} diff --git a/src/main/java/ru/evotor/tspiot/service/ITsPioTServiceWrapper.java b/src/main/java/ru/evotor/tspiot/service/ITsPioTServiceWrapper.java new file mode 100644 index 0000000000..58f8281f94 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/service/ITsPioTServiceWrapper.java @@ -0,0 +1,13 @@ +package ru.evotor.tspiot.service; + +import java.util.List; +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; +import ru.evotor.tspiot.model.MarkingCode; +import ru.evotor.tspiot.result.model.CodesCheckResult; +import ru.evotor.tspiot.result.model.KktInfo; + +public interface ITsPioTServiceWrapper { + KktInfo getKktInfo() throws TsPioTServiceException; + + CodesCheckResult getMarkedProductsInfo(List codes, String userUuid) throws TsPioTServiceException; +} diff --git a/src/main/java/ru/evotor/tspiot/service/TsPioTService.java b/src/main/java/ru/evotor/tspiot/service/TsPioTService.java new file mode 100644 index 0000000000..2a4ef59867 --- /dev/null +++ b/src/main/java/ru/evotor/tspiot/service/TsPioTService.java @@ -0,0 +1,177 @@ +package ru.evotor.tspiot.service; + +import android.app.Service; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.IBinder; +import android.os.Parcelable; +import android.os.RemoteException; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import ru.evotor.tspiot.ITsPioTService; +import ru.evotor.tspiot.TsPioTServiceConnector; +import ru.evotor.tspiot.exceptions.NullContextException; +import ru.evotor.tspiot.exceptions.ServiceAlreadyConnectedException; +import ru.evotor.tspiot.exceptions.TsPioTErrorHolderException; +import ru.evotor.tspiot.exceptions.TsPioTServiceOperationOnMainThreadException; +import ru.evotor.tspiot.exceptions.base.TsPioTServiceException; +import ru.evotor.tspiot.exceptions.UnknownException; +import ru.evotor.tspiot.model.MarkingCode; +import ru.evotor.tspiot.result.model.CodesCheckResult; +import ru.evotor.tspiot.result.model.KktInfo; +import ru.evotor.tspiot.result.TsPioTError; +import ru.evotor.tspiot.result.TsPioTResult; + +public class TsPioTService implements ITsPioTServiceWrapper { + + public static final String UNKNOWN_EXCEPTION_TEXT = "Request to TsPioTService failed"; + + private Context context; + + private final ExecutorService executor = Executors.newSingleThreadExecutor(); + + private ITsPioTService service; + + private volatile boolean serviceConnected = false; + + private final ServiceConnection serviceConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName componentName, IBinder iBinder) { + service = ITsPioTService.Stub.asInterface(iBinder); + serviceConnected = true; + + for(ITsPioTConnectionWrapper connectionWrapper : TsPioTServiceConnector.getConnectionWrappers()) { + connectionWrapper.onTsPioTServiceConnected(TsPioTService.this); + } + } + + @Override + public void onServiceDisconnected(ComponentName componentName) { + service = null; + serviceConnected = false; + context = null; + + for(ITsPioTConnectionWrapper connectionWrapper : TsPioTServiceConnector.getConnectionWrappers()) { + connectionWrapper.onTsPioTServiceDisconnected(); + } + } + }; + + public TsPioTService() { } + + public synchronized void connectService(Context userContext, boolean force) throws ServiceAlreadyConnectedException, NullContextException { + if (!force && service != null) { + throw new ServiceAlreadyConnectedException(); + } + + if (userContext == null) { + throw new NullContextException(); + } + + executor.execute(() -> { + context = userContext; + Intent pr = new Intent(TsPioTServiceConnector.ACTION_TSPIOT_SERVICE); + pr.setPackage(TsPioTServiceConnector.TARGET_PACKAGE); + pr.setClassName(TsPioTServiceConnector.TARGET_PACKAGE, TsPioTServiceConnector.TARGET_CLASS_NAME); + serviceConnected = false; + + boolean serviceBound = context.bindService(pr, serviceConnection, Service.BIND_AUTO_CREATE); + if (!serviceBound) { + serviceConnected = false; + } + }); + } + + public synchronized void reconnectService() throws NullContextException { + if (context == null) { + throw new NullContextException(); + } + + try { + connectService(context, true); + } catch (ServiceAlreadyConnectedException ignored) { } + } + + public synchronized void disconnectService() throws NullContextException { + if (context == null) { + throw new NullContextException(); + } + + executor.execute(() -> { + context.unbindService(serviceConnection); + service = null; + serviceConnected = false; + context = null; + + for(ITsPioTConnectionWrapper connectionWrapper : TsPioTServiceConnector.getConnectionWrappers()) { + connectionWrapper.onTsPioTServiceDisconnected(); + } + }); + } + + public boolean getServiceConnected() { return serviceConnected; } + + /** Метод для получения информации о драйвере ТС ПИоТ */ + @SuppressWarnings("rawtypes") + @Override + public KktInfo getKktInfo() throws TsPioTServiceException { + TsPioTServiceOperationOnMainThreadException.throwIfMainThread(); + + try { + TsPioTResult result = service.getKktInfo(); + Parcelable data = result.getData(); + + if (data != null) { + return (KktInfo) data; + } else { + TsPioTError error = result.getError(); + + if (error != null) { + throw new TsPioTErrorHolderException(error.getError()); + } else { + throw new UnknownException(UNKNOWN_EXCEPTION_TEXT); + } + } + } catch (RemoteException | RuntimeException ex) { + TsPioTServiceConnector.processException(ex); + throw new UnknownException(UNKNOWN_EXCEPTION_TEXT); + } + } + + /** Метод проверки марок */ + @SuppressWarnings("rawtypes") + @Override + public CodesCheckResult getMarkedProductsInfo( + @NonNull List codes, + @Nullable String userUuid + ) throws TsPioTServiceException { + TsPioTServiceOperationOnMainThreadException.throwIfMainThread(); + + try { + TsPioTResult result = service.getMarkedProductsInfo(codes, userUuid); + Parcelable data = result.getData(); + + if (data != null) { + return (CodesCheckResult) data; + } else { + TsPioTError error = result.getError(); + + if (error != null) { + throw new TsPioTErrorHolderException(error.getError()); + } else { + throw new UnknownException(UNKNOWN_EXCEPTION_TEXT); + } + } + } catch (RemoteException | RuntimeException ex) { + TsPioTServiceConnector.processException(ex); + throw new UnknownException(UNKNOWN_EXCEPTION_TEXT); + } + } +}