Skip to content

Commit

Permalink
Merge pull request #285 from barspi/refactor-additional-amounts
Browse files Browse the repository at this point in the history
Refactor additional amounts
  • Loading branch information
ar authored Sep 30, 2023
2 parents 87012c3 + 0d29bc2 commit 558669e
Show file tree
Hide file tree
Showing 11 changed files with 617 additions and 32 deletions.
20 changes: 10 additions & 10 deletions modules/cmf/src/main/java/org/jpos/cmf/AdditionalAmount.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<AdditionalAmount> {

private static final long serialVersionUID = 2526355280704001241L;
Expand Down
70 changes: 52 additions & 18 deletions modules/cmf/src/main/java/org/jpos/cmf/AmountType.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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 <br>
* 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"),
Expand All @@ -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"),
Expand All @@ -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"),
Expand All @@ -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"),
Expand All @@ -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"),

Expand All @@ -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;
}
};
}
83 changes: 83 additions & 0 deletions modules/cmf/src/main/java/org/jpos/cmf/CMFAdditionalAmount.java
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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);
}

}
5 changes: 2 additions & 3 deletions modules/cmf/src/main/java/org/jpos/cmf/CMFAmount.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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;
Expand All @@ -41,7 +40,7 @@
* {@link #serialize(boolean, int)}, that the lengths are in accordance and what you need.
* </p>
* <p><b>NOTE:</b>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}.
* </p>
*
*/
Expand Down
92 changes: 92 additions & 0 deletions modules/cmf/src/main/java/org/jpos/iso/AdditionalAmount.java
Original file line number Diff line number Diff line change
@@ -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);
}

}
Loading

0 comments on commit 558669e

Please sign in to comment.