Skip to content

Commit

Permalink
Modified transactions to use BigDecimal instead of floats due to roun…
Browse files Browse the repository at this point in the history
…ding errors.

Separated currency symbol and amount value in NewTransaction view
Updated database to store amounts as strings
  • Loading branch information
codinguser committed Jul 18, 2012
1 parent fe4a658 commit 1406471
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 52 deletions.
27 changes: 23 additions & 4 deletions GnucashMobile/res/layout/fragment_new_transaction.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,30 @@

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
android:layout_height="wrap_content" >
<!--
<TextView android:id="@+id/sign"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:layout_marginBottom="10dp"
android:textColor="@color/debit_red"
style="@style/ListItemText"
android:text="-" />
-->
<TextView android:id="@+id/currency_symbol"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:textColor="@color/debit_red"
android:gravity="right"
style="@style/ListItemText"
android:text="$" />

<EditText
android:id="@+id/input_transaction_amount"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_weight="3"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:ems="10"
Expand All @@ -40,7 +58,8 @@
style="@style/ListItemText" />

<ToggleButton android:id="@+id/input_transaction_type"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:minWidth="100dp"
Expand Down
8 changes: 4 additions & 4 deletions GnucashMobile/src/org/gnucash/android/data/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

package org.gnucash.android.data;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -198,11 +199,10 @@ public boolean hasUnexportedTransactions(){
* It takes into account debit and credit amounts
* @return Aggregate amount of all transactions in account.
*/
public double getBalance(){
double balance = 0;
public BigDecimal getBalance(){
BigDecimal balance = new BigDecimal(0);
for (Transaction transx : mTransactionsList) {
balance += transx.getAmount();
}
balance.add(transx.getAmount()); }
return balance;
}

Expand Down
53 changes: 44 additions & 9 deletions GnucashMobile/src/org/gnucash/android/data/Transaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

package org.gnucash.android.data;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Date;
Expand All @@ -44,7 +46,7 @@ public class Transaction {
*/
public enum TransactionType {DEBIT, CREDIT};

private double mAmount;
private BigDecimal mAmount;
private String mTransactionUID;
private String mName;
private String mDescription = "";
Expand All @@ -59,7 +61,25 @@ public enum TransactionType {DEBIT, CREDIT};
* @param amount Amount for the transaction
* @param name Name of the transaction
*/
public Transaction(double amount, String name) {
public Transaction(BigDecimal amount, String name) {
initDefaults();
setName(name);
setAmount(amount); //takes care of setting the type for us
}

public Transaction(double amount, String name){
initDefaults();
setName(name);
setAmount(amount);
}

/**
* Overloaded constructor. Creates a new transaction instance with the
* provided data and initializes the rest to default values.
* @param amount Amount for the transaction
* @param name Name of the transaction
*/
public Transaction(String amount, String name) {
initDefaults();
setName(name);
setAmount(amount); //takes care of setting the type for us
Expand All @@ -72,9 +92,9 @@ public Transaction(double amount, String name) {
* @param name Name of the transaction
* @param type Type of transaction
*/
public Transaction(double amount, String name, TransactionType type){
public Transaction(BigDecimal amount, String name, TransactionType type){
initDefaults();
this.mAmount = amount;
setAmount(amount);
this.mType = type;
this.mName = name;
}
Expand All @@ -83,7 +103,7 @@ public Transaction(double amount, String name, TransactionType type){
* Initializes the different fields to their default values.
*/
private void initDefaults(){
this.mAmount = 0;
setAmount(new BigDecimal(0));
this.mTimestamp = System.currentTimeMillis();
this.mType = TransactionType.DEBIT;
mTransactionUID = UUID.randomUUID().toString();
Expand All @@ -94,16 +114,31 @@ private void initDefaults(){
* Set the amount of this transaction
* @param mAmount Amount of the transaction
*/
public void setAmount(double amount) {
public void setAmount(BigDecimal amount) {
this.mAmount = amount;
mType = amount < 0 ? TransactionType.DEBIT : TransactionType.CREDIT;
this.mAmount.setScale(2, RoundingMode.HALF_EVEN);
mType = amount.doubleValue() < 0 ? TransactionType.DEBIT : TransactionType.CREDIT;
}

/**
* Set the amount of this transaction
* @param mAmount Amount of the transaction
*/
public void setAmount(String amount) {
this.mAmount = new BigDecimal(amount);
this.mAmount = mAmount.setScale(2, RoundingMode.HALF_EVEN);
mType = this.mAmount.doubleValue() < 0 ? TransactionType.DEBIT : TransactionType.CREDIT;
}

public void setAmount(double amount){
setAmount(new BigDecimal(amount));
}

/**
* Returns the amount involved in this transaction
* @return Amount in the transaction
*/
public double getAmount() {
public BigDecimal getAmount() {
return mAmount;
}

Expand Down Expand Up @@ -252,7 +287,7 @@ public Element toXml(Document doc){
transaction.appendChild(dateUser);
*/
Element amount = doc.createElement("TRNAMT");
amount.appendChild(doc.createTextNode(Double.toString(mAmount)));
amount.appendChild(doc.createTextNode(mAmount.toPlainString()));
transactionNode.appendChild(amount);

Element transID = doc.createElement("FITID");
Expand Down
10 changes: 5 additions & 5 deletions GnucashMobile/src/org/gnucash/android/db/DatabaseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DatabaseHelper";

private static final String DATABASE_NAME = "gnucash_db";
private static final int DATABASE_VERSION = 2;
private static final int DATABASE_VERSION = 3;

public static final String ACCOUNTS_TABLE_NAME = "accounts";
public static final String TRANSACTIONS_TABLE_NAME = "transactions";
Expand All @@ -44,7 +44,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
public static final String KEY_UID = "uid";
public static final String KEY_TYPE = "type";

public static final String KEY_AMOUNT = "amount";
public static final String KEY_AMOUNT = "amount";
public static final String KEY_ACCOUNT_UID = "account_uid";
public static final String KEY_DESCRIPTION = "description";
public static final String KEY_TIMESTAMP = "timestamp";
Expand All @@ -64,7 +64,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
+ KEY_UID + " varchar(255) not null, "
+ KEY_NAME + " varchar(255), "
+ KEY_TYPE + " varchar(255) not null, "
+ KEY_AMOUNT + " double not null, "
+ KEY_AMOUNT + " varchar(255) not null, "
+ KEY_DESCRIPTION + " text, "
+ KEY_TIMESTAMP + " integer not null, "
+ KEY_ACCOUNT_UID + " varchar(255) not null, "
Expand All @@ -90,8 +90,8 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ " which will destroy all old data");

if (oldVersion < newVersion){
if (oldVersion == 1 && newVersion == 2){
Log.i("DatabaseHelper", "Upgrading database to version 2");
Log.i("DatabaseHelper", "Upgrading database to version " + newVersion);
if (oldVersion == 1 && newVersion == 2){
String addColumnSql = "ALTER TABLE " + TRANSACTIONS_TABLE_NAME +
" ADD COLUMN " + KEY_EXPORTED + " tinyint default 0";
db.execSQL(addColumnSql);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public TransactionsDbAdapter(Context context) {
public long addTransaction(Transaction transaction){
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.KEY_NAME, transaction.getName());
contentValues.put(DatabaseHelper.KEY_AMOUNT, transaction.getAmount());
contentValues.put(DatabaseHelper.KEY_AMOUNT, transaction.getAmount().toPlainString());
contentValues.put(DatabaseHelper.KEY_TYPE, transaction.getTransactionType().name());
contentValues.put(DatabaseHelper.KEY_UID, transaction.getUID());
contentValues.put(DatabaseHelper.KEY_ACCOUNT_UID, transaction.getAccountUID());
Expand Down Expand Up @@ -168,7 +168,7 @@ public List<Transaction> getAllTransactionsForAccount(String accountUID){
* @return {@link Transaction} object constructed from database record
*/
public Transaction buildTransactionInstance(Cursor c){
Transaction transaction = new Transaction(c.getDouble(DatabaseAdapter.COLUMN_AMOUNT),
Transaction transaction = new Transaction(c.getString(DatabaseAdapter.COLUMN_AMOUNT),
c.getString(DatabaseAdapter.COLUMN_NAME));
transaction.setUID(c.getString(DatabaseAdapter.COLUMN_UID));
transaction.setAccountUID(c.getString(DatabaseAdapter.COLUMN_ACCOUNT_UID));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@

package org.gnucash.android.ui.transactions;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Currency;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;

import org.gnucash.android.R;
import org.gnucash.android.data.Account;
Expand Down Expand Up @@ -88,6 +89,7 @@ public class NewTransactionFragment extends SherlockFragment implements
private ToggleButton mTransactionTypeButton;
private EditText mNameEditText;
private EditText mAmountEditText;
private TextView mCurrencyTextView;
private EditText mDescriptionEditText;
private TextView mDateTextView;
private TextView mTimeTextView;
Expand Down Expand Up @@ -120,7 +122,8 @@ public void onActivityCreated(Bundle savedInstanceState) {
mDescriptionEditText = (EditText)getView().findViewById(R.id.input_description);
mDateTextView = (TextView) v.findViewById(R.id.input_date);
mTimeTextView = (TextView) v.findViewById(R.id.input_time);
mAmountEditText = (EditText) v.findViewById(R.id.input_transaction_amount);
mAmountEditText = (EditText) v.findViewById(R.id.input_transaction_amount);
mCurrencyTextView = (TextView) v.findViewById(R.id.currency_symbol);
mAccountsSpinner = (Spinner) v.findViewById(R.id.input_accounts_spinner);
mTransactionTypeButton = (ToggleButton) v.findViewById(R.id.input_transaction_type);

Expand Down Expand Up @@ -153,8 +156,7 @@ private void initializeViewsWithTransaction(){

mNameEditText.setText(mTransaction.getName());
mTransactionTypeButton.setChecked(mTransaction.getTransactionType() == TransactionType.DEBIT);
//multiply to balance out division by the TextWatcher attached to this view
mAmountEditText.setText(Double.toString(mTransaction.getAmount()));
mAmountEditText.setText(mTransaction.getAmount().toPlainString());
mDescriptionEditText.setText(mTransaction.getDescription());
mDateTextView.setText(DATE_FORMATTER.format(mTransaction.getTimeMillis()));
mTimeTextView.setText(TIME_FORMATTER.format(mTransaction.getTimeMillis()));
Expand All @@ -177,6 +179,7 @@ private void initializeViewsWithTransaction(){
* Binds the various views to the appropriate text
*/
private void initalizeViews() {
// mAmountEditText.setText("0");
Date time = new Date(System.currentTimeMillis());
mDateTextView.setText(DATE_FORMATTER.format(time));
mTimeTextView.setText(TIME_FORMATTER.format(time));
Expand Down Expand Up @@ -207,14 +210,20 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked){
int red = getResources().getColor(R.color.debit_red);
mTransactionTypeButton.setTextColor(red);
mAmountEditText.setTextColor(red);
mAmountEditText.setTextColor(red);
mCurrencyTextView.setTextColor(red);
}
else {
int green = getResources().getColor(R.color.credit_green);
mTransactionTypeButton.setTextColor(green);
mAmountEditText.setTextColor(green);
mCurrencyTextView.setTextColor(green);
}
mAmountEditText.setText(mAmountEditText.getText().toString()); //trigger an edit to update the number sign
String amountText = mAmountEditText.getText().toString();
if (amountText.length() > 0){
BigDecimal decimal = new BigDecimal(amountText);
mAmountEditText.setText(decimal.negate().toPlainString()); //trigger an edit to update the number sign
}
}
});

Expand Down Expand Up @@ -258,8 +267,7 @@ private void saveNewTransaction() {
String name = mNameEditText.getText().toString();
String description = mDescriptionEditText.getText().toString();
String amountString = mAmountEditText.getText().toString();
double amount = Double.parseDouble(stripCurrencyFormatting(amountString))/100;
amount *= mTransactionTypeButton.isChecked() ? -1 : 1; //set negative for debit
BigDecimal amount = new BigDecimal(stripCurrencyFormatting(amountString)).divide(new BigDecimal(100));
Calendar cal = new GregorianCalendar(
mDate.get(Calendar.YEAR),
mDate.get(Calendar.MONTH),
Expand Down Expand Up @@ -341,10 +349,7 @@ public void onTimeSet(TimePicker view, int hourOfDay, int minute) {
}

public static String stripCurrencyFormatting(String s){
String symbol = Currency.getInstance(Locale.getDefault()).getSymbol();
//if in scientific notation, do not remove the period
String regex = s.contains("E") ? "[" + symbol + ",-]" : "[" + symbol + ",.-]";
return s.replaceAll(regex, "");
return s.replace(".", "").replace(",", "");
}

private class ValidationsWatcher implements TextWatcher {
Expand Down Expand Up @@ -376,33 +381,30 @@ private class AmountInputFormatter implements TextWatcher {
private String current = null;

@Override
public void afterTextChanged(Editable s) {
public void afterTextChanged(Editable s) {

String cleanString = stripCurrencyFormatting(s.toString());
if (cleanString.length() == 0)
return;

double parsed = Double.parseDouble(cleanString);


BigDecimal amount = new BigDecimal(cleanString).divide(new BigDecimal(100), 2, RoundingMode.HALF_EVEN);
if (mTransactionTypeButton.isChecked() && amount.doubleValue() > 0)
amount = amount.negate();
DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance();
formatter.setMinimumFractionDigits(2);
formatter.setMaximumFractionDigits(2);
current = formatter.format(amount.doubleValue());
mAmountEditText.removeTextChangedListener(this);

String formattedString = NumberFormat.getCurrencyInstance().format(
(parsed / 100));

String prefix = mTransactionTypeButton.isChecked() ? " - " : "";

current = prefix + formattedString;
mAmountEditText.setText(current);
mAmountEditText.setSelection(current.length());

mAmountEditText.addTextChangedListener(this);

}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// nothing to see here, move along

}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ public void toXml(Document doc, Element parent){


//================= BEGIN ACCOUNT BALANCE INFO =================================
String balance = Double.toString(account.getBalance());
String balance = account.getBalance().toPlainString();
String formattedCurrentTimeString = getFormattedCurrentTime();

Element balanceAmount = doc.createElement("BALAMT");
Expand Down

0 comments on commit 1406471

Please sign in to comment.