Skip to content

Commit dfd54e3

Browse files
committed
Merge branch 'develop'
2 parents bbe3e2d + 7dcb254 commit dfd54e3

File tree

80 files changed

+1200
-6820
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

80 files changed

+1200
-6820
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
Change Log
22
===============================================================================
3+
Version 2.0.2 *(2015-11-20)*
4+
----------------------------
5+
* Fixed: Exporting to external service does not work in some devices
6+
* Fixed: Bar chart does not display negative amounts
7+
* Fixed: Crash when saving transaction with invalid amount expression
8+
* Fixed: Crash when displaying bar chart legend with accounts of same name
9+
* Fixed: Crashes when importing some GnuCash XML files on some devices
10+
* Improved: Remember last export destination
11+
* Improved: Display current imbalance in split editor
12+
* Improved: Set default commodity to the one used by imported file
13+
* Improved: Add support for unlimited fractional digits in commodities
14+
* Improved: Option to select date from which to export transactions
15+
316
Version 2.0.1 *(2015-11-05)*
417
----------------------------
518
* Feature: Menu options for moving/duplicating transactions

app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ apply plugin: 'io.fabric'
55

66
def versionMajor = 2
77
def versionMinor = 0
8-
def versionPatch = 1
9-
def versionBuild = 3
8+
def versionPatch = 2
9+
def versionBuild = 2
1010

