cloud_payments 0.0.2

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.rspec +4 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +10 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +106 -0
  8. data/Rakefile +7 -0
  9. data/cloud_payments.gemspec +28 -0
  10. data/config.ru +58 -0
  11. data/lib/cloud_payments.rb +34 -0
  12. data/lib/cloud_payments/client.rb +50 -0
  13. data/lib/cloud_payments/client/errors.rb +68 -0
  14. data/lib/cloud_payments/client/gateway_errors.rb +36 -0
  15. data/lib/cloud_payments/client/response.rb +22 -0
  16. data/lib/cloud_payments/client/serializer.rb +9 -0
  17. data/lib/cloud_payments/client/serializer/base.rb +46 -0
  18. data/lib/cloud_payments/client/serializer/multi_json.rb +17 -0
  19. data/lib/cloud_payments/config.rb +44 -0
  20. data/lib/cloud_payments/models.rb +4 -0
  21. data/lib/cloud_payments/models/model.rb +5 -0
  22. data/lib/cloud_payments/models/secure3d.rb +15 -0
  23. data/lib/cloud_payments/models/subscription.rb +49 -0
  24. data/lib/cloud_payments/models/transaction.rb +82 -0
  25. data/lib/cloud_payments/namespaces.rb +23 -0
  26. data/lib/cloud_payments/namespaces/base.rb +50 -0
  27. data/lib/cloud_payments/namespaces/cards.rb +25 -0
  28. data/lib/cloud_payments/namespaces/payments.rb +32 -0
  29. data/lib/cloud_payments/namespaces/subscriptions.rb +24 -0
  30. data/lib/cloud_payments/namespaces/tokens.rb +15 -0
  31. data/lib/cloud_payments/version.rb +3 -0
  32. data/spec/cloud_payments/client/response_spec.rb +35 -0
  33. data/spec/cloud_payments/client/serializer/multi_json_spec.rb +16 -0
  34. data/spec/cloud_payments/client_spec.rb +5 -0
  35. data/spec/cloud_payments/models/secure3d_spec.rb +37 -0
  36. data/spec/cloud_payments/models/subscription_spec.rb +141 -0
  37. data/spec/cloud_payments/models/transaction_spec.rb +254 -0
  38. data/spec/cloud_payments/namespaces/base_spec.rb +75 -0
  39. data/spec/cloud_payments/namespaces/cards_spec.rb +119 -0
  40. data/spec/cloud_payments/namespaces/payments_spec.rb +96 -0
  41. data/spec/cloud_payments/namespaces/subscriptions_spec.rb +82 -0
  42. data/spec/cloud_payments/namespaces/tokens_spec.rb +90 -0
  43. data/spec/cloud_payments/namespaces_spec.rb +45 -0
  44. data/spec/cloud_payments_spec.rb +14 -0
  45. data/spec/fixtures/apis/cards/auth/failed.yml +45 -0
  46. data/spec/fixtures/apis/cards/auth/secure3d.yml +15 -0
  47. data/spec/fixtures/apis/cards/auth/successful.yml +48 -0
  48. data/spec/fixtures/apis/cards/charge/failed.yml +45 -0
  49. data/spec/fixtures/apis/cards/charge/secure3d.yml +15 -0
  50. data/spec/fixtures/apis/cards/charge/successful.yml +48 -0
  51. data/spec/fixtures/apis/payments/confirm/failed.yml +6 -0
  52. data/spec/fixtures/apis/payments/confirm/failed_with_message.yml +6 -0
  53. data/spec/fixtures/apis/payments/confirm/successful.yml +6 -0
  54. data/spec/fixtures/apis/payments/post3ds/failed.yml +45 -0
  55. data/spec/fixtures/apis/payments/post3ds/successful.yml +48 -0
  56. data/spec/fixtures/apis/payments/refund/failed.yml +6 -0
  57. data/spec/fixtures/apis/payments/refund/failed_with_message.yml +6 -0
  58. data/spec/fixtures/apis/payments/refund/successful.yml +6 -0
  59. data/spec/fixtures/apis/payments/void/failed.yml +6 -0
  60. data/spec/fixtures/apis/payments/void/failed_with_message.yml +6 -0
  61. data/spec/fixtures/apis/payments/void/successful.yml +6 -0
  62. data/spec/fixtures/apis/ping/failed.yml +5 -0
  63. data/spec/fixtures/apis/ping/successful.yml +5 -0
  64. data/spec/fixtures/apis/subscriptions/cancel/successful.yml +6 -0
  65. data/spec/fixtures/apis/subscriptions/create/successful.yml +31 -0
  66. data/spec/fixtures/apis/subscriptions/find/successful.yml +31 -0
  67. data/spec/fixtures/apis/subscriptions/update/successful.yml +31 -0
  68. data/spec/fixtures/apis/tokens/auth/failed.yml +45 -0
  69. data/spec/fixtures/apis/tokens/auth/successful.yml +48 -0
  70. data/spec/fixtures/apis/tokens/charge/failed.yml +45 -0
  71. data/spec/fixtures/apis/tokens/charge/successful.yml +48 -0
  72. data/spec/spec_helper.rb +38 -0
  73. data/spec/support/examples.rb +27 -0
  74. data/spec/support/helpers.rb +89 -0
  75. metadata +244 -0
@@ -0,0 +1,5 @@
1
+ ---
2
+ :request:
3
+ :url: '/test'
4
+ :response:
5
+ :body: '{"Success":false}'
@@ -0,0 +1,5 @@
1
+ ---
2
+ :request:
3
+ :url: '/test'
4
+ :response:
5
+ :body: '{"Success":true}'
@@ -0,0 +1,6 @@
1
+ ---
2
+ :request:
3
+ :url: '/subscriptions/cancel'
4
+ :body: '{"Id":"sc_8cf8a9338fb"}'
5
+ :response:
6
+ :body: '{"Success":true,"Message": null}'
@@ -0,0 +1,31 @@
1
+ ---
2
+ :request:
3
+ :url: '/subscriptions/create'
4
+ :body: '{"Token":"477BBA133C182267F","AccountId":"user@example.com","Description":"Monthly subscription","Email":"user@example.com","Amount":1.02,"Currency":"RUB","RequireConfirmation":false,"StartDate":"2014-08-09T11:49:41","Interval":"Month","Period":1,"MaxPeriods":12}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model":{
9
+ "Id":"sc_8cf8a9338fb",
10
+ "AccountId":"user@example.com",
11
+ "Description":"Monthly subscription",
12
+ "Email":"user@example.com",
13
+ "Amount":1.02,
14
+ "CurrencyCode":0,
15
+ "Currency":"RUB",
16
+ "RequireConfirmation":false,
17
+ "StartDateIso":"2014-08-09T11:49:41",
18
+ "IntervalCode":1,
19
+ "Interval":"Month",
20
+ "Period":1,
21
+ "MaxPeriods":12,
22
+ "StatusCode":0,
23
+ "Status":"Active",
24
+ "SuccessfulTransactionsNumber":0,
25
+ "FailedTransactionsNumber":0,
26
+ "LastTransactionDateIso":"2014-08-09T11:49:41",
27
+ "NextTransactionDateIso":"2014-08-09T11:49:41"
28
+ },
29
+ "Success":true,
30
+ "Message": null
31
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ :request:
3
+ :url: '/subscriptions/get'
4
+ :body: '{"Id":"sc_8cf8a9338fb"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model":{
9
+ "Id":"sc_8cf8a9338fb",
10
+ "AccountId":"user@example.com",
11
+ "Description":"Monthly subscription",
12
+ "Email":"user@example.com",
13
+ "Amount":1.02,
14
+ "CurrencyCode":0,
15
+ "Currency":"RUB",
16
+ "RequireConfirmation":false,
17
+ "StartDateIso":"2014-08-09T11:49:41",
18
+ "IntervalCode":1,
19
+ "Interval":"Month",
20
+ "Period":1,
21
+ "MaxPeriods":12,
22
+ "StatusCode":0,
23
+ "Status":"Active",
24
+ "SuccessfulTransactionsNumber":0,
25
+ "FailedTransactionsNumber":0,
26
+ "LastTransactionDateIso":"2014-08-09T11:49:41",
27
+ "NextTransactionDateIso":"2014-08-09T11:49:41"
28
+ },
29
+ "Success":true,
30
+ "Message": null
31
+ }
@@ -0,0 +1,31 @@
1
+ ---
2
+ :request:
3
+ :url: '/subscriptions/update'
4
+ :body: '{"AccountId":"user2@example.com","Email":"user2@example.com","MaxPeriods":6,"Id":"sc_8cf8a9338fb"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model":{
9
+ "Id":"sc_8cf8a9338fb",
10
+ "AccountId":"user2@example.com",
11
+ "Description":"Monthly subscription",
12
+ "Email":"user2@example.com",
13
+ "Amount":1.02,
14
+ "CurrencyCode":0,
15
+ "Currency":"RUB",
16
+ "RequireConfirmation":false,
17
+ "StartDateIso":"2014-08-09T11:49:41",
18
+ "IntervalCode":1,
19
+ "Interval":"Month",
20
+ "Period":1,
21
+ "MaxPeriods":6,
22
+ "StatusCode":0,
23
+ "Status":"Active",
24
+ "SuccessfulTransactionsNumber":0,
25
+ "FailedTransactionsNumber":0,
26
+ "LastTransactionDateIso":"2014-08-09T11:49:41",
27
+ "NextTransactionDateIso":"2014-08-09T11:49:41"
28
+ },
29
+ "Success":true,
30
+ "Message": null
31
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ :request:
3
+ :url: '/payments/tokens/auth'
4
+ :body: '{"Amount":10,"Currency":"RUB","InvoiceId":"1234567","Description":"Payment for goods on example.com","AccountId":"user_x","Name":"CARDHOLDER NAME","Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model": {
9
+ "TransactionId": 12345,
10
+ "Amount": 10.0,
11
+ "Currency": "RUB",
12
+ "CurrencyCode": 0,
13
+ "PaymentAmount": 10.0,
14
+ "PaymentCurrency": "RUB",
15
+ "PaymentCurrencyCode": 0,
16
+ "InvoiceId": "1234567",
17
+ "AccountId": "user_x",
18
+ "Email": null,
19
+ "Description": "Payment for goods on example.com",
20
+ "JsonData": null,
21
+ "CreatedDate": "\/Date(1401718880000)\/",
22
+ "CreatedDateIso":"2014-08-09T11:49:41",
23
+ "TestMode": true,
24
+ "IpAddress": "195.91.194.13",
25
+ "IpCountry": "RU",
26
+ "IpCity": "Ufa",
27
+ "IpRegion": "Bashkortostan Republic",
28
+ "IpDistrict": "Volga Federal District",
29
+ "IpLatitude": 54.7355,
30
+ "IpLongitude": 55.991982,
31
+ "CardFirstSix": "411111",
32
+ "CardLastFour": "1111",
33
+ "CardType": "Visa",
34
+ "CardTypeCode": 0,
35
+ "IssuerBankCountry": "RU",
36
+ "Status": "Declined",
37
+ "StatusCode": 5,
38
+ "Reason": "InsufficientFunds",
39
+ "ReasonCode": 5051,
40
+ "CardHolderMessage": "Insufficient funds on account",
41
+ "Name": "CARDHOLDER NAME"
42
+ },
43
+ "Success": false,
44
+ "Message": null
45
+ }
@@ -0,0 +1,48 @@
1
+ ---
2
+ :request:
3
+ :url: '/payments/tokens/auth'
4
+ :body: '{"Amount":10,"Currency":"RUB","InvoiceId":"1234567","Description":"Payment for goods on example.com","AccountId":"user_x","Name":"CARDHOLDER NAME","Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model":{
9
+ "TransactionId":12345,
10
+ "Amount":10.0,
11
+ "Currency":"RUB",
12
+ "CurrencyCode":0,
13
+ "InvoiceId":"1234567",
14
+ "AccountId":"user_x",
15
+ "Email":null,
16
+ "Description":"Payment for goods on example.com",
17
+ "JsonData":null,
18
+ "CreatedDate":"\/Date(1401718880000)\/",
19
+ "CreatedDateIso":"2014-08-09T11:49:41",
20
+ "AuthDate":"\/Date(1401733880523)\/",
21
+ "AuthDateIso":"2014-08-09T11:49:42",
22
+ "ConfirmDate":null,
23
+ "ConfirmDateIso":null,
24
+ "AuthCode":"123456",
25
+ "TestMode":true,
26
+ "IpAddress":"195.91.194.13",
27
+ "IpCountry":"RU",
28
+ "IpCity":"Ufa",
29
+ "IpRegion":"Bashkortostan Republic",
30
+ "IpDistrict":"Volga Federal District",
31
+ "IpLatitude":54.7355,
32
+ "IpLongitude":55.991982,
33
+ "CardFirstSix":"411111",
34
+ "CardLastFour":"1111",
35
+ "CardType":"Visa",
36
+ "CardTypeCode":0,
37
+ "IssuerBankCountry":"RU",
38
+ "Status":"Authorized",
39
+ "StatusCode":3,
40
+ "Reason":"Approved",
41
+ "ReasonCode":0,
42
+ "CardHolderMessage":"Payment successful",
43
+ "Name":"CARDHOLDER NAME",
44
+ "Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"
45
+ },
46
+ "Success":true,
47
+ "Message": null
48
+ }
@@ -0,0 +1,45 @@
1
+ ---
2
+ :request:
3
+ :url: '/payments/tokens/charge'
4
+ :body: '{"Amount":10,"Currency":"RUB","InvoiceId":"1234567","Description":"Payment for goods on example.com","AccountId":"user_x","Name":"CARDHOLDER NAME","Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model": {
9
+ "TransactionId": 12345,
10
+ "Amount": 10.0,
11
+ "Currency": "RUB",
12
+ "CurrencyCode": 0,
13
+ "PaymentAmount": 10.0,
14
+ "PaymentCurrency": "RUB",
15
+ "PaymentCurrencyCode": 0,
16
+ "InvoiceId": "1234567",
17
+ "AccountId": "user_x",
18
+ "Email": null,
19
+ "Description": "Payment for goods on example.com",
20
+ "JsonData": null,
21
+ "CreatedDate": "\/Date(1401718880000)\/",
22
+ "CreatedDateIso":"2014-08-09T11:49:41",
23
+ "TestMode": true,
24
+ "IpAddress": "195.91.194.13",
25
+ "IpCountry": "RU",
26
+ "IpCity": "Ufa",
27
+ "IpRegion": "Bashkortostan Republic",
28
+ "IpDistrict": "Volga Federal District",
29
+ "IpLatitude": 54.7355,
30
+ "IpLongitude": 55.991982,
31
+ "CardFirstSix": "411111",
32
+ "CardLastFour": "1111",
33
+ "CardType": "Visa",
34
+ "CardTypeCode": 0,
35
+ "IssuerBankCountry": "RU",
36
+ "Status": "Declined",
37
+ "StatusCode": 5,
38
+ "Reason": "InsufficientFunds",
39
+ "ReasonCode": 5051,
40
+ "CardHolderMessage": "Insufficient funds on account",
41
+ "Name": "CARDHOLDER NAME"
42
+ },
43
+ "Success": false,
44
+ "Message": null
45
+ }
@@ -0,0 +1,48 @@
1
+ ---
2
+ :request:
3
+ :url: '/payments/tokens/charge'
4
+ :body: '{"Amount":10,"Currency":"RUB","InvoiceId":"1234567","Description":"Payment for goods on example.com","AccountId":"user_x","Name":"CARDHOLDER NAME","Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"}'
5
+ :response:
6
+ :body: >
7
+ {
8
+ "Model":{
9
+ "TransactionId":12345,
10
+ "Amount":10.0,
11
+ "Currency":"RUB",
12
+ "CurrencyCode":0,
13
+ "InvoiceId":"1234567",
14
+ "AccountId":"user_x",
15
+ "Email":null,
16
+ "Description":"Payment for goods on example.com",
17
+ "JsonData":null,
18
+ "CreatedDate":"\/Date(1401718880000)\/",
19
+ "CreatedDateIso":"2014-08-09T11:49:41",
20
+ "AuthDate":"\/Date(1401733880523)\/",
21
+ "AuthDateIso":"2014-08-09T11:49:42",
22
+ "ConfirmDate":"\/Date(1401733880523)\/",
23
+ "ConfirmDateIso":"2014-08-09T11:49:42",
24
+ "AuthCode":"123456",
25
+ "TestMode":true,
26
+ "IpAddress":"195.91.194.13",
27
+ "IpCountry":"RU",
28
+ "IpCity":"Ufa",
29
+ "IpRegion":"Bashkortostan Republic",
30
+ "IpDistrict":"Volga Federal District",
31
+ "IpLatitude":54.7355,
32
+ "IpLongitude":55.991982,
33
+ "CardFirstSix":"411111",
34
+ "CardLastFour":"1111",
35
+ "CardType":"Visa",
36
+ "CardTypeCode":0,
37
+ "IssuerBankCountry":"RU",
38
+ "Status":"Completed",
39
+ "StatusCode":3,
40
+ "Reason":"Approved",
41
+ "ReasonCode":0,
42
+ "CardHolderMessage":"Payment successful",
43
+ "Name":"CARDHOLDER NAME",
44
+ "Token":"a4e67841-abb0-42de-a364-d1d8f9f4b3c0"
45
+ },
46
+ "Success":true,
47
+ "Message": null
48
+ }
@@ -0,0 +1,38 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+
3
+ if ENV['CODECLIMATE_REPO_TOKEN']
4
+ require "codeclimate-test-reporter"
5
+ CodeClimate::TestReporter.start
6
+ end
7
+
8
+ require 'bundler'
9
+ Bundler.require(:default, :test)
10
+
11
+ WebMock.disable_net_connect!
12
+
13
+ Dir["./spec/support/**/*.rb"].each { |f| require f }
14
+
15
+ CloudPayments.configure do |c|
16
+ c.public_key = 'user'
17
+ c.secret_key = 'pass'
18
+ c.host = 'http://localhost:9292'
19
+ c.log = false
20
+ # c.raise_banking_errors = true
21
+ end
22
+
23
+ RSpec.configure do |config|
24
+ config.mock_with :rspec
25
+ config.include CloudPayments::RSpec::Helpers
26
+
27
+ config.after(:suite){ WebMock.allow_net_connect! }
28
+
29
+ # config.around :each, time_freeze: ->(v){ v.is_a?(Date) || v.is_a?(Time) || v.is_a?(String) } do |example|
30
+ # datetime = if example.metadata[:time_freeze].is_a?(String)
31
+ # DateTime.parse(example.metadata[:time_freeze])
32
+ # else
33
+ # example.metadata[:time_freeze]
34
+ # end
35
+
36
+ # Timecop.freeze(datetime){ example.run }
37
+ # end
38
+ end
@@ -0,0 +1,27 @@
1
+ RSpec.shared_examples :not_raise_without_attribute do |key, method = nil|
2
+ method = key unless method
3
+
4
+ context "without `#{key}` attribute" do
5
+ subject do
6
+ attrs = attributes.dup
7
+ attrs.delete(key)
8
+ described_class.new(attrs)
9
+ end
10
+
11
+ specify{ expect{ subject }.not_to raise_error }
12
+ end
13
+ end
14
+
15
+ RSpec.shared_examples :raise_without_attribute do |key, method = nil|
16
+ method = key unless method
17
+
18
+ context "without `#{key}` attribute" do
19
+ subject do
20
+ attrs = attributes.dup
21
+ attrs.delete(key)
22
+ described_class.new(attrs)
23
+ end
24
+
25
+ specify{ expect{ subject }.to raise_error(/\'#{method}\' is required/) }
26
+ end
27
+ end
@@ -0,0 +1,89 @@
1
+ require 'yaml'
2
+
3
+ module CloudPayments
4
+ module RSpec
5
+ module Helpers
6
+ class StubApiRequest
7
+ attr_reader :name
8
+
9
+ def initialize(name)
10
+ @name = name
11
+ end
12
+
13
+ def perform
14
+ webmock_stub.to_return(
15
+ status: response[:status] || 200,
16
+ body: response[:body] || '',
17
+ headers: response_headers
18
+ ) if webmock_stub
19
+ end
20
+
21
+ def to_return(options)
22
+ webmock_stub.to_return(return_options.merge(options)) if webmock_stub
23
+ end
24
+
25
+ def to_raise(*args)
26
+ webmock_stub.to_raise(*args) if webmock_stub
27
+ end
28
+
29
+ def to_timeout
30
+ webmock_stub.to_timeout if webmock_stub
31
+ end
32
+
33
+ private
34
+
35
+ def return_options
36
+ {
37
+ status: response[:status] || 200,
38
+ body: response[:body] || '',
39
+ headers: response_headers
40
+ }
41
+ end
42
+
43
+ def webmock_stub
44
+ @webmock_stub ||= begin
45
+ if fixture
46
+ WebMock::StubRegistry.instance.register_request_stub(WebMock::RequestStub.new(:post, url)).
47
+ with(body: request[:body] || '', headers: request_headers)
48
+ end
49
+ end
50
+ end
51
+
52
+ def url
53
+ "http://user:pass@localhost:9292#{request[:url]}"
54
+ end
55
+
56
+ def request_headers
57
+ { 'Content-Type' => 'application/json' }.merge(request[:headers] || {})
58
+ end
59
+
60
+ def response_headers
61
+ { 'Content-Type' => 'application/json' }.merge(response[:headers] || {})
62
+ end
63
+
64
+ def request
65
+ fixture[:request] || {}
66
+ end
67
+
68
+ def response
69
+ fixture[:response] || {}
70
+ end
71
+
72
+ def fixture
73
+ @fixture ||= begin
74
+ file = fixture_path.join("#{name}.yml").to_s
75
+ YAML.load(File.read(file)) if File.exists?(file)
76
+ end
77
+ end
78
+
79
+ def fixture_path
80
+ Pathname.new(File.expand_path('../../fixtures/apis', __FILE__))
81
+ end
82
+ end
83
+
84
+ def stub_api_request(name)
85
+ StubApiRequest.new(name)
86
+ end
87
+ end
88
+ end
89
+ end