moiper 0.0.1

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.
@@ -0,0 +1,58 @@
1
+ require "nokogiri"
2
+
3
+ module Moiper
4
+ class Payment
5
+ # The unique ID you can set for this payment. This is usefull to keep
6
+ # trak of which payment we will receive on the Moip's notification process.
7
+ attr_accessor :id
8
+
9
+ # The description of the purchase.
10
+ attr_accessor :description
11
+
12
+ # The amount to be billed from the user.
13
+ attr_accessor :price
14
+
15
+ # The URL where the user will be redirected after he finishes the
16
+ # payment process.
17
+ attr_accessor :return_url
18
+
19
+ # The URL where Moip will send notifications about your purchase updates.
20
+ attr_accessor :notification_url
21
+
22
+ # Create a new Moip Payment request
23
+ def initialize(options = {})
24
+ raise ArgumentError if options[:description].nil? || options[:description].empty?
25
+ raise ArgumentError if options[:price].nil? || options[:price].to_f <= 0
26
+
27
+ options.each do |attribute, value|
28
+ send "#{attribute}=", value
29
+ end
30
+ end
31
+
32
+ # Create the payment XML representation
33
+ def to_xml
34
+ builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
35
+ xml.EnviarInstrucao {
36
+ xml.InstrucaoUnica {
37
+ xml.Razao description
38
+ xml.IdProprio id
39
+
40
+ xml.Valores {
41
+ xml.Valor price, :moeda => "BRL"
42
+ }
43
+
44
+ xml.URLNotificacao notification_url
45
+ xml.URLRetorno return_url
46
+ }
47
+ }
48
+ end
49
+
50
+ builder.to_xml
51
+ end
52
+
53
+ def checkout
54
+ request = Request.new
55
+ request.process(to_xml)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,46 @@
1
+ require "net/http"
2
+ require "net/https"
3
+
4
+ module Moiper
5
+ class Request
6
+ CA_FILE = File.expand_path(File.dirname(__FILE__)) + "/cacert.pem"
7
+
8
+ attr_reader :response
9
+
10
+ def process(payload)
11
+ @response = post(payload)
12
+ Response.new(@response.body)
13
+ end
14
+
15
+ def client
16
+ @client ||= Net::HTTP.new(uri.host, uri.port).tap do |http|
17
+ http.use_ssl = true
18
+ http.ca_file = CA_FILE
19
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
20
+ end
21
+ end
22
+
23
+ def request
24
+ @request ||= Net::HTTP::Post.new(uri.path).tap do |request|
25
+ request.basic_auth Moiper.token, Moiper.key
26
+ request.content_type = "text/xml"
27
+ request["User-Agent"] = "Moiper/#{Moiper::VERSION}"
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def post(payload)
34
+ request.body = payload
35
+ client.request(request)
36
+ end
37
+
38
+ def uri
39
+ @uri ||= URI(Moiper.api_entrypoint + path)
40
+ end
41
+
42
+ def path
43
+ "ws/alpha/EnviarInstrucao/Unica"
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ module Moiper
2
+ class Response
3
+ def initialize(body)
4
+ @body = body
5
+ end
6
+
7
+ def success?
8
+ parsed_body.css("Status").text == "Sucesso"
9
+ end
10
+
11
+ def checkout_url
12
+ Moiper.api_entrypoint + "Instrucao.do?token=" + token if success?
13
+ end
14
+
15
+ def token
16
+ parsed_body.css("Token").text
17
+ end
18
+
19
+ def errors
20
+ parsed_body.css("Erro").map(&:text)
21
+ end
22
+
23
+ private
24
+
25
+ def parsed_body
26
+ @parsed_body ||= Nokogiri::XML(@body)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module Moiper
2
+ # Specify the current gem version
3
+ VERSION = "0.0.1"
4
+ end
data/lib/moiper.rb ADDED
@@ -0,0 +1,47 @@
1
+ require "moiper/version"
2
+ require "moiper/payment"
3
+ require "moiper/request"
4
+ require "moiper/response"
5
+
6
+ module Moiper
7
+ API_ENTRYPOINTS = {
8
+ :sandbox => "https://desenvolvedor.moip.com.br/sandbox/",
9
+ :production => "https://www.moip.com.br/"
10
+ }
11
+
12
+ class << self
13
+ # Set Moip's API token
14
+ attr_accessor :token
15
+
16
+ # Set Moip's API key
17
+ attr_accessor :key
18
+
19
+ # Define if requests should be made against Moip's sandbox
20
+ # environment. This is specially usefull when running
21
+ # on development or test mode. Default is false.
22
+ #
23
+ # Moiper.sandbox = true
24
+ #
25
+ attr_accessor :sandbox
26
+
27
+ # Configure Moiper options.
28
+ #
29
+ # Moiper.configure do |config|
30
+ # config.sandbox = true
31
+ # end
32
+ #
33
+ def configure(&block)
34
+ yield self
35
+ end
36
+
37
+ # Inform if in sandbox mode
38
+ def sandbox?
39
+ sandbox == true
40
+ end
41
+
42
+ # Returns the Moip API entrypoint based on the current environment
43
+ def api_entrypoint
44
+ sandbox? ? API_ENTRYPOINTS[:sandbox] : API_ENTRYPOINTS[:production]
45
+ end
46
+ end
47
+ end
data/moiper.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'moiper/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "moiper"
8
+ gem.version = Moiper::VERSION
9
+ gem.authors = ["Rodrigo Navarro"]
10
+ gem.email = ["rnavarro1@gmail.com"]
11
+ gem.description = %q{Moip payment service integration library.}
12
+ gem.summary = gem.description
13
+ gem.homepage = "http://rubygems.org/gems/moiper"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency "nokogiri"
21
+ gem.add_development_dependency "rspec"
22
+ end
@@ -0,0 +1,108 @@
1
+ require "spec_helper"
2
+
3
+ describe Moiper::Payment do
4
+ describe "#initialize" do
5
+ subject {
6
+ Moiper::Payment.new(
7
+ :description => "A chair",
8
+ :price => 1.99,
9
+ :id => "some unique id",
10
+ :return_url => "http://example.org/thank_you",
11
+ :notification_url => "http://example.org/moip/notification"
12
+ )
13
+ }
14
+
15
+ its(:description) { should eq "A chair" }
16
+ its(:price) { should == 1.99 }
17
+ its(:id) { should eq "some unique id" }
18
+ its(:return_url) { should eq "http://example.org/thank_you"}
19
+ its(:notification_url) { should eq "http://example.org/moip/notification" }
20
+
21
+ it "raises an error when no description is given" do
22
+ expect {
23
+ Moiper::Payment.new(
24
+ :price => 1.99,
25
+ :id => "some unique id",
26
+ :return_url => "http://example.org/thank_you",
27
+ :notification_url => "http://example.org/moip/notification"
28
+ )
29
+ }.to raise_error ArgumentError
30
+ end
31
+
32
+ it "raises an error when a blank description is given" do
33
+ expect {
34
+ Moiper::Payment.new(
35
+ :description => "",
36
+ :price => 1.99,
37
+ :id => "some unique id",
38
+ :return_url => "http://example.org/thank_you",
39
+ :notification_url => "http://example.org/moip/notification"
40
+ )
41
+ }.to raise_error ArgumentError
42
+ end
43
+
44
+ it "raises an error when no price is given" do
45
+ expect {
46
+ Moiper::Payment.new(
47
+ :description => "Some description",
48
+ :id => "some unique id",
49
+ :return_url => "http://example.org/thank_you",
50
+ :notification_url => "http://example.org/moip/notification"
51
+ )
52
+ }.to raise_error ArgumentError
53
+ end
54
+
55
+ it "raises an error when the price is zero" do
56
+ expect {
57
+ Moiper::Payment.new(
58
+ :description => "Some description",
59
+ :price => 0,
60
+ :id => "some unique id",
61
+ :return_url => "http://example.org/thank_you",
62
+ :notification_url => "http://example.org/moip/notification"
63
+ )
64
+ }.to raise_error ArgumentError
65
+ end
66
+
67
+ it "raises an error when the price is lower than zero" do
68
+ expect {
69
+ Moiper::Payment.new(
70
+ :description => "Some description",
71
+ :price => -10,
72
+ :id => "some unique id",
73
+ :return_url => "http://example.org/thank_you",
74
+ :notification_url => "http://example.org/moip/notification"
75
+ )
76
+ }.to raise_error ArgumentError
77
+ end
78
+ end
79
+
80
+ describe "#to_xml" do
81
+ let(:payment) {
82
+ Moiper::Payment.new(
83
+ :description => "A chair",
84
+ :price => 1.99,
85
+ :id => "some unique id",
86
+ :return_url => "http://example.org/thank_you",
87
+ :notification_url => "http://example.org/moip/notification"
88
+ )
89
+ }
90
+
91
+ let(:doc) { Nokogiri::XML(payment.to_xml) }
92
+
93
+ it { doc.at_css("> EnviarInstrucao").should_not be_nil }
94
+ it { doc.at_css("EnviarInstrucao > InstrucaoUnica").should_not be_nil }
95
+ it { doc.at_css("InstrucaoUnica > IdProprio").should_not be_nil }
96
+ it { doc.at_css("InstrucaoUnica > Valores").should_not be_nil }
97
+ it { doc.at_css("Valores > Valor").should_not be_nil }
98
+ it { doc.at_css("InstrucaoUnica > URLRetorno").should_not be_nil }
99
+ it { doc.at_css("InstrucaoUnica > URLNotificacao").should_not be_nil }
100
+
101
+ it { doc.at_css("InstrucaoUnica > IdProprio").text.should eq "some unique id"}
102
+ it { doc.at_css("Valores > Valor").text.should eq "1.99"}
103
+ it { doc.at_css("Valores > Valor").attributes["moeda"].value.should eq "BRL"}
104
+
105
+ it { doc.at_css("InstrucaoUnica > URLRetorno").text.should eq "http://example.org/thank_you" }
106
+ it { doc.at_css("InstrucaoUnica > URLNotificacao").text.should eq "http://example.org/moip/notification" }
107
+ end
108
+ end
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe Moiper::Request do
4
+ describe "#process" do
5
+ it "returns a Response object" do
6
+ response = Moiper::Request.new.process("<someXml></someXml>")
7
+ response.should be_kind_of Moiper::Response
8
+ end
9
+ end
10
+
11
+ describe "#client" do
12
+ let(:client) { Moiper::Request.new.client }
13
+
14
+ it "uses SSL" do
15
+ client.use_ssl?.should be_true
16
+ end
17
+
18
+ it "verifies the certificate" do
19
+ client.verify_mode.should == OpenSSL::SSL::VERIFY_PEER
20
+ end
21
+
22
+ it "uses the right ca file" do
23
+ client.ca_file.should == Moiper::Request::CA_FILE
24
+ end
25
+ end
26
+
27
+ describe "#request" do
28
+ subject { Moiper::Request.new.request }
29
+ its(:content_type) { should eq "text/xml" }
30
+
31
+ it "sets the correct token and key parameters" do
32
+ Net::HTTP::Post.any_instance.should_receive(:basic_auth).with(Moiper.token, Moiper.key)
33
+ Moiper::Request.new.request
34
+ end
35
+
36
+ it "has the correct user agent" do
37
+ headers = Hash[subject.each_capitalized.to_a]
38
+ headers["User-Agent"].should eq "Moiper/#{Moiper::VERSION}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ require "spec_helper"
4
+
5
+ describe Moiper::Response do
6
+ let(:success_response_fixture) {
7
+ %Q{
8
+ <?xml version="1.0"?>
9
+ <ns1:EnviarInstrucaoUnicaResponse xmlns:ns1="http://www.moip.com.br/ws/alpha/">
10
+ <Resposta>
11
+ <ID>201301221539573040000001453849</ID>
12
+ <Status>Sucesso</Status>
13
+ <Token>M2M0J1D3M0U1L2L2S1W5V3X9T5V7Y3X0W4U0M0Z0L0G02001S4F513N8N4J9</Token>
14
+ </Resposta>
15
+ </ns1:EnviarInstrucaoUnicaResponse>
16
+ }
17
+ }
18
+
19
+ let(:error_response_fixture) {
20
+ %Q{
21
+ <?xml version="1.0"?>
22
+ <ns1:EnviarInstrucaoUnicaResponse xmlns:ns1="http://www.moip.com.br/ws/alpha/">
23
+ <Resposta>
24
+ <ID>201301221546325890000001453860</ID>
25
+ <Status>Falha</Status>
26
+ <Erro Codigo="101">A razão do pagamento deve ser enviada obrigatoriamente</Erro>
27
+ <Erro Codigo="102">Id Próprio já foi utilizado em outra Instrução</Erro>
28
+ </Resposta>
29
+ </ns1:EnviarInstrucaoUnicaResponse>
30
+ }
31
+ }
32
+
33
+ describe "#checkout_url" do
34
+ context "when the response is success" do
35
+ it "returns the url the user should be redirected" do
36
+ response = Moiper::Response.new(success_response_fixture)
37
+ response.checkout_url.should eq Moiper.api_entrypoint + "Instrucao.do?token=" + response.token
38
+ end
39
+ end
40
+
41
+ context "when the response returns an error" do
42
+ it "returns nil" do
43
+ response = Moiper::Response.new(error_response_fixture)
44
+ response.checkout_url.should be_nil
45
+ end
46
+ end
47
+ end
48
+
49
+ describe "#success?" do
50
+ subject { Moiper::Response.new(body).success? }
51
+
52
+ context "when the response is success" do
53
+ let(:body) { success_response_fixture }
54
+ it { should be_true }
55
+ end
56
+
57
+ context "when the response returns an error" do
58
+ let(:body) { error_response_fixture }
59
+ it { should be_false }
60
+ end
61
+ end
62
+
63
+ describe "#errors" do
64
+ context "when the response is success" do
65
+ it "is an empty array" do
66
+ Moiper::Response.new(success_response_fixture).errors.should be_empty
67
+ end
68
+ end
69
+
70
+ context "when the response returns an error" do
71
+ it "returns an array with errors" do
72
+ errors = Moiper::Response.new(error_response_fixture).errors
73
+ errors.should include "A razão do pagamento deve ser enviada obrigatoriamente"
74
+ errors.should include "Id Próprio já foi utilizado em outra Instrução"
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ describe Moiper do
4
+ describe ".configure" do
5
+ it "yields Moiper" do
6
+ Moiper.configure do |config|
7
+ config.should be Moiper
8
+ end
9
+ end
10
+
11
+ it "sets a token configuration" do
12
+ Moiper.configure do |config|
13
+ config.token = "Some Token"
14
+ end
15
+
16
+ Moiper.token.should eq "Some Token"
17
+ end
18
+
19
+ it "sets a key configuration" do
20
+ Moiper.configure do |config|
21
+ config.key = "Some Key"
22
+ end
23
+
24
+ Moiper.key.should eq "Some Key"
25
+ end
26
+ end
27
+
28
+ describe ".sandbox?" do
29
+ it "is true when you set sandbox configuration true" do
30
+ Moiper.configure do |config|
31
+ config.sandbox = true
32
+ end
33
+
34
+ Moiper.sandbox?.should be_true
35
+ end
36
+
37
+ it "is false when you set sandbox configuration to false" do
38
+ Moiper.configure do |config|
39
+ config.sandbox = false
40
+ end
41
+
42
+ Moiper.sandbox?.should be_false
43
+ end
44
+ end
45
+
46
+ describe ".api_entrypoint" do
47
+ subject { Moiper.api_entrypoint }
48
+
49
+ it "is the sandbox url when sandbox is enabled" do
50
+ Moiper.sandbox = true
51
+ should == Moiper::API_ENTRYPOINTS[:sandbox]
52
+ end
53
+
54
+ it "is the production url when sandbox is disabled" do
55
+ Moiper.sandbox = false
56
+ should == Moiper::API_ENTRYPOINTS[:production]
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,11 @@
1
+ require "moiper"
2
+
3
+ RSpec.configure do |config|
4
+ config.before do
5
+ Moiper.configure do |config|
6
+ config.sandbox = true
7
+ config.token = "01010101010101010101010101010101"
8
+ config.key = "ABABABABABABABABABABABABABABABABABABABAB"
9
+ end
10
+ end
11
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: moiper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Rodrigo Navarro
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-01-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: &2160726500 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2160726500
25
+ - !ruby/object:Gem::Dependency
26
+ name: rspec
27
+ requirement: &2160725540 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2160725540
36
+ description: Moip payment service integration library.
37
+ email:
38
+ - rnavarro1@gmail.com
39
+ executables: []
40
+ extensions: []
41
+ extra_rdoc_files: []
42
+ files:
43
+ - .gitignore
44
+ - Gemfile
45
+ - LICENSE.txt
46
+ - README.md
47
+ - Rakefile
48
+ - lib/moiper.rb
49
+ - lib/moiper/cacert.pem
50
+ - lib/moiper/payment.rb
51
+ - lib/moiper/request.rb
52
+ - lib/moiper/response.rb
53
+ - lib/moiper/version.rb
54
+ - moiper.gemspec
55
+ - spec/moiper/payment_spec.rb
56
+ - spec/moiper/request_spec.rb
57
+ - spec/moiper/response_spec.rb
58
+ - spec/moiper_spec.rb
59
+ - spec/spec_helper.rb
60
+ homepage: http://rubygems.org/gems/moiper
61
+ licenses: []
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ segments:
73
+ - 0
74
+ hash: 657788424020654005
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ segments:
82
+ - 0
83
+ hash: 657788424020654005
84
+ requirements: []
85
+ rubyforge_project:
86
+ rubygems_version: 1.8.11
87
+ signing_key:
88
+ specification_version: 3
89
+ summary: Moip payment service integration library.
90
+ test_files:
91
+ - spec/moiper/payment_spec.rb
92
+ - spec/moiper/request_spec.rb
93
+ - spec/moiper/response_spec.rb
94
+ - spec/moiper_spec.rb
95
+ - spec/spec_helper.rb