1111
def buildTime() {
1212
def df = new SimpleDateFormat("yyyyMMdd HH:mm 'UTC'")

app/src/androidTest/java/org/gnucash/android/test/ui/ExportTransactionsTest.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import static android.support.test.espresso.Espresso.onView;
6262
import static android.support.test.espresso.action.ViewActions.click;
6363
import static android.support.test.espresso.assertion.ViewAssertions.matches;
64+
import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
6465
import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
6566
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
6667
import static android.support.test.espresso.matcher.ViewMatchers.isEnabled;
@@ -69,6 +70,8 @@
6970
import static android.support.test.espresso.matcher.ViewMatchers.withText;
7071
import static org.assertj.core.api.Assertions.assertThat;
7172
import static org.hamcrest.Matchers.allOf;
73+
import static org.hamcrest.Matchers.is;
74+
import static org.hamcrest.Matchers.not;
7275

7376
@RunWith(AndroidJUnit4.class)
7477
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@@ -192,6 +195,11 @@ public void testExport(ExportFormat format){
192195

193196
DrawerActions.openDrawer(R.id.drawer_layout);
194197
onView(withText(R.string.nav_menu_export)).perform(click());
198+
199+
onView(withId(R.id.spinner_export_destination)).perform(click());
200+
String[] destinations = getActivity().getResources().getStringArray(R.array.export_destinations);
201+
202+
onView(withText(destinations[0])).perform(click());
195203
onView(withText(format.name())).perform(click());
196204

197205
onView(withId(R.id.menu_save)).perform(click());
@@ -243,6 +251,26 @@ public void testShouldCreateExportSchedule(){
243251
assertThat(action.getEndTime()).isEqualTo(0);
244252
}
245253

254+
@Test
255+
public void testCreateBackup(){
256+
DrawerActions.openDrawer(R.id.drawer_layout);
257+
onView(withText(R.string.title_settings)).perform(click());
258+
onView(withText(R.string.header_backup_and_export_settings)).perform(click());
259+
260+
onView(withText(R.string.title_create_backup_pref)).perform(click());
261+
assertToastDisplayed(R.string.toast_backup_successful);
262+
}
263+
264+
/**
265+
* Checks that a specific toast message is displayed
266+
* @param toastString String that should be displayed
267+
*/
268+
private void assertToastDisplayed(int toastString) {
269+
onView(withText(toastString))
270+
.inRoot(withDecorView(not(is(getActivity().getWindow().getDecorView()))))
271+
.check(matches(isDisplayed()));
272+
}
273+
246274
//todo: add testing of export flag to unit test
247275
//todo: add test of ignore exported transactions to unit tests
248276
@Override

app/src/main/java/org/gnucash/android/app/GnuCashApplication.java

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import android.database.sqlite.SQLiteDatabase;
2626
import android.graphics.Color;
2727
import android.preference.PreferenceManager;
28+
import android.support.annotation.NonNull;
2829
import android.util.Log;
2930

3031
import com.crashlytics.android.Crashlytics;
@@ -41,6 +42,7 @@
4142
import org.gnucash.android.db.SplitsDbAdapter;
4243
import org.gnucash.android.db.TransactionsDbAdapter;
4344
import org.gnucash.android.model.Commodity;
45+
import org.gnucash.android.model.Money;
4446
import org.gnucash.android.service.SchedulerService;
4547

4648
import java.util.Currency;
@@ -124,7 +126,7 @@ public void onCreate(){
124126
mCommoditiesDbAdapter = new CommoditiesDbAdapter(mDb);
125127
mPricesDbAdapter = new PricesDbAdapter(mDb);
126128

127-
Commodity.DEFAULT_COMMODITY = mCommoditiesDbAdapter.getCommodity(getDefaultCurrencyCode());
129+
setDefaultCurrencyCode(getDefaultCurrencyCode());
128130
}
129131

130132
public static AccountsDbAdapter getAccountsDbAdapter() {
@@ -216,12 +218,21 @@ public static String getDefaultCurrencyCode(){
216218
}
217219

218220
/**
219-
* Returns the default commodity
220-
* @return Default commodity of application
221+
* Sets the default currency for the application in all relevant places:
222+
* <ul>
223+
* <li>Shared preferences</li>
224+
* <li>{@link Money#DEFAULT_CURRENCY_CODE}</li>
225+
* <li>{@link Commodity#DEFAULT_COMMODITY}</li>
226+
* </ul>
227+
* @param currencyCode ISO 4217 currency code
221228
* @see #getDefaultCurrencyCode()
222229
*/
223-
public static Commodity getDefaultCommodity(){
224-
return Commodity.DEFAULT_COMMODITY;
230+
public static void setDefaultCurrencyCode(@NonNull String currencyCode){
231+
PreferenceManager.getDefaultSharedPreferences(getAppContext()).edit()
232+
.putString(getAppContext().getString(R.string.key_default_currency), currencyCode)
233+
.apply();
234+
Money.DEFAULT_CURRENCY_CODE = currencyCode;
235+
Commodity.DEFAULT_COMMODITY = mCommoditiesDbAdapter.getCommodity(currencyCode);
225236
}
226237

227238
/**

app/src/main/java/org/gnucash/android/db/AccountsDbAdapter.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.gnucash.android.model.TransactionType;
4040

4141
import java.math.BigDecimal;
42+
import java.sql.Timestamp;
4243
import java.util.ArrayList;
4344
import java.util.Currency;
4445
import java.util.HashMap;
@@ -503,12 +504,11 @@ public List<Account> getSimpleAccountList(String where, String[] whereArgs, Stri
503504
}
504505
/**
505506
* Returns a list of accounts which have transactions that have not been exported yet
507+
* @param lastExportTimeStamp Timestamp after which to any transactions created/modified should be exported
506508
* @return List of {@link Account}s with unexported transactions
507-
* @deprecated This uses the exported flag in the database which is no longer supported.
508509
*/
509-
@Deprecated
510-
public List<Account> getExportableAccounts(){
511-
LinkedList<Account> accountsList = new LinkedList<Account>();
510+
public List<Account> getExportableAccounts(Timestamp lastExportTimeStamp){
511+
LinkedList<Account> accountsList = new LinkedList<>();
512512
Cursor cursor = mDb.query(
513513
TransactionEntry.TABLE_NAME + " , " + SplitEntry.TABLE_NAME +
514514
" ON " + TransactionEntry.TABLE_NAME + "." + TransactionEntry.COLUMN_UID + " = " +
@@ -517,8 +517,8 @@ public List<Account> getExportableAccounts(){
517517
AccountEntry.COLUMN_UID + " = " + SplitEntry.TABLE_NAME + "." +
518518
SplitEntry.COLUMN_ACCOUNT_UID,
519519
new String[]{AccountEntry.TABLE_NAME + ".*"},
520-
TransactionEntry.TABLE_NAME + "." + TransactionEntry.COLUMN_EXPORTED + " == 0",
521-
null,
520+
TransactionEntry.TABLE_NAME + "." + TransactionEntry.COLUMN_MODIFIED_AT + " > ?",
521+
new String[]{lastExportTimeStamp.toString()},
522522
AccountEntry.TABLE_NAME + "." + AccountEntry.COLUMN_UID,
523523
null,
524524
null
@@ -787,23 +787,24 @@ private Money computeBalance(String accountUID, long startTimestamp, long endTim
787787
}
788788

789789
/**
790-
* Returns the absolute balance of account list within the specified time range while taking sub-accounts
791-
* into consideration. The default currency takes as base currency.
790+
* Returns the balance of account list within the specified time range. The default currency
791+
* takes as base currency.
792792
* @param accountUIDList list of account UIDs
793793
* @param startTimestamp the start timestamp of the time range
794794
* @param endTimestamp the end timestamp of the time range
795-
* @return the absolute balance of account list
795+
* @return Money balance of account list
796796
*/
797797
public Money getAccountsBalance(List<String> accountUIDList, long startTimestamp, long endTimestamp) {
798798
String currencyCode = GnuCashApplication.getDefaultCurrencyCode();
799799
Money balance = Money.createZeroInstance(currencyCode);
800+
boolean hasDebitNormalBalance = getAccountType(accountUIDList.get(0)).hasDebitNormalBalance();
800801

801802
SplitsDbAdapter splitsDbAdapter = SplitsDbAdapter.getInstance();
802803
Money splitSum = (startTimestamp == -1 && endTimestamp == -1)
803-
? splitsDbAdapter.computeSplitBalance(accountUIDList, currencyCode, true)
804-
: splitsDbAdapter.computeSplitBalance(accountUIDList, currencyCode, true, startTimestamp, endTimestamp);
804+
? splitsDbAdapter.computeSplitBalance(accountUIDList, currencyCode, hasDebitNormalBalance)
805+
: splitsDbAdapter.computeSplitBalance(accountUIDList, currencyCode, hasDebitNormalBalance, startTimestamp, endTimestamp);
805806

806-
return balance.add(splitSum).absolute();
807+
return balance.add(splitSum);
807808
}
808809

809810
/**

app/src/main/java/org/gnucash/android/db/DatabaseHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion){
212212
/*
213213
* NOTE: In order to modify the database, create a new static method in the MigrationHelper class
214214
* called upgradeDbToVersion<#>, e.g. int upgradeDbToVersion10(SQLiteDatabase) in order to upgrade to version 10.
215-
* The upgrade method should return the current database version as the return value.
216-
* Then all you need to do is incremend the DatabaseSchema.DATABASE_VERSION to the appropriate number.
215+
* The upgrade method should return the upgraded database version as the return value.
216+
* Then all you need to do is increment the DatabaseSchema.DATABASE_VERSION to the appropriate number.
217217
*/
218218
if (oldVersion > newVersion) {
219219
throw new IllegalArgumentException("Database downgrades are not supported at the moment");

app/src/main/java/org/gnucash/android/db/DatabaseSchema.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class DatabaseSchema {
2828
* Database version.
2929
* With any change to the database schema, this number must increase
3030
*/
31-
public static final int DATABASE_VERSION = 9;
31+
public static final int DATABASE_VERSION = 11;
3232

3333
/**
3434
* Database version where Splits were introduced

app/src/main/java/org/gnucash/android/db/MigrationHelper.java

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,23 @@
2424
import android.database.Cursor;
2525
import android.database.sqlite.SQLiteDatabase;
2626
import android.os.Environment;
27+
import android.preference.PreferenceManager;
2728
import android.text.TextUtils;
2829
import android.util.Log;
2930

3031
import com.crashlytics.android.Crashlytics;
3132

3233
import org.gnucash.android.R;
3334
import org.gnucash.android.app.GnuCashApplication;
35+
import org.gnucash.android.export.ExportFormat;
36+
import org.gnucash.android.export.ExportParams;
3437
import org.gnucash.android.export.Exporter;
3538
import org.gnucash.android.importer.CommoditiesXmlHandler;
3639
import org.gnucash.android.model.AccountType;
3740
import org.gnucash.android.model.BaseModel;
3841
import org.gnucash.android.model.Commodity;
3942
import org.gnucash.android.model.Money;
43+
import org.gnucash.android.model.ScheduledAction;
4044
import org.gnucash.android.model.Transaction;
4145
import org.xml.sax.InputSource;
4246
import org.xml.sax.SAXException;
@@ -52,7 +56,9 @@
5256
import java.nio.channels.FileChannel;
5357
import java.sql.Timestamp;
5458
import java.util.ArrayList;
59+
import java.util.HashMap;
5560
import java.util.List;
61+
import java.util.Map;
5662

5763
import javax.xml.parsers.ParserConfigurationException;
5864
import javax.xml.parsers.SAXParser;
@@ -1058,4 +1064,110 @@ static int upgradeDbToVersion9(SQLiteDatabase db){
10581064
}
10591065
return oldVersion;
10601066
}
1067+
1068+
/**
1069+
* Upgrades the database to version 10
1070+
* <p>This method converts all saved scheduled export parameters to the new format using the
1071+
* timestamp of last export</p>
1072+
* @param db SQLite database
1073+
* @return 10 if upgrade was successful, 9 otherwise
1074+
*/
1075+
static int upgradeDbToVersion10(SQLiteDatabase db){
1076+
Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 9");
1077+
int oldVersion = 9;
1078+
1079+
db.beginTransaction();
1080+
try {
1081+
Cursor cursor = db.query(ScheduledActionEntry.TABLE_NAME,
1082+
new String[]{ScheduledActionEntry.COLUMN_UID, ScheduledActionEntry.COLUMN_TAG},
1083+
ScheduledActionEntry.COLUMN_TYPE + " = ?",
1084+
new String[]{ScheduledAction.ActionType.BACKUP.name()},
1085+
null, null, null);
1086+
1087+
ContentValues contentValues = new ContentValues();
1088+
while (cursor.moveToNext()){
1089+
String paramString = cursor.getString(cursor.getColumnIndexOrThrow(ScheduledActionEntry.COLUMN_TAG));
1090+
String[] tokens = paramString.split(";");
1091+
ExportParams params = new ExportParams(ExportFormat.valueOf(tokens[0]));
1092+
params.setExportTarget(ExportParams.ExportTarget.valueOf(tokens[1]));
1093+
params.setDeleteTransactionsAfterExport(Boolean.parseBoolean(tokens[3]));
1094+
1095+
boolean exportAll = Boolean.parseBoolean(tokens[2]);
1096+
if (exportAll){
1097+
params.setExportStartTime(Timestamp.valueOf(Exporter.TIMESTAMP_ZERO));
1098+
} else {
1099+
String lastExportTimeStamp = PreferenceManager.getDefaultSharedPreferences(GnuCashApplication.getAppContext())
1100+
.getString(Exporter.PREF_LAST_EXPORT_TIME, Exporter.TIMESTAMP_ZERO);
1101+
Timestamp timestamp = Timestamp.valueOf(lastExportTimeStamp);
1102+
params.setExportStartTime(timestamp);
1103+
}
1104+
1105+
String uid = cursor.getString(cursor.getColumnIndexOrThrow(ScheduledActionEntry.COLUMN_UID));
1106+
contentValues.clear();
1107+
contentValues.put(ScheduledActionEntry.COLUMN_UID, uid);
1108+
contentValues.put(ScheduledActionEntry.COLUMN_TAG, params.toCsv());
1109+
db.insert(ScheduledActionEntry.TABLE_NAME, null, contentValues);
1110+
}
1111+
1112+
cursor.close();
1113+
1114+
db.setTransactionSuccessful();
1115+
oldVersion = 10;
1116+
} finally {
1117+
db.endTransaction();
1118+
}
1119+
return oldVersion;
1120+
}
1121+
1122+
/**
1123+
* Upgrade database to version 11
1124+
* <p>
1125+
* Migrate scheduled backups and update export parameters to the new format
1126+
* </p>
1127+
* @param db SQLite database
1128+
* @return 11 if upgrade was successful, 10 otherwise
1129+
*/
1130+
static int upgradeDbToVersion11(SQLiteDatabase db){
1131+
Log.i(DatabaseHelper.LOG_TAG, "Upgrading database to version 9");
1132+
int oldVersion = 10;
1133+
1134+
db.beginTransaction();
1135+
try {
1136+
Cursor cursor = db.query(ScheduledActionEntry.TABLE_NAME, null,
1137+
ScheduledActionEntry.COLUMN_TYPE + "= ?",
1138+
new String[]{ScheduledAction.ActionType.BACKUP.name()}, null, null, null);
1139+
1140+
Map<String, String> uidToTagMap = new HashMap<>();
1141+
while (cursor.moveToNext()) {
1142+
String uid = cursor.getString(cursor.getColumnIndexOrThrow(ScheduledActionEntry.COLUMN_UID));
1143+
String tag = cursor.getString(cursor.getColumnIndexOrThrow(ScheduledActionEntry.COLUMN_TAG));
1144+
String[] tokens = tag.split(";");
1145+
try {
1146+
Timestamp timestamp = Timestamp.valueOf(tokens[2]);
1147+
} catch (IllegalArgumentException ex) {
1148+
tokens[2] = PreferenceManager.getDefaultSharedPreferences(GnuCashApplication.getAppContext())
1149+
.getString(Exporter.PREF_LAST_EXPORT_TIME, Exporter.TIMESTAMP_ZERO);
1150+
} finally {
1151+
tag = TextUtils.join(";", tokens);
1152+
}
1153+
uidToTagMap.put(uid, tag);
1154+
}
1155+
1156+
cursor.close();
1157+
1158+
ContentValues contentValues = new ContentValues();
1159+
for (Map.Entry<String, String> entry : uidToTagMap.entrySet()) {
1160+
contentValues.clear();
1161+
contentValues.put(ScheduledActionEntry.COLUMN_TAG, entry.getValue());
1162+
db.update(ScheduledActionEntry.TABLE_NAME, contentValues,
1163+
ScheduledActionEntry.COLUMN_UID + " = ?", new String[]{entry.getKey()});
1164+
}
1165+
1166+
db.setTransactionSuccessful();
1167+
oldVersion = 11;
1168+
} finally {
1169+
db.endTransaction();
1170+
}
1171+
return oldVersion;
1172+
}
10611173
}

0 commit comments

Comments
 (0)