001/* 002 * jPOS Project [http://jpos.org] 003 * Copyright (C) 2000-2026 jPOS Software SRL 004 * 005 * This program is free software: you can redistribute it and/or modify 006 * it under the terms of the GNU Affero General Public License as 007 * published by the Free Software Foundation, either version 3 of the 008 * License, or (at your option) any later version. 009 * 010 * This program is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 013 * GNU Affero General Public License for more details. 014 * 015 * You should have received a copy of the GNU Affero General Public License 016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 017 */ 018 019package org.jpos.iso; 020 021import org.jpos.iso.packager.XMLPackager; 022 023import java.io.*; 024import java.math.BigDecimal; 025import java.util.Objects; 026 027/** ISO component representing an amount with currency and decimal scale. */ 028public class ISOAmount 029 extends ISOComponent 030 implements Cloneable, Externalizable 031{ 032 static final long serialVersionUID = -6130248734056876225L; 033 private int fieldNumber; 034 private int currencyCode; 035 private String value; 036 private BigDecimal amount; 037 038 /** Default constructor. */ 039 public ISOAmount () { 040 super(); 041 setFieldNumber (-1); 042 } 043 /** Constructs an ISOAmount for the given field number. 044 * @param fieldNumber the ISO field number 045 */ 046 047 public ISOAmount (int fieldNumber) { 048 super (); 049 setFieldNumber (fieldNumber); 050 } 051 /** 052 * Constructs an ISOAmount with all fields. 053 * @param fieldNumber the ISO field number 054 * @param currencyCode the ISO 4217 currency code 055 * @param amount the monetary amount 056 * @throws ISOException if the value cannot be encoded 057 */ 058 public ISOAmount (int fieldNumber, int currencyCode, BigDecimal amount) throws ISOException { 059 super (); 060 setFieldNumber(fieldNumber); 061 this.currencyCode = currencyCode; 062 try { 063 this.amount = amount.setScale(ISOCurrency.getCurrency(currencyCode).getDecimals()); 064 } catch (ArithmeticException e) { 065 throw new ISOException ( 066 "rounding problem, amount=" + amount + " scale=" + ISOCurrency.getCurrency(currencyCode).getDecimals() 067 ); 068 } 069 } 070 public Object getKey() { 071 return fieldNumber; 072 } 073 public Object getValue() throws ISOException { 074 if (value == null) { 075 StringBuilder sb = new StringBuilder(); 076 sb.append (ISOUtil.zeropad (Integer.toString(currencyCode), 3)); 077 sb.append (Integer.toString (amount.scale())); 078 sb.append ( 079 ISOUtil.zeropad ( 080 amount.movePointRight(amount.scale()).toString(),12 081 ) 082 ); 083 value = sb.toString(); 084 } 085 return value; 086 087 } 088 public void setValue (Object obj) throws ISOException { 089 if (obj instanceof String) { 090 String s = (String) obj; 091 if (s.length() < 12) { 092 throw new ISOException ( 093 "ISOAmount invalid length " + s.length() 094 ); 095 } 096 try { 097 currencyCode = Integer.parseInt (s.substring(0,3)); 098 int dec = Integer.parseInt (s.substring(3,4)); 099 amount = new BigDecimal (s.substring(4)).movePointLeft (dec); 100 value = s; 101 } catch (NumberFormatException e) { 102 throw new ISOException (e.getMessage()); 103 } 104 } 105 } 106 public void setFieldNumber (int fieldNumber) { 107 this.fieldNumber = fieldNumber; 108 } 109 110 @Override 111 public int getFieldNumber () { 112 return fieldNumber; 113 } 114 /** Returns the monetary amount. 115 * @return the amount 116 */ 117 118 public BigDecimal getAmount () { 119 return amount; 120 } 121 /** Returns the decimal scale. 122 * @return the scale 123 */ 124 125 public int getScale() { 126 return amount.scale() % 10; 127 } 128 /** Returns the scale as a two-character string. 129 * @return scale string 130 */ 131 132 public String getScaleAsString() { 133 return Integer.toString(getScale()); 134 } 135 /** Returns the ISO 4217 currency code. 136 * @return currency code 137 */ 138 139 public int getCurrencyCode() { 140 return currencyCode; 141 } 142 /** Returns the currency code as a 3-digit string. 143 * @return currency code string 144 * @throws ISOException on error 145 */ 146 147 public String getCurrencyCodeAsString() throws ISOException { 148 return ISOUtil.zeropad(Integer.toString(currencyCode),3); 149 } 150 /** Returns the amount formatted as a legacy ISO string. 151 * @return formatted amount string 152 * @throws ISOException on error 153 */ 154 155 public String getAmountAsLegacyString() throws ISOException { 156 return ISOUtil.zeropad (amount.unscaledValue().toString(), 12); 157 } 158 /** Returns the amount as a formatted string. 159 * @return the formatted amount string 160 * @throws ISOException on error 161 */ 162 public String getAmountAsString() throws ISOException { 163 StringBuilder sb = new StringBuilder(16); 164 sb.append (ISOUtil.zeropad (Integer.toString (currencyCode),3)); 165 sb.append (Integer.toString(amount.scale() % 10)); 166 sb.append (ISOUtil.zeropad (amount.unscaledValue().toString(), 12)); 167 return sb.toString(); 168 } 169 public byte[] pack() throws ISOException { 170 throw new ISOException ("Not available"); 171 } 172 public int unpack(byte[] b) throws ISOException { 173 throw new ISOException ("Not available"); 174 } 175 public void unpack(InputStream in) throws ISOException { 176 throw new ISOException ("Not available"); 177 } 178 public void dump (PrintStream p, String indent) { 179 p.println (indent +"<"+XMLPackager.ISOFIELD_TAG + " " 180 +XMLPackager.ID_ATTR +"=\"" +fieldNumber +"\" " 181 +"currency=\"" +ISOUtil.zeropad (currencyCode, 3)+"\" " 182 +XMLPackager.TYPE_ATTR +"=\"amount\" " 183 +XMLPackager.VALUE_ATTR+"=\"" + amount.toString() +"\"/>" 184 ); 185 } 186 public void writeExternal (ObjectOutput out) throws IOException { 187 out.writeShort (fieldNumber); 188 try { 189 out.writeUTF ((String) getValue()); 190 } catch (ISOException e) { 191 throw new IOException (e); 192 } 193 } 194 public void readExternal (ObjectInput in) 195 throws IOException, ClassNotFoundException 196 { 197 fieldNumber = in.readShort (); 198 try { 199 setValue(in.readUTF()); 200 } catch (ISOException e) { 201 throw new IOException (e.getMessage()); 202 } 203 } 204 205 @Override 206 public boolean equals(Object o) { 207 if (this == o) return true; 208 if (o == null || getClass() != o.getClass()) return false; 209 ISOAmount isoAmount = (ISOAmount) o; 210 return fieldNumber == isoAmount.fieldNumber && 211 currencyCode == isoAmount.currencyCode && 212 Objects.equals(amount, isoAmount.amount); 213 } 214 215 @Override 216 public int hashCode() { 217 return Objects.hash(fieldNumber, currencyCode, amount); 218 } 219 220 @Override 221 public String toString() { 222 return "ISOAmount{" + 223 "fieldNumber=" + fieldNumber + 224 ", currencyCode=" + currencyCode + 225 ", amount=" + amount + 226 '}'; 227 } 228}