Skip to content

Commit 998527c

Browse files
committed
Merge pull request #228 from fefe982/dev-check-multi
Transaction involving multiple currencies cannot be modified. Also add some bug fix to make mutli-currency transactions display correctly. - Rewrite setSplits in Transaction. Now split is not added one by one through addSplit, but the split list is directly assigned. This way the currency information in split is kept. addSplit will reset the currency information. The currency information is used to display the correct currency symbol in split view. - In TransactionFormFragment, when a multi-currency transaction is loaded, every control is disabled except the split edit button. Pressing "save" or changing the account dropdown list on the upper left corner wouldn't change the transaction, an warning is shown instead. Transfer account dropdown is loaded with accounts without the currency restriction, so the correct transfer account can be shown. The split edit button will bring the SplitEditDialogFragment. - In SplitEditDialogFragment, when a multi-currency transaction is loaded, every control in each split is disabled. Pressing the "Add Split" button or "save" button would not change the transaction, a warning is shown instead. Balance in the lower right corner would not be calculated and fixed to zero. The account drop-down for each split is load without the currency restriction, so the correct account can be shown. As currency information for each split is kept (see 1), correct currency symbol is used for each split.
2 parents 0ac4f53 + 5781379 commit 998527c

6 files changed

Lines changed: 130 additions & 35 deletions

File tree

app/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@
325325
</string>
326326
<string name="label_dismiss">Dismiss</string>
327327
<string name="toast_transanction_amount_required">Enter an amount to save the transaction</string>
328+
<string name="toast_error_edit_multi_currency_transaction">Multi-currency transactions cannot be modified</string>
328329
<string name="menu_import_accounts">Import GnuCash Accounts</string>
329330
<string name="btn_import_accounts">Import Accounts</string>
330331
<string name="toast_error_importing_accounts">An error occurred while importing the GnuCash accounts</string>

app/src/org/gnucash/android/db/DatabaseAdapter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ private void createTempView() {
141141
// ) ,
142142
// 2
143143
// ) as trans_acct_a_uid ,
144-
// TOTAL ( CASE WHEN splits_type = 'DEBIT' THEN splits_amount ELSE - splits_amount END ) AS trans_acct_balance
144+
// TOTAL ( CASE WHEN splits_type = 'DEBIT' THEN splits_amount ELSE - splits_amount END ) AS trans_acct_balance,
145+
// COUNT ( DISTINCT accounts_currency ) as trans_currency_count
145146
// FROM trans_split_acct GROUP BY transactions_uid
146147
//
147148
// This temporary view would pick one Account_UID for each

app/src/org/gnucash/android/db/TransactionsDbAdapter.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,4 +597,22 @@ public void scheduleTransaction(Transaction recurringTransaction) {
597597
public Transaction getTransaction(String transactionUID) {
598598
return getTransaction(getID(transactionUID));
599599
}
600+
601+
public int getNumCurrencies(String transactionUID) {
602+
Cursor cursor = mDb.query("trans_extra_info",
603+
new String[]{"trans_currency_count"},
604+
"trans_acct_t_uid=?",
605+
new String[]{transactionUID},
606+
null, null, null);
607+
int numCurrencies = 0;
608+
try {
609+
if (cursor.moveToFirst()) {
610+
numCurrencies = cursor.getInt(0);
611+
}
612+
}
613+
finally {
614+
cursor.close();
615+
}
616+
return numCurrencies;
617+
}
600618
}

app/src/org/gnucash/android/model/Transaction.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,10 +185,7 @@ public List<Split> getSplits(String accountUID){
185185
* @param splitList List of splits for this transaction
186186
*/
187187
public void setSplits(List<Split> splitList){
188-
mSplitList.clear();
189-
for (Split split : splitList) {
190-
addSplit(split);
191-
}
188+
mSplitList = splitList;
192189
}
193190

194191
/**

app/src/org/gnucash/android/ui/transaction/TransactionFormFragment.java

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ public class TransactionFormFragment extends SherlockFragment implements
160160
*/
161161
private boolean mUseDoubleEntry;
162162

163+
/**
164+
* Flag to not if the transaction involves multiple currency
165+
*/
166+
private boolean mMultiCurrency;
167+
163168
/**
164169
* The AccountType of the account to which this transaction belongs.
165170
* Used for determining the accounting rules for credits and debits
@@ -220,9 +225,6 @@ public void onActivityCreated(Bundle savedInstanceState) {
220225
mAccountsDbAdapter = new AccountsDbAdapter(getActivity());
221226
mAccountType = mAccountsDbAdapter.getAccountType(mAccountUID);
222227

223-
//updateTransferAccountsList must only be called after initializing mAccountsDbAdapter
224-
updateTransferAccountsList();
225-
226228
ArrayAdapter<CharSequence> recurrenceAdapter = ArrayAdapter.createFromResource(getActivity(),
227229
R.array.recurrence_period_strings, android.R.layout.simple_spinner_item);
228230
recurrenceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@@ -231,6 +233,13 @@ public void onActivityCreated(Bundle savedInstanceState) {
231233
String transactionUID = getArguments().getString(UxArgument.SELECTED_TRANSACTION_UID);
232234
mTransactionsDbAdapter = new TransactionsDbAdapter(getActivity());
233235
mTransaction = mTransactionsDbAdapter.getTransaction(transactionUID);
236+
if (mTransaction != null) {
237+
mMultiCurrency = mTransactionsDbAdapter.getNumCurrencies(mTransaction.getUID()) > 1;
238+
}
239+
240+
//updateTransferAccountsList must only be called after initializing mAccountsDbAdapter
241+
// it needs mMultiCurrency to be properly initialized
242+
updateTransferAccountsList();
234243

235244
mDoubleAccountSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
236245
@Override
@@ -361,6 +370,23 @@ private void initializeViewsWithTransaction(){
361370
mCurrencyTextView.setText(accountCurrency.getSymbol());
362371

363372
setSelectedRecurrenceOption();
373+
if (mMultiCurrency) {
374+
enableControls(false);
375+
}
376+
}
377+
378+
private void enableControls(boolean b) {
379+
mDescriptionEditText.setEnabled(b);
380+
mNotesEditText.setEnabled(b);
381+
mDateTextView.setEnabled(b);
382+
mTimeTextView.setEnabled(b);
383+
mAmountEditText.setEnabled(b);
384+
mCurrencyTextView.setEnabled(b);
385+
mTransactionTypeButton.setEnabled(b);
386+
mDoubleAccountSpinner.setEnabled(b);
387+
// the next is always enabled, so the user can check the detailed info of splits
388+
// mOpenSplitsButton;
389+
mRecurringTransactionSpinner.setEnabled(b);
364390
}
365391

366392
private void setAmountEditViewVisible(int visibility) {
@@ -426,8 +452,8 @@ private void updateTransferAccountsList(){
426452
String accountUID = ((TransactionsActivity)getActivity()).getCurrentAccountUID();
427453

428454
String conditions = "(" + DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + accountUID
429-
+ "' AND " + DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = '" + mAccountsDbAdapter.getCurrencyCode(accountUID)
430-
+ "' AND " + DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + mAccountsDbAdapter.getGnuCashRootAccountUID()
455+
+ "' AND " + (mMultiCurrency ? "" : (DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = '" + mAccountsDbAdapter.getCurrencyCode(accountUID)
456+
+ "' AND ")) + DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + mAccountsDbAdapter.getGnuCashRootAccountUID()
431457
+ "' AND " + DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + " = 0"
432458
+ ")";
433459

@@ -459,7 +485,7 @@ private void openSplitEditor(){
459485
} else {
460486
Money biggestAmount = Money.createZeroInstance(mTransaction.getCurrencyCode());
461487
for (Split split : mTransaction.getSplits()) {
462-
if (split.getAmount().compareTo(biggestAmount) > 0)
488+
if (split.getAmount().asBigDecimal().compareTo(biggestAmount.asBigDecimal()) > 0)
463489
biggestAmount = split.getAmount();
464490
}
465491
baseAmountString = biggestAmount.toPlainString();
@@ -545,19 +571,23 @@ public void run() {
545571
* Callback when the account in the navigation bar is changed by the user
546572
* @param newAccountId Database record ID of the newly selected account
547573
*/
548-
public void onAccountChanged(long newAccountId){
549-
AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(getActivity());
550-
String currencyCode = accountsDbAdapter.getCurrencyCode(newAccountId);
551-
Currency currency = Currency.getInstance(currencyCode);
552-
mCurrencyTextView.setText(currency.getSymbol(Locale.getDefault()));
574+
public void onAccountChanged(long newAccountId) {
575+
if (mMultiCurrency) {
576+
Toast.makeText(getActivity(), R.string.toast_error_edit_multi_currency_transaction, Toast.LENGTH_LONG).show();
577+
return;
578+
}
579+
AccountsDbAdapter accountsDbAdapter = new AccountsDbAdapter(getActivity());
580+
String currencyCode = accountsDbAdapter.getCurrencyCode(newAccountId);
581+
Currency currency = Currency.getInstance(currencyCode);
582+
mCurrencyTextView.setText(currency.getSymbol(Locale.getDefault()));
553583

554584
mAccountType = accountsDbAdapter.getAccountType(newAccountId);
555585
mTransactionTypeButton.setAccountType(mAccountType);
556586

557-
updateTransferAccountsList();
587+
updateTransferAccountsList();
558588

559589
accountsDbAdapter.close();
560-
}
590+
}
561591

562592
/**
563593
* Collects information from the fragment views and uses it to create
@@ -700,7 +730,11 @@ public boolean onOptionsItemSelected(MenuItem item) {
700730
return true;
701731

702732
case R.id.menu_save:
703-
if (mAmountEditText.getText().length() == 0){
733+
if (mMultiCurrency) {
734+
Toast.makeText(getActivity(), R.string.toast_error_edit_multi_currency_transaction, Toast.LENGTH_LONG).show();
735+
finish();
736+
}
737+
else if (mAmountEditText.getText().length() == 0) {
704738
Toast.makeText(getActivity(), R.string.toast_transanction_amount_required, Toast.LENGTH_SHORT).show();
705739
} else
706740
saveNewTransaction();

app/src/org/gnucash/android/ui/transaction/dialog/SplitEditorDialogFragment.java

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ public class SplitEditorDialogFragment extends DialogFragment {
6868
private BigDecimal mBaseAmount = BigDecimal.ZERO;
6969

7070
private List<String> mRemovedSplitUIDs = new ArrayList<String>();
71+
72+
private boolean mMultiCurrency = false;
7173
/**
7274
* Create and return a new instance of the fragment with the appropriate paramenters
7375
* @param baseAmountString String with base amount which is being split
@@ -102,13 +104,24 @@ public void onActivityCreated(Bundle savedInstanceState) {
102104

103105
getDialog().setTitle("Transaction splits");
104106

105-
initArgs();
106107
mSplitItemViewList = new ArrayList<View>();
107108
mSplitsDbAdapter = new SplitsDbAdapter(getActivity());
108109

109110
//we are editing splits for a new transaction.
110111
// But the user may have already created some splits before. Let's check
111112
List<Split> splitList = ((TransactionFormFragment) getTargetFragment()).getSplitList();
113+
{
114+
Currency currency = null;
115+
for (Split split : splitList) {
116+
if (currency == null) {
117+
currency = split.getAmount().getCurrency();
118+
} else if (currency != split.getAmount().getCurrency()) {
119+
mMultiCurrency = true;
120+
}
121+
}
122+
}
123+
124+
initArgs();
112125
if (!splitList.isEmpty()) {
113126
//aha! there are some splits. Let's load those instead
114127
loadSplitViews(splitList);
@@ -131,6 +144,28 @@ private void loadSplitViews(List<Split> splitList) {
131144
for (Split split : splitList) {
132145
addSplitView(split);
133146
}
147+
if (mMultiCurrency) {
148+
enableAllControls(false);
149+
}
150+
}
151+
152+
private void enableAllControls(boolean b) {
153+
for (View splitView : mSplitItemViewList) {
154+
EditText splitMemoEditText = (EditText) splitView.findViewById(R.id.input_split_memo);
155+
final EditText splitAmountEditText = (EditText) splitView.findViewById(R.id.input_split_amount);
156+
ImageButton removeSplitButton = (ImageButton) splitView.findViewById(R.id.btn_remove_split);
157+
Spinner accountsSpinner = (Spinner) splitView.findViewById(R.id.input_accounts_spinner);
158+
final TextView splitCurrencyTextView = (TextView) splitView.findViewById(R.id.split_currency_symbol);
159+
final TextView splitUidTextView = (TextView) splitView.findViewById(R.id.split_uid);
160+
final TransactionTypeToggleButton splitTypeButton = (TransactionTypeToggleButton) splitView.findViewById(R.id.btn_split_type);
161+
splitMemoEditText.setEnabled(b);
162+
splitAmountEditText.setEnabled(b);
163+
removeSplitButton.setEnabled(b);
164+
accountsSpinner.setEnabled(b);
165+
splitCurrencyTextView.setEnabled(b);
166+
splitUidTextView.setEnabled(b);
167+
splitTypeButton.setEnabled(b);
168+
}
134169
}
135170

136171
/**
@@ -158,8 +193,8 @@ private void initArgs() {
158193
mBaseAmount = new BigDecimal(args.getString(UxArgument.AMOUNT_STRING));
159194

160195
String conditions = "(" //+ AccountEntry._ID + " != " + mAccountId + " AND "
161-
+ DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = '" + mAccountsDbAdapter.getCurrencyCode(mAccountUID)
162-
+ "' AND " + DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + mAccountsDbAdapter.getGnuCashRootAccountUID()
196+
+ (mMultiCurrency ? "" : (DatabaseSchema.AccountEntry.COLUMN_CURRENCY + " = '" + mAccountsDbAdapter.getCurrencyCode(mAccountUID)
197+
+ "' AND ")) + DatabaseSchema.AccountEntry.COLUMN_UID + " != '" + mAccountsDbAdapter.getGnuCashRootAccountUID()
163198
+ "' AND " + DatabaseSchema.AccountEntry.COLUMN_PLACEHOLDER + " = 0"
164199
+ ")";
165200
mCursor = mAccountsDbAdapter.fetchAccountsOrderedByFullName(conditions);
@@ -194,7 +229,7 @@ public void onClick(View view) {
194229
updateTransferAccountsList(accountsSpinner);
195230
accountsSpinner.setOnItemSelectedListener(new TypeButtonLabelUpdater(splitTypeButton));
196231

197-
Currency accountCurrency = Currency.getInstance(mAccountsDbAdapter.getCurrencyCode(mAccountUID));
232+
Currency accountCurrency = Currency.getInstance(mAccountsDbAdapter.getCurrencyCode(split.getAccountUID()));
198233
splitCurrencyTextView.setText(accountCurrency.getSymbol());
199234
splitTypeButton.setAmountFormattingListener(splitAmountEditText, splitCurrencyTextView);
200235
splitTypeButton.setChecked(mBaseAmount.signum() > 0);
@@ -258,17 +293,26 @@ public void onClick(View view) {
258293
mSaveButton.setOnClickListener(new View.OnClickListener() {
259294
@Override
260295
public void onClick(View view) {
261-
List<Split> splitList = extractSplitsFromView();
262-
((TransactionFormFragment) getTargetFragment()).setSplitList(splitList, mRemovedSplitUIDs);
263-
296+
if (mMultiCurrency) {
297+
Toast.makeText(getActivity(), R.string.toast_error_edit_multi_currency_transaction, Toast.LENGTH_LONG).show();
298+
}
299+
else {
300+
List<Split> splitList = extractSplitsFromView();
301+
((TransactionFormFragment) getTargetFragment()).setSplitList(splitList, mRemovedSplitUIDs);
302+
}
264303
dismiss();
265304
}
266305
});
267306

268307
mAddSplit.setOnClickListener(new View.OnClickListener() {
269308
@Override
270309
public void onClick(View view) {
271-
addSplitView(null);
310+
if (mMultiCurrency) {
311+
Toast.makeText(getActivity(), R.string.toast_error_edit_multi_currency_transaction, Toast.LENGTH_LONG).show();
312+
}
313+
else {
314+
addSplitView(null);
315+
}
272316
}
273317
});
274318
}
@@ -307,15 +351,15 @@ private void updateTotal(){
307351
List<Split> splitList = extractSplitsFromView();
308352
String currencyCode = mAccountsDbAdapter.getCurrencyCode(mAccountUID);
309353
Money splitSum = Money.createZeroInstance(currencyCode);
310-
311-
for (Split split : splitList) {
312-
Money amount = split.getAmount().absolute();
313-
if (split.getType() == TransactionType.DEBIT)
314-
splitSum = splitSum.subtract(amount);
315-
else
316-
splitSum = splitSum.add(amount);
354+
if (!mMultiCurrency) {
355+
for (Split split : splitList) {
356+
Money amount = split.getAmount().absolute();
357+
if (split.getType() == TransactionType.DEBIT)
358+
splitSum = splitSum.subtract(amount);
359+
else
360+
splitSum = splitSum.add(amount);
361+
}
317362
}
318-
319363
TransactionsActivity.displayBalance(mImbalanceTextView, splitSum);
320364
}
321365

0 commit comments

Comments
 (0)