epay 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. data/.gitignore +15 -0
  2. data/.travis.yml +5 -0
  3. data/CHANGELOG.md +13 -0
  4. data/Gemfile +2 -0
  5. data/Guardfile +10 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.markdown +21 -0
  8. data/Rakefile +8 -0
  9. data/bin/epay-console +8 -0
  10. data/epay.gemspec +55 -0
  11. data/lib/epay.rb +104 -0
  12. data/lib/epay/api.rb +92 -0
  13. data/lib/epay/api/response.rb +29 -0
  14. data/lib/epay/card.rb +23 -0
  15. data/lib/epay/model.rb +23 -0
  16. data/lib/epay/subscription.rb +132 -0
  17. data/lib/epay/transaction.rb +171 -0
  18. data/lib/epay/version.rb +3 -0
  19. data/lib/extensions/hash.rb +4 -0
  20. data/spec/api/response_spec.rb +71 -0
  21. data/spec/api_spec.rb +58 -0
  22. data/spec/card_spec.rb +21 -0
  23. data/spec/fixtures/vcr_cassettes/existing_subscription.yml +75 -0
  24. data/spec/fixtures/vcr_cassettes/existing_transaction.yml +47 -0
  25. data/spec/fixtures/vcr_cassettes/non_existing_transaction.yml +48 -0
  26. data/spec/fixtures/vcr_cassettes/subscription_authorization.yml +95 -0
  27. data/spec/fixtures/vcr_cassettes/subscription_creation.yml +101 -0
  28. data/spec/fixtures/vcr_cassettes/subscription_invalid_creation.yml +47 -0
  29. data/spec/fixtures/vcr_cassettes/subscriptions.yml +87 -0
  30. data/spec/fixtures/vcr_cassettes/transaction_creation.yml +90 -0
  31. data/spec/fixtures/vcr_cassettes/transaction_invalid_creation.yml +47 -0
  32. data/spec/fixtures/vcr_cassettes/transactions.yml +50 -0
  33. data/spec/helpers/http_responses.rb +13 -0
  34. data/spec/model_spec.rb +36 -0
  35. data/spec/spec_helper.rb +20 -0
  36. data/spec/subscription_spec.rb +139 -0
  37. data/spec/transaction_spec.rb +245 -0
  38. metadata +280 -0
