diff --git a/app/src/main/java/org/gnucash/android/model/Price.java b/app/src/main/java/org/gnucash/android/model/Price.java index 79c572f10..7ecdd1011 100644 --- a/app/src/main/java/org/gnucash/android/model/Price.java +++ b/app/src/main/java/org/gnucash/android/model/Price.java @@ -2,7 +2,11 @@ import org.gnucash.android.util.TimestampHelper; + +import java.math.BigDecimal; import java.sql.Timestamp; +import java.text.DecimalFormat; +import java.text.NumberFormat; /** * Model for commodity prices @@ -37,6 +41,19 @@ public Price(String commodityUID, String currencyUID){ mDate = TimestampHelper.getTimestampFromNow(); } + /** + * Create new instance with the GUIDs of the commodities and the specified exchange rate. + * @param commodity1UID GUID of the origin commodity + * @param commodity2UID GUID of the target commodity + * @param exchangeRate exchange rate between the commodities + */ + public Price(String commodity1UID, String commodity2UID, BigDecimal exchangeRate) { + this(commodity1UID, commodity2UID); + // Store 0.1234 as 1234/10000 + setValueNum(exchangeRate.unscaledValue().longValue()); + setValueDenom(BigDecimal.ONE.scaleByPowerOfTen(exchangeRate.scale()).longValue()); + } + public String getCommodityUID() { return mCommodityUID; } @@ -123,4 +140,20 @@ public void reduce() { mValueDenom /= commonDivisor; } } + + /** + * Returns the exchange rate as a string formatted with the default locale. + * + *

It will have up to 6 decimal places. + * + *

Example: "0.123456" + */ + @Override + public String toString() { + BigDecimal numerator = new BigDecimal(mValueNum); + BigDecimal denominator = new BigDecimal(mValueDenom); + DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(); + formatter.setMaximumFractionDigits(6); + return formatter.format(numerator.divide(denominator)); + } } diff --git a/app/src/main/java/org/gnucash/android/ui/transaction/dialog/TransferFundsDialogFragment.java b/app/src/main/java/org/gnucash/android/ui/transaction/dialog/TransferFundsDialogFragment.java index 2fccd5461..3538d2f8c 100644 --- a/app/src/main/java/org/gnucash/android/ui/transaction/dialog/TransferFundsDialogFragment.java +++ b/app/src/main/java/org/gnucash/android/ui/transaction/dialog/TransferFundsDialogFragment.java @@ -116,17 +116,21 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa Commodity currencyCommodity = commoditiesDbAdapter.getCommodity(mTargetCurrency.getCurrencyCode()); String currencyUID = currencyCommodity.getUID(); PricesDbAdapter pricesDbAdapter = PricesDbAdapter.getInstance(); - Pair price = pricesDbAdapter.getPrice(commodityUID, currencyUID); + Pair pricePair = pricesDbAdapter.getPrice(commodityUID, currencyUID); - if (price.first > 0 && price.second > 0) { + if (pricePair.first > 0 && pricePair.second > 0) { // a valid price exists - BigDecimal numerator = new BigDecimal(price.first); - BigDecimal denominator = new BigDecimal(price.second); - DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(); - mExchangeRateInput.setText(formatter.format(numerator.divide(denominator, MathContext.DECIMAL32))); + Price price = new Price(commodityUID, currencyUID); + price.setValueNum(pricePair.first); + price.setValueDenom(pricePair.second); + mExchangeRateInput.setText(price.toString()); + + BigDecimal numerator = new BigDecimal(pricePair.first); + BigDecimal denominator = new BigDecimal(pricePair.second); // convertedAmount = mOriginAmount * numerator / denominator BigDecimal convertedAmount = mOriginAmount.asBigDecimal().multiply(numerator) .divide(denominator, currencyCommodity.getSmallestFractionDigits(), BigDecimal.ROUND_HALF_EVEN); + DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(); mConvertedAmountInput.setText(formatter.format(convertedAmount)); } @@ -194,17 +198,24 @@ public Dialog onCreateDialog(Bundle savedInstanceState) { * Converts the currency amount with the given exchange rate and saves the price to the db */ private void transferFunds() { + Price price = null; + + CommoditiesDbAdapter commoditiesDbAdapter = CommoditiesDbAdapter.getInstance(); + String originCurrencyCode = commoditiesDbAdapter.getCommodityUID(mOriginAmount.getCurrency().getCurrencyCode()); + String targetCurrencyCode = commoditiesDbAdapter.getCommodityUID(mTargetCurrency.getCurrencyCode()); + if (mExchangeRateRadioButton.isChecked()){ + BigDecimal rate; String exchangeRateString = mExchangeRateInput.getText().toString(); DecimalFormat formatter = (DecimalFormat) NumberFormat.getNumberInstance(); formatter.setParseBigDecimal(true); - BigDecimal rate; try { rate = (BigDecimal) formatter.parse(exchangeRateString); } catch (ParseException e) { mExchangeRateInputLayout.setError(getString(R.string.error_invalid_exchange_rate)); return; } + price = new Price(originCurrencyCode, targetCurrencyCode, rate); mConvertedAmount = mOriginAmount.multiply(rate); } @@ -217,22 +228,20 @@ private void transferFunds() { BigDecimal amount = TransactionFormFragment.parseInputToDecimal(convertedAmount); mConvertedAmount = new Money(amount, Commodity.getInstance(mTargetCurrency.getCurrencyCode())); - } - if (mOnTransferFundsListener != null) { - PricesDbAdapter pricesDbAdapter = PricesDbAdapter.getInstance(); - CommoditiesDbAdapter commoditiesDbAdapter = CommoditiesDbAdapter.getInstance(); - Price price = new Price(commoditiesDbAdapter.getCommodityUID(mOriginAmount.getCurrency().getCurrencyCode()), - commoditiesDbAdapter.getCommodityUID(mTargetCurrency.getCurrencyCode())); - price.setSource(Price.SOURCE_USER); - // fractions cannot be exacted represented by BigDecimal. + price = new Price(originCurrencyCode, targetCurrencyCode); + // fractions cannot be exactly represented by BigDecimal. price.setValueNum(mConvertedAmount.getNumerator() * mOriginAmount.getDenominator()); price.setValueDenom(mOriginAmount.getNumerator() * mConvertedAmount.getDenominator()); - price.reduce(); - pricesDbAdapter.addRecord(price); + } + price.setSource(Price.SOURCE_USER); + price.reduce(); + PricesDbAdapter.getInstance().addRecord(price); + + if (mOnTransferFundsListener != null) mOnTransferFundsListener.transferComplete(mConvertedAmount); - } + dismiss(); } diff --git a/app/src/test/java/org/gnucash/android/test/unit/model/PriceTest.java b/app/src/test/java/org/gnucash/android/test/unit/model/PriceTest.java new file mode 100644 index 000000000..8df91036c --- /dev/null +++ b/app/src/test/java/org/gnucash/android/test/unit/model/PriceTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Àlex Magaz Graça + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.gnucash.android.test.unit.model; + +import org.gnucash.android.model.Price; +import org.junit.Test; + +import java.math.BigDecimal; +import java.util.Locale; + +import static org.assertj.core.api.Assertions.assertThat; + + +public class PriceTest { + @Test + public void creatingFromExchangeRate_ShouldGetPrecisionRight() { + Locale.setDefault(Locale.US); + + String exchangeRateString = "0.123456"; + BigDecimal exchangeRate = new BigDecimal(exchangeRateString); + Price price = new Price("commodity1UID", "commodity2UID", exchangeRate); + assertThat(price.toString()).isEqualTo(exchangeRateString); + + // ensure we don't get more decimal places than needed (0.123000) + exchangeRateString = "0.123"; + exchangeRate = new BigDecimal(exchangeRateString); + price = new Price("commodity1UID", "commodity2UID", exchangeRate); + assertThat(price.toString()).isEqualTo(exchangeRateString); + } + + @Test + public void toString_shouldUseDefaultLocale() { + Locale.setDefault(Locale.GERMANY); + + String exchangeRateString = "1.234"; + BigDecimal exchangeRate = new BigDecimal(exchangeRateString); + Price price = new Price("commodity1UID", "commodity2UID", exchangeRate); + assertThat(price.toString()).isEqualTo("1,234"); + } +}