duke-moip 0.2.0

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,26 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+ .bundle
21
+
22
+ ## PROJECT::SPECIFIC
23
+ lib/main.rb
24
+ config.yaml
25
+ config/
26
+ config/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # A sample Gemfile
2
+ source "http://rubygems.org"
3
+
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,48 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ moip (1.0.2)
5
+ activesupport (>= 2.3.2)
6
+ httparty (~> 0.12.0)
7
+ nokogiri (>= 1.5.0)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ activesupport (4.0.2)
13
+ i18n (~> 0.6, >= 0.6.4)
14
+ minitest (~> 4.2)
15
+ multi_json (~> 1.3)
16
+ thread_safe (~> 0.1)
17
+ tzinfo (~> 0.3.37)
18
+ atomic (1.1.14)
19
+ diff-lcs (1.2.4)
20
+ httparty (0.12.0)
21
+ json (~> 1.8)
22
+ multi_xml (>= 0.5.2)
23
+ i18n (0.6.9)
24
+ json (1.8.1)
25
+ mini_portile (0.5.2)
26
+ minitest (4.7.5)
27
+ multi_json (1.8.4)
28
+ multi_xml (0.5.5)
29
+ nokogiri (1.6.1)
30
+ mini_portile (~> 0.5.0)
31
+ rspec (2.13.0)
32
+ rspec-core (~> 2.13.0)
33
+ rspec-expectations (~> 2.13.0)
34
+ rspec-mocks (~> 2.13.0)
35
+ rspec-core (2.13.1)
36
+ rspec-expectations (2.13.0)
37
+ diff-lcs (>= 1.1.3, < 2.0)
38
+ rspec-mocks (2.13.1)
39
+ thread_safe (0.1.3)
40
+ atomic
41
+ tzinfo (0.3.38)
42
+
43
+ PLATFORMS
44
+ ruby
45
+
46
+ DEPENDENCIES
47
+ moip!
48
+ rspec (>= 2.1.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Guilherme Nascimento
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,87 @@
1
+ # MoIP
2
+
3
+ Esta Gem permite utilizar a API do MoIP, gateway de pagamentos do IG.
4
+
5
+ ## Pagamento direto
6
+
7
+ O Pagamento Direto é um recurso que a MoIP disponibiliza para aqueles clientes que necessitam de uma flexibilidade maior do que a Integração HTML pode oferecer.
8
+
9
+ Diferentemente de como é feito com a Integração HTML, seu cliente não precisa ser redirecionado para o site da MoIP para concluir a compra: tudo é feito dentro do ambiente do seu site, dando ao cliente uma maior segurança e confiança no processo.
10
+
11
+ As formas de pagamento disponibilizadas pela Gem são:
12
+
13
+ * Boleto
14
+ * Débito
15
+ * Cartão de Crédito
16
+
17
+ ## Instalação
18
+
19
+ Instale a Gem
20
+ gem install moip
21
+
22
+ Adicione a Gem ao Gemfile
23
+ gem "moip"
24
+
25
+ ## Utilização
26
+
27
+ O MoIP possui uma SandBox de testes que permite a simulação de pagamentos. Para utilizar a Gem com o SandBox, adicione a seguinte configuração no arquivo do environment que deseja utilizar.
28
+
29
+ ### config/environments/development.rb
30
+
31
+ MoIP.setup do |config|
32
+ config.uri = "https://desenvolvedor.moip.com.br/sandbox"
33
+ config.token = SEU_TOKEN
34
+ config.key = SUA_KEY
35
+ end
36
+
37
+ Após realizar os testes na SandBox, você poderá fazer a mudança para o ambiente de produção do MoIP de maneira simples. Basta inserir no arquivo de environment de produção o token e chave que serão utilizados. Por padrão a gem já utiliza a URI de produção do MoIP.
38
+
39
+ ###Crie os dados do pagador
40
+
41
+ pagador = { :nome => "Luiz Inácio Lula da Silva",
42
+ :id => "1",
43
+ :email => "presidente@planalto.gov.br",
44
+ :tel_cel => "(61)9999-9999",
45
+ :apelido => "Lula",
46
+ :identidade => "111.111.111-11",
47
+ :logradouro => "Praça dos Três Poderes",
48
+ :numero => "0",
49
+ :complemento => "Palácio do Planalto",
50
+ :bairro => "Zona Cívico-Administrativa",
51
+ :cidade => "Brasília",
52
+ :estado => "DF",
53
+ :pais => "BRA",
54
+ :cep => "70100-000",
55
+ :tel_fixo => "(61)3211-1221" }
56
+
57
+ ###Dados do boleto
58
+
59
+ boleto = { :valor => "50",
60
+ :id_proprio => "Pag#{rand(1000)}",
61
+ :forma => "BoletoBancario",
62
+ :dias_expiracao => 5,
63
+ :pagador => pagador,
64
+ :razao => "Camisa do Corinthians" }
65
+
66
+ ###Checkout
67
+
68
+ def checkout
69
+ response = MoIP::Client.checkout(boleto)
70
+
71
+ # exibe o boleto para impressão
72
+ redirect_to MoIP::Client.moip_page(response["Token"])
73
+ end
74
+
75
+ ###Erros
76
+
77
+ - MoIP::MissingPaymentTypeError - Quando falta a razão do pagamento na requisição.
78
+ - MoIP::MissingPayerError - Quando falta as informações do pagador na requisição.
79
+ - MoIP::WebServerResponseError - Quando há algum erro ao se enviar a solicitação ao servidor. Normalmente a razão do erro vem como resposta da mensagem.
80
+
81
+ ## Futuras implementações
82
+
83
+ * Pagamento Simples
84
+ * Pagamento Recorrente
85
+
86
+
87
+ Baseado no projeto do [Daniel Lopes](http://github.com/danielvlopes/moip_usage).
data/Rakefile ADDED
@@ -0,0 +1,19 @@
1
+ # coding: utf-8
2
+ require 'rubygems'
3
+ require 'rake'
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ task :default => :spec
8
+ RSpec::Core::RakeTask.new
9
+
10
+ require 'rdoc/task'
11
+ RDoc::Task.new do |rdoc|
12
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
13
+
14
+ rdoc.rdoc_dir = 'rdoc'
15
+ rdoc.title = "moip #{version}"
16
+ rdoc.rdoc_files.include('README*')
17
+ rdoc.rdoc_files.include('lib/**/*.rb')
18
+ end
19
+
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/lib/moip.rb ADDED
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require "rubygems"
3
+ require 'active_support/core_ext/module/attribute_accessors'
4
+ require 'active_support/deprecation'
5
+ require 'singleton'
6
+ require 'forwardable'
7
+
8
+ module MoIP
9
+
10
+ class ValidationError < StandardError; end
11
+
12
+ class MissingPaymentTypeError < ValidationError; end
13
+ class MissingPayerError < ValidationError; end
14
+ class MissingBirthdate < ValidationError; end
15
+
16
+ class InvalidCellphone < ValidationError; end
17
+ class InvalidExpiry < ValidationError; end
18
+ class InvalidInstitution < ValidationError; end
19
+ class InvalidPhone < ValidationError; end
20
+ class InvalidReceiving < ValidationError; end
21
+ class InvalidValue < ValidationError; end
22
+
23
+ autoload :DirectPayment, 'moip/direct_payment'
24
+ autoload :Client, 'moip/client'
25
+ autoload :Config, 'moip/config'
26
+
27
+ def self.config
28
+ Thread.current[:moip_config] ||= MoIP::Config.new
29
+ end
30
+
31
+ def self.setup
32
+ yield config if block_given?
33
+ end
34
+
35
+ STATUS = {1 => "authorized", 2 => "started", 3 => "printed", 4 => "completed", 5 => "canceled", 6 => "analysing"}
36
+
37
+ class << self
38
+ extend Forwardable
39
+ def_delegators :config, :uri, :token, :key
40
+ end
41
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+ require 'httparty'
3
+
4
+ module MoIP
5
+ class WebServerResponseError < StandardError ; end
6
+ class MissingConfigError < StandardError ; end
7
+ class MissingTokenError < StandardError ; end
8
+ class MissingKeyError < StandardError ; end
9
+
10
+ class Client
11
+ include HTTParty
12
+
13
+ base_uri "#{MoIP.uri}/ws/alpha"
14
+ basic_auth MoIP.token, MoIP.key
15
+
16
+ class << self
17
+
18
+ # Verifica conta
19
+ # URL Produção: https://www.moip.com.br/ws/alpha/VerificarConta/{login_moip}
20
+ # URL SandBox: https://desenvolvedor.moip.com.br/sandbox/ws/alpha/VerificarConta/{login_moip}
21
+ # XML de Resposta:
22
+ # <ns1:verificarContaResponse>
23
+ # <RespostaVerificarConta>
24
+ # <Status>{status da conta}</Status>
25
+ # </RespostaVerificarConta>
26
+ # </ns1:verificarContaResponse>
27
+ #
28
+ # Valores Esperados: {status da conta}
29
+ # Inexistente " Login inexistente no sistema MoIP "
30
+ # Criado " Login criado, porem não verificado "
31
+ # Verificado " Login verificado "
32
+ # MoIP::Client.verify 'aaa'
33
+
34
+ def verify account
35
+ full_data = peform_action!(:get, "VerificarConta/#{account}")
36
+ return full_data["ns1:verificarContaResponse"]["RespostaVerificarConta"]["Status"] == "Verificado"
37
+ end
38
+
39
+ # Envia uma instrução para pagamento único
40
+ def checkout(attributes = {})
41
+ body = DirectPayment.body(attributes)
42
+ # puts "************ XML ************"
43
+ # puts body
44
+ full_data = peform_action!(:post, 'EnviarInstrucao/Unica', :body => body)
45
+ # raise full_data.inspect
46
+ get_response!(full_data["ns1:EnviarInstrucaoUnicaResponse"]["Resposta"])
47
+ end
48
+
49
+ # Consulta dos dados das autorizações e pagamentos associados à Instrução
50
+ def query(token)
51
+ full_data = peform_action!(:get, "ConsultarInstrucao/#{token}")
52
+
53
+ get_response!(full_data["ns1:ConsultarTokenResponse"]["RespostaConsultar"])
54
+ end
55
+
56
+ # Retorna a URL de acesso ao MoIP
57
+ def moip_page(token)
58
+ raise(MissingTokenError, "É necessário informar um token para retornar os dados da transação") if token.nil?
59
+ "#{MoIP.uri}/Instrucao.do?token=#{token}"
60
+ end
61
+
62
+ # Monta o NASP
63
+ def notification(params)
64
+ notification = {}
65
+ notification[:transaction_id] = params["id_transacao"]
66
+ notification[:amount] = params["valor"]
67
+ notification[:status] = MoIP::STATUS[params["status_pagamento"].to_i]
68
+ notification[:code] = params["cod_moip"]
69
+ notification[:payment_type] = params["tipo_pagamento"]
70
+ notification[:email] = params["email_consumidor"]
71
+ notification
72
+ end
73
+
74
+ private
75
+
76
+ def peform_action!(action_name, url, options = {})
77
+
78
+ raise(MissingConfigError, "É necessário criar um arquivo de configuração para o moip. Veja mais em: https://github.com/moiplabs/moip-ruby") if MoIP.token.nil? && MoIP.key.nil?
79
+
80
+ raise(MissingTokenError, "É necessário informar um token na configuração") if MoIP.token.nil? || MoIP.token.empty?
81
+
82
+ raise(MissingKeyError, "É necessário informar um key na configuração") if MoIP.key.nil? || MoIP.key.empty?
83
+
84
+ response = self.send(action_name, url, options)
85
+ raise(WebServerResponseError, "Ocorreu um erro ao chamar o webservice") if response.nil?
86
+ response
87
+ end
88
+
89
+ def get_response!(data)
90
+ # raise data.inspect
91
+ err = data["Erro"].is_a?(Array) ? data["Erro"].join(", ") : data["Erro"]
92
+ raise(WebServerResponseError, err) if data["Status"] == "Falha"
93
+ data
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+ module MoIP
3
+ class Config
4
+ # URI para acessar o serviço
5
+ attr_accessor :uri
6
+ @uri = 'https://www.moip.com.br'
7
+
8
+ # Token de autenticação
9
+ attr_accessor :token
10
+
11
+ # Chave de acesso ao serviço
12
+ attr_accessor :key
13
+ end
14
+ end
@@ -0,0 +1,195 @@
1
+ # encoding: utf-8
2
+ require "nokogiri"
3
+
4
+ module MoIP
5
+
6
+ # Baseado em http://labs.moip.com.br/pdfs/Integra%C3%A7%C3%A3o%20API%20-%20Autorizar%20e%20Cancelar%20Pagamentos.pdf
7
+ CodigoErro = 0..999
8
+ CodigoEstado = %w{AC AL AM AP BA CE DF ES GO MA MG MS MT PA PB PE PI PR RJ RN RO RR RS SC SE SP TO}
9
+ CodigoMoeda = "BRL"
10
+ CodigoPais = "BRA"
11
+ Destino = %w{Nenhum MesmoCobranca AInformar PreEstabelecido}
12
+ InstituicaoPagamento = %w{MoIP Visa AmericanExpress Mastercard Diners BancoDoBrasil Bradesco Itau BancoReal Unibanco Aura Hipercard Paggo Banrisul}
13
+ FormaPagamento = %w{CarteiraMoIP CartaoCredito CartaoDebito DebitoBancario FinanciamentoBancario BoletoBancario}
14
+ FormaRestricao = %w{Contador Valor}
15
+ PapelIndividuo = %w{Integrador Recebedor Comissionado Pagado}
16
+ OpcaoDisponivel = %w{Sim Não PagadorEscolhe}
17
+ Parcelador = %w{Nenhum Administradora MoIP Recebedor}
18
+ StatusLembrete = %w{Enviado Realizado EmAndamento Aguardando Falha}
19
+ StatusPagamento = %w{Concluido EmAnalise Autorizado Iniciado Cancelado BoletoImpresso Estornado}
20
+ TipoDias = %w{Corridos Uteis}
21
+ TipoDuracao = %w{Minutos Horas Dias Semanas Meses Ano}
22
+ TipoFrete = %w{Proprio Correio}
23
+ TipoIdentidade = %w{CPF CNPJ}
24
+ TipoInstrucao = %w{Unico Recorrente PrePago PosPago Remessa}
25
+ TipoLembrete = %w{Email SMS}
26
+ TipoPeriodicidade = %w{Anual Mensal Semanal Diaria}
27
+ TipoRecebimento = %w{AVista Parcelado}
28
+ TipoRestricao = %w{Autorizacao Pagamento}
29
+ TipoStatus = %w{Sucesso Falha}
30
+
31
+ #
32
+ TiposComInstituicao = %w{CartaoCredito DebitoBancario}
33
+ TiposComNascimento = %w{CartaoCredito}
34
+ TiposComExpiracao = %w{CartaoCredito}
35
+
36
+ class DirectPayment
37
+
38
+ class << self
39
+
40
+ # Cria uma instrução de pagamento direto
41
+ def body(attributes = {})
42
+ raise(MissingPaymentTypeError, "É necessário informar a razão do pagamento") if attributes[:razao].nil?
43
+
44
+ raise(MissingPayerError, "É obrigatório passar as informações do pagador") if attributes[:pagador].nil?
45
+
46
+ raise(InvalidValue, "Valor deve ser maior que zero.") if attributes[:valor].nil? || attributes[:valor].to_f <= 0.0
47
+ raise(InvalidPhone, "Telefone deve ter o formato (99)9999-9999.") if attributes[:pagador][:tel_fixo] !~ /\(\d{2}\)?\d{4}-\d{4}/
48
+ raise(InvalidCellphone, "Telefone celular deve ter o formato (99)9999-9999.") if attributes[:pagador][:tel_cel] !~ /\(\d{2}\)?\d{4}-\d{4}/
49
+
50
+ raise(MissingBirthdate, "É obrigatório informar a data de nascimento") if TiposComNascimento.include?(attributes[:forma]) && attributes[:data_nascimento].nil?
51
+
52
+ raise(InvalidExpiry, "Data de expiração deve ter o formato 01-00 até 12-99.") if TiposComExpiracao.include?(attributes[:forma]) && attributes[:expiracao] !~ /(1[0-2]|0\d)\/\d{2}/
53
+
54
+ if attributes[:recebimento].nil?
55
+ attributes[:recebimento] = 'AVista'
56
+ else
57
+ raise(InvalidReceiving, "Recebimento é inválido. Escolha um destes: #{TipoRecebimento.join(', ')}") if ! TipoRecebimento.include?(attributes[:recebimento]) && TiposComInstituicao.include?(attributes[:forma])
58
+ end
59
+
60
+ raise(InvalidInstitution, "A instituição #{attributes[:instituicao]} é inválida. Escolha uma destas: #{InstituicaoPagamento.join(', ')}") if TiposComInstituicao.include?(attributes[:forma]) && !InstituicaoPagamento.include?(attributes[:instituicao])
61
+
62
+
63
+ builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
64
+
65
+ # Identificador do tipo de instrução
66
+ xml.EnviarInstrucao {
67
+ xml.InstrucaoUnica {
68
+
69
+ # Dados da transação
70
+ xml.Razao {
71
+ xml.text attributes[:razao]
72
+ }
73
+ xml.Valores {
74
+ xml.Valor(:moeda => "BRL") {
75
+ xml.text attributes[:valor]
76
+ }
77
+ }
78
+ xml.IdProprio {
79
+ xml.text attributes[:id_proprio]
80
+ }
81
+
82
+ if attributes[:pagador]
83
+ # Dados do pagador
84
+ xml.Pagador {
85
+ xml.Nome { xml.text attributes[:pagador][:nome] }
86
+ xml.IdPagador { xml.text attributes[:pagador][:id] }
87
+ xml.Email { xml.text attributes[:pagador][:email] }
88
+ xml.TelefoneCelular { xml.text attributes[:pagador][:tel_cel] } if attributes[:pagador][:tel_cel]
89
+ xml.Apelido { xml.text attributes[:pagador][:apelido] } if attributes[:pagador][:apelido]
90
+ xml.Identidade { xml.text attributes[:pagador][:identidade] } if attributes[:pagador][:identidade]
91
+ xml.EnderecoCobranca {
92
+ xml.Logradouro { xml.text attributes[:pagador][:logradouro] }
93
+ xml.Numero { xml.text attributes[:pagador][:numero] }
94
+ xml.Complemento { xml.text attributes[:pagador][:complemento] }
95
+ xml.Bairro { xml.text attributes[:pagador][:bairro] }
96
+ xml.Cidade { xml.text attributes[:pagador][:cidade] }
97
+ xml.Estado { xml.text attributes[:pagador][:estado] }
98
+ xml.Pais { xml.text attributes[:pagador][:pais] }
99
+ xml.CEP { xml.text attributes[:pagador][:cep] }
100
+ xml.TelefoneFixo { xml.text attributes[:pagador][:tel_fixo] }
101
+ }
102
+ }
103
+ end
104
+
105
+ if attributes[:forma]
106
+ # Definindo o pagamento direto
107
+ xml.PagamentoDireto {
108
+ xml.Forma {
109
+ xml.text attributes[:forma]
110
+ }
111
+
112
+ # Débito Bancário
113
+ if attributes[:forma] == "DebitoBancario"
114
+ xml.Instituicao {
115
+ xml.text attributes[:instituicao]
116
+ }
117
+ end
118
+
119
+ # Cartão de Crédito
120
+ if attributes[:forma] == "CartaoCredito"
121
+ xml.Instituicao {
122
+ xml.text attributes[:instituicao]
123
+ }
124
+ xml.CartaoCredito {
125
+ xml.Numero {
126
+ xml.text attributes[:numero]
127
+ }
128
+ xml.Expiracao {
129
+ xml.text attributes[:expiracao]
130
+ }
131
+ xml.CodigoSeguranca {
132
+ xml.text attributes[:codigo_seguranca]
133
+ }
134
+ xml.Portador {
135
+ xml.Nome {
136
+ xml.text attributes[:nome]
137
+ }
138
+ xml.Identidade(:Tipo => "CPF") {
139
+ xml.text attributes[:identidade]
140
+ }
141
+ xml.Telefone {
142
+ xml.text attributes[:telefone]
143
+ }
144
+ xml.DataNascimento {
145
+ xml.text attributes[:data_nascimento]
146
+ }
147
+ }
148
+ }
149
+ xml.Parcelamento {
150
+ xml.Parcelas {
151
+ xml.text attributes[:parcelas]
152
+ }
153
+ xml.Recebimento {
154
+ xml.text attributes[:recebimento]
155
+ }
156
+ }
157
+ end
158
+ }
159
+
160
+ # Boleto Bancario
161
+ if attributes[:forma] == "BoletoBancario"
162
+ # Dados extras
163
+ xml.Boleto {
164
+ xml.DiasExpiracao(:Tipo => "Corridos") {
165
+ xml.text attributes[:dias_expiracao]
166
+ }
167
+ xml.Instrucao1 {
168
+ xml.text attributes[:instrucao_1]
169
+ }
170
+ xml.URLLogo {
171
+ xml.text attributes[:url_logo]
172
+ }
173
+ }
174
+ end
175
+ end
176
+
177
+ if attributes[:url_retorno]
178
+ # URL de retorno
179
+ xml.URLRetorno {
180
+ xml.text attributes[:url_retorno]
181
+ }
182
+ end
183
+
184
+ }
185
+ }
186
+ end
187
+
188
+ builder.to_xml
189
+ end
190
+
191
+ end
192
+
193
+ end
194
+
195
+ end
data/moip.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = %q{duke-moip}
5
+ gem.version = "0.2.0"
6
+
7
+ gem.authors = ["Guilherme Nascimento", "Duke Khaos"]
8
+ gem.date = %q{2010-11-10}
9
+ gem.description = %q{Gem para utilização da API MoIP}
10
+ gem.email = %q{guilherme.ruby@gmail.com duke.m16@gmail.com}
11
+ gem.summary = %q{Gem para utilização da API MoIP}
12
+
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- spec/*.rb`.split("\n")
15
+
16
+ gem.homepage = %q{http://github.com/moiplabs/moip-ruby}
17
+ gem.require_paths = ["lib"]
18
+
19
+ gem.rdoc_options = ["--charset=UTF-8"]
20
+ gem.extra_rdoc_files = [ "LICENSE", "README.markdown"]
21
+
22
+ gem.add_development_dependency(%q<rspec>, [">= 2.1.0"])
23
+
24
+ gem.add_runtime_dependency(%q<nokogiri>, [">= 1.5.0"])
25
+ gem.add_runtime_dependency(%q<httparty>, ["~> 0.12.0"])
26
+
27
+ gem.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
28
+ end
data/spec/moip_spec.rb ADDED
@@ -0,0 +1,461 @@
1
+ # encoding: utf-8
2
+ require "moip"
3
+ require "digest/sha1"
4
+
5
+ MoIP::Client
6
+ MoIP::DirectPayment
7
+
8
+ describe "Make payments with the MoIP API" do
9
+ let(:id){ '1' }
10
+
11
+ before :all do
12
+ id = 1
13
+ @pagador = { :nome => "Luiz Inácio Lula da Silva",
14
+ :login_moip => "lula",
15
+ :email => "presidente@planalto.gov.br",
16
+ :tel_cel => "(61)9999-9999",
17
+ :apelido => "Lula",
18
+ :identidade => "111.111.111-11",
19
+ :logradouro => "Praça dos Três Poderes",
20
+ :numero => "0",
21
+ :complemento => "Palácio do Planalto",
22
+ :bairro => "Zona Cívico-Administrativa",
23
+ :cidade => "Brasília",
24
+ :estado => "DF",
25
+ :pais => "BRA",
26
+ :cep => "70100-000",
27
+ :tel_fixo => "(61)3211-1221" }
28
+
29
+ @billet_without_razao = { :valor => "8.90", :id_proprio => id,
30
+ :forma => "BoletoBancario", :pagador => @pagador}
31
+
32
+ @billet = { :valor => "8.90", :id_proprio => id,
33
+ :forma => "BoletoBancario", :pagador => @pagador ,
34
+ :razao=> "Pagamento" }
35
+
36
+ @debit = { :valor => "8.90", :id_proprio => id, :forma => "DebitoBancario",
37
+ :instituicao => "BancoDoBrasil", :pagador => @pagador,
38
+ :razao => "Pagamento" }
39
+
40
+ @credit = { :valor => "8.90", :id_proprio => id, :forma => "CartaoCredito",
41
+ :instituicao => "AmericanExpress",:numero => "345678901234564",
42
+ :expiracao => "08/11", :codigo_seguranca => "1234",
43
+ :nome => "João Silva", :identidade => "134.277.017.00",
44
+ :telefone => "(21)9208-0547", :data_nascimento => "25/10/1980",
45
+ :parcelas => "2", :recebimento => "AVista",
46
+ :pagador => @pagador, :razao => "Pagamento" }
47
+ end
48
+
49
+ context "misconfigured" do
50
+ it "should raise a missing config error " do
51
+ MoIP.setup do |config|
52
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
53
+ config.token = nil
54
+ config.key = nil
55
+ end
56
+
57
+ MoIP::Client # for autoload
58
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(MoIP::MissingConfigError)
59
+ end
60
+
61
+ it "should raise a missing token error when token is nil" do
62
+ MoIP.setup do |config|
63
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
64
+ config.token = nil
65
+ config.key = 'key'
66
+ end
67
+
68
+ MoIP::Client # for autoload
69
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(MoIP::MissingTokenError)
70
+ end
71
+
72
+ it "should raise a missing key error when key is nil" do
73
+
74
+ MoIP.setup do |config|
75
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
76
+ config.token = 'token'
77
+ config.key = nil
78
+ end
79
+
80
+ MoIP::Client # for autoload
81
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(MoIP::MissingKeyError)
82
+ end
83
+
84
+
85
+ it "should raise a missing token error when token is empty" do
86
+ MoIP.setup do |config|
87
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
88
+ config.token = ''
89
+ config.key = 'key'
90
+ end
91
+
92
+ MoIP::Client # for autoload
93
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(MoIP::MissingTokenError)
94
+ end
95
+
96
+ it "should raise a missing key error when key is empty" do
97
+
98
+ MoIP.setup do |config|
99
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
100
+ config.token = 'token'
101
+ config.key = ''
102
+ end
103
+
104
+ MoIP::Client # for autoload
105
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(MoIP::MissingKeyError)
106
+ end
107
+ end
108
+
109
+ context "thread safety" do
110
+ before do
111
+ MoIP.setup do |config|
112
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
113
+ config.token = 'token'
114
+ config.key = 'key'
115
+ end
116
+ end
117
+
118
+ it "should have a threadsafe config" do
119
+ thread = Thread.new do
120
+ MoIP.setup {|config| config.uri = 'https://desenvolvedor.moip.com.br/another_sandbox' }
121
+ MoIP.uri.should eq('https://desenvolvedor.moip.com.br/another_sandbox')
122
+ end
123
+
124
+ thread.join
125
+
126
+ MoIP.uri.should eq('https://desenvolvedor.moip.com.br/sandbox')
127
+ end
128
+ end
129
+
130
+ context "validations" do
131
+
132
+ before(:each) do
133
+ MoIP.setup do |config|
134
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
135
+ config.token = 'token'
136
+ config.key = 'key'
137
+ end
138
+ end
139
+
140
+ it "should raise invalid phone" do
141
+ @data = @credit.merge({:pagador => {:tel_fixo => 'InvalidPhone', :tel_cel => "(61)9999-9999"}})
142
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidPhone)
143
+ end
144
+ it "should raise invalid cellphone" do
145
+ @data = @credit.merge({:pagador => {:tel_cel => 'InvalidCellphone', :tel_fixo => "(61)9999-9999"}})
146
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidCellphone)
147
+ end
148
+ it "should raise invalid expiry" do
149
+ @data = @credit.merge({:expiracao => 'InvalidExpiry'})
150
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidExpiry)
151
+ end
152
+ it "should raise missing birthdate" do
153
+ @data = @credit.merge({:data_nascimento => nil})
154
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::MissingBirthdate)
155
+ end
156
+ it "should raise invalid institution error" do
157
+ @data = @credit.merge({:instituicao => 'InvalidInstitution'})
158
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidInstitution)
159
+ end
160
+ it "should raise invalid receiving error" do
161
+ @data = @credit.merge({:recebimento => 'InvalidReceiving'})
162
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidReceiving)
163
+ end
164
+ it "should raise invalid value error if 0" do
165
+ @data = @credit.merge({:valor => 0})
166
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidValue)
167
+ end
168
+ it "should raise invalid value error if '0'" do
169
+ @data = @credit.merge({:valor => '0'})
170
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidValue)
171
+ end
172
+ it "should raise invalid value error if 0.0" do
173
+ @data = @credit.merge({:valor => 0.0})
174
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidValue)
175
+ end
176
+ it "should raise invalid value error if '0.0'" do
177
+ @data = @credit.merge({:valor => '0.0'})
178
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidValue)
179
+ end
180
+ it "should raise invalid value error if -1" do
181
+ @data = @credit.merge({:valor => -1})
182
+ lambda { MoIP::Client.checkout(@data) }.should raise_error(MoIP::InvalidValue)
183
+ end
184
+ end
185
+
186
+ context "checkout" do
187
+ before(:each) do
188
+ MoIP.setup do |config|
189
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
190
+ config.token = 'token'
191
+ config.key = 'key'
192
+ end
193
+ MoIP::Client.stub!(:post).
194
+ and_return("ns1:EnviarInstrucaoUnicaResponse"=>
195
+ { "Resposta"=>
196
+ { "ID"=>Time.now.strftime("%y%m%d%H%M%S"),
197
+ "Status"=>"Sucesso",
198
+ "Token" => "T2N0L0X8E0S71217U2H3W1T4F4S4G4K731D010V0S0V0S080M010E0Q082X2"
199
+ }
200
+ })
201
+ end
202
+
203
+ context "when it is a billet checkout" do
204
+ before(:each) do
205
+ MoIP.setup do |config|
206
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
207
+ config.token = 'token'
208
+ config.key = 'key'
209
+ end
210
+ end
211
+ it "should raise an exception when razao parameter is not passed" do
212
+ error = "É necessário informar a razão do pagamento"
213
+
214
+ lambda { MoIP::Client.checkout(@billet_without_razao) }.should raise_error(MoIP::MissingPaymentTypeError,error)
215
+ end
216
+
217
+ it "should have status 'Sucesso'" do
218
+ response = MoIP::Client.checkout(@billet)
219
+ response["Status"].should == "Sucesso"
220
+ end
221
+ end
222
+
223
+ context "when it is a debit checkout" do
224
+ before(:each) do
225
+ MoIP.setup do |config|
226
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
227
+ config.token = 'token'
228
+ config.key = 'key'
229
+ end
230
+ end
231
+
232
+ it "should have status 'Sucesso' with valid arguments" do
233
+ response = MoIP::Client.checkout(@debit)
234
+ response["Status"].should == "Sucesso"
235
+ end
236
+
237
+ it "should have status 'Falha' when a instituition is not passed as argument" do
238
+ @incorrect_debit = { :valor => "37.90", :id_proprio => id,
239
+ :forma => "DebitoBancario", :pagador => @pagador,
240
+ :razao => "Pagamento"}
241
+
242
+ error = "Pagamento direto não é possível com a instituição de pagamento enviada"
243
+
244
+ MoIP::Client.stub!(:post).and_return("ns1:EnviarInstrucaoUnicaResponse"=>
245
+ { "Resposta"=>
246
+ {
247
+ "Status"=>"Falha",
248
+ "Erro"=>error
249
+ }
250
+ })
251
+ error = "Pagamento direto não é possível com a instituição de pagamento enviada"
252
+ lambda { MoIP::Client.checkout(@incorrect_debit) }.should
253
+ raise_error(MoIP::WebServerResponseError, error)
254
+ end
255
+
256
+ it "should raise an exception if payer informations were not passed" do
257
+ @incorrect_debit = { :valor => "37.90", :id_proprio => id,
258
+ :forma => "DebitoBancario",
259
+ :instituicao => "BancoDoBrasil",
260
+ :razao => "Pagamento"
261
+ }
262
+
263
+ lambda { MoIP::Client.checkout(@incorrect_debit) }.should
264
+ raise_error(MoIP::MissingPayerError, "É obrigatório passar as informações do pagador")
265
+ end
266
+ end
267
+
268
+ context "when it is a credit card checkout" do
269
+ before(:each) do
270
+ MoIP.setup do |config|
271
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
272
+ config.token = 'token'
273
+ config.key = 'key'
274
+ end
275
+ end
276
+
277
+ it "should have status 'Sucesso' with valid arguments" do
278
+ response = MoIP::Client.checkout(@credit)
279
+ response["Status"].should == "Sucesso"
280
+ end
281
+
282
+ it "should have status 'Falha' when the card informations were not passed as argument" do
283
+ @incorrect_credit = { :valor => "8.90", :id_proprio => id,
284
+ :forma => "CartaoCredito", :pagador => @pagador,
285
+ :razao => "Pagamento"
286
+ }
287
+
288
+ error = "Pagamento direto não é possível com a instituição de pagamento enviada"
289
+ MoIP::Client.stub!(:post).and_return("ns1:EnviarInstrucaoUnicaResponse"=>
290
+ {
291
+ "Resposta"=>
292
+ {
293
+ "Status"=>"Falha",
294
+ "Erro"=>error
295
+ }
296
+ })
297
+
298
+ error = "Pagamento direto não é possível com a instituição de pagamento enviada"
299
+ lambda { MoIP::Client.checkout(@incorrect_credit) }.should
300
+ raise_error(MoIP::WebServerResponseError, error)
301
+ end
302
+ end
303
+
304
+ context "in error scenario" do
305
+ before(:each) do
306
+ MoIP.setup do |config|
307
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
308
+ config.token = 'token'
309
+ config.key = 'key'
310
+ end
311
+ end
312
+ it "should raise an exception if response is nil" do
313
+ MoIP::Client.stub!(:post).and_return(nil)
314
+ lambda { MoIP::Client.checkout(@billet) }.should
315
+ raise_error(StandardError,"Ocorreu um erro ao chamar o webservice")
316
+ end
317
+
318
+ it "should raise an exception if status is fail" do
319
+ MoIP::Client.stub!(:post).and_return("ns1:EnviarInstrucaoUnicaResponse"=>
320
+ { "Resposta"=>
321
+ {"Status"=>"Falha",
322
+ "Erro"=>"O status da resposta é Falha"
323
+ }
324
+ })
325
+
326
+ lambda { MoIP::Client.checkout(@billet) }.should raise_error(StandardError, "O status da resposta é Falha")
327
+ end
328
+ end
329
+ end
330
+
331
+ context "query a transaction token" do
332
+
333
+ before(:each) do
334
+
335
+ MoIP.setup do |config|
336
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
337
+ config.token = 'token'
338
+ config.key = 'key'
339
+ end
340
+ MoIP::Client.stub!(:get).and_return("ns1:ConsultarTokenResponse"=>
341
+ { "RespostaConsultar"=>
342
+ {"Status"=>"Sucesso",
343
+ "ID"=>"201010291031001210000000046760"
344
+ }
345
+ })
346
+ end
347
+
348
+ it "should retrieve the transaction" do
349
+ response = MoIP::Client.query(token)
350
+ response["Status"].should == "Sucesso"
351
+ end
352
+
353
+ context "in a error scenario" do
354
+ before(:each) do
355
+ MoIP.setup do |config|
356
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
357
+ config.token = 'token'
358
+ config.key = 'key'
359
+ end
360
+ end
361
+ it "should retrieve status 'Falha'" do
362
+ MoIP::Client.stub!(:get).and_return("ns1:ConsultarTokenResponse"=>
363
+ { "RespostaConsultar"=>
364
+ {"Status"=>"Falha",
365
+ "Erro"=>"Instrução não encontrada",
366
+ "ID"=>"201010291102522860000000046768"
367
+ }
368
+ })
369
+ query = "000000000000000000000000000000000000000000000000000000000000"
370
+ lambda { MoIP::Client.query(query) }.should raise_error(StandardError, "Instrução não encontrada")
371
+ end
372
+ end
373
+ end
374
+
375
+ context "build the MoIP URL" do
376
+ before(:each) do
377
+ MoIP.setup do |config|
378
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
379
+ config.token = 'token'
380
+ config.key = 'key'
381
+ end
382
+ end
383
+
384
+ it "should build the correct URL" do
385
+ page = "https://desenvolvedor.moip.com.br/sandbox/Instrucao.do?token=#{token}"
386
+ MoIP::Client.moip_page(token).should == page
387
+ end
388
+
389
+ it "should raise an error if the token is not informed" do
390
+ error = "É necessário informar um token para retornar os dados da transação"
391
+ lambda { MoIP::Client.moip_page("").should
392
+ raise_error(ArgumentError, error) }
393
+ end
394
+
395
+ it "should raise an error if nil is passed as the token" do
396
+ error = "É necessário informar um token para retornar os dados da transação"
397
+ lambda { MoIP::Client.moip_page(nil).should
398
+ raise_error(ArgumentError, error) }
399
+ end
400
+
401
+ it "should raise a missing token error if nil is passed as the token" do
402
+ lambda { MoIP::Client.moip_page(nil).should raise_error(MissingTokenError) }
403
+ end
404
+
405
+ it "should raise a missing token error if an empty string is passed as the token" do
406
+ lambda { MoIP::Client.moip_page("").should raise_error(MissingTokenError) }
407
+ end
408
+ end
409
+
410
+ context "when receive notification" do
411
+ before(:each) do
412
+ MoIP.setup do |config|
413
+ config.uri = 'https://desenvolvedor.moip.com.br/sandbox'
414
+ config.token = 'token'
415
+ config.key = 'key'
416
+ end
417
+ @params = { "id_transacao" => "Pag62", "valor" => "8.90",
418
+ "status_pagamento" => "3", "cod_moip" => "001",
419
+ "forma_pagamento" => "73", "tipo_pagamento" => "BoletoBancario",
420
+ "email_consumidor" => "presidente@planalto.gov.br" }
421
+ end
422
+
423
+ it "should return a hash with the params extracted from NASP" do
424
+ response = { :transaction_id => "Pag62", :amount => "8.90",
425
+ :status => "printed", :code => "001",
426
+ :payment_type => "BoletoBancario",
427
+ :email => "presidente@planalto.gov.br" }
428
+
429
+ MoIP::Client.notification(@params).should == response
430
+ end
431
+
432
+ it "should return valid status based on status code" do
433
+ MoIP::STATUS[1].should == "authorized"
434
+ MoIP::STATUS[2].should == "started"
435
+ MoIP::STATUS[3].should == "printed"
436
+ MoIP::STATUS[4].should == "completed"
437
+ MoIP::STATUS[5].should == "canceled"
438
+ MoIP::STATUS[6].should == "analysing"
439
+ end
440
+ end
441
+
442
+ def id
443
+ "transaction_" + Digest::SHA1.hexdigest([Time.now, rand].join)
444
+ end
445
+
446
+ def token
447
+ "T2X0Q1N021E0B2S9U1P0V3Y0G1F570Y2P4M0P000M0Z0F0J0G0U4N6C7W5T9"
448
+ end
449
+
450
+ def collect_deprecations
451
+ old_behavior = ActiveSupport::Deprecation.behavior
452
+ deprecations = []
453
+ ActiveSupport::Deprecation.behavior = Proc.new do |message, callstack|
454
+ deprecations << message
455
+ end
456
+ result = yield
457
+ deprecations
458
+ ensure
459
+ ActiveSupport::Deprecation.behavior = old_behavior
460
+ end
461
+ end
metadata ADDED
@@ -0,0 +1,128 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: duke-moip
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Guilherme Nascimento
9
+ - Duke Khaos
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2010-11-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 2.1.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: 2.1.0
31
+ - !ruby/object:Gem::Dependency
32
+ name: nokogiri
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - ! '>='
37
+ - !ruby/object:Gem::Version
38
+ version: 1.5.0
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ! '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.5.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: httparty
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 0.12.0
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ~>
61
+ - !ruby/object:Gem::Version
62
+ version: 0.12.0
63
+ - !ruby/object:Gem::Dependency
64
+ name: activesupport
65
+ requirement: !ruby/object:Gem::Requirement
66
+ none: false
67
+ requirements:
68
+ - - ! '>='
69
+ - !ruby/object:Gem::Version
70
+ version: 2.3.2
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: 2.3.2
79
+ description: Gem para utilização da API MoIP
80
+ email: guilherme.ruby@gmail.com duke.m16@gmail.com
81
+ executables: []
82
+ extensions: []
83
+ extra_rdoc_files:
84
+ - LICENSE
85
+ - README.markdown
86
+ files:
87
+ - .document
88
+ - .gitignore
89
+ - Gemfile
90
+ - Gemfile.lock
91
+ - LICENSE
92
+ - README.markdown
93
+ - Rakefile
94
+ - VERSION
95
+ - lib/moip.rb
96
+ - lib/moip/client.rb
97
+ - lib/moip/config.rb
98
+ - lib/moip/direct_payment.rb
99
+ - moip.gemspec
100
+ - spec/moip_spec.rb
101
+ homepage: http://github.com/moiplabs/moip-ruby
102
+ licenses: []
103
+ post_install_message:
104
+ rdoc_options:
105
+ - --charset=UTF-8
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
110
+ requirements:
111
+ - - ! '>='
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.23
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Gem para utilização da API MoIP
126
+ test_files:
127
+ - spec/moip_spec.rb
128
+ has_rdoc: