moiper 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ script: bundle exec rspec -bfd spec
3
+ rvm:
4
+ - 1.8.7
5
+ - 1.9.2
6
+ - 1.9.3
7
+ - jruby
8
+ - ree
9
+ - rbx-18mode
10
+ - rbx-19mode
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Moiper
2
2
 
3
+ [![Build Status](https://travis-ci.org/reu/moiper.png?branch=master)](https://travis-ci.org/reu/moiper)
4
+
3
5
  [Moip payment service](http://moip.com.br/) integration library.
4
6
 
5
7
  ## Installation
@@ -59,7 +61,7 @@ You need to redirect your user to the url returned by `response.checkout_url`. A
59
61
 
60
62
  ### Notifications
61
63
 
62
- Moip will notify your application about order updates through [NASP](http://labs.moip.com.br/referencia/nasp/). Moiper provides a Rails controller helper to you can easily intercept these notifications with the `moip_notification` method.
64
+ Moip will notify your application about order updates through [NASP](http://labs.moip.com.br/referencia/nasp/). Moiper provides a Rails controller helper so you can easily intercept these notifications with the `moip_notification` method.
63
65
 
64
66
  ```ruby
65
67
  class OrdersController < ApplicationController
@@ -81,6 +83,14 @@ class OrdersController < ApplicationController
81
83
  end
82
84
  ```
83
85
 
86
+ If you are not using Rails, you can manually instantiate a Moiper::Notification class by passing the POST parameters received from Moip's request.
87
+
88
+ ```ruby
89
+ post "/moip/callback" do
90
+ notification = Moiper::Notification.new(params)
91
+ end
92
+ ```
93
+
84
94
  #### Payment Status
85
95
 
86
96
  Following are the possible payment statuses returned by the `Moip::Notification#payment_status`.
@@ -6,31 +6,47 @@ require "moiper/notification"
6
6
  require "moiper/railtie" if defined? Rails
7
7
 
8
8
  module Moiper
9
+ # The available Moip entrypoints
10
+ # @see http://labs.moip.com.br/referencia/autenticacao_api/#ambientes
11
+ # The Moip's official documentation regarding its entrypoints
9
12
  API_ENTRYPOINTS = {
10
13
  :sandbox => "https://desenvolvedor.moip.com.br/sandbox/",
11
14
  :production => "https://www.moip.com.br/"
12
15
  }
13
16
 
14
17
  class << self
15
- # Set Moip's API token
18
+ # @!group Configurable options
19
+
20
+ # @return [String] Moip's API token
16
21
  attr_accessor :token
17
22
 
18
- # Set Moip's API key
23
+ # @return [String] Moip's API key
19
24
  attr_accessor :key
20
25
 
21
26
  # Define if requests should be made against Moip's sandbox
22
27
  # environment. This is specially usefull when running
23
- # on development or test mode. Default is false.
28
+ # on development or test mode. Default is false
29
+ #
30
+ # @see http://labs.moip.com.br/referencia/autenticacao_api/#sandbox
31
+ # Moip's official documentation regarding sandbox activation
24
32
  #
25
- # Moiper.sandbox = true
33
+ # @example
34
+ # Moiper.sandbox = true
26
35
  #
36
+ # @return [Boolean] current sandbox state
27
37
  attr_accessor :sandbox
28
38
 
29
- # Configure Moiper options.
39
+ # @!endgroup
40
+
41
+ # Configure Moiper's options
42
+ #
43
+ # @yieldparam config [Moiper]
44
+ # @return [void]
30
45
  #
31
- # Moiper.configure do |config|
32
- # config.sandbox = true
33
- # end
46
+ # @example
47
+ # Moiper.configure do |config|
48
+ # config.sandbox = true
49
+ # end
34
50
  #
35
51
  def configure(&block)
36
52
  yield self
@@ -41,7 +57,7 @@ module Moiper
41
57
  sandbox == true
42
58
  end
43
59
 
44
- # Returns the Moip API entrypoint based on the current environment
60
+ # @return [String] the Moip API entrypoint based on the current environment
45
61
  def api_entrypoint
46
62
  sandbox? ? API_ENTRYPOINTS[:sandbox] : API_ENTRYPOINTS[:production]
47
63
  end
@@ -1,5 +1,7 @@
1
1
  module Moiper
2
2
  class Notification
3
+ # @see http://labs.moip.com.br/parametro/statuspagamento/
4
+ # The list of payment status on the Moip's official documentation
3
5
  PAYMENT_STATUSES = {
4
6
  1 => :authorized,
5
7
  2 => :started,
@@ -11,6 +13,8 @@ module Moiper
11
13
  9 => :reimbursed
12
14
  }
13
15
 
16
+ # @see http://labs.moip.com.br/parametro/instituicaopagamento/
17
+ # The list of financial institutions on the Moip's official documentation
14
18
  FINANCIAL_INSTITUTIONS = {
15
19
  1 => "MoIP",
16
20
  3 => "Visa",
@@ -25,6 +29,8 @@ module Moiper
25
29
  88 => "Banrisul"
26
30
  }
27
31
 
32
+ # @see http://labs.moip.com.br/parametro/formapagamento/
33
+ # The list of payment methods on the Moip's official documentation
28
34
  PAYMENT_METHODS = {
29
35
  "BoletoBancario" => :payment_form,
30
36
  "CartaoDeCredito" => :credit_card,
@@ -41,38 +47,57 @@ module Moiper
41
47
  @params = params
42
48
  end
43
49
 
50
+ # @return [String] informed unique identifier
44
51
  def id
45
52
  params["id_transacao"]
46
53
  end
47
54
 
55
+ # @return [Float] amount paid by the user
48
56
  def price
49
57
  params["valor"].to_i / 100.0
50
58
  end
51
59
 
60
+ # @return [Symbol] payment status
61
+ # @see PAYMENT_STATUSES The full list of possible payment statuses
62
+ # returned
52
63
  def payment_status
53
64
  PAYMENT_STATUSES[params["status_pagamento"].to_i]
54
65
  end
55
66
 
67
+ # @return [Integer] the internal Moip identifier for this transaction
56
68
  def moip_id
57
69
  params["cod_moip"].to_i
58
70
  end
59
71
 
72
+ # @return [String] financial institution name
73
+ # @see FINANCIAL_INSTITUTIONS The full list of possible financial
74
+ # institutions returned
60
75
  def financial_institution
61
76
  FINANCIAL_INSTITUTIONS[params["forma_pagamento"].to_i]
62
77
  end
63
78
 
79
+ # @return [String] payment method used by this transaction
80
+ # @see PAYMENT_METHODS The full list of possible payment
81
+ # method returned
64
82
  def payment_method
65
83
  PAYMENT_METHODS[params["tipo_pagamento"]]
66
84
  end
67
85
 
86
+ # @return [Integer] number of quotas that the payment was
87
+ # divided
68
88
  def quotas
69
89
  params["parcelas"].to_i
70
90
  end
71
91
 
92
+ # @return [String] user email address
72
93
  def user_email
73
94
  params["email_consumidor"]
74
95
  end
75
96
 
97
+ # @return [String] additional information provided by the financial
98
+ # institution regarding this transaction when it has a canceled status
99
+ # @see http://labs.moip.com.br/referencia/classificacao-de-cancelamento/
100
+ # The Moip's official documentation regarting payment cancelling
76
101
  def additional_info
77
102
  params["classificacao"]
78
103
  end
@@ -1,5 +1,32 @@
1
1
  module Moiper
2
2
  module NotificationControllerHelper
3
+ # Helper method to abstract how to create a notification during the Moip's
4
+ # NASP request.
5
+ #
6
+ # @see http://labs.moip.com.br/referencia/nasp/ Moip's NASP documentation
7
+ #
8
+ # @param data [Hash] controller parameters
9
+ # @yieldparam [Notification] notification update from Moip
10
+ # @return [Notification]
11
+ #
12
+ # @example Usage inside a Rails controller
13
+ # class OrdersController < ApplicationController
14
+ # include Moiper::NotificationControllerHelper
15
+ #
16
+ # def confirm
17
+ # moip_notification do |notification|
18
+ # # Here you can update your database with updated information.
19
+ # # Ex:
20
+ # @order = Order.find_by_unique_identifier(notification.id)
21
+ # @order.update_attribute :status, notification.payment_status
22
+ # @order.save
23
+ #
24
+ # # Moip will recognize the request as successfully if the statuses
25
+ # # are 200, 201, 202, 203, 204, 205, 206 or 207.
26
+ # head 200
27
+ # end
28
+ # end
29
+ # end
3
30
  def moip_notification(data = params, &block)
4
31
  notification = Notification.new(data)
5
32
  yield notification if block_given?
@@ -2,27 +2,44 @@ require "nokogiri"
2
2
 
3
3
  module Moiper
4
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.
5
+ # @return [String] the unique ID you can set for this payment. This is usefull to keep
6
+ # track of which payment we will receive on the Moip's notification process
7
7
  attr_accessor :id
8
8
 
9
- # The description of the purchase.
9
+ # @return [String] the description of the purchase
10
10
  attr_accessor :description
11
11
 
12
- # The amount to be billed from the user.
12
+ # @return [Float] the amount to be billed from the user
13
13
  attr_accessor :price
14
14
 
15
- # The URL where the user will be redirected after he finishes the
16
- # payment process.
15
+ # @return [Float] the amount to be increased from the final price
16
+ attr_accessor :accretion
17
+
18
+ # @return [Float] the amount to be deducted from the final price
19
+ attr_accessor :deduction
20
+
21
+ # @return [String] the URL where the user will be redirected after he finishes the
22
+ # payment process.
17
23
  attr_accessor :return_url
18
24
 
19
- # The URL where Moip will send notifications about your purchase updates.
25
+ # @return [String] the URL where Moip will send notifications about your purchase updates
20
26
  attr_accessor :notification_url
21
27
 
22
28
  # Create a new Moip Payment request
29
+ #
30
+ # @param [Hash] options the options to create the payment with
31
+ # @option options [String] :description {#description}
32
+ # @option options [String, #to_s] :id {#id}
33
+ # @option options [#to_f] :price {#price}
34
+ # @option options [#to_f] :accretion {#accretion}
35
+ # @option options [#to_f] :deduction {#deduction}
36
+ # @option options [String, #to_s] :return_url {#return_url}
37
+ # @option options [String, #to_s] :notification_url {#notification_url}
38
+ #
39
+ # @raise [ArgumentError] if description or price options are blank
23
40
  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
41
+ raise ArgumentError, "You must inform a description" if options[:description].nil? || options[:description].empty?
42
+ raise ArgumentError, "You must inform a price" if options[:price].nil? || options[:price].to_f <= 0
26
43
 
27
44
  options.each do |attribute, value|
28
45
  send "#{attribute}=", value
@@ -30,6 +47,7 @@ module Moiper
30
47
  end
31
48
 
32
49
  # Create the payment XML representation
50
+ # @return [String] Moip's formatted XML
33
51
  def to_xml
34
52
  builder = Nokogiri::XML::Builder.new(:encoding => "UTF-8") do |xml|
35
53
  xml.EnviarInstrucao {
@@ -39,6 +57,8 @@ module Moiper
39
57
 
40
58
  xml.Valores {
41
59
  xml.Valor price, :moeda => "BRL"
60
+ xml.Acrescimo accretion, :moeda => "BRL" if accretion
61
+ xml.Deducao deduction, :moeda => "BRL" if deduction
42
62
  }
43
63
 
44
64
  xml.URLNotificacao notification_url if notification_url
@@ -50,6 +70,8 @@ module Moiper
50
70
  builder.to_xml
51
71
  end
52
72
 
73
+ # Send a new payment request to Moip
74
+ # @return [Response] the Moip response
53
75
  def checkout
54
76
  request = Request.new
55
77
  request.process(to_xml)
@@ -2,6 +2,7 @@ module Moiper
2
2
  class Railtie < Rails::Railtie
3
3
  # Expose Moiper's configuration to the Rails application configuration.
4
4
  #
5
+ # @example
5
6
  # module MyApplication
6
7
  # class Application < Rails::Application
7
8
  # config.moiper.sandbox = true
@@ -11,10 +12,13 @@ module Moiper
11
12
  # end
12
13
  config.moiper = Moiper
13
14
 
15
+ # Load notification controller helper
14
16
  initializer "load notification controller helper" do
15
17
  require "moiper/notification_controller_helper"
16
18
  end
17
19
 
20
+ # Automatically read and configure Moiper with the content
21
+ # of the config/moiper.yml file if it is present
18
22
  initializer "load moiper.yml file" do
19
23
  config_file = Rails.root.join("config", "moiper.yml")
20
24
 
@@ -5,13 +5,17 @@ module Moiper
5
5
  class Request
6
6
  CA_FILE = File.expand_path(File.dirname(__FILE__)) + "/cacert.pem"
7
7
 
8
- attr_reader :response
9
-
8
+ # Process a given payload
9
+ # @param payload [String]
10
+ # @return [Response] the response from Moip
10
11
  def process(payload)
11
- @response = post(payload)
12
- Response.new(@response.body)
12
+ response = post(payload)
13
+ Response.new(response.body)
13
14
  end
14
15
 
16
+ # @!group HTTP handling
17
+
18
+ # @return [Net::HTTP::Session] the http session client
15
19
  def client
16
20
  @client ||= Net::HTTP.new(uri.host, uri.port).tap do |http|
17
21
  http.use_ssl = true
@@ -20,6 +24,9 @@ module Moiper
20
24
  end
21
25
  end
22
26
 
27
+ # @return [Net::HTTP::Post] the http POST request already
28
+ # configured with the right agent, content type and
29
+ # basic authentication headers
23
30
  def request
24
31
  @request ||= Net::HTTP::Post.new(uri.path).tap do |request|
25
32
  request.basic_auth Moiper.token, Moiper.key
@@ -28,6 +35,8 @@ module Moiper
28
35
  end
29
36
  end
30
37
 
38
+ # @!endgroup
39
+
31
40
  private
32
41
 
33
42
  def post(payload)
@@ -39,6 +48,8 @@ module Moiper
39
48
  @uri ||= URI(Moiper.api_entrypoint + path)
40
49
  end
41
50
 
51
+ # @api private
52
+ # @return [String] path where the request should be made
42
53
  def path
43
54
  "ws/alpha/EnviarInstrucao/Unica"
44
55
  end
@@ -1,21 +1,29 @@
1
1
  module Moiper
2
2
  class Response
3
+ # @param body [String] the response body from Moip
3
4
  def initialize(body)
4
5
  @body = body
5
6
  end
6
7
 
8
+ # Detects if the response was successfully
9
+ # @return [Boolean]
7
10
  def success?
8
11
  parsed_body.css("Status").text == "Sucesso"
9
12
  end
10
13
 
14
+ # @return [String, nil] the URL which the user should be redirected
15
+ # to finish payment process or nil if the request was not successfully
11
16
  def checkout_url
12
17
  Moiper.api_entrypoint + "Instrucao.do?token=" + token if success?
13
18
  end
14
19
 
20
+ # @return [String] the response token
15
21
  def token
16
22
  parsed_body.css("Token").text
17
23
  end
18
24
 
25
+ # List the possible errors returned by Moip
26
+ # @return [Array<String>]
19
27
  def errors
20
28
  parsed_body.css("Erro").map(&:text)
21
29
  end
@@ -1,4 +1,3 @@
1
1
  module Moiper
2
- # Specify the current gem version
3
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
4
3
  end
@@ -82,6 +82,8 @@ describe Moiper::Payment do
82
82
  Moiper::Payment.new(
83
83
  :description => "A chair",
84
84
  :price => 1.99,
85
+ :accretion => 0.5,
86
+ :deduction => 0.3,
85
87
  :id => "some unique id",
86
88
  :return_url => "http://example.org/thank_you",
87
89
  :notification_url => "http://example.org/moip/notification"
@@ -99,9 +101,16 @@ describe Moiper::Payment do
99
101
  it { doc.at_css("InstrucaoUnica > URLNotificacao").should_not be_nil }
100
102
 
101
103
  it { doc.at_css("InstrucaoUnica > IdProprio").text.should eq "some unique id"}
104
+
102
105
  it { doc.at_css("Valores > Valor").text.should eq "1.99"}
103
106
  it { doc.at_css("Valores > Valor").attributes["moeda"].value.should eq "BRL"}
104
107
 
108
+ it { doc.at_css("Valores > Acrescimo").text.should eq "0.5"}
109
+ it { doc.at_css("Valores > Acrescimo").attributes["moeda"].value.should eq "BRL"}
110
+
111
+ it { doc.at_css("Valores > Deducao").text.should eq "0.3"}
112
+ it { doc.at_css("Valores > Deducao").attributes["moeda"].value.should eq "BRL"}
113
+
105
114
  it { doc.at_css("InstrucaoUnica > URLRetorno").text.should eq "http://example.org/thank_you" }
106
115
  it { doc.at_css("InstrucaoUnica > URLNotificacao").text.should eq "http://example.org/moip/notification" }
107
116
 
@@ -34,8 +34,7 @@ describe Moiper::Request do
34
34
  end
35
35
 
36
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}"
37
+ subject.get_fields("user-agent")[0].should eq "Moiper/#{Moiper::VERSION}"
39
38
  end
40
39
  end
41
40
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moiper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-23 00:00:00.000000000 Z
12
+ date: 2013-01-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: nokogiri
16
- requirement: &2152746220 !ruby/object:Gem::Requirement
16
+ requirement: &2160708660 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2152746220
24
+ version_requirements: *2160708660
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rspec
27
- requirement: &2152745700 !ruby/object:Gem::Requirement
27
+ requirement: &2160708220 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2152745700
35
+ version_requirements: *2160708220
36
36
  description: Moip payment service integration library.
37
37
  email:
38
38
  - rnavarro1@gmail.com
@@ -41,6 +41,7 @@ extensions: []
41
41
  extra_rdoc_files: []
42
42
  files:
43
43
  - .gitignore
44
+ - .travis.yml
44
45
  - Gemfile
45
46
  - LICENSE.txt
46
47
  - README.md
@@ -76,7 +77,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
77
  version: '0'
77
78
  segments:
78
79
  - 0
79
- hash: 1028028193519655170
80
+ hash: -1487992565957500539
80
81
  required_rubygems_version: !ruby/object:Gem::Requirement
81
82
  none: false
82
83
  requirements:
@@ -85,7 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
86
  version: '0'
86
87
  segments:
87
88
  - 0
88
- hash: 1028028193519655170
89
+ hash: -1487992565957500539
89
90
  requirements: []
90
91
  rubyforge_project:
91
92
  rubygems_version: 1.8.11