Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Currency #614

Merged
merged 3 commits into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Written in 2015 by Sam Hamilton - samhamilton
Written in 2015 by Leonardo Carvalho - CarvalhoLeonardo
Written in 2015 by Swapnil M Mane - swapnilmmane
Written in 2015 by Anton Akhiar - akhiar
Written in 2015-2018 by Jens Hardings - jenshp
Written in 2015-2023 by Jens Hardings - jenshp
Written in 2016 by Shifeng Zhang - zhangshifeng
Written in 2016 by Scott Gray - lektran
Written in 2016 by Mark Haney - mphaney
Expand Down Expand Up @@ -94,7 +94,7 @@ Written in 2015 by Jimmy Shen - shendepu
Written in 2015-2016 by Sam Hamilton - samhamilton
Written in 2015 by Leonardo Carvalho - CarvalhoLeonardo
Written in 2015 by Anton Akhiar - akhiar
Written in 2015-2016 by Jens Hardings - jenshp
Written in 2015-2023 by Jens Hardings - jenshp
Written in 2016 by Shifeng Zhang - zhangshifeng
Written in 2016 by Scott Gray - lektran
Written in 2016 by Mark Haney - mphaney
Expand Down
4 changes: 3 additions & 1 deletion framework/entity/BasicEntities.xml
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ along with this software (see the LICENSE.md file). If not, see
<field name="uomId" type="id" is-pk="true"/>
<field name="uomTypeEnumId" type="id"/>
<field name="abbreviation" type="text-short"/>
<field name="description" type="text-medium"/>
<field name="description" type="text-medium" enable-localization="true"/>
<field name="fractionDigits" type="number-integer"/>
<field name="symbol" type="text-short" enable-localization="true"/>
<relationship type="one" title="UomType" related="moqui.basic.Enumeration" short-alias="type">
<key-map field-name="uomTypeEnumId"/></relationship>
<relationship type="many" related="moqui.basic.UomConversion" short-alias="conversions">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import org.moqui.BaseArtifactException;
import org.moqui.context.L10nFacade;
import org.moqui.entity.EntityCondition;
import org.moqui.entity.EntityValue;
import org.moqui.entity.EntityFind;

Expand All @@ -23,6 +24,8 @@
import javax.xml.bind.DatatypeConverter;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.sql.Date;
import java.sql.Time;
Expand Down Expand Up @@ -100,13 +103,14 @@ public String localize(String original, Locale locale) {
}

