diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b75cde53..5bcbc16ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ Change Log =============================================================================== +Version 1.6.2 *(2015-07-16)* +---------------------------- +* Fixed: Editing accounts causing the account's transactions to be deleted + Version 1.6.1 *(2015-07-08)* ---------------------------- * Fixed: Crash when importing some scheduled transations with custom period strings diff --git a/app/build.gradle b/app/build.gradle index e13248646..3488837fc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'crashlytics' def versionMajor = 1 def versionMinor = 6 -def versionPatch = 1 +def versionPatch = 2 def versionBuild = 0 def buildTime() { diff --git a/app/src/androidTest/java/org/gnucash/android/test/ui/AccountsActivityTest.java b/app/src/androidTest/java/org/gnucash/android/test/ui/AccountsActivityTest.java index 618310d49..57df65076 100644 --- a/app/src/androidTest/java/org/gnucash/android/test/ui/AccountsActivityTest.java +++ b/app/src/androidTest/java/org/gnucash/android/test/ui/AccountsActivityTest.java @@ -37,6 +37,8 @@ import org.gnucash.android.model.Account; import org.gnucash.android.model.AccountType; import org.gnucash.android.model.Money; +import org.gnucash.android.model.Split; +import org.gnucash.android.model.Transaction; import org.gnucash.android.receivers.AccountCreator; import org.gnucash.android.ui.account.AccountsActivity; import org.gnucash.android.ui.account.AccountsListFragment; @@ -45,6 +47,7 @@ import org.junit.Test; import org.junit.runner.RunWith; +import java.math.BigDecimal; import java.util.Currency; import java.util.List; @@ -71,6 +74,7 @@ @RunWith(AndroidJUnit4.class) public class AccountsActivityTest extends ActivityInstrumentationTestCase2 { private static final String DUMMY_ACCOUNT_CURRENCY_CODE = "USD"; + private static final Currency DUMMY_ACCOUNT_CURRENCY = Currency.getInstance(DUMMY_ACCOUNT_CURRENCY_CODE); private static final String DUMMY_ACCOUNT_NAME = "Dummy account"; public static final String DUMMY_ACCOUNT_UID = "dummy-account"; private DatabaseHelper mDbHelper; @@ -226,7 +230,7 @@ public void testChangeParentAccount() { */ @Test public void shouldHideParentAccountViewWhenNoParentsExist(){ - onView(withText(DUMMY_ACCOUNT_NAME)).perform(click()); + onView(allOf(withText(DUMMY_ACCOUNT_NAME), isDisplayed())).perform(click()); onView(withId(R.id.fragment_transaction_list)).perform(swipeRight()); onView(withText(R.string.label_create_account)).check(matches(isDisplayed())).perform(click()); sleep(1000); @@ -264,6 +268,31 @@ public void testEditAccount(){ assertThat(latest.getCurrency().getCurrencyCode()).isEqualTo(DUMMY_ACCOUNT_CURRENCY_CODE); } + @Test + public void editingAccountShouldNotDeleteTransactions(){ + onView(allOf(withText(DUMMY_ACCOUNT_NAME), isDisplayed())) + .perform(longClick()); + Account account = new Account("Transfer Account"); + + Transaction transaction = new Transaction("Simple trxn"); + Split split = new Split(new Money(BigDecimal.TEN, DUMMY_ACCOUNT_CURRENCY), account.getUID()); + transaction.addSplit(split); + transaction.addSplit(split.createPair(DUMMY_ACCOUNT_UID)); + account.addTransaction(transaction); + mAccountsDbAdapter.addAccount(account); + + assertThat(mAccountsDbAdapter.getAccount(DUMMY_ACCOUNT_UID).getTransactionCount()).isEqualTo(1); + assertThat(mSplitsDbAdapter.getSplitsForTransaction(transaction.getUID())).hasSize(2); + + onView(withId(R.id.context_menu_edit_accounts)).perform(click()); + + onView(withId(R.id.menu_save)).perform(click()); + assertThat(mAccountsDbAdapter.getAccount(DUMMY_ACCOUNT_UID).getTransactionCount()).isEqualTo(1); + assertThat(mSplitsDbAdapter.fetchSplitsForAccount(DUMMY_ACCOUNT_UID).getCount()).isEqualTo(1); + assertThat(mSplitsDbAdapter.getSplitsForTransaction(transaction.getUID())).hasSize(2); + + } + /** * Sleep the thread for a specified period * @param millis Duration to sleep in milliseconds diff --git a/app/src/main/java/org/gnucash/android/app/GnuCashApplication.java b/app/src/main/java/org/gnucash/android/app/GnuCashApplication.java index 247296f55..d7bf90819 100644 --- a/app/src/main/java/org/gnucash/android/app/GnuCashApplication.java +++ b/app/src/main/java/org/gnucash/android/app/GnuCashApplication.java @@ -159,16 +159,7 @@ public static boolean shouldSaveOpeningBalances(boolean defaultValue){ * @return Default currency code string for the application */ public static String getDefaultCurrencyCode(){ - Locale locale = Locale.getDefault(); - //sometimes the locale en_UK is returned which causes a crash with Currency - if (locale.getCountry().equals("UK")) { - locale = new Locale(locale.getLanguage(), "GB"); - } - - //for unsupported locale es_LG - if (locale.getCountry().equals("LG")){ - locale = new Locale(locale.getLanguage(), "ES"); - } + Locale locale = getDefaultLocale(); String currencyCode = "USD"; //start with USD as the default SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); @@ -183,6 +174,29 @@ public static String getDefaultCurrencyCode(){ return currencyCode; } + /** + * Returns the default locale which is used for currencies, while handling special cases for + * locales which are not supported for currency such as en_GB + * @return The default locale for this device + */ + public static Locale getDefaultLocale() { + Locale locale = Locale.getDefault(); + //sometimes the locale en_UK is returned which causes a crash with Currency + if (locale.getCountry().equals("UK")) { + locale = new Locale(locale.getLanguage(), "GB"); + } + + //for unsupported locale es_LG + if (locale.getCountry().equals("LG")){ + locale = new Locale(locale.getLanguage(), "ES"); + } + + if (locale.getCountry().equals("en")){ + locale = Locale.US; + } + return locale; + } + /** * Starts the service for scheduled events and schedules an alarm to call the service twice daily. *

If the alarm already exists, this method does nothing. If not, the alarm will be created diff --git a/app/src/main/java/org/gnucash/android/db/AccountsDbAdapter.java b/app/src/main/java/org/gnucash/android/db/AccountsDbAdapter.java index 8b2d7f87f..d536727eb 100644 --- a/app/src/main/java/org/gnucash/android/db/AccountsDbAdapter.java +++ b/app/src/main/java/org/gnucash/android/db/AccountsDbAdapter.java @@ -148,6 +148,7 @@ public long addAccount(Account account){ * @return number of rows inserted */ public long bulkAddAccounts(List accountList){ + List transactionList = new ArrayList<>(accountList.size()*2); long nRow = 0; try { mDb.beginTransaction(); @@ -187,12 +188,17 @@ public long bulkAddAccounts(List accountList){ //Log.d(LOG_TAG, "Replacing account in db"); replaceStatement.execute(); nRow ++; + transactionList.addAll(account.getTransactions()); } mDb.setTransactionSuccessful(); } finally { mDb.endTransaction(); } + + if (nRow > 0 && !transactionList.isEmpty()){ + mTransactionsAdapter.bulkAddTransactions(transactionList); + } return nRow; } /** diff --git a/app/src/main/java/org/gnucash/android/model/Money.java b/app/src/main/java/org/gnucash/android/model/Money.java index 340bf5415..7013dd309 100644 --- a/app/src/main/java/org/gnucash/android/model/Money.java +++ b/app/src/main/java/org/gnucash/android/model/Money.java @@ -92,14 +92,18 @@ public final class Money implements Comparable{ * A zero instance with the currency of the default locale. * This can be used anywhere where a starting amount is required without having to create a new object */ - private static final Money sDefaultZero = Money.createZeroInstance(GnuCashApplication.getDefaultCurrencyCode()); + private static Money sDefaultZero; /** * Returns a Money instance initialized to the local currency and value 0 * @return Money instance of value 0 in locale currency */ public static Money getZeroInstance(){ - return sDefaultZero; + if (sDefaultZero == null) { + String currencyCode = Currency.getInstance(GnuCashApplication.getDefaultLocale()).getCurrencyCode(); + sDefaultZero = new Money(BigDecimal.ZERO, Currency.getInstance(currencyCode)); + } + return sDefaultZero; } /** @@ -180,7 +184,7 @@ public static Money createZeroInstance(String currencyCode){ */ private void init() { mCurrency = Currency.getInstance(Money.DEFAULT_CURRENCY_CODE); - mAmount = new BigDecimal(0).setScale(DEFAULT_DECIMAL_PLACES, DEFAULT_ROUNDING_MODE); + mAmount = BigDecimal.ZERO.setScale(DEFAULT_DECIMAL_PLACES, DEFAULT_ROUNDING_MODE); } /** diff --git a/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java b/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java index 257cec3b4..5d583bdd9 100644 --- a/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java +++ b/app/src/main/java/org/gnucash/android/ui/account/AccountFormFragment.java @@ -30,6 +30,7 @@ import android.support.v4.app.FragmentManager; import android.support.v4.widget.SimpleCursorAdapter; import android.text.TextUtils; +import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -701,8 +702,9 @@ public void onDestroy() { * Reads the fields from the account form and saves as a new account */ private void saveAccount() { + Log.i("AccountFormFragment", "Saving account"); // accounts to update, in case we're updating full names of a sub account tree - ArrayList accountsToUpdate = new ArrayList(); + ArrayList accountsToUpdate = new ArrayList<>(); boolean nameChanged = false; if (mAccount == null){ String name = getEnteredName(); diff --git a/app/src/test/java/org/gnucash/android/test/unit/db/AccountsDbAdapterTest.java b/app/src/test/java/org/gnucash/android/test/unit/db/AccountsDbAdapterTest.java index 2e548558d..fc5d33e78 100644 --- a/app/src/test/java/org/gnucash/android/test/unit/db/AccountsDbAdapterTest.java +++ b/app/src/test/java/org/gnucash/android/test/unit/db/AccountsDbAdapterTest.java @@ -22,6 +22,7 @@ import org.robolectric.annotation.Config; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Currency; import java.util.List; @@ -64,6 +65,30 @@ public void shouldBeAlphabeticallySortedByDefault(){ assertThat(accountsList).contains(second, Index.atIndex(1)); } + @Test + public void bulkAddAccountsShouldNotModifyTransactions(){ + Account account1 = new Account("AlphaAccount"); + Account account2 = new Account("BetaAccount"); + Transaction transaction = new Transaction("MyTransaction"); + Split split = new Split(Money.getZeroInstance(), account1.getUID()); + transaction.addSplit(split); + transaction.addSplit(split.createPair(account2.getUID())); + account1.addTransaction(transaction); + account2.addTransaction(transaction); + + List accounts = new ArrayList<>(); + accounts.add(account1); + accounts.add(account2); + + mAccountsDbAdapter.bulkAddAccounts(accounts); + + SplitsDbAdapter splitsDbAdapter = SplitsDbAdapter.getInstance(); + assertThat(splitsDbAdapter.getSplitsForTransactionInAccount(transaction.getUID(), account1.getUID())).hasSize(1); + assertThat(splitsDbAdapter.getSplitsForTransactionInAccount(transaction.getUID(), account2.getUID())).hasSize(1); + + assertThat(mAccountsDbAdapter.getAccount(account1.getUID()).getTransactions()).hasSize(1); + } + @Test public void shouldAddAccountsToDatabase(){ Account account1 = new Account("AlphaAccount"); diff --git a/app/src/test/java/org/gnucash/android/test/unit/util/GnucashTestRunner.java b/app/src/test/java/org/gnucash/android/test/unit/util/GnucashTestRunner.java index 46064551a..c5dc5e017 100644 --- a/app/src/test/java/org/gnucash/android/test/unit/util/GnucashTestRunner.java +++ b/app/src/test/java/org/gnucash/android/test/unit/util/GnucashTestRunner.java @@ -2,9 +2,11 @@ import org.junit.runners.model.InitializationError; import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.annotation.Config; import org.robolectric.internal.bytecode.ClassInfo; import org.robolectric.internal.bytecode.InstrumentingClassLoaderConfig; import org.robolectric.internal.bytecode.ShadowMap; +import org.robolectric.manifest.AndroidManifest; import java.util.Arrays; import java.util.Collections; @@ -29,6 +31,11 @@ protected ShadowMap createShadowMap() { .newBuilder().addShadowClass(ShadowCrashlytics.class).build(); } + @Override + protected AndroidManifest getAppManifest(Config config) { + return super.getAppManifest(config); + } + @Override public InstrumentingClassLoaderConfig createSetup() { return new InstrumenterConfig();