diff --git a/src/main/java/ru/evotor/framework/core/action/datamapper/PositionMapper.java b/src/main/java/ru/evotor/framework/core/action/datamapper/PositionMapper.java index 2c69c7252..8a1b6e383 100644 --- a/src/main/java/ru/evotor/framework/core/action/datamapper/PositionMapper.java +++ b/src/main/java/ru/evotor/framework/core/action/datamapper/PositionMapper.java @@ -26,6 +26,7 @@ import ru.evotor.framework.receipt.position.PartialRealization; import ru.evotor.framework.receipt.position.PreferentialMedicine; import ru.evotor.framework.receipt.position.SettlementMethod; +import ru.evotor.framework.receipt.position.VolumeSortAccountingRealization; public final class PositionMapper { @@ -87,6 +88,8 @@ public final class PositionMapper { private static final String KEY_PARTIAL_REALIZATION = "partialRealization"; + private static final String KEY_VOLUME_SORT_ACCOUNTING_REALIZATION = "volumeSortAccountingRealization"; + @Nullable public static Position from(@Nullable Bundle bundle) { if (bundle == null) { @@ -148,6 +151,9 @@ public static Position from(@Nullable Bundle bundle) { PartialRealization partialRealization = PartialRealization.from(bundle.getBundle(KEY_PARTIAL_REALIZATION)); + VolumeSortAccountingRealization volumeSortAccountingRealization = + VolumeSortAccountingRealization.from(bundle.getBundle(KEY_VOLUME_SORT_ACCOUNTING_REALIZATION)); + if (quantity == null || price == null || priceWithDiscountPosition == null @@ -188,6 +194,7 @@ public static Position from(@Nullable Bundle bundle) { builder.setPreferentialMedicine(preferentialMedicine); builder.setClassificationCode(classificationCode); builder.setPartialRealization(partialRealization); + builder.setVolumeSortAccountingRealization(volumeSortAccountingRealization); return builder.build(); } @@ -268,6 +275,12 @@ public static Bundle toBundle(@Nullable Position position) { final PartialRealization partialRealization = position.getPartialRealization(); bundle.putBundle(KEY_PARTIAL_REALIZATION, partialRealization != null ? partialRealization.toBundle() : null); + final VolumeSortAccountingRealization volumeSortAccountingRealization = position.getVolumeSortAccountingRealization(); + bundle.putBundle( + KEY_VOLUME_SORT_ACCOUNTING_REALIZATION, + volumeSortAccountingRealization != null ? volumeSortAccountingRealization.toBundle() : null + ); + return bundle; } diff --git a/src/main/java/ru/evotor/framework/kkt/FiscalTags.kt b/src/main/java/ru/evotor/framework/kkt/FiscalTags.kt index d4d481021..09e43589b 100644 --- a/src/main/java/ru/evotor/framework/kkt/FiscalTags.kt +++ b/src/main/java/ru/evotor/framework/kkt/FiscalTags.kt @@ -192,4 +192,14 @@ object FiscalTags { */ const val MEASURE_CODE = 2108 + /** + * дополнительный реквизит предмета расчета + */ + const val ADDITIONAL_REQUISITE_OF_SUBJECT_OF_CALCULATION = 1191 + + /** + * выбытие по ОСУ + */ + const val VOLUME_SORT_ACCOUNTING_REALIZATION = ADDITIONAL_REQUISITE_OF_SUBJECT_OF_CALCULATION + } diff --git a/src/main/java/ru/evotor/framework/receipt/Position.java b/src/main/java/ru/evotor/framework/receipt/Position.java index 80f54c332..890107334 100644 --- a/src/main/java/ru/evotor/framework/receipt/Position.java +++ b/src/main/java/ru/evotor/framework/receipt/Position.java @@ -31,6 +31,7 @@ import ru.evotor.framework.receipt.position.PartialRealization; import ru.evotor.framework.receipt.position.PreferentialMedicine; import ru.evotor.framework.receipt.position.SettlementMethod; +import ru.evotor.framework.receipt.position.VolumeSortAccountingRealization; /** * Позиция чека. @@ -39,7 +40,7 @@ public class Position implements Parcelable { /** * Текущая версия объекта Position */ - private static final int VERSION = 9; + private static final int VERSION = 10; /** * Магическое число для идентификации использования версионирования объекта. */ @@ -193,6 +194,18 @@ public class Position implements Parcelable { @Nullable private PartialRealization partialRealization; + /** + * Выбытие по объемно-сортовому учету(ОСУ) 1191 + *

+ * Доступно только для следующих типов товара: + * - молочная продукция {@link ProductType#DAIRY_MARKED} + * - вода {@link ProductType#WATER_MARKED} + *

+ */ + @FiscalRequisite(tag = FiscalTags.VOLUME_SORT_ACCOUNTING_REALIZATION) + @Nullable + private VolumeSortAccountingRealization volumeSortAccountingRealization; + public Position( String uuid, @Nullable String productUuid, @@ -261,6 +274,7 @@ public Position(Position position) { this.classificationCode = position.getClassificationCode(); this.preferentialMedicine = position.getPreferentialMedicine(); this.partialRealization = position.getPartialRealization(); + this.volumeSortAccountingRealization = position.getVolumeSortAccountingRealization(); } /** @@ -540,6 +554,15 @@ public PartialRealization getPartialRealization() { return partialRealization; } + /** + * @return Выбытие по объемно-сортовому учету(ОСУ) 1191 + */ + @FiscalRequisite(tag = FiscalTags.VOLUME_SORT_ACCOUNTING_REALIZATION) + @Nullable + public VolumeSortAccountingRealization getVolumeSortAccountingRealization() { + return volumeSortAccountingRealization; + } + @Override public boolean equals(Object o) { return equals(o, false); @@ -601,6 +624,8 @@ private boolean equals(Object o, boolean exceptQuantity) { return false; if (!Objects.equals(partialRealization, position.partialRealization)) return false; + if (!Objects.equals(volumeSortAccountingRealization, position.volumeSortAccountingRealization)) + return false; return Objects.equals(subPositions, position.subPositions); } @@ -632,6 +657,7 @@ public int hashCode() { result = 31 * result + (classificationCode != null ? classificationCode.hashCode() : 0); result = 31 * result + (preferentialMedicine != null ? preferentialMedicine.hashCode() : 0); result = 31 * result + (partialRealization != null ? partialRealization.hashCode() : 0); + result = 31 * result + (volumeSortAccountingRealization != null ? volumeSortAccountingRealization.hashCode() : 0); return result; } @@ -663,6 +689,7 @@ public String toString() { ", classificationCode=" + classificationCode + ", preferentialMedicine=" + preferentialMedicine + ", partial=" + partialRealization + + ", volumeSortAccountingRealization=" + volumeSortAccountingRealization + '}'; } @@ -750,6 +777,8 @@ private void writeAdditionalFields(Parcel dest, int flags) { // Partial realization dest.writeBundle(this.partialRealization != null ? this.partialRealization.toBundle() : null); dest.writeInt(this.measure.getCode()); + // Volume Sort Accounting Realization + dest.writeBundle(this.volumeSortAccountingRealization != null ? this.volumeSortAccountingRealization.toBundle() : null); } protected Position(Parcel in) { @@ -836,6 +865,9 @@ private void readAdditionalFields(Parcel in, String measureName, int measurePrec if (version >= 9) { measureCode = in.readInt(); } + if (version >= 10) { + readVolumeSortAccountingRealization(in); + } this.measure = new Measure( measureName, measurePrecision, @@ -887,6 +919,12 @@ private void readPartialRealization(Parcel in) { this.partialRealization = PartialRealization.Companion.from(in.readBundle(PartialRealization.class.getClassLoader())); } + private void readVolumeSortAccountingRealization(Parcel in) { + this.volumeSortAccountingRealization = VolumeSortAccountingRealization.Companion.from( + in.readBundle(VolumeSortAccountingRealization.class.getClassLoader()) + ); + } + public static final Creator CREATOR = new Creator() { @Override public Position createFromParcel(Parcel source) { @@ -1416,6 +1454,17 @@ public Builder toPartialRealization( return this; } + public Builder toVolumeSortAccountingRealization( + @NonNull BigDecimal volumeSortQuantity, + @NonNull String gtin + ) { + position.volumeSortAccountingRealization = new VolumeSortAccountingRealization( + gtin, + volumeSortQuantity + ); + return this; + } + private void setAlcoParams( Mark mark, BigDecimal alcoholByVolume, @@ -1589,6 +1638,22 @@ public Builder setPartialRealization(@Nullable PartialRealization partialRealiza return this; } + /** + * Реализация по ОСУ для позиции доступна только если тип товара является одним из: + *

+ * вода {@link ProductType#WATER_MARKED} + * молочная продукция {@link ProductType#DAIRY_MARKED} + * не может использоваться совместно с setPartialRealization + * + * @param volumeSortAccountingRealization реализация по ОСУ + */ + public Builder setVolumeSortAccountingRealization( + @Nullable VolumeSortAccountingRealization volumeSortAccountingRealization + ) { + position.volumeSortAccountingRealization = volumeSortAccountingRealization; + return this; + } + public Position build() { return new Position(position); } diff --git a/src/main/java/ru/evotor/framework/receipt/PositionTable.kt b/src/main/java/ru/evotor/framework/receipt/PositionTable.kt index 1dc41f6a3..8e73fc1b9 100644 --- a/src/main/java/ru/evotor/framework/receipt/PositionTable.kt +++ b/src/main/java/ru/evotor/framework/receipt/PositionTable.kt @@ -36,6 +36,8 @@ object PositionTable { const val COLUMN_IMPORTATION_DATA_COUNTRY_ORIGIN_CODE = "IMPORTATION_DATA_COUNTRY_ORIGIN_CODE" const val COLUMN_IMPORTATION_DATA_CUSTOMS_DECLARATION_NUMBER = "IMPORTATION_DATA_CUSTOMS_DECLARATION_NUMBER" const val COLUMN_PARTIAL_QUANTITY_IN_PACKAGE = "PARTIAL_REALIZATION_QUANTITY_IN_PACKAGE" + const val COLUMN_VOLUME_SORT_ACCOUNTING_QUANTITY = "VOLUME_SORT_ACCOUNTING_QUANTITY" + const val COLUMN_VOLUME_SORT_ACCOUNTING_GTIN = "VOLUME_SORT_ACCOUNTING_GTIN" object ExtraKeyJSONKeys { const val KEY_IDENTITY = "identity" diff --git a/src/main/java/ru/evotor/framework/receipt/ReceiptApi.kt b/src/main/java/ru/evotor/framework/receipt/ReceiptApi.kt index 10b8b1fd4..0855e80cb 100644 --- a/src/main/java/ru/evotor/framework/receipt/ReceiptApi.kt +++ b/src/main/java/ru/evotor/framework/receipt/ReceiptApi.kt @@ -19,15 +19,10 @@ import ru.evotor.framework.receipt.mapper.FiscalReceiptMapper import ru.evotor.framework.receipt.position.ImportationData import ru.evotor.framework.receipt.position.Mark import ru.evotor.framework.receipt.position.PreferentialMedicine -import ru.evotor.framework.receipt.position.mapper.AgentRequisitesMapper -import ru.evotor.framework.receipt.position.mapper.PositionPartialRealizationMapper -import ru.evotor.framework.receipt.position.mapper.PreferentialMedicineMapper -import ru.evotor.framework.receipt.position.mapper.SettlementMethodMapper +import ru.evotor.framework.receipt.position.mapper.* import ru.evotor.framework.receipt.provider.FiscalReceiptContract import java.math.BigDecimal import java.util.* -import kotlin.collections.ArrayList -import kotlin.collections.HashMap @WorkerThread object ReceiptApi { @@ -450,6 +445,7 @@ object ReceiptApi { .setImportationData(importationData) .setExcise(excise) .setPartialRealization(PositionPartialRealizationMapper.fromCursor(cursor)) + .setVolumeSortAccountingRealization(VolumeSortAccountingRealizationMapper.fromCursor(cursor)) return builder.build() } diff --git a/src/main/java/ru/evotor/framework/receipt/position/VolumeSortAccountingRealization.kt b/src/main/java/ru/evotor/framework/receipt/position/VolumeSortAccountingRealization.kt new file mode 100644 index 000000000..e1f883ad3 --- /dev/null +++ b/src/main/java/ru/evotor/framework/receipt/position/VolumeSortAccountingRealization.kt @@ -0,0 +1,38 @@ +package ru.evotor.framework.receipt.position + +import android.os.Bundle +import ru.evotor.IBundlable +import ru.evotor.framework.optBigDecimal +import java.math.BigDecimal + + +data class VolumeSortAccountingRealization ( + /** + * Идентификатор продукта GTIN + */ + val gtin: String, + /** + * Количество товара по ОСУ + */ + val volumeSortQuantity: BigDecimal +) : IBundlable { + + override fun toBundle() = Bundle().apply { + putString(KEY_VOLUME_SORT_QUANTITY, volumeSortQuantity.toPlainString()) + putString(KEY_GTIN, gtin) + } + + companion object { + + private const val KEY_VOLUME_SORT_QUANTITY = "VolumeSortQuantity" + private const val KEY_GTIN = "GTIN" + + @JvmStatic + fun from(bundle: Bundle?): VolumeSortAccountingRealization? = bundle?.let { + val volumeSortQuantity = it.optBigDecimal(KEY_VOLUME_SORT_QUANTITY) ?: return null + val gtin = it.getString(KEY_GTIN) ?: return null + + VolumeSortAccountingRealization(volumeSortQuantity = volumeSortQuantity, gtin = gtin) + } + } +} diff --git a/src/main/java/ru/evotor/framework/receipt/position/mapper/VolumeSortAccountingRealizationMapper.kt b/src/main/java/ru/evotor/framework/receipt/position/mapper/VolumeSortAccountingRealizationMapper.kt new file mode 100644 index 000000000..13416633e --- /dev/null +++ b/src/main/java/ru/evotor/framework/receipt/position/mapper/VolumeSortAccountingRealizationMapper.kt @@ -0,0 +1,21 @@ +package ru.evotor.framework.receipt.position.mapper + +import android.database.Cursor +import ru.evotor.framework.optQuantity +import ru.evotor.framework.optString +import ru.evotor.framework.receipt.PositionTable +import ru.evotor.framework.receipt.position.VolumeSortAccountingRealization + +internal object VolumeSortAccountingRealizationMapper { + + internal fun fromCursor(cursor: Cursor): VolumeSortAccountingRealization? { + val volumeSortQuantity = cursor.optQuantity(PositionTable.COLUMN_VOLUME_SORT_ACCOUNTING_QUANTITY) + ?: return null + val gtin = cursor.optString(PositionTable.COLUMN_VOLUME_SORT_ACCOUNTING_GTIN) + ?: return null + return VolumeSortAccountingRealization( + volumeSortQuantity = volumeSortQuantity, + gtin = gtin + ) + } +}