moiper 0.1.1 → 0.1.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.
@@ -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