@Override
public String formatCurrency(Object amount, String uomId) { return formatCurrency(amount, uomId, null, getLocale()); }
public String formatCurrencyNoSymbol(Object amount, String uomId) { return formatCurrency(amount, uomId, null, getLocale(), true); }
@Override
public String formatCurrency(Object amount, String uomId, Integer fractionDigits) {
return formatCurrency(amount, uomId, fractionDigits, getLocale());
}
public String formatCurrency(Object amount, String uomId) { return formatCurrency(amount, uomId, null, getLocale(), false); }
@Override
public String formatCurrency(Object amount, String uomId, Integer fractionDigits) { return formatCurrency(amount, uomId, fractionDigits, getLocale(), false); }
@Override
public String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale) {
public String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale) { return formatCurrency(amount, uomId, fractionDigits, locale, false); }
public String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale, boolean hideSymbol) {
if (amount == null) return "";
if (amount instanceof CharSequence) {
if (((CharSequence) amount).length() == 0) {
Expand All @@ -116,30 +120,53 @@ public String formatCurrency(Object amount, String uomId, Integer fractionDigits
}
}

if (locale == null) locale = getLocale();
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
String currencySymbol = null;
if (hideSymbol)
currencySymbol = "";
EntityValue uom = null;
if (uomId != null && uomId.length() > 0) {
List<EntityValue> uomList = eci.getEntity().find("moqui.basic.Uom").condition("uomId", uomId).condition("uomTypeEnumId", "UT_CURRENCY_MEASURE").list();
if (uomList.size() > 0) {
uom = uomList.get(0);
String symbol = uom.getString("symbol");
if (currencySymbol == null && symbol != null)
currencySymbol = symbol;
Object fractionDigitsField = uom.get("fractionDigits");
if (fractionDigits == null && fractionDigitsField != null) {
if (fractionDigitsField instanceof Integer)
fractionDigits = (Integer)fractionDigitsField;
else if (fractionDigitsField instanceof Long)
fractionDigits = ((Long)fractionDigitsField).intValue();
}
}
}

Currency currency = null;
if (uomId != null && uomId.length() > 0) {
try {
currency = Currency.getInstance(uomId);
if (currencySymbol == null)
currencySymbol = currency.getSymbol();
if (fractionDigits == null)
fractionDigits = currency.getDefaultFractionDigits();
} catch (Exception e) {
if (logger.isTraceEnabled()) logger.trace("Ignoring IllegalArgumentException for Currency parse: " + e.toString());
}
}

if (locale == null) locale = getLocale();
if (currency != null) {
NumberFormat nf = NumberFormat.getCurrencyInstance(locale);
nf.setCurrency(currency);
if (fractionDigits == null) fractionDigits = currency.getDefaultFractionDigits();
nf.setMaximumFractionDigits(fractionDigits);
nf.setMinimumFractionDigits(fractionDigits);
return nf.format(amount);
} else {
NumberFormat nf = NumberFormat.getInstance();
if (fractionDigits == null) fractionDigits = 2;
nf.setMaximumFractionDigits(fractionDigits);
nf.setMinimumFractionDigits(fractionDigits);
return nf.format(amount);
}
if (currencySymbol == null)
currencySymbol = "";

if (fractionDigits == null)
fractionDigits = 2;
nf.setMaximumFractionDigits(fractionDigits);
nf.setMinimumFractionDigits(fractionDigits);
DecimalFormatSymbols dfSymbols = new DecimalFormatSymbols(locale);
dfSymbols.setCurrencySymbol(currencySymbol);
((DecimalFormat)nf).setDecimalFormatSymbols(dfSymbols);

return nf.format(amount);
}

@Override
Expand All @@ -152,10 +179,29 @@ public BigDecimal roundCurrency(BigDecimal amount, String uomId, boolean precise
}
@Override
public BigDecimal roundCurrency(BigDecimal amount, String uomId, boolean precise, RoundingMode mode) {
Currency currency = Currency.getInstance(uomId);
int nDigits = currency.getDefaultFractionDigits();
if (precise) nDigits++;
return amount.setScale(nDigits, mode);
if (amount == null)
return null;
List<EntityValue> uomList = eci.getEntity().find("moqui.basic.Uom").condition("uomId", uomId).condition("uomTypeEnumId", "UT_CURRENCY_MEASURE").list();
Integer fractionDigits = null;
if (uomList.size() > 0) {
Object fractionDigitsField = uomList.get(0).get("fractionDigits");
if (fractionDigitsField != null) {
if (fractionDigitsField instanceof Integer)
fractionDigits = (Integer)fractionDigitsField;
else if (fractionDigitsField instanceof Long)
fractionDigits = ((Long)fractionDigitsField).intValue();
}
}
if (fractionDigits == null) {
Currency currency = Currency.getInstance(uomId);
fractionDigits = currency.getDefaultFractionDigits();
}
if (fractionDigits == null) {
fractionDigits = 2;
}
if (precise) fractionDigits++;
eci.getLogger().info("Rounding to " + fractionDigits + " digits.");
return amount.setScale(fractionDigits, mode);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1823,6 +1823,7 @@ class ScreenRenderImpl implements ScreenRender {
String fieldValue = (String) null
String textAttr = widgetNode.attribute("text")
String currencyAttr = widgetNode.attribute("currency-unit-field")
String currencyNoSymbolAttr = widgetNode.attribute("currency-hide-symbol")
if (textAttr != null && ! textAttr.isEmpty()) {
String textMapAttr = widgetNode.attribute("text-map")
Map textMap = (Map) null
Expand All @@ -1833,9 +1834,16 @@ class ScreenRenderImpl implements ScreenRender {
} else {
fieldValue = ec.resourceFacade.expand(textAttr, null)
}
if (currencyAttr != null && !currencyAttr.isEmpty())
fieldValue = ec.l10nFacade.formatCurrency(fieldValue, ec.resourceFacade.expression(currencyAttr, null) as String)
if (currencyAttr != null && !currencyAttr.isEmpty()) {
if (currencyNoSymbolAttr == "true")
fieldValue = ec.l10nFacade.formatCurrencyNoSymbol(fieldValue, ec.resourceFacade.expression(currencyAttr, null) as String)
else
fieldValue = ec.l10nFacade.formatCurrency(fieldValue, ec.resourceFacade.expression(currencyAttr, null) as String)
}
} else if (currencyAttr != null && !currencyAttr.isEmpty()) {
if (currencyNoSymbolAttr == "true")
fieldValue = ec.l10nFacade.formatCurrencyNoSymbol(getFieldValue(fieldNode, ""), ec.resourceFacade.expression(currencyAttr, null) as String)
else
fieldValue = ec.l10nFacade.formatCurrency(getFieldValue(fieldNode, ""), ec.resourceFacade.expression(currencyAttr, null) as String)
} else {
fieldValue = getFieldValueString(widgetNode)
Expand Down
7 changes: 6 additions & 1 deletion framework/src/main/java/org/moqui/context/L10nFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ public interface L10nFacade {
* @param uomId The uomId (ISO currency code), required.
* @param fractionDigits Number of digits after the decimal point to display. If null defaults to number defined
* by java.util.Currency.defaultFractionDigits() for the specified currency in uomId.
* @param locale Locale to use for formatting.
* @param hideSymbol option to hide the Symbol of the currency and only display the number formatted according
* to locale.
* @return The formatted currency amount.
*/
String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale, boolean hideSymbol);
String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale);
String formatCurrency(Object amount, String uomId, Integer fractionDigits);
String formatCurrency(Object amount, String uomId);
String formatCurrency(Object amount, String uomId, Integer fractionDigits, Locale locale);
String formatCurrencyNoSymbol(Object amount, String uomId);

/** Round currency according to the currency's specified amount of digits and rounding method.
* @param amount The amount in BigDecimal to be rounded.
Expand Down
4 changes: 4 additions & 0 deletions framework/xsd/xml-form-3.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -897,6 +897,10 @@ along with this software (see the LICENSE.md file). If not, see
<xs:annotation><xs:documentation>Specifies the currency uomId (ISO code) used to format the value.
Will only format as currency if this is specified.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="currency-hide-symbol" default="false" type="xs:string">
<xs:annotation><xs:documentation>When currency-unit-field has value, defines whether currency symbol will be
hidden or displayed normally.</xs:documentation></xs:annotation>
</xs:attribute>
<xs:attribute name="format" type="xs:string">
<xs:annotation><xs:documentation>Used to format the output of Number/Time/Date/Timestamp/etc objects.
With auto-fields-service will inherit from service parameter.</xs:documentation></xs:annotation>
Expand Down
Loading