payu-latam 1.0.5 → 1.0.6
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/README.md +162 -1
- data/lib/pay_u.rb +11 -0
- data/lib/pay_u/client.rb +87 -0
- data/lib/pay_u/configuration.rb +4 -0
- data/lib/pay_u/constants.rb +4 -2
- data/lib/pay_u/credit_card.rb +35 -0
- data/lib/pay_u/customer.rb +34 -0
- data/lib/pay_u/errors.rb +7 -0
- data/lib/pay_u/form.rb +1 -1
- data/lib/pay_u/plan.rb +67 -0
- data/lib/pay_u/resource.rb +81 -0
- data/lib/pay_u/subscription.rb +57 -0
- data/lib/pay_u/util/string.rb +12 -0
- data/lib/pay_u/version.rb +2 -1
- data/payu-latam.gemspec +1 -0
- data/spec/fixtures/credit_card.rb +12 -0
- data/spec/fixtures/plan.rb +15 -0
- data/spec/fixtures/responses/customer.json +5 -0
- data/spec/fixtures/responses/plan.json +18 -0
- data/spec/fixtures/responses/plan_not_found.json +4 -0
- data/spec/fixtures/responses/subscription.json +29 -0
- data/spec/helpers/stub.rb +35 -0
- data/spec/pay_u/configuration_spec.rb +4 -0
- data/spec/pay_u/confirmation_spec.rb +0 -1
- data/spec/pay_u/credit_card_spec.rb +21 -0
- data/spec/pay_u/form_spec.rb +0 -4
- data/spec/pay_u/plan_spec.rb +64 -0
- data/spec/pay_u/response_spec.rb +0 -1
- data/spec/pay_u/subscription_spec.rb +58 -0
- data/spec/spec_helper.rb +6 -0
- metadata +44 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bc5ce65d0810e098497cd40608afac89a03abb5dbc95d56bd14cedda3ff6684f
|
4
|
+
data.tar.gz: e0ddbaa78f080c1fb1a7401ae66dfec04aa96b625c008332e129757dbe6885cc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7c73c6e9c7dc40ae5301c9444fe8a72cd03c219ffc8304e3f23aa239c0d44acfac7df705dfbceae2678c3c2f70de5880a5421ad72ebd740a51c47712ec0e9ac
|
7
|
+
data.tar.gz: 9decca14c41d0d8250986b4500ebae9ef09ee8aba4f077d79f2099362813d96f1848128f18bbf6b2d461458b28e32e30b0429e0d8ae63c3a20a320bbe0012869
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -20,17 +20,178 @@ PayU.configure do |config|
|
|
20
20
|
config.api_key = "4Vj8eK4rloUd272L48hsrarnUA" # Replace with your own API key
|
21
21
|
config.merchant_id = 508_029 # Replace with your own merchant ID
|
22
22
|
config.test = true # Test mode
|
23
|
+
config.account_ids = {
|
24
|
+
AR: 512_322,
|
25
|
+
BR: 512_327,
|
26
|
+
CL: 512_325,
|
27
|
+
CO: 512_321,
|
28
|
+
MX: 512_324,
|
29
|
+
PA: 512_326,
|
30
|
+
PE: 512_323,
|
31
|
+
}
|
23
32
|
end
|
24
33
|
|
25
34
|
order = PayU::Order.new(
|
26
35
|
amount: 20_000,
|
27
36
|
currency: :COP,
|
28
|
-
description: "Test PAYU"
|
37
|
+
description: "Test PAYU",
|
29
38
|
)
|
30
39
|
|
40
|
+
# Form params for WebCheckout
|
31
41
|
order.form.params
|
32
42
|
```
|
33
43
|
|
44
|
+
## Resources
|
45
|
+
|
46
|
+
### Order
|
47
|
+
|
48
|
+
The base object to build a transaction.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
#<PayU::Order:0x007f95818e5c10
|
52
|
+
@account_id=nil,
|
53
|
+
@amount=0.3e1,
|
54
|
+
@cc_number="************0086",
|
55
|
+
@currency=:USD,
|
56
|
+
@description=nil,
|
57
|
+
@email="test@test.com",
|
58
|
+
@extra_1="extra 1",
|
59
|
+
@extra_2="extra 2",
|
60
|
+
@extra_3="extra 3",
|
61
|
+
@payment_method="VISA",
|
62
|
+
@payment_method_code=2,
|
63
|
+
@reference_code="2205229",
|
64
|
+
@response_code=1,
|
65
|
+
@response_message="APPROVED",
|
66
|
+
@status_code=4,
|
67
|
+
@tax=nil,
|
68
|
+
@tax_return_base=nil,
|
69
|
+
@transaction_id="957aa79c-135d-413e-b7fc-aaaa0000cccc">
|
70
|
+
|
71
|
+
order.form # Form object
|
72
|
+
order.approved? # Transaction was approved
|
73
|
+
order.declined? # Transaction was declined
|
74
|
+
order.error? # Transaction failed
|
75
|
+
order.pending? # Transaction is pending
|
76
|
+
order.expired? # Transaction expired
|
77
|
+
```
|
78
|
+
|
79
|
+
### Confirmation
|
80
|
+
|
81
|
+
A confirmation object from the confirmation Webhook (POST when transaction is finalized)
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
#<PayU::Confirmation:0x007f95818e5cb0
|
85
|
+
@order=#<PayU::Order:0x007f95818e5c10…> # Order object
|
86
|
+
@signature="cc3c8101113b056bc4b5b3d289dbb106", # Signature to verify
|
87
|
+
@signer=#<PayU::Signer::Confirmation:0x007f95822e3b40…>> # Signer to verify signature
|
88
|
+
|
89
|
+
confirmation.valid? # Signature is valid
|
90
|
+
```
|
91
|
+
|
92
|
+
### Response
|
93
|
+
|
94
|
+
A response object from the response Webhook (GET when the user leaves the payment page and is sent back to the commerce)
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
#<PayU::Order:0x007f8a33bf7e48
|
98
|
+
@order=#<PayU::Order:0x007f8a33bf7e48…> # Order object
|
99
|
+
@signature="cc3c8101113b056bc4b5b3d289dbb106", # Signature to verify
|
100
|
+
@signer=#<PayU::Signer::Response:0x007f8a33bdf9d8…>> # Signer to verify signature
|
101
|
+
|
102
|
+
order.valid? # Signature is valid
|
103
|
+
```
|
104
|
+
|
105
|
+
### Customer
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
PayU::Customer.create(
|
109
|
+
name: "Sample User Name",
|
110
|
+
email: "sample@sample.com",
|
111
|
+
)
|
112
|
+
```
|
113
|
+
|
114
|
+
### Credit card
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
PayU::CreditCard.create(
|
118
|
+
name: "Sample User Name",
|
119
|
+
document: "1020304050",
|
120
|
+
number: "4242424242424242",
|
121
|
+
exp_month: 12,
|
122
|
+
exp_year: 20,
|
123
|
+
type: "VISA",
|
124
|
+
customer_id: 4ef04ef0aaaa,
|
125
|
+
)
|
126
|
+
```
|
127
|
+
|
128
|
+
### Plan
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
PayU::Plan.create(
|
132
|
+
account_id: 512_321,
|
133
|
+
code: SecureRandom.hex(8),
|
134
|
+
description: "Plan",
|
135
|
+
interval: "MONTH",
|
136
|
+
interval_count: 1,
|
137
|
+
max_payments_allowed: 12,
|
138
|
+
payment_attempts_delay: 1,
|
139
|
+
data: {PLAN_VALUE: 20_000, PLAN_TAX: 0, PLAN_TAX_RETURN_BASE: 0},
|
140
|
+
currency: :COP,
|
141
|
+
)
|
142
|
+
```
|
143
|
+
|
144
|
+
### Subscription
|
145
|
+
|
146
|
+
Subscription object that ties a customer, a plan, and a credit card.
|
147
|
+
|
148
|
+
```ruby
|
149
|
+
#<PayU::Subscription:0x007fe0de8e4790
|
150
|
+
@current_period_end=2019-03-26 23:59:59 -0500,
|
151
|
+
@current_period_start=2019-02-27 00:00:00 -0500,
|
152
|
+
@customer=
|
153
|
+
#<PayU::Customer:0x007fe0de8d43e0
|
154
|
+
@credit_cards=
|
155
|
+
[#<PayU::CreditCard:0x007fe0de8ce288
|
156
|
+
@address={},
|
157
|
+
@customer_id=nil,
|
158
|
+
@document=nil,
|
159
|
+
@exp_month=nil,
|
160
|
+
@exp_year=nil,
|
161
|
+
@name=nil,
|
162
|
+
@number=nil,
|
163
|
+
@token="db092e5e-65aa-48c6-92b1-aaaa0000cccc",
|
164
|
+
@type=nil>],
|
165
|
+
@email="sample@sample.com",
|
166
|
+
@id="4ef04ef0aaaa",
|
167
|
+
@name="Sample User Name">,
|
168
|
+
@delivery_address={},
|
169
|
+
@extra_1=nil,
|
170
|
+
@extra_2=nil,
|
171
|
+
@id="44f09r1p5561",
|
172
|
+
@immediate_payment=true,
|
173
|
+
@installments=1,
|
174
|
+
@notify_url="https://example.com",
|
175
|
+
@plan=
|
176
|
+
#<PayU::Plan:0x007fe0de8d7a68
|
177
|
+
@account_id=512321,
|
178
|
+
@code="4689fe81dd927aae",
|
179
|
+
@currency=:COP,
|
180
|
+
@data={"PLAN_TAX_RETURN_BASE"=>0, "PLAN_TAX"=>0, "PLAN_VALUE"=>20000},
|
181
|
+
@description="Plan",
|
182
|
+
@id="6da3e0b5-cfb6-430d-93ef-aaaa0000cccc",
|
183
|
+
@interval=:MONTH,
|
184
|
+
@interval_count=1,
|
185
|
+
@max_payment_attempts=nil,
|
186
|
+
@max_payments_allowed=nil,
|
187
|
+
@max_pending_payments=nil,
|
188
|
+
@payment_attempts_delay=nil,
|
189
|
+
@trial_days=nil>,
|
190
|
+
@quantity=1,
|
191
|
+
@trial_days=nil>
|
192
|
+
```
|
193
|
+
|
194
|
+
|
34
195
|
## Sandbox
|
35
196
|
|
36
197
|
- Sandbox endpoint
|
data/lib/pay_u.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
require "bigdecimal"
|
2
|
+
require "faraday"
|
2
3
|
require "virtus"
|
3
4
|
|
4
5
|
require "pay_u/version"
|
5
6
|
|
6
7
|
require "pay_u/constants"
|
7
8
|
require "pay_u/configuration"
|
9
|
+
require "pay_u/errors"
|
10
|
+
require "pay_u/util/string"
|
11
|
+
|
8
12
|
require "pay_u/signer/base"
|
9
13
|
require "pay_u/signer/form"
|
10
14
|
require "pay_u/signer/response"
|
@@ -13,3 +17,10 @@ require "pay_u/order"
|
|
13
17
|
require "pay_u/form"
|
14
18
|
require "pay_u/response"
|
15
19
|
require "pay_u/confirmation"
|
20
|
+
|
21
|
+
require "pay_u/client"
|
22
|
+
require "pay_u/resource"
|
23
|
+
require "pay_u/plan"
|
24
|
+
require "pay_u/credit_card"
|
25
|
+
require "pay_u/customer"
|
26
|
+
require "pay_u/subscription"
|
data/lib/pay_u/client.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require "base64"
|
2
|
+
|
3
|
+
class PayU::Client
|
4
|
+
include Singleton
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@client ||= Faraday.new(url: PayU.configuration.api_url) do |connection|
|
8
|
+
connection.request :url_encoded
|
9
|
+
connection.response :logger if PayU.configuration.test?
|
10
|
+
connection.adapter Faraday.default_adapter
|
11
|
+
connection.basic_auth "pRRXKOl8ikMmt9u", "4Vj8eK4rloUd272L48hsrarnUA"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def get(url)
|
17
|
+
response = @client.get(&perform_request(url))
|
18
|
+
|
19
|
+
process_response(response)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def post(url, params: {})
|
24
|
+
response = @client.post(&perform_request_with_params(url, params))
|
25
|
+
|
26
|
+
process_response(response)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def put(url, params: {})
|
31
|
+
response = @client.put(&perform_request_with_params(url, params))
|
32
|
+
|
33
|
+
process_response(response)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def delete(url)
|
38
|
+
response = @client.delete(&perform_request(url))
|
39
|
+
|
40
|
+
response.success?
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
private def perform_request(url)
|
45
|
+
proc do |request|
|
46
|
+
request.url "payments-api/#{url}"
|
47
|
+
request.headers = request.headers.merge(default_headers)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private def perform_request_with_params(url, params)
|
53
|
+
proc do |request|
|
54
|
+
request.url "payments-api/#{url}"
|
55
|
+
request.headers = request.headers.merge(default_headers)
|
56
|
+
request.body = params.delete_if { |_, value| value.nil? }.to_json
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
private def process_response(response)
|
62
|
+
raise PayU::UnauthorizedError, "Unauthorized" if !response.success? && response.status == 401
|
63
|
+
|
64
|
+
body = JSON.parse(response.body)
|
65
|
+
|
66
|
+
return raise_error(response) unless response.success?
|
67
|
+
|
68
|
+
body
|
69
|
+
end
|
70
|
+
|
71
|
+
private def raise_error(response)
|
72
|
+
body = JSON.parse(response.body)
|
73
|
+
|
74
|
+
error_message = body["errorList"] ? body["errorList"].join : body["description"]
|
75
|
+
|
76
|
+
raise PayU::NotFoundError, error_message if response.status == 404
|
77
|
+
raise PayU::Error, error_message
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
private def default_headers
|
82
|
+
{
|
83
|
+
"Content-Type" => "application/json; charset=utf-8",
|
84
|
+
"Accept" => "application/json",
|
85
|
+
}
|
86
|
+
end
|
87
|
+
end
|
data/lib/pay_u/configuration.rb
CHANGED
@@ -8,6 +8,8 @@ module PayU
|
|
8
8
|
attribute :test, Boolean
|
9
9
|
attribute :response_url, String
|
10
10
|
attribute :confirmation_url, String
|
11
|
+
attribute :api_url, String
|
12
|
+
attribute :webcheckout_url, String
|
11
13
|
|
12
14
|
SANDBOX_API_KEY = "4Vj8eK4rloUd272L48hsrarnUA".freeze
|
13
15
|
SANDBOX_MERCHANT_ID = 508_029
|
@@ -28,6 +30,8 @@ module PayU
|
|
28
30
|
self.merchant_id = ENV.fetch("PAYU_MERCHANT_ID", SANDBOX_MERCHANT_ID) if merchant_id.nil?
|
29
31
|
self.test = ENV.fetch("PAYU_TEST", true) if test.nil?
|
30
32
|
self.account_ids = SANDBOX_ACCOUNT_IDS if account_ids.nil?
|
33
|
+
self.api_url = test ? PayU::TEST_API_URL : PayU::LIVE_API_URL
|
34
|
+
self.webcheckout_url = test ? PayU::TEST_WEBCHECKOUT_URL : PayU::LIVE_WEBCHECKOUT_URL
|
31
35
|
end
|
32
36
|
|
33
37
|
|
data/lib/pay_u/constants.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module PayU
|
2
|
-
|
3
|
-
|
2
|
+
TEST_API_URL = "https://sandbox.api.payulatam.com/".freeze
|
3
|
+
LIVE_API_URL = "https://api.payulatam.com/".freeze
|
4
|
+
TEST_WEBCHECKOUT_URL = "https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/".freeze
|
5
|
+
LIVE_WEBCHECKOUT_URL = "https://checkout.payulatam.com/ppp-web-gateway-payu/".freeze
|
4
6
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
class PayU::CreditCard
|
2
|
+
include Virtus.model
|
3
|
+
include PayU::Resource
|
4
|
+
|
5
|
+
ENDPOINT = "rest/v#{PayU::API_VERSION}/creditCards".freeze
|
6
|
+
|
7
|
+
attribute :token, String
|
8
|
+
attribute :name, String
|
9
|
+
attribute :document, String
|
10
|
+
attribute :number, String
|
11
|
+
attribute :exp_month, Integer
|
12
|
+
attribute :exp_year, Integer
|
13
|
+
attribute :type, String
|
14
|
+
attribute :address, Hash
|
15
|
+
attribute :customer_id, String
|
16
|
+
|
17
|
+
def to_params
|
18
|
+
{
|
19
|
+
name: name,
|
20
|
+
document: document,
|
21
|
+
number: number,
|
22
|
+
expMonth: exp_month,
|
23
|
+
expYear: exp_year,
|
24
|
+
type: type,
|
25
|
+
address: address,
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
def create_url
|
31
|
+
raise StandardError, "Missing customer id" unless customer_id
|
32
|
+
|
33
|
+
"#{PayU::Customer::ENDPOINT}/#{customer_id}/creditCards"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class PayU::Customer
|
2
|
+
include Virtus.model
|
3
|
+
include PayU::Resource
|
4
|
+
|
5
|
+
ENDPOINT = "rest/v#{PayU::API_VERSION}/customers".freeze
|
6
|
+
|
7
|
+
attribute :id, String
|
8
|
+
attribute :name, String
|
9
|
+
attribute :email, String
|
10
|
+
attribute :credit_cards, Array[PayU::CreditCard]
|
11
|
+
|
12
|
+
def self.new_from_api(params)
|
13
|
+
customer = super(params)
|
14
|
+
|
15
|
+
customer.name = params["fullName"]
|
16
|
+
|
17
|
+
if params["creditCards"]
|
18
|
+
customer.credit_cards = params["creditCards"].map do |credit_card|
|
19
|
+
PayU::CreditCard.new_from_api(credit_card)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
customer
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
def to_params
|
28
|
+
{
|
29
|
+
fullName: name,
|
30
|
+
email: email,
|
31
|
+
creditCards: credit_cards.map(&:to_params),
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
data/lib/pay_u/errors.rb
ADDED
data/lib/pay_u/form.rb
CHANGED
data/lib/pay_u/plan.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
class PayU::Plan
|
2
|
+
include Virtus.model
|
3
|
+
include PayU::Resource
|
4
|
+
|
5
|
+
ENDPOINT = "rest/v#{PayU::API_VERSION}/plans".freeze
|
6
|
+
|
7
|
+
attribute :account_id, Integer
|
8
|
+
attribute :id, String
|
9
|
+
attribute :code, String
|
10
|
+
attribute :description, String
|
11
|
+
attribute :interval, Symbol
|
12
|
+
attribute :interval_count, Integer
|
13
|
+
attribute :max_payments_allowed, Integer
|
14
|
+
attribute :max_payment_attempts, Integer
|
15
|
+
attribute :payment_attempts_delay, Integer
|
16
|
+
attribute :max_pending_payments, Integer
|
17
|
+
attribute :trial_days, Integer
|
18
|
+
attribute :data, Hash
|
19
|
+
attribute :currency, Symbol
|
20
|
+
|
21
|
+
def self.new_from_api(params)
|
22
|
+
plan = super(params)
|
23
|
+
|
24
|
+
plan.code = params["planCode"]
|
25
|
+
plan.currency = params["additionalValues"].first["currency"].to_s
|
26
|
+
plan.data = params["additionalValues"].inject({}) do |memo, hash|
|
27
|
+
memo.merge(hash["name"].to_s => hash["value"])
|
28
|
+
end
|
29
|
+
|
30
|
+
plan
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def to_params
|
35
|
+
{
|
36
|
+
accountId: account_id,
|
37
|
+
planCode: code,
|
38
|
+
description: description,
|
39
|
+
interval: interval,
|
40
|
+
intervalCount: interval_count,
|
41
|
+
maxPaymentsAllowed: max_payments_allowed,
|
42
|
+
paymentAttemptsDelay: payment_attempts_delay,
|
43
|
+
additionalValues: data.map do |name, value|
|
44
|
+
{name: name, value: value, currency: currency.to_s}
|
45
|
+
end,
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def to_update_params
|
51
|
+
{
|
52
|
+
planCode: code,
|
53
|
+
description: description,
|
54
|
+
paymentAttemptsDelay: payment_attempts_delay,
|
55
|
+
maxPendingPayments: max_pending_payments,
|
56
|
+
maxPaymentAttempts: max_payment_attempts,
|
57
|
+
additionalValues: data.map do |name, value|
|
58
|
+
{name: name, value: value, currency: currency.to_s}
|
59
|
+
end,
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
private def identifier
|
65
|
+
code
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module PayU::Resource
|
2
|
+
def self.included(base)
|
3
|
+
base.extend(ClassMethods)
|
4
|
+
end
|
5
|
+
|
6
|
+
|
7
|
+
def save
|
8
|
+
return update if id
|
9
|
+
|
10
|
+
self.attributes = self.class.create(attributes).attributes
|
11
|
+
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def delete
|
17
|
+
self.class.client.delete url
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
def create_url
|
22
|
+
self.class::ENDPOINT
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def to_update_params
|
27
|
+
to_params
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
private def update
|
32
|
+
response = self.class.client.put url, params: to_update_params
|
33
|
+
self.attributes = attributes.merge(self.class.new_from_api(response).attributes)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
private def identifier
|
38
|
+
id
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
private def url
|
43
|
+
"#{self.class::ENDPOINT}/#{identifier}"
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
module ClassMethods
|
48
|
+
def client
|
49
|
+
@client ||= PayU::Client.instance
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def new_from_api(params)
|
54
|
+
resource = new
|
55
|
+
|
56
|
+
resource.attributes = params.inject({}) do |memo, (key, value)|
|
57
|
+
local_key = key.to_underscore.to_sym
|
58
|
+
|
59
|
+
resource.respond_to?(local_key) ? memo.merge(local_key => value) : memo
|
60
|
+
end
|
61
|
+
|
62
|
+
resource
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def retrieve(identifier)
|
67
|
+
response = client.get "#{self::ENDPOINT}/#{identifier}"
|
68
|
+
|
69
|
+
new_from_api(response)
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
def create(params)
|
74
|
+
resource = new(params)
|
75
|
+
|
76
|
+
response = client.post resource.create_url, params: resource.to_params
|
77
|
+
|
78
|
+
new_from_api(response)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
class PayU::Subscription
|
2
|
+
include Virtus.model
|
3
|
+
include PayU::Resource
|
4
|
+
|
5
|
+
ENDPOINT = "rest/v#{PayU::API_VERSION}/subscriptions".freeze
|
6
|
+
|
7
|
+
attribute :id, String
|
8
|
+
attribute :quantity, Integer
|
9
|
+
attribute :installments, Integer
|
10
|
+
attribute :trial_days, Integer
|
11
|
+
attribute :current_period_start, Time
|
12
|
+
attribute :current_period_end, Time
|
13
|
+
attribute :immediate_payment, Boolean
|
14
|
+
attribute :extra_1, String
|
15
|
+
attribute :extra_2, String
|
16
|
+
attribute :delivery_address, Hash
|
17
|
+
attribute :notify_url, String
|
18
|
+
attribute :plan, PayU::Plan
|
19
|
+
attribute :customer, PayU::Customer
|
20
|
+
|
21
|
+
def self.new_from_api(params)
|
22
|
+
subscription = super(params)
|
23
|
+
|
24
|
+
subscription.extra_1 = params["extra1"]
|
25
|
+
subscription.extra_2 = params["extra2"]
|
26
|
+
subscription.current_period_start = Time.at(params["currentPeriodStart"] / 1000)
|
27
|
+
subscription.current_period_end = Time.at(params["currentPeriodEnd"] / 1000)
|
28
|
+
|
29
|
+
subscription.plan = PayU::Plan.new_from_api(params["plan"])
|
30
|
+
subscription.customer = PayU::Customer.new_from_api(params["customer"])
|
31
|
+
|
32
|
+
subscription
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def to_params
|
37
|
+
{
|
38
|
+
quantity: quantity,
|
39
|
+
installments: installments,
|
40
|
+
trialDays: trial_days,
|
41
|
+
immediatePayment: immediate_payment,
|
42
|
+
extra1: extra_1,
|
43
|
+
extra2: extra_2,
|
44
|
+
customer: customer.to_params,
|
45
|
+
plan: plan.to_params,
|
46
|
+
deliveryAddress: delivery_address,
|
47
|
+
notifyUrl: notify_url,
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
def to_update_params
|
53
|
+
{
|
54
|
+
creditCardToken: customer.credit_cards.first.token,
|
55
|
+
}
|
56
|
+
end
|
57
|
+
end
|
data/lib/pay_u/version.rb
CHANGED
data/payu-latam.gemspec
CHANGED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Fixtures
|
2
|
+
def self.plan
|
3
|
+
{
|
4
|
+
account_id: 512_321,
|
5
|
+
code: SecureRandom.hex(8),
|
6
|
+
description: "Plan",
|
7
|
+
interval: "MONTH",
|
8
|
+
interval_count: 1,
|
9
|
+
max_payments_allowed: 12,
|
10
|
+
payment_attempts_delay: 1,
|
11
|
+
data: {PLAN_VALUE: 20_000, PLAN_TAX: 0, PLAN_TAX_RETURN_BASE: 0},
|
12
|
+
currency: :COP,
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
{
|
2
|
+
"id": "0bbc2f6c-c12e-41a3-b261-60fc83014fe1",
|
3
|
+
"planCode": "{{code}}",
|
4
|
+
"description": "Plan",
|
5
|
+
"accountId": "512321",
|
6
|
+
"intervalCount": 1,
|
7
|
+
"interval": "MONTH",
|
8
|
+
"maxPaymentsAllowed": 12,
|
9
|
+
"maxPaymentAttempts": 0,
|
10
|
+
"paymentAttemptsDelay": 1,
|
11
|
+
"maxPendingPayments": 0,
|
12
|
+
"trialDays": 0,
|
13
|
+
"additionalValues": [
|
14
|
+
{ "name": "PLAN_TAX", "value": 0, "currency": "COP" },
|
15
|
+
{ "name": "PLAN_VALUE", "value": 20000, "currency": "COP" },
|
16
|
+
{ "name": "PLAN_TAX_RETURN_BASE", "value": 0, "currency": "COP" }
|
17
|
+
]
|
18
|
+
}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
{
|
2
|
+
"id": "44f09r1p5561",
|
3
|
+
"plan": {
|
4
|
+
"id": "6da3e0b5-cfb6-430d-93ef-f654eda54e16",
|
5
|
+
"planCode": "{{code}}",
|
6
|
+
"description": "Plan",
|
7
|
+
"accountId": "512321",
|
8
|
+
"intervalCount": 1,
|
9
|
+
"interval": "MONTH",
|
10
|
+
"additionalValues": [
|
11
|
+
{ "name": "PLAN_TAX_RETURN_BASE", "value": 0, "currency": "COP" },
|
12
|
+
{ "name": "PLAN_TAX", "value": 0, "currency": "COP" },
|
13
|
+
{ "name": "PLAN_VALUE", "value": 20000, "currency": "COP" }
|
14
|
+
]
|
15
|
+
},
|
16
|
+
"customer": {
|
17
|
+
"id": "4ef0aqk8kipn",
|
18
|
+
"fullName": "Sample User Name",
|
19
|
+
"email": "sample@sample.com",
|
20
|
+
"creditCards": [{ "token": "db092e5e-65aa-48c6-92b1-1b2581e93015" }]
|
21
|
+
},
|
22
|
+
"quantity": "1",
|
23
|
+
"installments": "1",
|
24
|
+
"currentPeriodStart": 1551243600000,
|
25
|
+
"currentPeriodEnd": 1553662799000,
|
26
|
+
"immediatePayment": true,
|
27
|
+
"deliveryAddress": {},
|
28
|
+
"notifyUrl": "https://example.com"
|
29
|
+
}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Helpers
|
2
|
+
def stub_subscription_request
|
3
|
+
stub_request(:post, /#{PayU::Subscription::ENDPOINT}/)
|
4
|
+
.to_return do |request|
|
5
|
+
{body: File.new("./spec/fixtures/responses/subscription.json").read
|
6
|
+
.gsub("{{code}}", JSON.parse(request.body)["plan"]["planCode"])}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def stub_plan_request
|
12
|
+
stub_request(:any, /#{PayU::Plan::ENDPOINT}/)
|
13
|
+
.to_return do |request|
|
14
|
+
code = if request.method == :post
|
15
|
+
JSON.parse(request.body)["planCode"]
|
16
|
+
else
|
17
|
+
request.uri.path.split("/").last
|
18
|
+
end
|
19
|
+
|
20
|
+
{body: File.new("./spec/fixtures/responses/plan.json").read.gsub("{{code}}", code)}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def stub_customer_request
|
26
|
+
stub_request(:post, /#{PayU::Customer::ENDPOINT}$/)
|
27
|
+
.to_return(body: File.new("./spec/fixtures/responses/customer.json"))
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def stub_credit_card_request
|
32
|
+
stub_request(:post, %r{#{PayU::Customer::ENDPOINT}/.+/creditCards})
|
33
|
+
.to_return(body: {token: SecureRandom.uuid}.to_json)
|
34
|
+
end
|
35
|
+
end
|
@@ -3,6 +3,10 @@ require "spec_helper"
|
|
3
3
|
RSpec.describe PayU::Configuration do
|
4
4
|
let(:default_api_key) { "4Vj8eK4rloUd272L48hsrarnUA" }
|
5
5
|
|
6
|
+
after do
|
7
|
+
PayU.reset
|
8
|
+
end
|
9
|
+
|
6
10
|
it "assigns defaults" do
|
7
11
|
expect(PayU.configuration.api_key).to eq(default_api_key)
|
8
12
|
expect(PayU.configuration.test).to be_truthy
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe PayU::CreditCard do
|
4
|
+
before do
|
5
|
+
stub_customer_request
|
6
|
+
|
7
|
+
stub_credit_card_request
|
8
|
+
end
|
9
|
+
|
10
|
+
it "creates credit card token" do
|
11
|
+
customer = PayU::Customer.create(
|
12
|
+
name: "Sample User Name",
|
13
|
+
email: "sample@sample.com",
|
14
|
+
)
|
15
|
+
credit_card = PayU::CreditCard.create(Fixtures.credit_card.merge(customer_id: customer.id))
|
16
|
+
|
17
|
+
expect(credit_card.token).to(
|
18
|
+
match(/\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/),
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
data/spec/pay_u/form_spec.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe PayU::Plan do
|
4
|
+
before do
|
5
|
+
stub_request(:any, /#{PayU::Plan::ENDPOINT}/)
|
6
|
+
.to_return do |request|
|
7
|
+
code = if request.method == :post
|
8
|
+
JSON.parse(request.body)["planCode"]
|
9
|
+
else
|
10
|
+
request.uri.path.split("/").last
|
11
|
+
end
|
12
|
+
|
13
|
+
{body: File.new("./spec/fixtures/responses/plan.json").read.gsub("{{code}}", code)}
|
14
|
+
end
|
15
|
+
|
16
|
+
stub_request(:get, %r{#{PayU::Plan::ENDPOINT}/non-existent}).to_return(
|
17
|
+
status: 404,
|
18
|
+
body: File.new("./spec/fixtures/responses/plan_not_found.json"),
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "creates plan" do
|
23
|
+
plan = PayU::Plan.create(Fixtures.plan)
|
24
|
+
|
25
|
+
expect(plan.id).to match(/\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "retrieves plan" do
|
29
|
+
code = "pro-#{SecureRandom.hex(4)}"
|
30
|
+
plan = PayU::Plan.create(Fixtures.plan.merge(code: code))
|
31
|
+
|
32
|
+
found_plan = PayU::Plan.retrieve(plan.code)
|
33
|
+
|
34
|
+
expect(found_plan.id).to match(plan.id)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "updates plan" do
|
38
|
+
WebMock.disable!
|
39
|
+
plan = PayU::Plan.create(Fixtures.plan)
|
40
|
+
id = plan.id
|
41
|
+
description = "Description"
|
42
|
+
|
43
|
+
plan.description = description
|
44
|
+
plan.save
|
45
|
+
|
46
|
+
expect(plan.id).to eq(id)
|
47
|
+
expect(plan.description).to eq(description)
|
48
|
+
|
49
|
+
WebMock.enable!
|
50
|
+
end
|
51
|
+
|
52
|
+
it "deletes plan" do
|
53
|
+
WebMock.disable!
|
54
|
+
plan = PayU::Plan.create(Fixtures.plan)
|
55
|
+
|
56
|
+
plan.delete
|
57
|
+
|
58
|
+
expect do
|
59
|
+
PayU::Plan.retrieve(plan.code)
|
60
|
+
end.to raise_exception(PayU::NotFoundError, /Subscription plan not found/)
|
61
|
+
|
62
|
+
WebMock.enable!
|
63
|
+
end
|
64
|
+
end
|
data/spec/pay_u/response_spec.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe PayU::CreditCard do
|
4
|
+
before do
|
5
|
+
stub_subscription_request
|
6
|
+
|
7
|
+
stub_plan_request
|
8
|
+
end
|
9
|
+
|
10
|
+
context "new plan" do
|
11
|
+
it "creates subscripition" do
|
12
|
+
plan_params = Fixtures.plan
|
13
|
+
subscription = PayU::Subscription.create(
|
14
|
+
subscription_params.merge(plan: plan_params),
|
15
|
+
)
|
16
|
+
|
17
|
+
expect(subscription.id).not_to be_nil
|
18
|
+
expect(subscription.customer.name).to eq(customer_params[:name])
|
19
|
+
expect(subscription.customer.email).to eq(customer_params[:email])
|
20
|
+
expect(subscription.plan.code).to eq(plan_params[:code])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context "existing plan" do
|
25
|
+
it "creates subscripition" do
|
26
|
+
plan = PayU::Plan.create(Fixtures.plan)
|
27
|
+
subscription = PayU::Subscription.create(subscription_params.merge(plan: {code: plan.code}))
|
28
|
+
|
29
|
+
expect(subscription.id).not_to be_nil
|
30
|
+
expect(subscription.customer.name).to eq(customer_params[:name])
|
31
|
+
expect(subscription.customer.email).to eq(customer_params[:email])
|
32
|
+
expect(subscription.plan.code).to eq(plan.code)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private def subscription_params
|
37
|
+
{
|
38
|
+
quantity: 1,
|
39
|
+
installments: 1,
|
40
|
+
trial_days: 0,
|
41
|
+
immediate_payment: true,
|
42
|
+
notify_url: "https://example.com",
|
43
|
+
customer: customer_params,
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
private def customer_params
|
48
|
+
{
|
49
|
+
name: "Sample User Name",
|
50
|
+
email: "sample@sample.com",
|
51
|
+
credit_cards: credit_cards_params,
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
private def credit_cards_params
|
56
|
+
[Fixtures.credit_card]
|
57
|
+
end
|
58
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "simplecov"
|
2
2
|
require "coveralls"
|
3
|
+
require "webmock/rspec"
|
3
4
|
|
4
5
|
SimpleCov.formatters = [
|
5
6
|
SimpleCov::Formatter::HTMLFormatter,
|
@@ -13,6 +14,9 @@ require "pry"
|
|
13
14
|
require "bundler/setup"
|
14
15
|
require "pay_u"
|
15
16
|
|
17
|
+
Dir["./spec/fixtures/*.rb"].each { |fixture| require fixture }
|
18
|
+
Dir["./spec/helpers/*.rb"].each { |fixture| require fixture }
|
19
|
+
|
16
20
|
if ENV["CIRCLE_ARTIFACTS"]
|
17
21
|
dir = File.join(ENV["CIRCLE_ARTIFACTS"], "coverage")
|
18
22
|
SimpleCov.coverage_dir(dir)
|
@@ -28,4 +32,6 @@ RSpec.configure do |config|
|
|
28
32
|
config.expect_with :rspec do |c|
|
29
33
|
c.syntax = :expect
|
30
34
|
end
|
35
|
+
|
36
|
+
config.include Helpers
|
31
37
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: payu-latam
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Slang
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: faraday
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0.15'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0.15'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: virtus
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -181,24 +195,42 @@ files:
|
|
181
195
|
- bin/console
|
182
196
|
- bin/setup
|
183
197
|
- lib/pay_u.rb
|
198
|
+
- lib/pay_u/client.rb
|
184
199
|
- lib/pay_u/configuration.rb
|
185
200
|
- lib/pay_u/confirmation.rb
|
186
201
|
- lib/pay_u/constants.rb
|
202
|
+
- lib/pay_u/credit_card.rb
|
203
|
+
- lib/pay_u/customer.rb
|
204
|
+
- lib/pay_u/errors.rb
|
187
205
|
- lib/pay_u/form.rb
|
188
206
|
- lib/pay_u/order.rb
|
207
|
+
- lib/pay_u/plan.rb
|
208
|
+
- lib/pay_u/resource.rb
|
189
209
|
- lib/pay_u/response.rb
|
190
210
|
- lib/pay_u/signer/base.rb
|
191
211
|
- lib/pay_u/signer/confirmation.rb
|
192
212
|
- lib/pay_u/signer/form.rb
|
193
213
|
- lib/pay_u/signer/response.rb
|
214
|
+
- lib/pay_u/subscription.rb
|
215
|
+
- lib/pay_u/util/string.rb
|
194
216
|
- lib/pay_u/version.rb
|
195
217
|
- payu-latam.gemspec
|
196
218
|
- spec/fixtures/confirmation.rb
|
219
|
+
- spec/fixtures/credit_card.rb
|
220
|
+
- spec/fixtures/plan.rb
|
197
221
|
- spec/fixtures/response.rb
|
222
|
+
- spec/fixtures/responses/customer.json
|
223
|
+
- spec/fixtures/responses/plan.json
|
224
|
+
- spec/fixtures/responses/plan_not_found.json
|
225
|
+
- spec/fixtures/responses/subscription.json
|
226
|
+
- spec/helpers/stub.rb
|
198
227
|
- spec/pay_u/configuration_spec.rb
|
199
228
|
- spec/pay_u/confirmation_spec.rb
|
229
|
+
- spec/pay_u/credit_card_spec.rb
|
200
230
|
- spec/pay_u/form_spec.rb
|
231
|
+
- spec/pay_u/plan_spec.rb
|
201
232
|
- spec/pay_u/response_spec.rb
|
233
|
+
- spec/pay_u/subscription_spec.rb
|
202
234
|
- spec/pay_u_spec.rb
|
203
235
|
- spec/spec_helper.rb
|
204
236
|
homepage: https://slangapp.com
|
@@ -227,10 +259,20 @@ specification_version: 4
|
|
227
259
|
summary: Ruby bindings for the PayU Latam API
|
228
260
|
test_files:
|
229
261
|
- spec/fixtures/confirmation.rb
|
262
|
+
- spec/fixtures/credit_card.rb
|
263
|
+
- spec/fixtures/plan.rb
|
230
264
|
- spec/fixtures/response.rb
|
265
|
+
- spec/fixtures/responses/customer.json
|
266
|
+
- spec/fixtures/responses/plan.json
|
267
|
+
- spec/fixtures/responses/plan_not_found.json
|
268
|
+
- spec/fixtures/responses/subscription.json
|
269
|
+
- spec/helpers/stub.rb
|
231
270
|
- spec/pay_u/configuration_spec.rb
|
232
271
|
- spec/pay_u/confirmation_spec.rb
|
272
|
+
- spec/pay_u/credit_card_spec.rb
|
233
273
|
- spec/pay_u/form_spec.rb
|
274
|
+
- spec/pay_u/plan_spec.rb
|
234
275
|
- spec/pay_u/response_spec.rb
|
276
|
+
- spec/pay_u/subscription_spec.rb
|
235
277
|
- spec/pay_u_spec.rb
|
236
278
|
- spec/spec_helper.rb
|