diff --git a/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmount.java b/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmount.java
index 714bbbebab..897c4e21a3 100644
--- a/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmount.java
+++ b/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmount.java
@@ -23,6 +23,10 @@
import java.math.BigDecimal;
import java.util.Objects;
+/**
+ * @deprecated Use {@link org.jpos.cmf.CMFAdditionalAmount}
+ */
+@Deprecated
@SuppressWarnings("WeakerAccess")
public class AdditionalAmount {
@@ -111,16 +115,12 @@ public String serialize() {
long absAmt= getAmount().movePointRight(getCurrencyMinorUnit()).abs().longValue();
- @SuppressWarnings("StringBufferReplaceableByString")
- StringBuilder sb = new StringBuilder();
- sb.append(getAccountType());
- sb.append(getAmountType().toString());
- sb.append(getCurrencyCode());
- sb.append(getCurrencyMinorUnit());
- sb.append(getAmount().compareTo(BigDecimal.ZERO) >= 0 ? "C" : "D");
- sb.append(StringUtils.leftPad(Long.toString(absAmt), 12, '0'));
-
- return sb.toString();
+ return getAccountType() +
+ getAmountType().toString() +
+ getCurrencyCode() +
+ getCurrencyMinorUnit() +
+ (getAmount().compareTo(BigDecimal.ZERO) >= 0 ? "C" : "D") +
+ StringUtils.leftPad(Long.toString(absAmt), 12, '0');
}
@Override
diff --git a/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmountsWrapper.java b/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmountsWrapper.java
index 213121ecba..22dc19b43a 100644
--- a/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmountsWrapper.java
+++ b/modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmountsWrapper.java
@@ -27,7 +27,10 @@
/**
* Handles additional amounts field content - DE-054
+ *
+ * @deprecated Use {@link org.jpos.iso.AdditionalAmountsWrapper}
*/
+@Deprecated
public final class AdditionalAmountsWrapper extends LinkedHashSet {
private static final long serialVersionUID = 2526355280704001241L;
diff --git a/modules/cmf/src/main/java/org/jpos/cmf/AmountType.java b/modules/cmf/src/main/java/org/jpos/cmf/AmountType.java
index b796acc319..adfec3140e 100644
--- a/modules/cmf/src/main/java/org/jpos/cmf/AmountType.java
+++ b/modules/cmf/src/main/java/org/jpos/cmf/AmountType.java
@@ -1,6 +1,6 @@
/*
* jPOS Project [http://jpos.org]
- * Copyright (C) 2000-2021 jPOS Software SRL
+ * Copyright (C) 2000-2023 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,18 +18,21 @@
package org.jpos.cmf;
+import org.jpos.iso.AdditionalAmountType;
+import org.jpos.iso.AdditionalAmountTypeConverter;
+
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
/**
* See jPOS-CMF.pdf DE-054
- * Some extra entries are based on ISO-8583:2003
+ * Some extra entries are based on ISO-8583:2003 and other common specs.
*/
-public enum AmountType {
+public enum AmountType implements AdditionalAmountType {
ISO_RESERVED("00"),
- // Account related balances
+ // 0x..1x - Account related balances
ACCOUNT_LEDGER_CURRENT_BALANCE("01"),
ACCOUNT_AVAILABLE_BALANCE("02"),
AMOUNT_OWING("03"),
@@ -40,6 +43,7 @@ public enum AmountType {
DESTINATION_ACCOUNT_AVAILABLE_BALANCE("08"),
CREDIT_LINE("09"),
AMOUNT_ON_HOLD("10"),
+ PREPAID_ONLINE_BILL_FEE("17"), // Mastercard
// 2x - Card related amounts
AMOUNT_REMAINING_THIS_CYCLE("20"),
@@ -48,17 +52,32 @@ public enum AmountType {
AMOUNT_CASH("40"),
AMOUNT_GOODS_AND_SERVICES("41"),
AMOUNT_SURCHARGE("42"),
+ TOTAL_CUMULATIVE_AMOUNT("43"), // Visa: total cumulative, for series of incremental transactions
+ AMOUNT_PRE_CURRENCY_CONVERSION("45"), // Visa
// 5x - Electronic benefit amounts
BEGINNING_BALANCE("50"),
PRE_AUTH_AMOUNT("51"),
+ CLIENT_PROVIDED_FEES("56"), // Visa
+
+ // Visa, Mastercard, others, usually used for partials.
+ // Left as reference/placeholder/pragmatism here, but in jPOS-CMF is more appropriate to use DE-030
+ ORIGINAL_AMOUNT("57"),
- // custom CMF
+ // other custom mappings
GRATUITY("80"),
AMOUNT_TAXABLE("81"),
+ TRANSIT_AMOUNT("4T"), // Visa
+ // HEALTHCARE USA
+ HEALTHCARE_AMOUNT_COPAYMENT("3S"), // Visa
+ HEALTHCARE_AMOUNT_ELIGIBILITY("4S"), // Mastercard: 10
+ HEALTHCARE_AMOUNT_PRESCRIPTION("4U"), // Mastercard: 11
+ HEALTHCARE_AMOUNT_VISION("4V"), // Mastercard: 12
+ HEALTHCARE_AMOUNT_CLINIC("4W"), // Visa: clinic/other qualified medical
+ HEALTHCARE_AMOUNT_DENTAL("4X"), // Visa
- // PRIVATE RESERVED
+ // OTHER PRIVATE RESERVED (may be repurposed/renamed in the future)
PRIVATE_RESERVED_1S("1S"),
PRIVATE_RESERVED_1T("1T"),
PRIVATE_RESERVED_1U("1U"),
@@ -77,7 +96,6 @@ public enum AmountType {
PRIVATE_RESERVED_2Y("2Y"),
PRIVATE_RESERVED_2Z("2Z"),
- PRIVATE_RESERVED_3S("3S"),
PRIVATE_RESERVED_3T("3T"),
PRIVATE_RESERVED_3U("3U"),
PRIVATE_RESERVED_3V("3V"),
@@ -86,12 +104,6 @@ public enum AmountType {
PRIVATE_RESERVED_3Y("3Y"),
PRIVATE_RESERVED_3Z("3Z"),
- PRIVATE_RESERVED_4S("4S"),
- PRIVATE_RESERVED_4T("4T"),
- PRIVATE_RESERVED_4U("4U"),
- PRIVATE_RESERVED_4V("4V"),
- PRIVATE_RESERVED_4W("4W"),
- PRIVATE_RESERVED_4X("4X"),
PRIVATE_RESERVED_4Y("4Y"),
PRIVATE_RESERVED_4Z("4Z"),
@@ -118,18 +130,40 @@ public enum AmountType {
this.code = code;
}
+ public String getCode() {
+ return code;
+ }
+
+ /** shorter alias for getCode, in the style of enum name(), required by {@link AdditionalAmountType} */
@Override
- public String toString() {
+ public String code() {
return code;
}
- public String getCode() {
+
+ @Override
+ public String toString() {
return code;
}
public static AmountType fromCode(String code) {
Objects.requireNonNull(code);
- AmountType ret = byCode.get(code.toUpperCase());
- if (ret == null) throw new IllegalArgumentException("Invalid amount type: " + code);
- return ret;
+ return byCode.get(code.toUpperCase());
}
+
+
+ // ----- inner converter (dummy, since this is from CMF to CMF, but left here as reference implementation)
+
+ public static AdditionalAmountTypeConverter CONVERTER = new AdditionalAmountTypeConverter() {
+ public String toCMF(String code) {
+ Objects.requireNonNull(code);
+ AmountType t = byCode.get(code.toUpperCase());
+ return t != null ? t.code() : null;
+ }
+
+ public String fromCMF(String cmfCode) {
+ Objects.requireNonNull(cmfCode);
+ AmountType t = byCode.get(cmfCode.toUpperCase());
+ return t != null ? t.code() : null;
+ }
+ };
}
diff --git a/modules/cmf/src/main/java/org/jpos/cmf/CMFAdditionalAmount.java b/modules/cmf/src/main/java/org/jpos/cmf/CMFAdditionalAmount.java
new file mode 100644
index 0000000000..1f2c76edd2
--- /dev/null
+++ b/modules/cmf/src/main/java/org/jpos/cmf/CMFAdditionalAmount.java
@@ -0,0 +1,83 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2023 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.cmf;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jpos.iso.AdditionalAmount;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+
+/**
+ * Represents one occurrence of an Additional Amount (from DE-54) in jPOS-CMF format.
+ */
+public class CMFAdditionalAmount extends AdditionalAmount {
+
+ public final static int SERIALIZED_DATA_LENGTH = 21;
+
+ public CMFAdditionalAmount() {
+ }
+
+ public CMFAdditionalAmount(String accountType, BigDecimal amount, String currencyCode,
+ String amountType, int currencyMinorUnit) {
+ super(accountType, amount, currencyCode, amountType, currencyMinorUnit);
+ }
+
+ @Override
+ public String serialize() {
+ if (getAmountTypeCode() == null)
+ throw new IllegalStateException("Amount type not set");
+
+ if (getAmount() == null)
+ throw new IllegalStateException("Amount not set");
+
+ long absAmt= getAmount().movePointRight(getCurrencyMinorUnit()).abs().longValue();
+
+ return getAccountType() +
+ getAmountTypeCode() +
+ getCurrencyCode() +
+ getCurrencyMinorUnit() +
+ (getAmount().compareTo(BigDecimal.ZERO) >= 0 ? "C" : "D") +
+ StringUtils.leftPad(Long.toString(absAmt), 12, '0');
+ }
+
+ public static AdditionalAmount parse(String data) {
+ Objects.requireNonNull(data);
+
+ if (data.length() != SERIALIZED_DATA_LENGTH)
+ throw new IllegalArgumentException("Invalid data length");
+
+ String accountType = StringUtils.mid(data, 0, 2);
+ String amountType = StringUtils.mid(data, 2, 2);
+ String currencyCode = StringUtils.mid(data, 4, 3);
+ int minorUnit = Integer.parseInt(StringUtils.mid(data, 7, 1));
+
+ String amountSign = StringUtils.mid(data, 8, 1);
+ BigDecimal amount = new BigDecimal(StringUtils.right(data, 12)).movePointLeft(minorUnit);
+
+ if (!"C.D".contains(amountSign))
+ throw new IllegalArgumentException("Invalid amount sign");
+
+ if ("D".equalsIgnoreCase(amountSign))
+ amount = amount.negate();
+
+ return new CMFAdditionalAmount(accountType, amount, currencyCode, amountType, minorUnit);
+ }
+
+}
diff --git a/modules/cmf/src/main/java/org/jpos/cmf/CMFAmount.java b/modules/cmf/src/main/java/org/jpos/cmf/CMFAmount.java
index af6122dc52..5aa852238d 100644
--- a/modules/cmf/src/main/java/org/jpos/cmf/CMFAmount.java
+++ b/modules/cmf/src/main/java/org/jpos/cmf/CMFAmount.java
@@ -1,6 +1,6 @@
/*
* jPOS Project [http://jpos.org]
- * Copyright (C) 2000-2021 jPOS Software SRL
+ * Copyright (C) 2000-2023 jPOS Software SRL
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
@@ -18,7 +18,6 @@
package org.jpos.cmf;
-import org.apache.commons.lang3.BitField;
import org.jpos.iso.ISOCurrency;
import org.jpos.iso.ISOException;
import org.jpos.iso.ISOUtil;
@@ -41,7 +40,7 @@
* {@link #serialize(boolean, int)}, that the lengths are in accordance and what you need.
*
* NOTE:This class does not handle additional amounts (DE-054).
- * For that, use {@link AdditionalAmount} and {@link AdditionalAmountsWrapper}.
+ * For that, use {@link org.jpos.iso.AdditionalAmount} and {@link org.jpos.iso.AdditionalAmountsWrapper}.
*
*
*/
diff --git a/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmount.java b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmount.java
new file mode 100644
index 0000000000..4de02f77c0
--- /dev/null
+++ b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmount.java
@@ -0,0 +1,92 @@
+package org.jpos.iso;
+
+import java.math.BigDecimal;
+import java.util.Objects;
+
+public abstract class AdditionalAmount {
+ private String accountType;
+ private String amountType;
+ private BigDecimal amount;
+ private String currencyCode;
+ private int currencyMinorUnit;
+
+ public AdditionalAmount() {
+ }
+
+ protected AdditionalAmount(String accountType, BigDecimal amount, String currencyCode,
+ String amountType, int currencyMinorUnit) {
+
+ setAccountType(accountType);
+ setAmount(amount);
+ setCurrencyCode(currencyCode);
+ setAmountTypeCode(amountType);
+ setCurrencyMinorUnit(currencyMinorUnit);
+ }
+
+ public abstract String serialize();
+
+ public String getAccountType() {
+ return accountType;
+ }
+
+ public void setAccountType(String accountType) {
+ Objects.requireNonNull(accountType);
+
+ if (accountType.length() != 2)
+ throw new IllegalArgumentException("Invalid account type length");
+
+ this.accountType = accountType;
+ }
+
+ /**
+ * @return The internal amount type 2-char string
+ */
+ public String getAmountTypeCode() {
+ return amountType;
+ }
+
+ public void setAmountTypeCode(String amountType) {
+ Objects.requireNonNull(amountType);
+ this.amountType = amountType;
+ }
+
+ public BigDecimal getAmount() {
+ return amount;
+ }
+
+ public void setAmount(BigDecimal amount) {
+ Objects.requireNonNull(amount);
+ this.amount = amount;
+ }
+
+ public String getCurrencyCode() {
+ return currencyCode;
+ }
+
+ public void setCurrencyCode(String currencyCode) {
+ Objects.requireNonNull(currencyCode);
+
+ if (currencyCode.length() != 3)
+ throw new IllegalArgumentException("Invalid currency code");
+
+ this.currencyCode = currencyCode;
+ }
+
+ public int getCurrencyMinorUnit() {
+ return currencyMinorUnit;
+ }
+
+ public void setCurrencyMinorUnit(int currencyMinorUnit) {
+ if (currencyMinorUnit < 0 || currencyMinorUnit > 9)
+ throw new IllegalArgumentException("Invalid currency minor unit value");
+
+ this.currencyMinorUnit = currencyMinorUnit;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() +
+ String.format (" {%s,%s,%s,%d,%s}", accountType, amountType, currencyCode, currencyMinorUnit, amount);
+ }
+
+}
diff --git a/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountType.java b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountType.java
new file mode 100644
index 0000000000..5a1b00343f
--- /dev/null
+++ b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountType.java
@@ -0,0 +1,24 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2023 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.iso;
+
+public interface AdditionalAmountType {
+ String code();
+ String name();
+}
diff --git a/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountTypeConverter.java b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountTypeConverter.java
new file mode 100644
index 0000000000..4310820436
--- /dev/null
+++ b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountTypeConverter.java
@@ -0,0 +1,33 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2023 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.iso;
+
+public interface AdditionalAmountTypeConverter {
+ /**
+ * Convert from an Additional Amount Type 2-digit code in an 8583 spec into the equivalent jPOS-CMF spec.
+ * @return may return null if this code is not mapped by CMF.
+ */
+ String toCMF(String code);
+
+ /**
+ * Convert from an Additional Amount Type 2-digit code in an jPOS-CMF into the equivalent of another 8583 spec.
+ * @return may return null if the CMF code is not mapped by the external 8583 spec.
+ */
+ String fromCMF(String cmfCode);
+}
diff --git a/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountsWrapper.java b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountsWrapper.java
new file mode 100644
index 0000000000..28b228bfff
--- /dev/null
+++ b/modules/cmf/src/main/java/org/jpos/iso/AdditionalAmountsWrapper.java
@@ -0,0 +1,138 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2023 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.iso;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Predicate;
+
+/**
+ * Handles additional amounts field content (DE-054 in most 8583 specs)
+ */
+public class AdditionalAmountsWrapper extends LinkedHashSet {
+
+ private static final long serialVersionUID = 2526355280704001242L;
+
+ /**
+ * Parses a full string of Additional Amount occurrences (usually DE-054) using a helper
+ * parser and the given length for each occurrence.
+ * @param data a String of one or more occurrences of Additional Amount
+ * @param amtLength the length of each occurrence
+ * @param parser a function that receives a single occurrence String, and returns an {@link AdditionalAmount} instance
+ * @return an instance of this class that wraps all the occurrences
+ */
+ public static AdditionalAmountsWrapper parse(
+ String data,
+ final int amtLength,
+ Function parser)
+ {
+ if (data.length() % amtLength != 0)
+ throw new IllegalArgumentException("Invalid length");
+
+ AdditionalAmountsWrapper amounts = new AdditionalAmountsWrapper();
+
+ for (int i = 0; i < data.length(); i += amtLength) {
+ AdditionalAmount amount = parser.apply(StringUtils.mid(data, i, amtLength));
+ amounts.add(amount);
+ }
+
+ return amounts;
+ }
+
+ public String serialize() {
+ StringBuilder sb = new StringBuilder();
+ forEach(amount -> sb.append(amount.serialize()));
+ return sb.toString();
+ }
+
+ public AdditionalAmount getAny(Predicate p) {
+ for (AdditionalAmount addAmnt : this) {
+ if (p.test(addAmnt))
+ return addAmnt;
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of the additional amounts that match the filter criteria.
+ *
+ * If one of the filters is null, it's not considered in the criteria.
+ *
+ * @param accountType the account type to filter amounts by.
+ * @param amountType the amount type to filter amounts by.
+ * @return a list of the additional amounts that match the filter criteria.
+ */
+ public List listByTypes(String accountType, String amountType) {
+ ArrayList amounts = new ArrayList<>();
+ for (AdditionalAmount amount : this) {
+ if ((accountType == null || amount.getAccountType().equals(accountType)) &&
+ (amountType == null || amount.getAmountTypeCode().equals(amountType))) {
+ amounts.add(amount);
+ }
+ }
+
+ return amounts;
+ }
+
+ /**
+ * Returns true when the wrapper has the given {@code amountType}.
+ *
+ * @param amountType the amount type code.
+ * @return true when the wrapper has the given {@code amountType}.
+ * @throws NullPointerException if {@code amountType} is {@code null}
+ */
+ public boolean containsAmountType(String amountType) {
+ Objects.requireNonNull(amountType);
+ return getAny(a -> amountType.equals(a.getAmountTypeCode())) != null;
+ }
+
+ /**
+ * Returns the first occurrence of the additional amount that matches the filter criteria.
+ *
+ * @param amountType the amount type to filter amounts by
+ * @return the first occurrence of the additional amount that matches the filter criteria, or null if none matches
+ * @throws NullPointerException if {@code amountType} is {@code null}
+ */
+ public AdditionalAmount getFirstByAmountType(String amountType) {
+ Objects.requireNonNull(amountType);
+ for (AdditionalAmount addAmnt : this) {
+ if (amountType.equals(addAmnt.getAmountTypeCode()))
+ return addAmnt;
+ }
+ return null;
+ }
+
+ /**
+ * Returns a list of the additional amounts that match the filter criteria.
+ *
+ * @param amountType the amount type to filter amounts by.
+ * @return a list of the additional amounts that match the filter criteria.
+ * @throws NullPointerException if {@code amountType} is {@code null}
+ */
+ public List listByAmountType(String amountType) {
+ Objects.requireNonNull(amountType);
+ return listByTypes(null, amountType);
+ }
+
+}
diff --git a/modules/cmf/src/test/java/org/jpos/cmf/AdditionalAmountsWrapperTest.java b/modules/cmf/src/test/java/org/jpos/cmf/AdditionalAmountsWrapperTest.java
index 57c134dbba..e28865e6db 100644
--- a/modules/cmf/src/test/java/org/jpos/cmf/AdditionalAmountsWrapperTest.java
+++ b/modules/cmf/src/test/java/org/jpos/cmf/AdditionalAmountsWrapperTest.java
@@ -25,7 +25,7 @@
import static org.junit.jupiter.api.Assertions.*;
-
+@Deprecated
public final class AdditionalAmountsWrapperTest {
@Test
diff --git a/modules/cmf/src/test/java/org/jpos/iso/AdditionalAmountsWrapperTest.java b/modules/cmf/src/test/java/org/jpos/iso/AdditionalAmountsWrapperTest.java
new file mode 100644
index 0000000000..ab146e11d0
--- /dev/null
+++ b/modules/cmf/src/test/java/org/jpos/iso/AdditionalAmountsWrapperTest.java
@@ -0,0 +1,179 @@
+/*
+ * jPOS Project [http://jpos.org]
+ * Copyright (C) 2000-2023 jPOS Software SRL
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.jpos.iso;
+
+import org.junit.jupiter.api.Test;
+
+import org.jpos.cmf.AmountType;
+import org.jpos.cmf.CMFAdditionalAmount;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public final class AdditionalAmountsWrapperTest {
+ static AdditionalAmountTypeConverter CONVERTER = AmountType.CONVERTER;
+
+ @Test
+ public void test_contains_amountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("10.00"), "858", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("12.00"), "858", AmountType.AMOUNT_TAXABLE.code(), 1));
+
+ assertTrue(wrapper.containsAmountType(AmountType.AMOUNT_TAXABLE.code()));
+ assertTrue(wrapper.containsAmountType(AmountType.AMOUNT_CASH.code()));
+ assertFalse(wrapper.containsAmountType(AmountType.AMOUNT_REMAINING_THIS_CYCLE.code()));
+ }
+
+ @Test
+ public void test_get_by_amountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("10.00"), "858", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("12.00"), "858", AmountType.AMOUNT_TAXABLE.code(), 1));
+
+ assertNotNull(wrapper.getFirstByAmountType(AmountType.AMOUNT_TAXABLE.code()));
+ assertNotNull(wrapper.getFirstByAmountType(AmountType.AMOUNT_CASH.code()));
+ assertNull(wrapper.getFirstByAmountType(AmountType.AMOUNT_REMAINING_THIS_CYCLE.code()));
+ }
+
+
+ @Test
+ public void testParseInvalidLengthData() {
+ String sample = "00028582C00000010000000018582C0000001000";
+ assertThrows(IllegalArgumentException.class,
+ () -> AdditionalAmountsWrapper.parse(sample, CMFAdditionalAmount.SERIALIZED_DATA_LENGTH, CMFAdditionalAmount::parse));
+ }
+
+ @Test
+ public void testSuccessfulParse() {
+ String sample = "00" + "02" + "858"+"2" + "C"+"000000100000" +
+ "00" + "01" + "858"+"2" + "C"+"000000100000";
+
+ AdditionalAmountsWrapper wrapper = AdditionalAmountsWrapper.parse(sample, CMFAdditionalAmount.SERIALIZED_DATA_LENGTH, CMFAdditionalAmount::parse);
+ assertEquals(2, wrapper.size());
+ }
+
+ @Test
+ public void testParseAndSerialize() {
+ String sample = "00" + "02" + "840"+"2" + "C"+"000000100000" +
+ "00" + "01" + "858"+"2" + "C"+"000000100000";
+
+ AdditionalAmountsWrapper wrapper = AdditionalAmountsWrapper.parse(sample, CMFAdditionalAmount.SERIALIZED_DATA_LENGTH, CMFAdditionalAmount::parse);
+ assertEquals(sample, wrapper.serialize());
+ }
+
+ @Test
+ public void testParseAndSerializeOneItem() {
+ String sample = "00" + "01" + "858"+"2" + "C"+"000000100000";
+
+ AdditionalAmountsWrapper wrapper = AdditionalAmountsWrapper.parse(sample, CMFAdditionalAmount.SERIALIZED_DATA_LENGTH, CMFAdditionalAmount::parse);
+
+ assertEquals(1, wrapper.size());
+ assertEquals(sample, wrapper.serialize());
+ }
+
+ @Test
+ public void test_listByAmountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("400.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+
+ List amounts = wrapper.listByAmountType(AmountType.AMOUNT_SURCHARGE.code());
+
+ assertNotNull(amounts);
+ assertEquals(2, amounts.size());
+ }
+
+ @Test
+ public void test_listByTypes_WithAccountAndAmountTypes() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("400.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+
+ List amounts = wrapper.listByTypes("00", AmountType.AMOUNT_SURCHARGE.code());
+ assertNotNull(amounts);
+ assertEquals(1, amounts.size());
+ }
+
+ @Test
+ public void test_listByTypes_WithNullAccountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("400.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+
+ List amounts = wrapper.listByTypes(null, AmountType.AMOUNT_SURCHARGE.code());
+ assertNotNull(amounts);
+ assertEquals(2, amounts.size());
+ }
+
+
+
+ @Test
+ public void test_getFirstByAmountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("30", new BigDecimal("400.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+
+ AdditionalAmount amount = wrapper.getFirstByAmountType(AmountType.AMOUNT_SURCHARGE.code());
+
+ assertNotNull(amount);
+ assertEquals(new BigDecimal("200.00"), amount.getAmount());
+ assertEquals("00", amount.getAccountType());
+ }
+
+ @Test
+ public void test_containsAmountType() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 1));
+ wrapper.add(new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 1));
+
+ assertTrue(wrapper.containsAmountType(AmountType.AMOUNT_SURCHARGE.code()));
+ assertTrue(wrapper.containsAmountType(AmountType.AMOUNT_CASH.code()));
+ assertFalse(wrapper.containsAmountType(AmountType.AMOUNT_REMAINING_THIS_CYCLE.code()));
+ }
+
+ @Test
+ public void toStringTest() {
+ AdditionalAmountsWrapper wrapper = new AdditionalAmountsWrapper();
+
+ AdditionalAmount as = new CMFAdditionalAmount("00", new BigDecimal("200.00"), "840", AmountType.AMOUNT_SURCHARGE.code(), 2);
+ AdditionalAmount ac = new CMFAdditionalAmount("00", new BigDecimal("300.00"), "840", AmountType.AMOUNT_CASH.code(), 2);
+ wrapper.add(as);
+ wrapper.add(ac);
+
+ assertEquals("CMFAdditionalAmount {00,42,840,2,200.00}", as.toString());
+ assertEquals("CMFAdditionalAmount {00,40,840,2,300.00}", ac.toString());
+ assertEquals("[CMFAdditionalAmount {00,42,840,2,200.00}, CMFAdditionalAmount {00,40,840,2,300.00}]", wrapper.toString());
+ }
+}
+
+
+