Skip to content

Commit

Permalink
Made the SimpleAccount and the SimpleTransaction more thread-safe by …
Browse files Browse the repository at this point in the history
…adding volatile fields
  • Loading branch information
ghacupha committed Apr 1, 2018
1 parent ad094fa commit 64891fe
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 20 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ Changelog for ghacupha book-keeper.
## Unreleased
### No issue

**Made the SimpleAccount and the SimpleTransaction more thread-safe by adding volatile fields**


[ad094fa9fe28690](https://github.com/ghacupha/book-keeper/commit/ad094fa9fe28690) ghacupha *2018-04-01 10:31:35*

**configured builds to ensure the commands are working**


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Arrays;
import java.util.Collection;
import java.util.Currency;
import java.util.List;
Expand Down Expand Up @@ -106,11 +107,11 @@ public void addEntry(Entry entry) throws MismatchedCurrencyException, UntimelyBo
@Override
public AccountBalance balance(TimePoint asAt) {

log.debug("Account balance enquiry raised as at {}", asAt);
log.debug("Account balance enquiry raised as at {}, for account : {}", asAt, this);

AccountBalance balance = balance(new DateRange(accountDetails.getOpeningDate(), asAt));

log.debug("Returning accounting balance as at : {} as : {}", asAt, balance);
log.debug("Returning accounting balance for {} as at : {} as : {}", this, asAt, balance);

return balance;
}
Expand All @@ -131,7 +132,7 @@ public AccountBalance balance(int... asAt) {

AccountBalance balance = balance(new SimpleDate(asAt[0],asAt[1],asAt[2]));

log.debug("Returning accounting balance as at : {} as : {}", asAt, balance);
log.debug("Returning accounting balance for {} ,as at : {} as : {}",this, Arrays.toString(asAt), balance);

return balance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,22 @@ public final class SimpleTransaction implements Transaction {

private static final Logger log = LoggerFactory.getLogger(SimpleTransaction.class);

private final String label;

private final TimePoint date;

private volatile boolean wasPosted;
private final Currency currency;

private final List<Entry> entries = new CopyOnWriteArrayList<>();

SimpleTransaction(TimePoint date, Currency currency) {
SimpleTransaction(String label,TimePoint date, Currency currency) {

this.label = label;
this.date = date;
this.currency = currency;

log.info("SimpleTransaction created {}",this);
}

private static Double mapCashToDouble(Entry entry) {
Expand Down Expand Up @@ -148,26 +153,26 @@ public Set<Entry> getEntries() {

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleTransaction that = (SimpleTransaction) o;
return wasPosted == that.wasPosted && Objects.equals(date, that.date) && Objects.equals(currency, that.currency) && Objects.equals(entries, that.entries);
return wasPosted == that.wasPosted &&
Objects.equals(label, that.label) &&
Objects.equals(date, that.date) &&
Objects.equals(currency, that.currency) &&
Objects.equals(entries, that.entries);
}

@Override
public int hashCode() {
return Objects.hash(date, wasPosted, currency, entries);

return Objects.hash(label, date, wasPosted, currency, entries);
}

@Override
public String toString() {
final StringBuffer sb = new StringBuffer("SimpleTransaction{");
sb.append("date=").append(date);
sb.append(", wasPosted=").append(wasPosted);
final StringBuilder sb = new StringBuilder("{");
sb.append(label).append('\'');
sb.append(", date=").append(date);
sb.append(", currency=").append(currency);
sb.append(", entries=").append(entries);
sb.append('}');
Expand Down
29 changes: 25 additions & 4 deletions src/test/java/io/github/ghacupha/keeper/book/base/AccountTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import io.github.ghacupha.keeper.book.util.MismatchedCurrencyException;
import io.github.ghacupha.keeper.book.util.UnableToPostException;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Currency;

Expand All @@ -18,6 +20,8 @@

public class AccountTest {

private static final Logger log = LoggerFactory.getLogger(AccountTest.class);

// Required for the reversal tests
private Account advertisement = new SimpleAccount(DEBIT,Currency.getInstance("KES"),new AccountDetails("Advertisements","5280", SimpleDate.on(2017,3,31)));
private Account vat = new SimpleAccount(CREDIT,Currency.getInstance("KES"),new AccountDetails("VAT","5281", SimpleDate.on(2017,3,31)));
Expand All @@ -29,57 +33,74 @@ public class AccountTest {
@Test
public void directedTransactionWorks() throws Exception, UnableToPostException, MismatchedCurrencyException, ImmutableEntryException {

// Create the transaction
Transaction payForBillBoards = new SimpleTransaction(new SimpleDate(2017,11,2),Currency.getInstance("KES"));
log.info("Testing if the transaction will work. First we create the pay for bills Transaction, using period 2017-11-2, and currency KES");
Transaction payForBillBoards = new SimpleTransaction("BillboardsPayment",new SimpleDate(2017,11,2),Currency.getInstance("KES"));

log.info("Done. We DEBIT the Advertisement account, and credit the VAT and Banker's Cheque accounts....");
payForBillBoards.addEntry(DEBIT,HardCash.shilling(200),advertisement,new EntryDetails("Billboards ltd inv 10"));
payForBillBoards.addEntry(CREDIT,HardCash.shilling(32),vat,new EntryDetails("VAT for billBoards"));
payForBillBoards.addEntry(CREDIT,HardCash.shilling(168),chequeAccount,new EntryDetails("CHQ IFO Billboards Ltd"));

// non-posted
log.info("Ok so we have not yet posted the transaction but we want to check if the balances have been effected into the 3 accounts");
assertEquals(AccountBalance.newBalance(HardCash.shilling(0),DEBIT),advertisement.balance(2018,1,3));
assertEquals(AccountBalance.newBalance(HardCash.shilling(0),CREDIT),vat.balance(2018,1,3));
assertEquals(AccountBalance.newBalance(HardCash.shilling(0),CREDIT),chequeAccount.balance(2018,1,3));

// after posting
log.info("Nothing? Good. So now lets post the transaction...");
payForBillBoards.post();

log.info("Posted. Now lets check if the balances in the account reflect our intentions");
assertEquals(AccountBalance.newBalance(HardCash.shilling(200),DEBIT),advertisement.balance(2017,11,30));
assertEquals(AccountBalance.newBalance(HardCash.shilling(32),CREDIT),vat.balance(2017,11,30));
assertEquals(AccountBalance.newBalance(HardCash.shilling(168),CREDIT),chequeAccount.balance(2017,11,30));

// Reimbursement Transaction
Transaction reimbursement = new SimpleTransaction(new SimpleDate(2017,12,20), Currency.getInstance("KES"));
log.info("Alright now we gotta reimburse Edwin for the meeting expenses, when he met with the Billboard guys. We create the" +
" reimbursement transaction, as of 2017-12-20 in currency KES");
Transaction reimbursement = new SimpleTransaction("Edwin\'s reimbursement",new SimpleDate(2017,12,20), Currency.getInstance("KES"));

log.info("Alright, all we gotta do is debit the advertisement account and credit Edwin's account...");
reimbursement.addEntry(DEBIT,HardCash.shilling(150),advertisement,new EntryDetails("Reimburse Edwin For Meeting expenses with Billboard guys"));
reimbursement.addEntry(CREDIT,HardCash.shilling(150), edwinsAccount,new EntryDetails("Reimbursement for meeting expenses with billboard guys"));

// before posting
log.info("Again, we are going to check if the system has inappropriately added money into Edwin's account before our explicit posting...");
assertEquals(AccountBalance.newBalance(HardCash.shilling(0),CREDIT), edwinsAccount.balance(2017,12,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(200),DEBIT),advertisement.balance(2017,12,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(32),CREDIT),vat.balance(2017,12,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(168),CREDIT),chequeAccount.balance(2017,12,31));

// after posting the reimbursement
log.info("Nothing there. Good. Let us post the reimbursement transaction...");
reimbursement.post();
log.info("Done. Now lets check if the account have the balances we expect. Edwin should have 150 joys, advertisements should be at 350...");
assertEquals(AccountBalance.newBalance(HardCash.shilling(150),CREDIT), edwinsAccount.balance(2018,1,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(350),DEBIT),advertisement.balance(2018,1,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(32),CREDIT),vat.balance(2018,1,31));
assertEquals(AccountBalance.newBalance(HardCash.shilling(168),CREDIT),chequeAccount.balance(2018,1,31));

// what if the manager wants a previous position as at 5th November 2017
log.info("Ok, this new strategy guy, for some obviously unholy reason wants to know our position as at 2017-11-05, time for some replay...");
assertEquals(AccountBalance.newBalance(HardCash.shilling(0),CREDIT), edwinsAccount.balance(2017,11,5));
assertEquals(AccountBalance.newBalance(HardCash.shilling(200),DEBIT),advertisement.balance(2017,11,5));
assertEquals(AccountBalance.newBalance(HardCash.shilling(32),CREDIT),vat.balance(2017,11,5));
assertEquals(AccountBalance.newBalance(HardCash.shilling(168),CREDIT),chequeAccount.balance(2017,11,5));

// Someone screwed up the taxes, we have to reverse
Transaction taxReversal = new SimpleTransaction(SimpleDate.on(2018,4,20), Currency.getInstance("KES"));
log.info("The internal audit reveals that someone had screwed up our taxes. Our taxes should be on the asset side by at least 13 joys. " +
"Time to create some tax reversal transaction as at 2018-04-20, in KES as always");
Transaction taxReversal = new SimpleTransaction("Tax reversal",SimpleDate.on(2018,4,20), Currency.getInstance("KES"));

log.info("Adding entries to the tax reversal. We need to debit VAT by 45 joys and CREDIT advertisement expense by the same amount");
taxReversal.addEntry(DEBIT,HardCash.shilling(45),vat,new EntryDetails("Reversal of Excess VAT"));
taxReversal.addEntry(CREDIT,HardCash.shilling(45),advertisement,new EntryDetails("Reversal of Excess VAT"));

log.info("We now post the tax reversal transaction");
taxReversal.post();

log.info("As per internal audit the VAT should be at 13 joys, asset side. Meaning the advertisement should be an expense of just 305");
// balance after reversal transaction is posted...
assertEquals(AccountBalance.newBalance(HardCash.shilling(150),CREDIT), edwinsAccount.balance(2018,4,25));
assertEquals(AccountBalance.newBalance(HardCash.shilling(305),DEBIT),advertisement.balance(2018,4,25));
Expand Down

0 comments on commit 64891fe

Please sign in to comment.