-
Notifications
You must be signed in to change notification settings - Fork 539
Commit
…ause inconsistency in the split value and quantity Splits now implement Parcelable - easing passing of data between TransactionForm and SplitEditor Update the transaction UID of all splits whenever the UID of a transaction is set Add tests for multi-currency transaction creation and editing - fixes #506 - closes #524
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -191,10 +191,13 @@ public void testAddTransactionShouldRequireAmount(){ | |
.check(matches(isDisplayed())) | ||
.perform(typeText("Lunch")); | ||
|
||
onView(withId(R.id.menu_save)).perform(click()); | ||
Espresso.closeSoftKeyboard(); | ||
|
||
onView(withId(R.id.menu_save)) | ||
.check(matches(isDisplayed())) | ||
.perform(click()); | ||
onView(withText(R.string.title_add_transaction)).check(matches(isDisplayed())); | ||
|
||
Espresso.closeSoftKeyboard(); | ||
sleep(1000); | ||
|
||
assertToastDisplayed(R.string.toast_transanction_amount_required); | ||
|
@@ -294,7 +297,9 @@ public void testAddMultiCurrencyTransaction(){ | |
Espresso.pressBack(); //close calculator keyboard | ||
|
||
onView(withId(R.id.input_transfer_account_spinner)).perform(click()); | ||
onView(withText(euroAccount.getFullName())).check(matches(isDisplayed())).perform(click()); | ||
onView(withText(euroAccount.getFullName())) | ||
.check(matches(isDisplayed())) | ||
.perform(click()); | ||
|
||
This comment has been minimized.
Sorry, something went wrong. |
||
onView(withId(R.id.menu_save)).perform(click()); | ||
|
||
|
@@ -309,7 +314,7 @@ public void testAddMultiCurrencyTransaction(){ | |
List<Transaction> allTransactions = mTransactionsDbAdapter.getAllTransactionsForAccount(TRANSACTIONS_ACCOUNT_UID); | ||
assertThat(allTransactions).hasSize(transactionCount+1); | ||
Transaction multiTrans = allTransactions.get(0); | ||
|
||
assertThat(multiTrans.getSplits()).hasSize(2); | ||
assertThat(multiTrans.getSplits()).extracting("mAccountUID") | ||
.contains(TRANSACTIONS_ACCOUNT_UID) | ||
.contains(euroAccount.getUID()); | ||
|
@@ -339,7 +344,15 @@ public void testEditTransaction(){ | |
|
||
Transaction editedTransaction = mTransactionsDbAdapter.getRecord(mTransaction.getUID()); | ||
assertThat(editedTransaction.getDescription()).isEqualTo(trnName); | ||
assertThat(editedTransaction.getSplits()).isEqualTo(mTransaction.getSplits()); | ||
assertThat(editedTransaction.getSplits()).hasSize(2); | ||
|
||
Split split = mTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0); | ||
Split editedSplit = editedTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0); | ||
assertThat(split.isEquivalentTo(editedSplit)).isTrue(); | ||
|
||
split = mTransaction.getSplits(TRANSFER_ACCOUNT_UID).get(0); | ||
editedSplit = editedTransaction.getSplits(TRANSFER_ACCOUNT_UID).get(0); | ||
assertThat(split.isEquivalentTo(editedSplit)).isTrue(); | ||
} | ||
This comment has been minimized.
Sorry, something went wrong.
rivaldi8
Collaborator
|
||
|
||
/** | ||
|
@@ -403,8 +416,7 @@ public void testSplitEditor(){ | |
|
||
onView(withId(R.id.split_list_layout)).check(matches(allOf(isDisplayed(), hasDescendant(withId(R.id.input_split_amount))))); | ||
|
||
onView(withId(R.id.menu_add_split)).perform(click()); | ||
|
||
onView(allOf(withId(R.id.input_split_amount), withText("-499"))).perform(clearText()); | ||
onView(allOf(withId(R.id.input_split_amount), withText(""))).perform(typeText("400")); | ||
|
||
onView(withId(R.id.menu_save)).perform(click()); | ||
|
@@ -798,9 +810,9 @@ public void editingTransferAccount_shouldKeepSplitAmountsConsistent() { | |
String trnDescription = "Multicurrency Test Trn"; | ||
Transaction multiTransaction = new Transaction(trnDescription); | ||
Split split1 = new Split(expectedValue, TRANSACTIONS_ACCOUNT_UID); | ||
split1.setType(TransactionType.DEBIT); | ||
split1.setType(TransactionType.CREDIT); | ||
Split split2 = new Split(expectedValue, expectedQty, euroAccount.getUID()); | ||
split2.setType(TransactionType.CREDIT); | ||
split2.setType(TransactionType.DEBIT); | ||
multiTransaction.addSplit(split1); | ||
multiTransaction.addSplit(split2); | ||
multiTransaction.setCommodity(COMMODITY); | ||
|
@@ -811,6 +823,10 @@ public void editingTransferAccount_shouldKeepSplitAmountsConsistent() { | |
assertThat(savedTransaction.getSplits()).extracting("mQuantity").contains(expectedQty); | ||
assertThat(savedTransaction.getSplits()).extracting("mValue").contains(expectedValue); | ||
|
||
assertThat(savedTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0) | ||
.isEquivalentTo(multiTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0))) | ||
.isTrue(); | ||
|
||
refreshTransactionsList(); | ||
|
||
//open transaction for editing | ||
|
@@ -832,10 +848,17 @@ public void editingTransferAccount_shouldKeepSplitAmountsConsistent() { | |
|
||
onView(withId(R.id.menu_save)).perform(click()); | ||
|
||
Transaction editedTransaction = mTransactionsDbAdapter.getRecord(multiTransaction.getUID()); | ||
assertThat(editedTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0) | ||
.isEquivalentTo(savedTransaction.getSplits(TRANSACTIONS_ACCOUNT_UID).get(0))) | ||
.isTrue(); | ||
|
||
Money firstAcctBalance = mAccountsDbAdapter.getAccountBalance(TRANSACTIONS_ACCOUNT_UID); | ||
assertThat(firstAcctBalance).isEqualTo(editedTransaction.getBalance(TRANSACTIONS_ACCOUNT_UID)); | ||
|
||
Money transferBalance = mAccountsDbAdapter.getAccountBalance(TRANSFER_ACCOUNT_UID); | ||
assertThat(transferBalance).isEqualTo(expectedValue); | ||
assertThat(transferBalance).isEqualTo(editedTransaction.getBalance(TRANSFER_ACCOUNT_UID)); | ||
|
||
Transaction editedTransaction = mTransactionsDbAdapter.getRecord(multiTransaction.getUID()); | ||
assertThat(editedTransaction.getBalance(TRANSFER_ACCOUNT_UID)).isEqualTo(expectedValue); | ||
|
||
Split transferAcctSplit = editedTransaction.getSplits(TRANSFER_ACCOUNT_UID).get(0); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
package org.gnucash.android.model; | ||
|
||
|
||
import android.os.Parcel; | ||
import android.os.Parcelable; | ||
import android.support.annotation.NonNull; | ||
|
||
import org.gnucash.android.db.adapter.AccountsDbAdapter; | ||
|
@@ -17,7 +19,7 @@ | |
* | ||
* @author Ngewi Fet <ngewif@gmail.com> | ||
*/ | ||
public class Split extends BaseModel{ | ||
public class Split extends BaseModel implements Parcelable{ | ||
|
||
/** | ||
* Flag indicating that the split has been reconciled | ||
|
@@ -89,12 +91,13 @@ public Split(@NonNull Money value, @NonNull Money quantity, String accountUID){ | |
|
||
/** | ||
* Initialize split with a value amount and account | ||
* @param amount Money value amount of this split. Value is always in the currency the owning transaction | ||
* @param accountUID String UID of transfer account | ||
* @param amount Money value amount of this split. Value is always in the currency the owning transaction. | ||
* This amount will be assigned as both the value and the quantity of this split | ||
* @param accountUID String UID of owning account | ||
*/ | ||
public Split(@NonNull Money amount, String accountUID){ | ||
setQuantity(amount); | ||
setValue(amount); | ||
setQuantity(new Money(amount)); | ||
setAccountUID(accountUID); | ||
//NOTE: This is a rather simplististic approach to the split type. | ||
//It typically also depends on the account type of the account. But we do not want to access | ||
|
@@ -442,6 +445,34 @@ public static Split parseSplit(String splitCsvString) { | |
} | ||
} | ||
|
||
/** | ||
* Two splits are considered equivalent if all the fields (excluding GUID and timestamps - created, modified, reconciled) are equal. | ||
* Any two splits which are equal are also equivalent, but the reverse is not true | ||
* <p>The difference with to {@link #equals(Object)} is that the GUID of the split is not considered. | ||
* This is useful in cases where a new split is generated for a transaction with the same properties, | ||
* but a new GUID is generated e.g. when editing a transaction and modifying the splits</p> | ||
* | ||
* @param split Other split for which to test equivalence | ||
* @return {@code true} if both splits are equivalent, {@code false} otherwise | ||
*/ | ||
public boolean isEquivalentTo(Split split){ | ||
if (this == split) return true; | ||
if (super.equals(split)) return true; | ||
|
||
if (mReconcileState != split.mReconcileState) return false; | ||
if (!mValue.equals(split.mValue)) return false; | ||
if (!mQuantity.equals(split.mQuantity)) return false; | ||
if (!mTransactionUID.equals(split.mTransactionUID)) return false; | ||
if (!mAccountUID.equals(split.mAccountUID)) return false; | ||
if (mSplitType != split.mSplitType) return false; | ||
return mMemo != null ? mMemo.equals(split.mMemo) : split.mMemo == null; | ||
} | ||
|
||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
codinguser
Author
Owner
|
||
/** | ||
* Two splits are considered equal if all their properties excluding timestampes (created, modified, reconciled) are equal. | ||
* @param o Other split to compare for equality | ||
* @return {@code true} if this split is equal to {@code o}, {@code false} otherwise | ||
*/ | ||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
|
@@ -457,7 +488,6 @@ public boolean equals(Object o) { | |
if (!mAccountUID.equals(split.mAccountUID)) return false; | ||
if (mSplitType != split.mSplitType) return false; | ||
return mMemo != null ? mMemo.equals(split.mMemo) : split.mMemo == null; | ||
|
||
} | ||
|
||
@Override | ||
|
@@ -472,4 +502,74 @@ public int hashCode() { | |
result = 31 * result + (int) mReconcileState; | ||
return result; | ||
} | ||
|
||
@Override | ||
public int describeContents() { | ||
return 0; | ||
} | ||
|
||
@Override | ||
public void writeToParcel(Parcel dest, int flags) { | ||
dest.writeString(getUID()); | ||
dest.writeString(mAccountUID); | ||
dest.writeString(mTransactionUID); | ||
dest.writeString(mSplitType.name()); | ||
|
||
dest.writeLong(mValue.getNumerator()); | ||
dest.writeLong(mValue.getDenominator()); | ||
dest.writeString(mValue.getCommodity().getCurrencyCode()); | ||
|
||
dest.writeLong(mQuantity.getNumerator()); | ||
dest.writeLong(mQuantity.getDenominator()); | ||
dest.writeString(mQuantity.getCommodity().getCurrencyCode()); | ||
|
||
dest.writeString(mMemo == null ? "" : mMemo); | ||
dest.writeString(String.valueOf(mReconcileState)); | ||
dest.writeString(mReconcileDate.toString()); | ||
} | ||
|
||
/** | ||
* Constructor for creating a Split object from a Parcel | ||
* @param source Source parcel containing the split | ||
* @see #CREATOR | ||
*/ | ||
private Split(Parcel source){ | ||
setUID(source.readString()); | ||
mAccountUID = source.readString(); | ||
mTransactionUID = source.readString(); | ||
mSplitType = TransactionType.valueOf(source.readString()); | ||
|
||
long valueNum = source.readLong(); | ||
long valueDenom = source.readLong(); | ||
String valueCurrency = source.readString(); | ||
mValue = new Money(valueNum, valueDenom, valueCurrency); | ||
|
||
long qtyNum = source.readLong(); | ||
long qtyDenom = source.readLong(); | ||
String qtyCurrency = source.readString(); | ||
mQuantity = new Money(qtyNum, qtyDenom, qtyCurrency); | ||
|
||
String memo = source.readString(); | ||
mMemo = memo.isEmpty() ? null : memo; | ||
mReconcileState = source.readString().charAt(0); | ||
mReconcileDate = Timestamp.valueOf(source.readString()); | ||
} | ||
|
||
/** | ||
* Creates new Parcels containing the information in this split during serialization | ||
*/ | ||
public static final Parcelable.Creator<Split> CREATOR | ||
= new Parcelable.Creator<Split>() { | ||
|
||
@Override | ||
public Split createFromParcel(Parcel source) { | ||
return new Split(source); | ||
} | ||
|
||
@Override | ||
public Split[] newArray(int size) { | ||
return new Split[size]; | ||
} | ||
}; | ||
|
||
} |
2 comments
on commit 96a2045
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'm amazed at how clean saveNewTransaction is now :)
However, that's a lot of changes for a bug fix! It should rather contain the minimum to fix it. When opening the "annotate" of this files in the future, it'll be difficult to know if some changes are really part of the bug fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree that it is a rather big changeset. I started going to make a small fix. But then I realized that saveNewTransaction()
just kept getting messier. So I decided to refactor it all and change the way SplitEditor works a bit. Hence the new branch.
This had the advantage of cleaning up the code greatly, improving the SplitEditor workflow to better mirror GnuCash desktop, and also fixing the bug.
I actually would also prefer it to be a smaller fix. But this is why I took the precaution of adding a few more tests and having you review it. At least we also still have the beta phase coming up. So hopefully any breaking things will be caught there.
These changes should be part of the previous commit.