@@ -0,0 +1,90 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx
6
+ body: merchantnumber=8887978&cardno=5555555555555000&cvc=999&expmonth=10&expyear=15&amount=6000&currency=208&orderid=TEST-ORDER-12345&accepturl=https%3A%2F%2Fssl.ditonlinebetalingssystem.dk%2Fauth%2Fdefault.aspx%3Faccept%3D1&declineurl=https%3A%2F%2Fssl.ditonlinebetalingssystem.dk%2Fauth%2Fdefault.aspx%3Fdecline%3D1&description=For%20the%20cool%20products&cardholder=Jack%20Jensen&group=Test-transactions&instantcapture=0
7
+ headers:
8
+ Accept:
9
+ - ! '*/*; q=0.5, application/xml'
10
+ Accept-Encoding:
11
+ - gzip, deflate
12
+ Content-Length:
13
+ - '417'
14
+ Content-Type:
15
+ - application/x-www-form-urlencoded
16
+ User-Agent:
17
+ - Ruby
18
+ response:
19
+ status:
20
+ code: 302
21
+ message: Found
22
+ headers:
23
+ Cache-Control:
24
+ - private
25
+ Content-Type:
26
+ - text/html; charset=iso-8859-1
27
+ Location:
28
+ - https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx?accept=1&tid=8840215&orderid=TEST-ORDER-12345&amount=6000&cur=208&date=20120214&time=1147&cardnopostfix=5000&tcardno=555555XXXXXX5000&cardid=4&transfee=0
29
+ Set-Cookie:
30
+ - ASP.NET_SessionId=ttcv4fb3oby30sayyisibj55; path=/; HttpOnly
31
+ X-Aspnet-Version:
32
+ - 2.0.50727
33
+ X-Powered-By:
34
+ - ASP.NET
35
+ Date:
36
+ - Tue, 14 Feb 2012 10:46:46 GMT
37
+ Content-Length:
38
+ - '368'
39
+ body: ! "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved
40
+ to <a href=\"https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx?accept=1&amp;tid=8840215&amp;orderid=TEST-ORDER-12345&amp;amount=6000&amp;cur=208&amp;date=20120214&amp;time=1147&amp;cardnopostfix=5000&amp;tcardno=555555XXXXXX5000&amp;cardid=4&amp;transfee=0\">here</a>.</h2>\r\n</body></html>\r\n"
41
+ http_version: !!null
42
+ recorded_at: Tue, 14 Feb 2012 10:47:50 GMT
43
+ - request:
44
+ method: post
45
+ uri: https://ssl.ditonlinebetalingssystem.dk/remote/payment.asmx
46
+ body: ! "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soap:Envelope xmlns:xsi=\"http://schemas.xmlsoap.org/soap/envelope/\"
47
+ xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n
48
+ \ <soap:Body>\n <gettransaction xmlns=\"https://ssl.ditonlinebetalingssystem.dk/remote/payment\">\n
49
+ \ <transactionid>8840215</transactionid>\n <merchantnumber>8887978</merchantnumber>\n
50
+ \ </gettransaction>\n </soap:Body>\n</soap:Envelope>\n"
51
+ headers:
52
+ Accept:
53
+ - ! '*/*; q=0.5, application/xml'
54
+ Accept-Encoding:
55
+ - gzip, deflate
56
+ Content-Type:
57
+ - text/xml; charset=utf-8
58
+ Soapaction:
59
+ - https://ssl.ditonlinebetalingssystem.dk/remote/payment/gettransaction
60
+ Content-Length:
61
+ - '453'
62
+ User-Agent:
63
+ - Ruby
64
+ response:
65
+ status:
66
+ code: 200
67
+ message: OK
68
+ headers:
69
+ Cache-Control:
70
+ - private, max-age=0
71
+ Content-Type:
72
+ - text/xml; charset=utf-8
73
+ X-Aspnet-Version:
74
+ - 2.0.50727
75
+ X-Powered-By:
76
+ - ASP.NET
77
+ Date:
78
+ - Tue, 14 Feb 2012 10:46:46 GMT
79
+ Content-Length:
80
+ - '1836'
81
+ body: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
82
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><gettransactionResponse
83
+ xmlns="https://ssl.ditonlinebetalingssystem.dk/remote/payment"><gettransactionResult>true</gettransactionResult><transactionInformation><group>Test-transactions</group><authamount>6000</authamount><currency>208</currency><cardtypeid>4</cardtypeid><capturedamount>0</capturedamount><creditedamount>0</creditedamount><orderid>TEST-ORDER-12345</orderid><description>For
84
+ the cool products</description><authdate>2012-02-14T11:47:00</authdate><captureddate>0001-01-01T00:00:00</captureddate><deleteddate>0001-01-01T00:00:00</deleteddate><crediteddate>0001-01-01T00:00:00</crediteddate><status>PAYMENT_NEW</status><history><TransactionHistoryInfo><transactionHistoryID>21568611</transactionHistoryID><logonID>0</logonID><username
85
+ /><eventMsg>Payment moved to group Test-transactions</eventMsg><created>2012-02-14T11:47:00</created></TransactionHistoryInfo><TransactionHistoryInfo><transactionHistoryID>21568610</transactionHistoryID><logonID>0</logonID><username
86
+ /><eventMsg>Payment authorized with amount 60,00 and currency code 208</eventMsg><created>2012-02-14T11:47:00</created></TransactionHistoryInfo></history><transactionid>8840215</transactionid><cardholder>Jack
87
+ Jensen</cardholder><mode>MODE_EPAY</mode><msc>false</msc><fraudStatus>0</fraudStatus><payerCountryCode> </payerCountryCode><issuedCountryCode> </issuedCountryCode><fee>0</fee><splitpayment>false</splitpayment><acquirer>EUROLINE</acquirer><tcardno>555555XXXXXX5000</tcardno><expmonth>10</expmonth><expyear>15</expyear></transactionInformation><epayresponse>-1</epayresponse></gettransactionResponse></soap:Body></soap:Envelope>
88
+ http_version: !!null
89
+ recorded_at: Tue, 14 Feb 2012 10:47:50 GMT
90
+ recorded_with: VCR 2.0.0.rc1
@@ -0,0 +1,47 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx
6
+ body: merchantnumber=8887978&cardno=5555555555555118&cvc=999&expmonth=10&expyear=15&amount=6000&currency=208&orderid=TEST-ORDER-12345&accepturl=https%3A%2F%2Fssl.ditonlinebetalingssystem.dk%2Fauth%2Fdefault.aspx%3Faccept%3D1&declineurl=https%3A%2F%2Fssl.ditonlinebetalingssystem.dk%2Fauth%2Fdefault.aspx%3Fdecline%3D1&description=For%20the%20cool%20products&cardholder=Jack%20Jensen&group=Test-transactions&instantcapture=0
7
+ headers:
8
+ Accept:
9
+ - ! '*/*; q=0.5, application/xml'
10
+ Accept-Encoding:
11
+ - gzip, deflate
12
+ Content-Length:
13
+ - '417'
14
+ Content-Type:
15
+ - application/x-www-form-urlencoded
16
+ User-Agent:
17
+ - Ruby
18
+ response:
19
+ status:
20
+ code: 302
21
+ message: Found
22
+ headers:
23
+ Cache-Control:
24
+ - private
25
+ Content-Type:
26
+ - text/html; charset=iso-8859-1
27
+ Location:
28
+ - https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx?decline=1&error=118&orderid=TEST-ORDER-12345&errortext=Betalingen
29
+ blev afvist da det indtastede kortnummer ikke kan findes. Pr%f8v og indtaste
30
+ kortets oplysninger igen eller pr%f8v med et andet betalingskort.
31
+ Set-Cookie:
32
+ - ASP.NET_SessionId=k44l3g55x4sofwm3esjkga45; path=/; HttpOnly
33
+ X-Aspnet-Version:
34
+ - 2.0.50727
35
+ X-Powered-By:
36
+ - ASP.NET
37
+ Date:
38
+ - Tue, 14 Feb 2012 10:47:46 GMT
39
+ Content-Length:
40
+ - '395'
41
+ body: ! "<html><head><title>Object moved</title></head><body>\r\n<h2>Object moved
42
+ to <a href=\"https://ssl.ditonlinebetalingssystem.dk/auth/default.aspx?decline=1&amp;error=118&amp;orderid=TEST-ORDER-12345&amp;errortext=Betalingen
43
+ blev afvist da det indtastede kortnummer ikke kan findes. Pr%f8v og indtaste
44
+ kortets oplysninger igen eller pr%f8v med et andet betalingskort.\">here</a>.</h2>\r\n</body></html>\r\n"
45
+ http_version: !!null
46
+ recorded_at: Tue, 14 Feb 2012 10:48:50 GMT
47
+ recorded_with: VCR 2.0.0.rc1
@@ -0,0 +1,50 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://ssl.ditonlinebetalingssystem.dk/remote/payment.asmx
6
+ body: ! "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<soap:Envelope xmlns:xsi=\"http://schemas.xmlsoap.org/soap/envelope/\"
7
+ xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n
8
+ \ <soap:Body>\n <gettransaction xmlns=\"https://ssl.ditonlinebetalingssystem.dk/remote/payment\">\n
9
+ \ <transactionid>8786997</transactionid>\n <merchantnumber>8887978</merchantnumber>\n
10
+ \ </gettransaction>\n </soap:Body>\n</soap:Envelope>\n"
11
+ headers:
12
+ Accept:
13
+ - ! '*/*; q=0.5, application/xml'
14
+ Accept-Encoding:
15
+ - gzip, deflate
16
+ Content-Type:
17
+ - text/xml; charset=utf-8
18
+ Soapaction:
19
+ - https://ssl.ditonlinebetalingssystem.dk/remote/payment/gettransaction
20
+ Content-Length:
21
+ - '453'
22
+ User-Agent:
23
+ - Ruby
24
+ response:
25
+ status:
26
+ code: 200
27
+ message: OK
28
+ headers:
29
+ Cache-Control:
30
+ - private, max-age=0
31
+ Content-Type:
32
+ - text/xml; charset=utf-8
33
+ X-Aspnet-Version:
34
+ - 2.0.50727
35
+ X-Powered-By:
36
+ - ASP.NET
37
+ Date:
38
+ - Mon, 13 Feb 2012 12:38:22 GMT
39
+ Content-Length:
40
+ - '1518'
41
+ body: <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
42
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><gettransactionResponse
43
+ xmlns="https://ssl.ditonlinebetalingssystem.dk/remote/payment"><gettransactionResult>true</gettransactionResult><transactionInformation><group
44
+ /><authamount>7900</authamount><currency>208</currency><cardtypeid>18</cardtypeid><capturedamount>0</capturedamount><creditedamount>0</creditedamount><orderid>orderid</orderid><description
45
+ /><authdate>2012-02-10T11:30:00</authdate><captureddate>0001-01-01T00:00:00</captureddate><deleteddate>0001-01-01T00:00:00</deleteddate><crediteddate>0001-01-01T00:00:00</crediteddate><status>PAYMENT_NEW</status><history><TransactionHistoryInfo><transactionHistoryID>21437164</transactionHistoryID><logonID>-1</logonID><username
46
+ /><eventMsg>Payment authorized with amount 79,00 and currency code 208</eventMsg><created>2012-02-10T11:30:00</created></TransactionHistoryInfo></history><transactionid>8786997</transactionid><cardholder
47
+ /><mode>MODE_EPAY</mode><msc>false</msc><fraudStatus>0</fraudStatus><payerCountryCode> </payerCountryCode><issuedCountryCode> </issuedCountryCode><fee>0</fee><splitpayment>false</splitpayment><acquirer>EUROLINE</acquirer><tcardno>333333XXXXXX3000</tcardno><expmonth>10</expmonth><expyear>12</expyear></transactionInformation><epayresponse>-1</epayresponse></gettransactionResponse></soap:Body></soap:Envelope>
48
+ http_version: !!null
49
+ recorded_at: Mon, 13 Feb 2012 12:39:25 GMT
50
+ recorded_with: VCR 2.0.0.rc1
@@ -0,0 +1,13 @@
1
+ module HttpResponses
2
+ def self.included(base) do
3
+ before do
4
+ stub_request(:post, 'https://ssl.ditonlinebetalingssystem.dk/remote/payment.asmx') { 'lol?' }
5
+ end
6
+ end
7
+
8
+ def stub_soap_request(url, action, parameters)
9
+ Epay::Api.stub(:request).with(url, actions, parameters) do
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ module Epay
4
+ class MockedModel
5
+ include Model
6
+
7
+ def self.inspectable_attributes
8
+ %w(id description another_attribute)
9
+ end
10
+
11
+ def description
12
+ 'Description'
13
+ end
14
+
15
+ def another_attribute
16
+ 'Another'
17
+ end
18
+ end
19
+
20
+ describe 'Model' do
21
+ let(:model) do
22
+ MockedModel.new(42)
23
+ end
24
+
25
+ describe "inspection" do
26
+ it "contains id" do
27
+ model.inspect.to_s.should =~ /id: 42/
28
+ end
29
+
30
+ it "contains attributes" do
31
+ model.inspect.to_s.should =~ /description: "Description"/
32
+ model.inspect.to_s.should =~ /another_attribute: "Another"/
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ require 'vcr'
2
+ require 'webmock/rspec'
3
+
4
+ require 'epay'
5
+
6
+ module Epay
7
+ EXISTING_TRANSACTION_ID = 8786997
8
+ NON_EXISTING_TRANSACTION_ID = 12345678
9
+ end
10
+
11
+ RSpec.configure do |c|
12
+ c.before(:all) do
13
+ Epay.merchant_number = 8887978
14
+ end
15
+ end
16
+
17
+ VCR.configure do |c|
18
+ c.cassette_library_dir = 'spec/fixtures/vcr_cassettes'
19
+ c.hook_into :webmock
20
+ end
@@ -0,0 +1,139 @@
1
+ require 'spec_helper'
2
+
3
+ module Epay
4
+ describe Subscription do
5
+ let(:subscription) do
6
+ VCR.use_cassette('existing_subscription') do
7
+ Subscription.find(387544)
8
+ end
9
+ end
10
+
11
+ describe "attributes" do
12
+ it "has created_at" do
13
+ subscription.created_at.should == Time.local(2012, 2, 9, 12, 11)
14
+ end
15
+
16
+ it "has description" do
17
+ subscription.description.should == "Test-subscriber"
18
+ end
19
+ end
20
+
21
+ describe "#transactions" do
22
+ it "returns a list of transactions" do
23
+ subscription.transactions.first.should be_a Transaction
24
+ end
25
+
26
+ context "when no transactions has been made" do
27
+ it "returns an empty list" do
28
+ subscription.data.delete('transactionList')
29
+ subscription.transactions.should == []
30
+ end
31
+ end
32
+
33
+ context "when one transaction has been made" do
34
+ it "returns list of transactions" do
35
+ subscription.data['transactionList'] = {"TransactionInformationType"=>{"group"=>nil, "authamount"=>"59000", "currency"=>"208", "cardtypeid"=>"4", "capturedamount"=>"0", "creditedamount"=>"0", "orderid"=>"__dev__-1-10000", "description"=>nil, "authdate"=>"2012-03-12T19:56:00", "captureddate"=>"0001-01-01T00:00:00", "deleteddate"=>"0001-01-01T00:00:00", "crediteddate"=>"0001-01-01T00:00:00", "status"=>"PAYMENT_NEW", "history"=>{"TransactionHistoryInfo"=>{"transactionHistoryID"=>"22572373", "logonID"=>"-1", "username"=>nil, "eventMsg"=>"Payment authorized with amount 590,00 and currency code 208", "created"=>"2012-03-12T19:56:00"}}, "transactionid"=>"9239756", "cardholder"=>nil, "mode"=>"MODE_EPAY", "msc"=>"false", "fraudStatus"=>"0", "payerCountryCode"=>" ", "issuedCountryCode"=>" ", "fee"=>"0", "splitpayment"=>"false", "acquirer"=>"EUROLINE", "tcardno"=>"555555XXXXXX5000", "expmonth"=>"1", "expyear"=>"12"}}
36
+ subscription.transactions.first.should be_a Transaction
37
+ end
38
+ end
39
+ end
40
+
41
+ describe "#card" do
42
+ it "returns card" do
43
+ Card.should_receive(:new).with(:exp_year => 12, :exp_month => 10, :kind => :visa, :number => '333333XXXXXX3000')
44
+ subscription.card
45
+ end
46
+
47
+ context "when no transaction has been made" do
48
+ it "returns card with no number" do
49
+ subscription.stub(:transactions) { [] }
50
+ Card.should_receive(:new).with(:exp_year => 12, :exp_month => 10, :kind => :visa, :number => nil)
51
+ subscription.card
52
+ end
53
+ end
54
+ end
55
+
56
+ describe ".all" do
57
+ it "returns a list of subscriptions" do
58
+ VCR.use_cassette('subscriptions') do
59
+ subscriptions = Subscription.all
60
+ subscriptions.should be_a Enumerable
61
+ subscriptions.first.should be_a Subscription
62
+ end
63
+ end
64
+ end
65
+
66
+ describe "#delete" do
67
+ it "requests to api" do
68
+ subscription_id = subscription.id
69
+
70
+ Api.should_receive(:request).with(SUBSCRIPTION_SOAP_URL, 'delete', :subscriptionid => subscription_id) {
71
+ mock(Api::Response, :success? => true)
72
+ }
73
+
74
+ subscription.delete
75
+ end
76
+ end
77
+
78
+ describe ".create" do
79
+ context "when card data is valid" do
80
+ let(:subscription) do
81
+ VCR.use_cassette('subscription_creation') do
82
+ Subscription.create(:card_no => '5555555555555000', :exp_year => '15', :exp_month => '10', :cvc => '999', :description => 'A new subscriber', :currency => :DKK)
83
+ end
84
+ end
85
+
86
+ it "returns subscription" do
87
+ subscription.should be_a Subscription
88
+ subscription.transactions.should be_empty
89
+ end
90
+
91
+ it "is has card with card number" do
92
+ subscription.card_no.should == '555555XXXXXX5000'
93
+ end
94
+ end
95
+
96
+ context "when card data is invalid" do
97
+ describe "the returned subscription" do
98
+ let(:subscription) do
99
+ VCR.use_cassette('subscription_invalid_creation') do
100
+ Subscription.create(:card_no => '5555555555555118', :exp_year => '15', :exp_month => '10', :cvc => '999', :description => 'A new subscriber', :currency => :DKK)
101
+ end
102
+ end
103
+
104
+ it "has error code" do
105
+ subscription.error.should == '118'
106
+ end
107
+
108
+ it "is isn't valid" do
109
+ subscription.should_not be_valid
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#authorize" do
116
+ it "returns new transaction" do
117
+ VCR.use_cassette('subscription_authorization') do
118
+ transaction = subscription.authorize(:order_no => 'NEW ORDER', :amount => 10.0, :currency => :DKK)
119
+ transaction.should be_a Transaction
120
+ end
121
+ end
122
+
123
+ context "when authorization fails" do
124
+ it "returns transaction with error code etc." do
125
+ subscription
126
+
127
+ response = mock(Api::Response)
128
+ response.stub(:success?) { false }
129
+ response.stub(:data) { {'pbsresponse' => '404'} }
130
+
131
+ Api.stub(:request).with(SUBSCRIPTION_SOAP_URL, 'authorize', anything).and_yield(response)
132
+
133
+ Transaction.should_receive(:new).with(nil, 'error' => '404', 'failed' => true)
134
+ subscription.authorize(:order_no => 'NEW ORDER', :amount => 10.0, :currency => :DKK)
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,245 @@
1
+ require 'spec_helper'
2
+
3
+ module Epay
4
+ describe Transaction do
5
+ let(:transaction) do
6
+ VCR.use_cassette('existing_transaction') do
7
+ Transaction.find(EXISTING_TRANSACTION_ID)
8
+ end
9
+ end
10
+
11
+ describe "attributes" do
12
+ it "has description" do
13
+ transaction.description.should == "Description of transaction"
14
+ end
15
+
16
+ it "has amount" do
17
+ transaction.amount.should == 79.0
18
+ end
19
+
20
+ it "has card" do
21
+ Card.should_receive(:new).with(:number => '333333XXXXXX3000', :exp_year => 12, :exp_month => 10, :kind => :visa)
22
+ transaction.card
23
+ end
24
+
25
+ it "has group" do
26
+ transaction.group.should == 'Group'
27
+ end
28
+
29
+ it "has cardholder" do
30
+ transaction.cardholder.should == 'John Doe'
31
+ end
32
+
33
+ it "has acquirer" do
34
+ transaction.acquirer.should == 'EUROLINE'
35
+ end
36
+
37
+ it "has currency" do
38
+ transaction.currency.should == :DKK
39
+ end
40
+
41
+ it "has order no" do
42
+ transaction.order_no.should == 'MY-ORDER-ID'
43
+ end
44
+
45
+ it "has created_at" do
46
+ transaction.created_at.should == Time.local(2012, 2, 10, 11, 30, 0)
47
+ end
48
+
49
+ it "has error" do
50
+ transaction.data.stub(:[]).with('error') { 404 }
51
+ transaction.error.should == 404
52
+ end
53
+
54
+ it "has credited_amount" do
55
+ transaction.credited_amount == 3
56
+ end
57
+ end
58
+
59
+ describe "#test?" do
60
+ it "is true when mode is EPAY or TEST" do
61
+ transaction.data.stub(:[]).with('mode') { 'MODE_EPAY' }
62
+ transaction.test?.should be_true
63
+
64
+ transaction.data.stub(:[]).with('mode') { 'MODE_TEST' }
65
+ transaction.test?.should be_true
66
+ end
67
+
68
+ it "is false when in production" do
69
+ transaction.data.stub(:[]).with('mode') { 'MODE_PRODUCTION' }
70
+ transaction.test?.should be_false
71
+ end
72
+ end
73
+
74
+ describe "#production?" do
75
+ it "is opposite of test?" do
76
+ transaction.stub(:test?) { false }
77
+ transaction.production?.should be_true
78
+
79
+ transaction.stub(:test?) { true }
80
+ transaction.production?.should be_false
81
+ end
82
+ end
83
+
84
+ describe "#captured?" do
85
+ it "is true when captured_at is set" do
86
+ transaction.stub(:captured_at) { Time.now }
87
+ transaction.captured?.should be_true
88
+ end
89
+
90
+ it "is false when captured_at isn't set" do
91
+ transaction.stub(:captured_at) { nil }
92
+ transaction.captured?.should be_false
93
+ end
94
+ end
95
+
96
+ describe "#failed?" do
97
+ it "is true when 'failed' is set" do
98
+ transaction.should_not be_failed
99
+ transaction.data.stub(:[]).with('failed') { true }
100
+ transaction.should be_failed
101
+ end
102
+ end
103
+
104
+ describe "#success?" do
105
+ it "is true unless failed" do
106
+ transaction.stub(:failed?) { false }
107
+ transaction.success?.should be_true
108
+
109
+ transaction.stub(:failed?) { true }
110
+ transaction.success?.should be_false
111
+ end
112
+ end
113
+
114
+ describe "#permanent_error?" do
115
+ it "is true unless error code is temporary" do
116
+ transaction.stub(:failed?) { true }
117
+ transaction.stub(:temporary_error?) { false }
118
+ transaction.permanent_error?.should be_true
119
+ end
120
+ end
121
+
122
+ describe "#temporary_error?" do
123
+ it "is true if error code is a temporary code" do
124
+ transaction.stub(:failed?) { true }
125
+ transaction.stub(:error) { '915' }
126
+ transaction.temporary_error?.should be_true
127
+ end
128
+ end
129
+
130
+ describe "#capture" do
131
+ it "calls capture action with transaction id and amount in minor" do
132
+ transaction.stub(:amount) { 10 }
133
+ Api.should_receive(:request).with(PAYMENT_SOAP_URL, 'capture', :transactionid => transaction.id, :amount => 1000).and_return(mock('response', :success? => false))
134
+ transaction.capture
135
+ end
136
+
137
+ context "when request is success" do
138
+ it "reloads and returns true" do
139
+ transaction
140
+ Api.stub(:request).with(PAYMENT_SOAP_URL, 'capture', anything).and_return(mock('response', :success? => true))
141
+ transaction.should_receive(:reload)
142
+ transaction.capture.should be_true
143
+ end
144
+ end
145
+
146
+ context "when request fails" do
147
+ it "returns false" do
148
+ transaction
149
+ Epay::Api.stub(:request) { mock('response', :success? => false) }
150
+ transaction.capture.should be_false
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "#credit" do
156
+ context "if amount to be credited is given" do
157
+ it "credits the amount" do
158
+ transaction_id = transaction.id
159
+ Api.should_receive(:request).with(PAYMENT_SOAP_URL, 'credit', :transactionid => transaction_id, :amount => 1000).and_return(mock('response', :success => true))
160
+ transaction.credit(10)
161
+ end
162
+ end
163
+
164
+ context "with no amount given" do
165
+ it "credits full authorization amount" do
166
+ transaction.stub(:credited_amount) { 10 }
167
+ transaction.stub(:amount) { 60 }
168
+ Api.should_receive(:request).with(PAYMENT_SOAP_URL, 'credit', :transactionid => transaction.id, :amount => 5000).and_return(mock('response', :success => true))
169
+ transaction.credit
170
+ end
171
+ end
172
+ end
173
+
174
+ describe ".create" do
175
+ context "with valid card data" do
176
+ it "returns transaction" do
177
+ VCR.use_cassette('transaction_creation') do
178
+ transaction = Transaction.create(
179
+ :card_no => '5555555555555000',
180
+ :exp_year => '15',
181
+ :exp_month => '10',
182
+ :cvc => '999',
183
+ :description => 'For the cool products',
184
+ :currency => :DKK,
185
+ :amount => 60,
186
+ :group => 'Test-transactions',
187
+ :cardholder => 'Jack Jensen',
188
+ :order_no => 'TEST-ORDER-12345'
189
+ )
190
+
191
+ transaction.should be_a Transaction
192
+ transaction.success?.should be_true
193
+ transaction.amount.should == 60
194
+ transaction.cardholder.should == 'Jack Jensen'
195
+ end
196
+ end
197
+ end
198
+
199
+ context "with invalid card data" do
200
+ it "returns failed transaction" do
201
+ VCR.use_cassette('transaction_invalid_creation') do
202
+ transaction = Transaction.create(
203
+ :card_no => '5555555555555118',
204
+ :exp_year => '15',
205
+ :exp_month => '10',
206
+ :cvc => '999',
207
+ :description => 'For the cool products',
208
+ :currency => :DKK,
209
+ :amount => 60,
210
+ :group => 'Test-transactions',
211
+ :cardholder => 'Jack Jensen',
212
+ :order_no => 'TEST-ORDER-12345'
213
+ )
214
+
215
+ transaction.should be_a Transaction
216
+ transaction.success?.should be_false
217
+ transaction.amount.should == 60
218
+ transaction.cardholder.should == 'Jack Jensen'
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ describe ".find" do
225
+ it "returns a transaction" do
226
+ VCR.use_cassette('existing_transaction') do
227
+ Transaction.find(EXISTING_TRANSACTION_ID).should be_a Transaction
228
+ end
229
+ end
230
+
231
+ it "reloads transaction data" do
232
+ Transaction.any_instance.should_receive(:reload)
233
+ Transaction.find(EXISTING_TRANSACTION_ID)
234
+ end
235
+
236
+ context "when transaction doesn't exist" do
237
+ it "raises exception" do
238
+ VCR.use_cassette('non_existing_transaction') do
239
+ lambda { Transaction.find(NON_EXISTING_TRANSACTION_ID) }.should raise_error(TransactionNotFound)
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end