payu_payments 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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +178 -0
- data/Rakefile +24 -0
- data/lib/payu_payments.rb +34 -0
- data/lib/payu_payments/caller.rb +60 -0
- data/lib/payu_payments/client.rb +42 -0
- data/lib/payu_payments/credit_card.rb +78 -0
- data/lib/payu_payments/model.rb +88 -0
- data/lib/payu_payments/plan.rb +72 -0
- data/lib/payu_payments/recurring_bill_item.rb +30 -0
- data/lib/payu_payments/subscription.rb +28 -0
- data/lib/payu_payments/version.rb +3 -0
- data/payu_payments.gemspec +30 -0
- data/spec/caller_spec.rb +108 -0
- data/spec/client_spec.rb +93 -0
- data/spec/config_spec.rb +17 -0
- data/spec/credit_card_spec.rb +23 -0
- data/spec/plan_spec.rb +39 -0
- data/spec/spec_helper.rb +8 -0
- metadata +173 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
payu_payments
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.9.3-p194
|
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 CristianV
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# PayuPayments
|
2
|
+
|
3
|
+
A wrapper for the [PayuLatam.com](http://www.payulatam.com/) payment gateway, it include the
|
4
|
+
managment of clients, plans, subscriptions and creditCards.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
gem 'payu_payments'
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install payu_payments
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
All the clases work as a simple CRUD objects, the models also have a
|
23
|
+
basic attributes validations.
|
24
|
+
|
25
|
+
## Configuration
|
26
|
+
|
27
|
+
To use the gem you need to set the keys available on your account
|
28
|
+
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
PayuPayments.config do |config|
|
32
|
+
config.api_key = "xxxxxxxxxxxxxx"
|
33
|
+
config.api_login = "xxxxxxx"
|
34
|
+
config.merchant_id = "123456"
|
35
|
+
config.account = "7890"
|
36
|
+
config.mode = "development" # or production to point to production end-point
|
37
|
+
end
|
38
|
+
|
39
|
+
```
|
40
|
+
|
41
|
+
|
42
|
+
### Clients
|
43
|
+
|
44
|
+
To perform transactions with the API an entity representing the
|
45
|
+
custormer needs to be created, this entity is de Client and can be
|
46
|
+
created and updated using the PayuPayments::Client class.
|
47
|
+
|
48
|
+
```ruby
|
49
|
+
@client = PayuPayments::Client.new(:fullName => "john Doe", :email => "johndoe@gmail.com")
|
50
|
+
|
51
|
+
# or
|
52
|
+
|
53
|
+
@client = PayuPayments::Client.new
|
54
|
+
@client.fullName = "john Doe"
|
55
|
+
@client.email = "johndoe@gmail.com"
|
56
|
+
|
57
|
+
@client.save
|
58
|
+
```
|
59
|
+
You can also retrieve clients from the API if you know it's id
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
|
63
|
+
@client = PayuPayments::Client.find(123)
|
64
|
+
@client.fullName = "New name"
|
65
|
+
@client.save
|
66
|
+
|
67
|
+
```
|
68
|
+
|
69
|
+
|
70
|
+
### Credit Cards
|
71
|
+
|
72
|
+
You can store a tokenized credit card on the gateway tekenization
|
73
|
+
service by adding it to a client, in that way the credit card will be
|
74
|
+
stored directly in the PCI compliant gateway and can be used to charge the
|
75
|
+
client in future transactiosn without requiring to fill the credit card
|
76
|
+
form again.
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
@client = PayuPayments::Client.find(123)
|
80
|
+
|
81
|
+
creditCard: {
|
82
|
+
name: "Sample User Name",
|
83
|
+
document: "1020304050",
|
84
|
+
number: "4242424242424242",
|
85
|
+
expMonth: "01",
|
86
|
+
expYear: "2020",
|
87
|
+
type: "VISA",
|
88
|
+
address: {
|
89
|
+
line1: "Address Name",
|
90
|
+
line2: "17 25",
|
91
|
+
line3: "Of 301",
|
92
|
+
postalCode: "00000",
|
93
|
+
city: "City Name",
|
94
|
+
state: "State Name",
|
95
|
+
country: "CO",
|
96
|
+
phone: "300300300"
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
credit_card = @client.add_credit_card(creditCard)
|
101
|
+
|
102
|
+
### To list the credit cards from a client
|
103
|
+
|
104
|
+
@client.credit_cards
|
105
|
+
```
|
106
|
+
|
107
|
+
### Plans
|
108
|
+
|
109
|
+
To create a recurring payment model you need to create plans, plans
|
110
|
+
describe the different ways that you can sell your suscription based
|
111
|
+
products, here you describe the product how much you will charge for it an
|
112
|
+
how you want to charge for it
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
planParams = {
|
116
|
+
plan: {
|
117
|
+
planCode: "sample-plan-code-001",
|
118
|
+
description: "Sample Plan 001",
|
119
|
+
accountId: "1",
|
120
|
+
intervalCount: "1",
|
121
|
+
interval: "MONTH",
|
122
|
+
maxPaymentsAllowed: "12",
|
123
|
+
maxPaymentAttempts: "3",
|
124
|
+
paymentAttemptsDelay: "1",
|
125
|
+
maxPendingPayments: "0",
|
126
|
+
trialDays: "30",
|
127
|
+
additionalValues: {
|
128
|
+
additionalValue: [{ name: "PLAN_VALUE",
|
129
|
+
value: "20000",
|
130
|
+
currency: "COP"
|
131
|
+
},
|
132
|
+
{
|
133
|
+
name: "PLAN_TAX",
|
134
|
+
value: "1600",
|
135
|
+
currency: "COP"
|
136
|
+
}]
|
137
|
+
}
|
138
|
+
}
|
139
|
+
}
|
140
|
+
plan = PayuPayments::Plan.new(planParams)
|
141
|
+
plan.save
|
142
|
+
|
143
|
+
# or
|
144
|
+
plan = PayuPayments::Plan.create(planParams)
|
145
|
+
```
|
146
|
+
### Subscriptions
|
147
|
+
|
148
|
+
Subscription will glue all together to create a subscription based
|
149
|
+
products, with a suscription you will bind a
|
150
|
+
client with a tokenized credit card with a plan,
|
151
|
+
|
152
|
+
```ruby
|
153
|
+
PayuPayments::Subscription.create(subscription: {
|
154
|
+
quantity: "1",
|
155
|
+
installments: "1",
|
156
|
+
trialDays: "15",
|
157
|
+
customer: {
|
158
|
+
id: @client.id,
|
159
|
+
creditCards: {
|
160
|
+
creditCard: { "token": credit_card.token }
|
161
|
+
}
|
162
|
+
},
|
163
|
+
plan: { "planCode": plan.planCode }
|
164
|
+
})
|
165
|
+
|
166
|
+
# to check a client susbscriptions
|
167
|
+
@client.subscriptions
|
168
|
+
|
169
|
+
```
|
170
|
+
|
171
|
+
|
172
|
+
## Contributing
|
173
|
+
|
174
|
+
1. Fork it ( http://github.com/<my-github-username>/payu_payments/fork )
|
175
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
176
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
177
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
178
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
$LOAD_PATH << File.expand_path("../lib", __FILE__)
|
3
|
+
Dir.chdir(File.expand_path("..", __FILE__))
|
4
|
+
|
5
|
+
require 'payu_payments'
|
6
|
+
require "bundler/gem_tasks"
|
7
|
+
require 'rspec/core/rake_task'
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new('spec')
|
10
|
+
|
11
|
+
desc "Payupayments console"
|
12
|
+
task :console do
|
13
|
+
require 'irb'
|
14
|
+
require 'irb/completion'
|
15
|
+
require 'payu_payments'
|
16
|
+
require 'pry'
|
17
|
+
|
18
|
+
ARGV.clear
|
19
|
+
IRB.start
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
# If you want to make this the default task
|
24
|
+
task :default => :spec
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require "payu_payments/version"
|
2
|
+
|
3
|
+
%w{ model caller client plan credit_card subscription recurring_bill_item }.each do |f|
|
4
|
+
require "payu_payments/#{f}"
|
5
|
+
end
|
6
|
+
|
7
|
+
|
8
|
+
module PayuPayments
|
9
|
+
|
10
|
+
def self.config(&block)
|
11
|
+
@configuration ||= Configuration.new
|
12
|
+
|
13
|
+
unless block.nil?
|
14
|
+
yield @configuration
|
15
|
+
else
|
16
|
+
@configuration.config
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Configuration
|
21
|
+
attr_accessor :api_key, :api_login, :merchant_id, :account, :mode, :show_log
|
22
|
+
def initialize
|
23
|
+
@show_log = false
|
24
|
+
end
|
25
|
+
def config
|
26
|
+
{:api_key => @api_key,
|
27
|
+
:api_login => @api_login,
|
28
|
+
:merchant_id => @merchant_id,
|
29
|
+
:account => @account,
|
30
|
+
:show_log => @show_log,
|
31
|
+
:mode => @mode}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require "base64"
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module PayuPayments
|
6
|
+
class Caller
|
7
|
+
include ::HTTParty
|
8
|
+
include Model
|
9
|
+
|
10
|
+
API = "https://api.payulatam.com"
|
11
|
+
API_SANDBOX = "https://stg.api.payulatam.com"
|
12
|
+
|
13
|
+
attr_accessor :access, :base, :resource, :errors
|
14
|
+
format :json
|
15
|
+
alias :attr :base
|
16
|
+
|
17
|
+
def set_base_uri
|
18
|
+
self.class.base_uri(PayuPayments.config[:mode] == "production" ? API : API_SANDBOX)
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(params={})
|
22
|
+
@access = PayuPayments.config
|
23
|
+
self.set_base_uri
|
24
|
+
self.class.debug_output $stdout if @access[:show_log]
|
25
|
+
|
26
|
+
@base = OpenStruct.new
|
27
|
+
base.marshal_load params
|
28
|
+
@errors = []
|
29
|
+
end
|
30
|
+
|
31
|
+
def http_call(type, url, params={})
|
32
|
+
if ["post", "put"].include? type
|
33
|
+
headers = { 'Accept' => "application/json",
|
34
|
+
'Content-Type' => 'application/json; charset=UTF-8',
|
35
|
+
'Authorization' => "Basic #{basic_auth}"}
|
36
|
+
resp = self.class.send(type, url, :body => params.to_json, :verify => (access[:mode] == "production"), :headers => headers)
|
37
|
+
else
|
38
|
+
headers = { 'Accept' => "application/json",
|
39
|
+
'Authorization' => "Basic #{basic_auth}"}
|
40
|
+
resp = self.class.send(type, url, :query => params, :verify => (access[:mode] == "production"), :headers => headers)
|
41
|
+
end
|
42
|
+
|
43
|
+
respond_with = (resp == "" or resp.nil?) ? {} : resp.inject({ }) { |h, (k,v)| h[k.to_sym] = v; h }
|
44
|
+
|
45
|
+
if resp.code.to_s.match(/2\d\d/)
|
46
|
+
respond_with
|
47
|
+
else
|
48
|
+
{"type" => respond_with[:type], "description" => respond_with[:description]}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def basic_auth
|
56
|
+
Base64.encode64("#{access[:api_login]}:#{access[:api_key]}")
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module PayuPayments
|
2
|
+
class Client < Caller
|
3
|
+
|
4
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
5
|
+
# Client attributes from Payu documentation
|
6
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
7
|
+
#
|
8
|
+
# id
|
9
|
+
# ullName
|
10
|
+
# emai
|
11
|
+
# creditCards
|
12
|
+
# subscriptions
|
13
|
+
|
14
|
+
def initialize(params={})
|
15
|
+
super
|
16
|
+
@resource = "customers"
|
17
|
+
end
|
18
|
+
|
19
|
+
def add_credit_card(params)
|
20
|
+
cc = CreditCard.new(params)
|
21
|
+
cc.attr.customerId = self.base.id
|
22
|
+
cc.save
|
23
|
+
end
|
24
|
+
|
25
|
+
def subscriptions
|
26
|
+
self.base.subscriptions.map do |sub|
|
27
|
+
subscription = Subscription.new
|
28
|
+
subscription.base.marshal_load(sub)
|
29
|
+
subscription
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def credit_cards
|
34
|
+
self.base.creditCards.each.map do |sub|
|
35
|
+
cc = CreditCard.new
|
36
|
+
cc.base.marshal_load(sub)
|
37
|
+
cc
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module PayuPayments
|
2
|
+
|
3
|
+
class CreditCard < Caller
|
4
|
+
|
5
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
6
|
+
# Credit Card attributes from Payu documentation
|
7
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
8
|
+
#
|
9
|
+
# Token Longitud = [0,36] String Token asociado a una tarjeta de crédito.
|
10
|
+
# customerId Longitud = #[0,64] String Código de identificación del cliente al cual pertenece la tarjeta de crédito
|
11
|
+
# Number Longitud = [13,20] # Patrón = [0-9]*{13,20} String Número de la tarjeta de crédito
|
12
|
+
# expMonth Min = 1,#Máx = 12 Integer Mes de expiración de la tarjeta de crédito.
|
13
|
+
# expYear Min= 0,
|
14
|
+
# Max = 2999 Integer Año de expiración de la tarjeta de crédito.
|
15
|
+
# Si el valor es de dos dígitos corresponde al año comprendido entre 2000 (00) y 2099 (99).
|
16
|
+
# Si el valor es de más de dos dígitos se toma literal, siendo el año 2000 como mínimo posible.
|
17
|
+
# Type Enumeration Corresponde a la franquicia o tipo de tarjeta de crédito. Los posibles valores son:
|
18
|
+
# VISA, AMEX, DINERS, MASTERCARD, ELO, SHOPPING, NARANJA, CABAL y ARGENCARD.
|
19
|
+
# Name 255 String Nombre del tarjeta habiente.
|
20
|
+
# document Longitud = #[5, 30] String Número del documento de identificad del tarjeta habiente.
|
21
|
+
# address - Address Dirección de correspondencia del tarjeta habiente asociado con la tarjeta de crédito.
|
22
|
+
# issuerBank 255 String Nombre del banco emisor de la tarjeta de crédito.
|
23
|
+
#
|
24
|
+
# City Longitud = [0, 50] String Nombre de la ciudad.
|
25
|
+
# country Longitud = [2, 2] String Código ISO 3166 (2 letras – Alpha 2) del país de la dirección.
|
26
|
+
#Ver países soportados
|
27
|
+
# linea1 Longitud = [0, 100] String Primera línea de la dirección.
|
28
|
+
# linea2 Longitud = [0, 100] String Segunda línea de la dirección o número de la dirección.
|
29
|
+
# linea3 Longitud = [0, 100] String Tercera línea de la dirección o complemento de la dirección.
|
30
|
+
# phone Longitud = [0, 20] String Teléfono asociado a la dirección.
|
31
|
+
# postalCode Longitud = [0, 20] String Código postal de la dirección.
|
32
|
+
# State Longitud = [0, 40] String Nombre del estado de la dirección.
|
33
|
+
|
34
|
+
def initialize(params={})
|
35
|
+
super
|
36
|
+
@resource = "creditCards"
|
37
|
+
end
|
38
|
+
|
39
|
+
def save
|
40
|
+
if valid?
|
41
|
+
@url = new? ? "#{API_PATH}/customers/#{attr.customerId}/#{@resource}" : "#{API_PATH}/#{@resource}/#{base.id}"
|
42
|
+
super
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.create(customer_id, params)
|
49
|
+
url = "#{API_PATH}/customers/#{attr.customerId}/#{@resource}"
|
50
|
+
self.base.marshal_load params
|
51
|
+
resp = http_call("post", url, attr.marshal_dump)
|
52
|
+
base.marshal_load resp
|
53
|
+
end
|
54
|
+
|
55
|
+
def destroy(customer_id, id)
|
56
|
+
customer_id = self.attr.customerId
|
57
|
+
id = self.attr.id
|
58
|
+
@url = "#{API_PATH}/customers/#{customer_id}/#{@resource}/#{id}}"
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def valid?
|
63
|
+
self.validate
|
64
|
+
self.errors.count == 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def validate
|
68
|
+
self.errors = []
|
69
|
+
[:customerId, :number, :expMonth, :expYear, :type, :document, :address, :name].each do |field|
|
70
|
+
validate_presence_of(field)
|
71
|
+
end
|
72
|
+
|
73
|
+
validate_lenght_of(:expYear, 4)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
module Model
|
2
|
+
API_PATH = "/payments-api/rest/v4.3"
|
3
|
+
|
4
|
+
def self.included(base)
|
5
|
+
base.send :extend, ClassMethods
|
6
|
+
end
|
7
|
+
|
8
|
+
def save
|
9
|
+
verb = new? ? "post" : "put"
|
10
|
+
@url ||= new? ? "#{API_PATH}/#{@resource}" : "#{API_PATH}/#{@resource}/#{base.id}"
|
11
|
+
resp = http_call(verb, @url, base.marshal_dump)
|
12
|
+
|
13
|
+
if resp.is_a?(Array)
|
14
|
+
error = {field: resp[0], message: resp[1]}
|
15
|
+
self.errors << error
|
16
|
+
false
|
17
|
+
else
|
18
|
+
base.marshal_load resp
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def load
|
24
|
+
resp = http_call("get", "#{API_PATH}/#{@resource}/#{self.attr.id}")
|
25
|
+
base.marshal_load resp
|
26
|
+
end
|
27
|
+
|
28
|
+
def destroy
|
29
|
+
@id ||= self.attr.id
|
30
|
+
@url ||= "#{API_PATH}/#{@resource}/#{@id}"
|
31
|
+
resp = http_call("delete", @url)
|
32
|
+
base.marshal_load resp unless resp.is_a? Array
|
33
|
+
resp
|
34
|
+
end
|
35
|
+
|
36
|
+
def new?
|
37
|
+
base.id.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def method_missing(method_name, *arguments, &block)
|
41
|
+
if base.marshal_dump.include?(method_name.to_s.strip.to_sym) || method_name.match(/.*=$/)
|
42
|
+
base.send(method_name.to_s.strip, *arguments, &block)
|
43
|
+
else
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# xxxxxxxxxxxxxxxxx validations xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
50
|
+
|
51
|
+
def validate_presence_of(field)
|
52
|
+
if (self.attr.send(field.to_s).nil? or self.attr.send(field.to_s) == "")
|
53
|
+
error = {}
|
54
|
+
error[:field] = field
|
55
|
+
error[:message] = "#{field} can't be blank"
|
56
|
+
self.errors << error
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def validate_lenght_of(field, lenght)
|
61
|
+
unless self.attr.send(field.to_s).nil?
|
62
|
+
if self.attr.send(field.to_s).length != lenght
|
63
|
+
error = {}
|
64
|
+
error[:field] = field
|
65
|
+
error[:message] = "lenght of #{field} should be #{lenght}"
|
66
|
+
self.errors << error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Class Methods
|
72
|
+
module ClassMethods
|
73
|
+
def find(id)
|
74
|
+
resp = self.new
|
75
|
+
json = resp.http_call("get", "#{API_PATH}/#{resp.resource}/#{id}")
|
76
|
+
|
77
|
+
unless json["type"] == "NOT_FOUND"
|
78
|
+
self.new json
|
79
|
+
else
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def create(params)
|
85
|
+
http_call("post", "#{API_PATH}/#{@resource}", base.marshal_dump)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module PayuPayments
|
2
|
+
class Plan < Caller
|
3
|
+
|
4
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
5
|
+
# Plan attributes from Payu documentation
|
6
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
7
|
+
#
|
8
|
+
# id 36 String Identificador del plan en la plataforma de PayU.
|
9
|
+
# planCode 255 String Código único que el comercio le asigna al plan para su posterior identificación. Este código de plan no se puede volver a repetir aun cuando el plan sea borrado.
|
10
|
+
# description 255 String Descripción del plan.
|
11
|
+
# accountId Integer Identificador de la cuenta del comercio al cual se asocia el plan.
|
12
|
+
# interval 5 String Intervalo que define cada cuanto se realiza el cobro de la suscripción. Los valores posibles son:
|
13
|
+
# DAY, WEEK, MONTH y YEAR.
|
14
|
+
# intervalCount Integer Cantidad del intervalo que define cada cuanto se realiza el cobro de la suscripción.
|
15
|
+
# additionalValue.currency 3 String Código ISO 4217 de la moneda del valor asociado al plan.
|
16
|
+
# additionalValue.name 255 String Nombre del campo del valor asociado al plan. Los valores posibles son:
|
17
|
+
# PLAN_VALUE: valor total de plan.
|
18
|
+
# PLAN_TAX_VALUE: valor de los impuestos asociados al valor del plan.
|
19
|
+
# PLAN_TAX_RETURN_BASE: valor base para el retorno de impuestos asociados al plan.
|
20
|
+
# additionalValue.value Decimal Valor del plan, impuesto o base de retorno de acuerdo a plan.additionalValue.name.
|
21
|
+
# trialDays Integer Cantidad de días de prueba de la suscripción.
|
22
|
+
# maxPaymentAttempts Máx. 3 Integer Cantidad total de reintentos para cada pago rechazado de la suscripción.
|
23
|
+
# maxPaymentsAllowed Integer Cantidad total de pagos de la suscripción.
|
24
|
+
# maxPendingPayments Integer Cantidad máxima de pagos pendientes que puede tener una suscripción antes de ser cancelada.
|
25
|
+
# paymentAttemptsDelay Integer Cantidad de días de espera entre los reintentos de pago de la suscripción.
|
26
|
+
|
27
|
+
def initialize(params={})
|
28
|
+
super
|
29
|
+
@resource = "plans"
|
30
|
+
end
|
31
|
+
|
32
|
+
def save
|
33
|
+
verb = new? ? "post" : "put"
|
34
|
+
url = new? ? "#{API_PATH}/#{@resource}" : "#{API_PATH}/#{@resource}/#{base.planCode}"
|
35
|
+
not_allowed_for_update = [:maxPaymentsAllowed, :trialDays, :id, :intervalCount, :interval, :accountId]
|
36
|
+
|
37
|
+
params = base.marshal_dump
|
38
|
+
not_allowed_for_update.each {|x| params.delete(x) } unless new?
|
39
|
+
resp = http_call(verb, url, params)
|
40
|
+
|
41
|
+
base.marshal_load resp
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.create_base_month_plan(name, value, custom_options={})
|
45
|
+
params = {
|
46
|
+
planCode: name,
|
47
|
+
description: "#{name} plan",
|
48
|
+
accountId: PayuPayments.config[:account],
|
49
|
+
intervalCount: 1,
|
50
|
+
interval: "MONTH",
|
51
|
+
maxPaymentsAllowed: 2000,
|
52
|
+
maxPaymentAttempts: 3,
|
53
|
+
paymentAttemptsDelay: 5,
|
54
|
+
maxPendingPayments: 0,
|
55
|
+
trialDays: 0,
|
56
|
+
additionalValues: [{
|
57
|
+
name: "PLAN_VALUE",
|
58
|
+
value: value,
|
59
|
+
currency: "COP"
|
60
|
+
}]
|
61
|
+
}
|
62
|
+
params.merge!(custom_options)
|
63
|
+
self.new params
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def destroy
|
68
|
+
@id = self.attr.planCode
|
69
|
+
super
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module PayuPayments
|
2
|
+
|
3
|
+
class RecurringBillItem < Caller
|
4
|
+
def initialize(params={})
|
5
|
+
super
|
6
|
+
@resource = "recurringBillItems"
|
7
|
+
end
|
8
|
+
|
9
|
+
def save
|
10
|
+
verb = new? ? "post" : "put"
|
11
|
+
url = new? ? "#{API_PATH}/subscriptions/#{base.subscription_id}/#{@resource}" : "#{API_PATH}/#{@resource}/#{base.id}"
|
12
|
+
resp = http_call(verb, url, base.marshal_dump)
|
13
|
+
base.marshal_load resp
|
14
|
+
end
|
15
|
+
|
16
|
+
def create(params)
|
17
|
+
url = "#{API_PATH}/subscriptions/#{attr.subscription_id}/#{@resource}"
|
18
|
+
resp = http_call(verb, url, base.marshal_dump)
|
19
|
+
base.marshal_load resp
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_recurring_bill_items
|
23
|
+
url = "#{API_PATH}/#{@resource}/params"
|
24
|
+
resp = http_call(verb, url, base.marshal_dump)
|
25
|
+
base.marshal_load resp
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module PayuPayments
|
2
|
+
|
3
|
+
class Subscription < Caller
|
4
|
+
|
5
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
6
|
+
# Subscription attributes from Payu documentation
|
7
|
+
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
8
|
+
#
|
9
|
+
# id 36 String Identificador de la suscripción en la plataforma PayU.
|
10
|
+
# quantity - Integer Cantidad de planes a adquirir con la suscripción.
|
11
|
+
# installments - Integer Número de cuotas en las que se diferirá cada cobro de la suscripción.
|
12
|
+
# trialDays - Integer Días de prueba que téndra la suscripción sin generar cobros.
|
13
|
+
# customer - Customer Cliente asociado a la suscripción.
|
14
|
+
# customer.credidcards - CreditCard Tarjeta de crédito asociada al cliente.
|
15
|
+
# plan - Plan Plan asociado a la suscripción.
|
16
|
+
|
17
|
+
def initialize(params={})
|
18
|
+
super
|
19
|
+
@resource = "subscriptions"
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_extra_charges(params={})
|
23
|
+
url = "#{API_PATH}/#{self.attr.id}/recurringBillItems"
|
24
|
+
http_call("put", url, params)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'payu_payments/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "payu_payments"
|
8
|
+
spec.version = PayuPayments::VERSION
|
9
|
+
spec.authors = ["CristianV"]
|
10
|
+
spec.email = ["cristian@kommit.co"]
|
11
|
+
spec.summary = %q{Payulatam payments gatewat API gem}
|
12
|
+
spec.description = %q{Payulatam payments gatewat API gem}
|
13
|
+
spec.homepage = "https://github.com/kommitters/payu_payments"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
# Dependency
|
22
|
+
spec.add_dependency "httparty"
|
23
|
+
|
24
|
+
# Development
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.5"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
spec.add_development_dependency "guard-rspec"
|
29
|
+
spec.add_development_dependency "pry"
|
30
|
+
end
|
data/spec/caller_spec.rb
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PayuPayments
|
4
|
+
|
5
|
+
describe Caller do
|
6
|
+
|
7
|
+
it "Should set a base container to hold attributes" do
|
8
|
+
call = Caller.new
|
9
|
+
expect(call.base).to be_an_instance_of(OpenStruct)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should get access credentials from config" do
|
13
|
+
::PayuPayments.config do |config|
|
14
|
+
config.api_key = "6u39nqhq8ftd0hlvnjfs66eh8c"
|
15
|
+
config.api_login = "11959c415b33d0c"
|
16
|
+
config.merchant_id = "500238"
|
17
|
+
config.account = "5009"
|
18
|
+
config.mode = "development"
|
19
|
+
end
|
20
|
+
|
21
|
+
call = Caller.new
|
22
|
+
expect(call.access[:api_key]).to eq("6u39nqhq8ftd0hlvnjfs66eh8c")
|
23
|
+
expect(call.access[:api_login]).to eq("11959c415b33d0c")
|
24
|
+
expect(call.access[:merchant_id]).to eq("500238")
|
25
|
+
expect(call.access[:account]).to eq("5009")
|
26
|
+
expect(call.access[:mode]).to eq("development")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "Should construct a base object with the initial params" do
|
30
|
+
call = Caller.new(:name => "jhon", :last_name => "Doe", :number => 123)
|
31
|
+
expect(call.base.name).to eq("jhon")
|
32
|
+
expect(call.base.last_name).to eq("Doe")
|
33
|
+
expect(call.base.number).to eq(123)
|
34
|
+
end
|
35
|
+
|
36
|
+
context "validations" do
|
37
|
+
|
38
|
+
it "should be able to validate the lenght of a fiekd" do
|
39
|
+
call = Caller.new(:name => "jhon")
|
40
|
+
call.validate_lenght_of(:name, 5)
|
41
|
+
expect(call.errors.count).to eq(1)
|
42
|
+
expect(call.errors.first[:message]).to eq("lenght of name should be 5")
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
context "performing http calls" do
|
50
|
+
let (:resp) {a = {"valor1" => "hola"}; a.stub(:code => "200"); a}
|
51
|
+
before :each do
|
52
|
+
::PayuPayments.config do |config|
|
53
|
+
config.api_key = "6u39nqhq8ftd0hlvnjfs66eh8c"
|
54
|
+
config.api_login = "11959c415b33d0c"
|
55
|
+
config.merchant_id = "500238"
|
56
|
+
config.account = "5009"
|
57
|
+
config.mode = "development"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should be able to perform POST calls" do
|
62
|
+
attr = {fullName: "john doe", email: "jhon@doe.com"}
|
63
|
+
call = Caller.new(attr)
|
64
|
+
call.stub(:basic_auth => "abc123")
|
65
|
+
headers = { 'Accept' => "application/json",
|
66
|
+
'Content-Type' => 'application/json; charset=UTF-8',
|
67
|
+
'Authorization' => "Basic abc123"}
|
68
|
+
Caller.should_receive(:send).with("post", "/someurl", :body => attr.to_json, :verify => false, :headers => headers).and_return(resp)
|
69
|
+
call.http_call("post", "/someurl", attr)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be able to perform PUT calls" do
|
73
|
+
attr = {fullName: "john doe", email: "jhon@doe.com"}
|
74
|
+
call = Caller.new(attr)
|
75
|
+
call.stub(:basic_auth => "abc123")
|
76
|
+
headers = { 'Accept' => "application/json",
|
77
|
+
'Content-Type' => 'application/json; charset=UTF-8',
|
78
|
+
'Authorization' => "Basic abc123"}
|
79
|
+
Caller.should_receive(:send).with("put", "/someurl", :body => attr.to_json, :verify => false, :headers => headers).and_return(resp)
|
80
|
+
call.http_call("put", "/someurl", attr)
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
it "should be able to perform GET calls" do
|
85
|
+
attr = {fullName: "john doe", email: "jhon@doe.com"}
|
86
|
+
call = Caller.new(attr)
|
87
|
+
call.stub(:basic_auth => "abc123")
|
88
|
+
headers = { 'Accept' => "application/json",
|
89
|
+
'Authorization' => "Basic abc123"}
|
90
|
+
Caller.should_receive(:send).with("get", "/someurl", :query => attr, :verify => false, :headers => headers).and_return(resp)
|
91
|
+
call.http_call("get", "/someurl", attr)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should be able to perform DELETE calls" do
|
95
|
+
attr = {fullName: "john doe", email: "jhon@doe.com"}
|
96
|
+
call = Caller.new(attr)
|
97
|
+
call.stub(:basic_auth => "abc123")
|
98
|
+
headers = { 'Accept' => "application/json",
|
99
|
+
'Authorization' => "Basic abc123"}
|
100
|
+
Caller.should_receive(:send).with("delete", "/someurl", :query => attr, :verify => false, :headers => headers).and_return(resp)
|
101
|
+
call.http_call("delete", "/someurl", attr)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PayuPayments
|
4
|
+
|
5
|
+
describe Client do
|
6
|
+
it "should be able to create a client" do
|
7
|
+
client = Client.new(:fullName => "John Doe", :email => "johndoe@gmail.com")
|
8
|
+
client.should_receive(:http_call).with("post", "/payments-api/rest/v4.3/customers", {:fullName => "John Doe", :email => "johndoe@gmail.com"}).and_return(:fullName => "John Doe", :email => "johndoe@gmail.com")
|
9
|
+
client.save
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be able to find a client with its id" do
|
13
|
+
call = Client.new
|
14
|
+
call.should_receive(:http_call).with("get","/payments-api/rest/v4.3/customers/1").and_return(:fullName => "John Doe", :email => "johndoe@gmail.com", :id => 1)
|
15
|
+
Client.should_receive(:new).twice.and_return(call)
|
16
|
+
client = Client.find(1)
|
17
|
+
expect(client).to be_an_instance_of(Client)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should save a credit card related to the client" do
|
21
|
+
client = Client.new(:id => "123", :fullName => "John Doe", :email => "johndoe@gmail.com")
|
22
|
+
cc = CreditCard.new
|
23
|
+
CreditCard.should_receive(:new).and_return(cc)
|
24
|
+
cc.stub(:save => true)
|
25
|
+
client.add_credit_card({number: "1234", :name => "John Doe"})
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should be able to load credit cards" do
|
29
|
+
response = {
|
30
|
+
id: "2mkls9xekm",
|
31
|
+
fullName: "Pedro Perez",
|
32
|
+
email: "pperez@payulatam.com",
|
33
|
+
creditCards: [
|
34
|
+
{
|
35
|
+
token: "da2224a9-58b7-482a-9866-199de911c23f",
|
36
|
+
customerId: "2mkls9xekm",
|
37
|
+
number: "************4242",
|
38
|
+
name: "Usuario Prueba",
|
39
|
+
type: "VISA",
|
40
|
+
address: {
|
41
|
+
line1: "Street 93B",
|
42
|
+
line2: "17 25",
|
43
|
+
line3: "Office 301",
|
44
|
+
city: "Bogota",
|
45
|
+
country: "CO",
|
46
|
+
postalCode: "00000",
|
47
|
+
phone: "300300300"
|
48
|
+
}
|
49
|
+
}
|
50
|
+
]
|
51
|
+
}
|
52
|
+
Client.should_receive(:find).and_return(Client.new(response))
|
53
|
+
client = Client.find("2mkls9xekm")
|
54
|
+
expect(client.base.id).to eq("2mkls9xekm")
|
55
|
+
expect(client.credit_cards[0].attr.number).to eql("************4242")
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should be able to load subscriptions" do
|
59
|
+
response = {
|
60
|
+
id: "2mkls9xekm",
|
61
|
+
fullName: "Pedro Perez",
|
62
|
+
email: "pperez@payulatam.com",
|
63
|
+
subscriptions: [
|
64
|
+
{
|
65
|
+
id: "2mlhk3qxji",
|
66
|
+
quantity: "1",
|
67
|
+
installments: "1",
|
68
|
+
currentPeriodStart: "2013-08-30T10:46:41.477-05:00",
|
69
|
+
currentPeriodEnd: "2013-09-29T10:46:41.477-05:00",
|
70
|
+
plan: {
|
71
|
+
id: "414215a2-c990-4525-ba84-072181988d09",
|
72
|
+
planCode: "PLAN-REST-16",
|
73
|
+
description: "Plan rest test",
|
74
|
+
accountId: "1",
|
75
|
+
intervalCount: "1",
|
76
|
+
interval: "MONTH",
|
77
|
+
additionalValues: [
|
78
|
+
{
|
79
|
+
name: "PLAN_VALUE",
|
80
|
+
value: "20000",
|
81
|
+
currency: "COP"
|
82
|
+
}]
|
83
|
+
}
|
84
|
+
}
|
85
|
+
]
|
86
|
+
}
|
87
|
+
Client.should_receive(:find).and_return(Client.new(response))
|
88
|
+
client = Client.find("2mkls9xekm")
|
89
|
+
expect(client.base.id).to eq("2mkls9xekm")
|
90
|
+
expect(client.subscriptions[0].attr.id).to eql("2mlhk3qxji")
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe PayuPayments do
|
3
|
+
|
4
|
+
context "Configuration" do
|
5
|
+
it "should be able to set configuration keys" do
|
6
|
+
PayuPayments.config do |config|
|
7
|
+
config.api_key = "xxx"
|
8
|
+
config.merchant_id = "123"
|
9
|
+
config.account = "abc123"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be able to read configuration keys" do
|
14
|
+
PayuPayments.config[:api_key].should == "xxx"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PayuPayments
|
4
|
+
|
5
|
+
describe CreditCard do
|
6
|
+
it "should be able to validate a credit card" do
|
7
|
+
cc = CreditCard.new
|
8
|
+
expect(cc.valid?).to eq(false)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should tell me where the errors are" do
|
12
|
+
cc = CreditCard.new
|
13
|
+
cc.valid?
|
14
|
+
expect(cc.errors.count).to be > 0
|
15
|
+
expect(cc.errors.first[:field]).to eql(:customerId)
|
16
|
+
expect(cc.errors.first[:message]).to eql("customerId can't be blank")
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not allow to save a credit card with erros" do
|
20
|
+
expect(CreditCard.new.save).to be(false)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/plan_spec.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module PayuPayments
|
4
|
+
describe Plan do
|
5
|
+
|
6
|
+
it "should be able to create a plan" do
|
7
|
+
plan = {
|
8
|
+
plan: {
|
9
|
+
planCode: "sample-plan-code-001",
|
10
|
+
description: "Sample Plan 001",
|
11
|
+
accountId: "1",
|
12
|
+
intervalCount: "1",
|
13
|
+
interval: "MONTH",
|
14
|
+
maxPaymentsAllowed: "12",
|
15
|
+
maxPaymentAttempts: "3",
|
16
|
+
paymentAttemptsDelay: "1",
|
17
|
+
maxPendingPayments: "0",
|
18
|
+
trialDays: "30",
|
19
|
+
additionalValues: {
|
20
|
+
additionalValue: [{ name: "PLAN_VALUE",
|
21
|
+
value: "20000",
|
22
|
+
currency: "COP"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
name: "PLAN_TAX",
|
26
|
+
value: "1600",
|
27
|
+
currency: "COP"
|
28
|
+
}]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
my_plan = Plan.new(plan)
|
33
|
+
my_plan.should_receive(:http_call).with("post", "/payments-api/rest/v4.3/plans", plan).and_return(plan)
|
34
|
+
my_plan.save
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,173 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: payu_payments
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- CristianV
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-03-01 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: !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: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: bundler
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '1.5'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '1.5'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: guard-rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: pry
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
description: Payulatam payments gatewat API gem
|
111
|
+
email:
|
112
|
+
- cristian@kommit.co
|
113
|
+
executables: []
|
114
|
+
extensions: []
|
115
|
+
extra_rdoc_files: []
|
116
|
+
files:
|
117
|
+
- .gitignore
|
118
|
+
- .rspec
|
119
|
+
- .ruby-gemset
|
120
|
+
- .ruby-version
|
121
|
+
- Gemfile
|
122
|
+
- Guardfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- lib/payu_payments.rb
|
127
|
+
- lib/payu_payments/caller.rb
|
128
|
+
- lib/payu_payments/client.rb
|
129
|
+
- lib/payu_payments/credit_card.rb
|
130
|
+
- lib/payu_payments/model.rb
|
131
|
+
- lib/payu_payments/plan.rb
|
132
|
+
- lib/payu_payments/recurring_bill_item.rb
|
133
|
+
- lib/payu_payments/subscription.rb
|
134
|
+
- lib/payu_payments/version.rb
|
135
|
+
- payu_payments.gemspec
|
136
|
+
- spec/caller_spec.rb
|
137
|
+
- spec/client_spec.rb
|
138
|
+
- spec/config_spec.rb
|
139
|
+
- spec/credit_card_spec.rb
|
140
|
+
- spec/plan_spec.rb
|
141
|
+
- spec/spec_helper.rb
|
142
|
+
homepage: https://github.com/kommitters/payu_payments
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ! '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
none: false
|
157
|
+
requirements:
|
158
|
+
- - ! '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
requirements: []
|
162
|
+
rubyforge_project:
|
163
|
+
rubygems_version: 1.8.23
|
164
|
+
signing_key:
|
165
|
+
specification_version: 3
|
166
|
+
summary: Payulatam payments gatewat API gem
|
167
|
+
test_files:
|
168
|
+
- spec/caller_spec.rb
|
169
|
+
- spec/client_spec.rb
|
170
|
+
- spec/config_spec.rb
|
171
|
+
- spec/credit_card_spec.rb
|
172
|
+
- spec/plan_spec.rb
|
173
|
+
- spec/spec_helper.rb
|