Created
June 17, 2010 22:50
-
-
Save haru01/442912 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rubygems' | |
require 'mongo_mapper' | |
require 'pp' | |
MongoMapper.database = 'accounting-patterns' | |
# see accounting transaction http://martinfowler.com/apsupp/accounting.pdf | |
class AccountService | |
class AcccountingRunner | |
def initialize | |
@transaction = AccountingTransaction.new | |
end | |
attr_accessor :transaction | |
def from name, amount | |
entry = Entry.new(:amount => -amount) | |
entry.tmp_account = Account.find_by_name name | |
entry.account = Account.find_by_name name | |
@transaction.entries << entry | |
end | |
def to name, amount | |
entry = Entry.new(:amount => amount) | |
entry.tmp_account = Account.find_by_name name | |
entry.account = Account.find_by_name name | |
@transaction.entries << entry | |
end | |
def valid? | |
@transaction.total_zero? | |
end | |
def destory | |
@transaction.entries.delete_all | |
@transaction.delete | |
end | |
end | |
def send_money | |
runner = AcccountingRunner.new | |
yield runner | |
if runner.valid? | |
# runner.transaction.save! saveしてないんだが。。。 | |
else | |
runner.destory | |
raise "バランスしません" | |
end | |
end | |
end | |
class Account | |
include MongoMapper::Document | |
key :name, String, :required => true, :unique => true | |
many :entries, :order => 'create_at asc' | |
def balance | |
entries.inject(0) do |result, entry| | |
result + entry.amount | |
end | |
end | |
end | |
class Entry | |
attr_accessor :tmp_account | |
include MongoMapper::Document | |
key :amount, Integer | |
belongs_to :account | |
timestamps! | |
end | |
class AccountingTransaction | |
include MongoMapper::Document | |
many :entries | |
timestamps! | |
def total_zero? | |
entries.inject(0) {|result, entry| result + entry.amount } == 0 | |
end | |
end | |
describe "accounting transaction" do | |
before(:each) do | |
init_db | |
end | |
let(:account_service) { AccountService.new} | |
context "送金 佐藤さんから田中さんへの例" do | |
before(:each) do | |
account_service.send_money do |runner| | |
runner.from("佐藤", 99) | |
runner.to("田中", 99) | |
end | |
end | |
it "移動の総量は0であること" do | |
trn = AccountingTransaction.last :order => "timestamps" | |
trn.should be_total_zero | |
end | |
it "送り元の balance が減っていること" do | |
sato = Account.find_by_name("佐藤") | |
sato.balance.should == 200 - 99 | |
end | |
it "送り先の balance が増えていること" do | |
sato = Account.find_by_name("田中") | |
sato.balance.should == 300 + 99 | |
end | |
end | |
context "送金 鈴木さんから 佐藤さん,田中さんへの例" do | |
before(:each) do | |
account_service.send_money do |runner| | |
runner.from("鈴木", 260) | |
runner.to("佐藤", 110) | |
runner.to("田中", 150) | |
end | |
end | |
it "移動の総量は0であること" do | |
AccountingTransaction.count.should == 1 | |
trn = AccountingTransaction.last :order => "timestamps" | |
trn.should be_total_zero | |
end | |
it "送り元の balance が減っていること" do | |
a = Account.find_by_name("鈴木") | |
a.balance.should == 700 - 260 | |
end | |
it "送り先1の balance が増えていること" do | |
a = Account.find_by_name("佐藤") | |
a.balance.should == 200 + 110 | |
end | |
it "送り先2の balance が増えていること" do | |
a = Account.find_by_name("田中") | |
a.balance.should == 300 + 150 | |
end | |
end | |
context "バランスしない 送金のケース" do | |
it "初期か状態であること" do | |
AccountingTransaction.count.should == 0 | |
lambda { | |
account_service.send_money do |runner| | |
runner.from("鈴木", 260) | |
runner.to("田中", 150) | |
end | |
}.should raise_error("バランスしません") | |
should_init | |
end | |
def should_init | |
suzuki = Account.find_by_name("鈴木") | |
suzuki.balance.should == 700 | |
sato = Account.find_by_name("佐藤") | |
sato.balance.should == 200 | |
tanaka = Account.find_by_name("田中") | |
tanaka.balance.should == 300 | |
end | |
end | |
def init_db | |
Account.delete_all | |
Entry.delete_all | |
AccountingTransaction.delete_all | |
sato = Account.new (:name => "佐藤") | |
sato.entries << Entry.new(:amount => 200) | |
# sato.save saveしていないんだが。。。。 こうゆうもの? | |
tanaka = Account.new (:name => "田中") | |
tanaka.entries << Entry.new(:amount => 300) | |
# tanaka.save | |
tanaka = Account.new (:name => "鈴木") | |
tanaka.entries << Entry.new(:amount => 700) | |
#tanaka.save | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment