liqpay 0.1.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +4 -0
- data/README.md +78 -54
- data/lib/liqpay.rb +2 -3
- data/lib/liqpay/base_operation.rb +10 -6
- data/lib/liqpay/liqpay_helper.rb +5 -2
- data/lib/liqpay/request.rb +31 -52
- data/lib/liqpay/response.rb +12 -21
- data/lib/liqpay/version.rb +1 -1
- data/liqpay.gemspec +0 -1
- metadata +13 -29
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb8c24034981cbb7c7ce37aac9f8bb24746b8e2f
|
4
|
+
data.tar.gz: 4a65b5598669d54294f98bd40dadd0acfda7d6ec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 44978d20a3d2e76a3e8af6c143a9f2b7cf12ef7a615cbb131fead7a56ad2f84747c9714d496161e32c6659f909b22cffaafcb9046b70758c173a95d22dd12f27
|
7
|
+
data.tar.gz: 1830483461086edb9144f5ecbaca1205e1746bd35879bb00ff7d19c8f97784a61eba06e7d0d9e8080964f128c89267e3d0927acc3c70575aad928ffc27fb4f81
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,47 +1,62 @@
|
|
1
1
|
# LiqPAY
|
2
2
|
|
3
|
-
This Ruby gem implements the [LiqPAY](
|
3
|
+
This Ruby gem implements the [LiqPAY](https://www.liqpay.com) billing system API, as described in [the LiqPAY documentation](https://www.liqpay.com/doc).
|
4
4
|
|
5
|
-
|
5
|
+
**Users of version 0.1.2 and earlier:** your version of the gem uses the older, deprecated LiqPAY API; you should migrate to v1.0.0, but it requires you to change configuration and set up a server callback endpoint, so it's not a trivial upgrade.
|
6
|
+
|
7
|
+
## Demo
|
8
|
+
|
9
|
+
There is a demo app at http://liqpay-demo.herokuapp.com, source at https://github.com/leonid-shevtsov/liqpay_demo
|
6
10
|
|
7
11
|
## Installation
|
8
12
|
|
9
|
-
Include the [liqpay gem](https://rubygems.org/gems/liqpay) in your
|
13
|
+
Include the [liqpay gem](https://rubygems.org/gems/liqpay) in your `Gemfile`:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'liqpay', '~>1.0.0'
|
17
|
+
```
|
18
|
+
|
19
|
+
The gem requries at least Ruby 1.9.
|
10
20
|
|
11
21
|
## Configuration
|
12
22
|
|
13
|
-
|
23
|
+
You can provide all of the payment options in the request object, but the recommended way is setting the `Liqpay.default_options` hash somewhere in
|
14
24
|
your initializers.
|
15
25
|
|
16
|
-
You
|
17
|
-
provided by LiqPAY when you sign up
|
26
|
+
You should supply the `public_key` and `private_key` options, that are
|
27
|
+
provided by LiqPAY when you sign up and create a shop on the [shops page](https://www.liqpay.com/admin/business):
|
18
28
|
|
19
|
-
|
29
|
+
```ruby
|
30
|
+
# config/initializers/liqpay.rb
|
31
|
+
Liqpay.default_options = {
|
32
|
+
public_key: ENV['LIQPAY_PUBLIC_KEY'],
|
33
|
+
private_key: ENV['LIQPAY_PRIVATE_KEY'],
|
34
|
+
currency: 'UAH'
|
35
|
+
}
|
36
|
+
```
|
37
|
+
|
38
|
+
|
39
|
+
## Processing payments through LiqPay
|
20
40
|
|
21
41
|
### General flow
|
22
42
|
|
23
|
-
1. User initiates the payment process; you redirect him to LiqPAY via POST, providing necessary parameters
|
43
|
+
1. User initiates the payment process; you redirect him to LiqPAY via a POST form, providing necessary parameters such as the payment's amount, order id and description.
|
24
44
|
|
25
45
|
2. Users completes payment through LiqPAY.
|
26
46
|
|
27
|
-
3. LiqPAY redirects the user to the URL you specified.
|
47
|
+
3. LiqPAY redirects the user to the URL you specified with GET.
|
28
48
|
|
29
|
-
4. You
|
49
|
+
4. You wait for a callback that LiqPAY will POST to your designated `server_url`.
|
30
50
|
|
31
51
|
5. If the payment was successful: You process the payment on your side.
|
32
52
|
|
33
53
|
6. If the payment was cancelled: You cancel the operation.
|
34
54
|
|
35
|
-
|
36
|
-
browser-driven flow.
|
55
|
+
The most recent version of the LiqPAY API *requires* you to have a serverside endpoint, which makes it impossible to test it with a local address.
|
37
56
|
|
38
57
|
### Implementation in Rails
|
39
58
|
|
40
|
-
0. Configure Liqpay
|
41
|
-
|
42
|
-
# config/initializers/liqpay.rb
|
43
|
-
Liqpay.default_options[:merchant_id] = 'MY_MERCHANT_ID'
|
44
|
-
Liqpay.default_options[:merchant_signature] = 'MY_MERCHANT_SIGNATURE'
|
59
|
+
0. Configure Liqpay
|
45
60
|
|
46
61
|
1. Create a `Liqpay::Request` object
|
47
62
|
|
@@ -53,61 +68,70 @@ browser-driven flow.
|
|
53
68
|
model (I suggest that you should), pass its ID. If not, it can be a random
|
54
69
|
string stored in the session, or whatever, but *it must be unique*.
|
55
70
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
71
|
+
```ruby
|
72
|
+
@liqpay_request = Liqpay::Request.new(
|
73
|
+
amount: '999.99',
|
74
|
+
currency: 'UAH',
|
75
|
+
order_id: '123',
|
76
|
+
description: 'Some Product',
|
77
|
+
result_url: order_url(@order),
|
78
|
+
server_url: liqpay_payment_url
|
79
|
+
)
|
80
|
+
```
|
63
81
|
|
64
82
|
**Note that this does not do anything permanent.** No saves to the database, no
|
65
83
|
requests to LiqPAY.
|
66
84
|
|
67
|
-
|
68
|
-
|
69
85
|
2. Put a payment button somewhere
|
70
86
|
|
71
87
|
As you need to make a POST request, there is definitely going to be a form somewhere.
|
72
88
|
|
73
89
|
To output a form consisting of a single "Pay with LiqPAY" button, do
|
74
90
|
|
75
|
-
|
91
|
+
```erb
|
92
|
+
<%=liqpay_button @liqpay_request %>
|
93
|
+
```
|
76
94
|
|
77
95
|
Or:
|
78
96
|
|
79
|
-
|
97
|
+
```erb
|
98
|
+
<%=liqpay_button @liqpay_request, title: "Pay now!" %>
|
99
|
+
```
|
80
100
|
|
81
101
|
Or:
|
82
102
|
|
83
|
-
|
84
|
-
|
85
|
-
|
103
|
+
```erb
|
104
|
+
<%=liqpay_button @liqpay_request do %>
|
105
|
+
<%=link_to 'Pay now!', '#', onclick: 'document.forms[0].submit();' %>
|
106
|
+
<% end %>
|
107
|
+
```
|
86
108
|
|
87
109
|
3. Set up a receiving endpoint.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
rescue Liqpay::InvalidResponse
|
108
|
-
# handle error
|
109
|
-
end
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
# config/routes.rb
|
113
|
+
post '/liqpay_payment' => 'payments#liqpay_payment'
|
114
|
+
|
115
|
+
# app/controllers/payments_controller.rb
|
116
|
+
class PaymentsController < ApplicationController
|
117
|
+
# Skipping forgery protection here is important
|
118
|
+
protect_from_forgery :except => :liqpay_payment
|
119
|
+
|
120
|
+
def liqpay_payment
|
121
|
+
@liqpay_response = Liqpay::Response.new(params)
|
122
|
+
|
123
|
+
if @liqpay_response.success?
|
124
|
+
# check that order_id is valid
|
125
|
+
# check that amount matches
|
126
|
+
# handle success
|
127
|
+
else
|
128
|
+
# handle error
|
110
129
|
end
|
130
|
+
rescue Liqpay::InvalidResponse
|
131
|
+
# handle error
|
132
|
+
end
|
133
|
+
end
|
134
|
+
```
|
111
135
|
|
112
136
|
That's about it.
|
113
137
|
|
@@ -119,4 +143,4 @@ That's about it.
|
|
119
143
|
|
120
144
|
- - -
|
121
145
|
|
122
|
-
2012 Leonid Shevtsov
|
146
|
+
Ruby implementation (c) 2012-2014 Leonid Shevtsov
|
data/lib/liqpay.rb
CHANGED
@@ -5,9 +5,8 @@ require 'liqpay/response'
|
|
5
5
|
require 'liqpay/railtie' if defined?(Rails)
|
6
6
|
|
7
7
|
module Liqpay
|
8
|
-
|
9
|
-
|
10
|
-
SUPPORTED_CURRENCIES = %w(UAH USD EUR RUR)
|
8
|
+
LIQPAY_ENDPOINT_URL = 'https://www.liqpay.com/api/pay'
|
9
|
+
SUPPORTED_CURRENCIES = %w(UAH USD EUR RUB)
|
11
10
|
|
12
11
|
@default_options = {}
|
13
12
|
class << self; attr_accessor :default_options; end
|
@@ -3,22 +3,26 @@ require 'base64'
|
|
3
3
|
|
4
4
|
module Liqpay
|
5
5
|
class BaseOperation
|
6
|
-
attr_accessor :
|
6
|
+
attr_accessor :public_key, :private_key
|
7
7
|
|
8
8
|
def initialize(options={})
|
9
9
|
options.replace(Liqpay.default_options.merge(options))
|
10
10
|
|
11
|
-
@
|
12
|
-
@
|
11
|
+
@public_key = options[:public_key]
|
12
|
+
@private_key = options[:private_key]
|
13
13
|
end
|
14
14
|
|
15
15
|
def signature
|
16
|
-
@signature ||= sign(
|
16
|
+
@signature ||= sign(signature_fields)
|
17
|
+
end
|
18
|
+
|
19
|
+
def signature_fields
|
20
|
+
raise NotImplementedError
|
17
21
|
end
|
18
22
|
|
19
23
|
private
|
20
|
-
def sign(
|
21
|
-
Base64.encode64(Digest::SHA1.digest(
|
24
|
+
def sign(fields)
|
25
|
+
Base64.encode64(Digest::SHA1.digest(@private_key + fields.join(''))).strip
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
data/lib/liqpay/liqpay_helper.rb
CHANGED
@@ -12,8 +12,11 @@ module Liqpay
|
|
12
12
|
def liqpay_button(liqpay_request, options={}, &block)
|
13
13
|
id = options.fetch(:id, 'liqpay_form')
|
14
14
|
title = options.fetch(:title, 'Pay with LiqPAY')
|
15
|
-
content_tag(:form, :id => id, :action => Liqpay::
|
16
|
-
result =
|
15
|
+
content_tag(:form, :id => id, :action => Liqpay::LIQPAY_ENDPOINT_URL, :method => :post) do
|
16
|
+
result = liqpay_request.form_fields.map{|name, value|
|
17
|
+
hidden_field_tag(name, value)
|
18
|
+
}.join("\n").html_safe
|
19
|
+
|
17
20
|
if block_given?
|
18
21
|
result += yield
|
19
22
|
else
|
data/lib/liqpay/request.rb
CHANGED
@@ -7,77 +7,56 @@ module Liqpay
|
|
7
7
|
attr_accessor :amount
|
8
8
|
# REQUIRED Currency of payment - one of `Liqpay::SUPPORTED_CURRENCIES`
|
9
9
|
attr_accessor :currency
|
10
|
-
# REQUIRED
|
10
|
+
# REQUIRED Description to be displayed to the user
|
11
|
+
attr_accessor :description
|
12
|
+
# RECOMMENDED Arbitrary but unique ID (May be REQUIRED by LiqPay configuration)
|
11
13
|
attr_accessor :order_id
|
12
14
|
# RECOMMENDED URL that the user will be redirected to after payment
|
13
15
|
attr_accessor :result_url
|
14
16
|
# RECOMMENDED URL that'll receive the order details in the background.
|
15
17
|
attr_accessor :server_url
|
16
|
-
#
|
17
|
-
attr_accessor :
|
18
|
-
#
|
19
|
-
|
20
|
-
# LiqPAY requires users to provide a phone number before payment.
|
21
|
-
# If you know the user's phone number, you can provide it so he
|
22
|
-
# doesn't have to enter it manually.
|
23
|
-
attr_accessor :default_phone
|
24
|
-
# Method of payment. One or more (comma-separated) of:
|
25
|
-
# card - by card
|
26
|
-
# liqpay - by liqpay account
|
27
|
-
attr_accessor :pay_way
|
28
|
-
|
29
|
-
attr_accessor :exp_time
|
30
|
-
attr_accessor :goods_id
|
18
|
+
# OPTIONAL type of payment = either `buy` (the default) or `donate`
|
19
|
+
attr_accessor :type
|
20
|
+
# OPTIONAL UI language - `ru` or `en`
|
21
|
+
attr_accessor :language
|
31
22
|
|
32
23
|
def initialize(options={})
|
33
24
|
super(options)
|
34
|
-
|
35
|
-
@result_url = options[:result_url]
|
36
|
-
@server_url = options[:server_url]
|
37
|
-
@order_id = options[:order_id]
|
25
|
+
|
38
26
|
@amount = options[:amount]
|
39
27
|
@currency = options[:currency]
|
40
28
|
@description = options[:description]
|
41
|
-
@
|
42
|
-
@
|
29
|
+
@order_id = options[:order_id]
|
30
|
+
@result_url = options[:result_url]
|
31
|
+
@server_url = options[:server_url]
|
32
|
+
@type = options[:type]
|
33
|
+
@language = options[:language]
|
43
34
|
@kamikaze = options[:kamikaze]
|
44
35
|
end
|
45
36
|
|
46
|
-
def
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
def xml
|
51
|
-
@xml ||= make_xml
|
37
|
+
def signature_fields
|
38
|
+
[amount, currency, public_key, order_id, type, description, result_url, server_url]
|
52
39
|
end
|
53
40
|
|
54
|
-
|
55
|
-
private
|
56
|
-
def encode(xml)
|
57
|
-
Base64.encode64(xml).gsub(/\s/,'')
|
58
|
-
end
|
59
|
-
|
60
|
-
def make_xml
|
41
|
+
def form_fields
|
61
42
|
validate! unless @kamikaze
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
}
|
75
|
-
}.to_xml
|
43
|
+
{
|
44
|
+
public_key: public_key,
|
45
|
+
amount: amount,
|
46
|
+
currency: currency,
|
47
|
+
description: description,
|
48
|
+
order_id: order_id,
|
49
|
+
result_url: result_url,
|
50
|
+
server_url: server_url,
|
51
|
+
type: type,
|
52
|
+
signature: signature,
|
53
|
+
language: language
|
54
|
+
}.reject{|k,v| v.nil?}
|
76
55
|
end
|
77
56
|
|
57
|
+
private
|
78
58
|
def validate!
|
79
|
-
|
80
|
-
%w(merchant_id merchant_signature currency amount order_id).each do |required_field|
|
59
|
+
%w(public_key amount currency description).each do |required_field|
|
81
60
|
raise Liqpay::Exception.new(required_field + ' is a required field') unless self.send(required_field).to_s != ''
|
82
61
|
end
|
83
62
|
|
@@ -89,7 +68,7 @@ module Liqpay
|
|
89
68
|
raise Liqpay::Exception.new('amount must be a number')
|
90
69
|
end
|
91
70
|
|
92
|
-
raise Liqpay::Exception.new('
|
71
|
+
raise Liqpay::Exception.new('amount must be rounded to 2 decimal digits') unless self.amount.round(2) == self.amount
|
93
72
|
|
94
73
|
raise Liqpay::Exception.new('amount must be more than 0.01') unless amount > 0.01
|
95
74
|
end
|
data/lib/liqpay/response.rb
CHANGED
@@ -1,15 +1,12 @@
|
|
1
1
|
require 'base64'
|
2
|
-
require 'nokogiri'
|
3
2
|
require 'liqpay/base_operation'
|
4
3
|
|
5
4
|
module Liqpay
|
6
5
|
class Response < BaseOperation
|
7
6
|
SUCCESS_STATUSES = %w(success wait_secure)
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
ATTRIBUTES = %w(merchant_id order_id amount currency description status code transaction_id pay_way sender_phone goods_id pays_count)
|
12
|
-
%w(merchant_id order_id description goods_id pays_count).each do |attr|
|
8
|
+
ATTRIBUTES = %w(public_key order_id amount currency description type status transaction_id sender_phone)
|
9
|
+
%w(public_key order_id description type).each do |attr|
|
13
10
|
attr_reader attr
|
14
11
|
end
|
15
12
|
|
@@ -22,20 +19,18 @@ module Liqpay
|
|
22
19
|
# success
|
23
20
|
# wait_secure - success, but the card wasn't known to the system
|
24
21
|
attr_reader :status
|
25
|
-
# Error code
|
26
|
-
attr_reader :code
|
27
22
|
# LiqPAY's internal transaction ID
|
28
23
|
attr_reader :transaction_id
|
29
|
-
# Chosen method of payment
|
30
|
-
attr_reader :pay_way
|
31
24
|
# Payer's phone
|
32
25
|
attr_reader :sender_phone
|
33
26
|
|
34
|
-
def initialize(options = {})
|
27
|
+
def initialize(params = {}, options = {})
|
35
28
|
super(options)
|
36
29
|
|
37
|
-
|
38
|
-
|
30
|
+
ATTRIBUTES.each do |attribute|
|
31
|
+
instance_variable_set "@#{attribute}", params[attribute]
|
32
|
+
end
|
33
|
+
@request_signature = params["signature"]
|
39
34
|
|
40
35
|
decode!
|
41
36
|
end
|
@@ -45,19 +40,15 @@ module Liqpay
|
|
45
40
|
SUCCESS_STATUSES.include? self.status
|
46
41
|
end
|
47
42
|
|
43
|
+
def signature_fields
|
44
|
+
[amount, currency, public_key, order_id, type, description, status, transaction_id, sender_phone]
|
45
|
+
end
|
46
|
+
|
48
47
|
private
|
49
48
|
def decode!
|
50
|
-
|
51
|
-
|
52
|
-
if sign(@xml, @merchant_signature) != @signature
|
49
|
+
if signature != @request_signature
|
53
50
|
raise Liqpay::InvalidResponse
|
54
51
|
end
|
55
|
-
|
56
|
-
doc = Nokogiri.XML(@xml)
|
57
|
-
|
58
|
-
ATTRIBUTES.each do |attr|
|
59
|
-
self.instance_variable_set('@'+attr, doc.at(attr).try(:content))
|
60
|
-
end
|
61
52
|
end
|
62
53
|
end
|
63
54
|
end
|
data/lib/liqpay/version.rb
CHANGED
data/liqpay.gemspec
CHANGED
@@ -11,7 +11,6 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.summary = %q{LiqPAY billing API implementation in Ruby}
|
12
12
|
s.description = %q{LiqPAY billing API implementation in Ruby}
|
13
13
|
|
14
|
-
s.add_dependency 'nokogiri'
|
15
14
|
s.add_development_dependency 'rake'
|
16
15
|
|
17
16
|
s.files = `git ls-files`.split("\n")
|
metadata
CHANGED
@@ -1,38 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: liqpay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Leonid Shevtsov
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2014-03-14 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
16
|
-
requirement:
|
17
|
-
none: false
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
|
-
type: :
|
20
|
+
type: :development
|
23
21
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: rake
|
27
|
-
requirement: &70239324844620 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
29
23
|
requirements:
|
30
|
-
- -
|
24
|
+
- - '>='
|
31
25
|
- !ruby/object:Gem::Version
|
32
26
|
version: '0'
|
33
|
-
type: :development
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *70239324844620
|
36
27
|
description: LiqPAY billing API implementation in Ruby
|
37
28
|
email:
|
38
29
|
- leonid@shevtsov.me
|
@@ -55,32 +46,25 @@ files:
|
|
55
46
|
- liqpay.gemspec
|
56
47
|
homepage: https://github.com/leonid-shevtsov/liqpay
|
57
48
|
licenses: []
|
49
|
+
metadata: {}
|
58
50
|
post_install_message:
|
59
51
|
rdoc_options: []
|
60
52
|
require_paths:
|
61
53
|
- lib
|
62
54
|
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
-
none: false
|
64
55
|
requirements:
|
65
|
-
- -
|
56
|
+
- - '>='
|
66
57
|
- !ruby/object:Gem::Version
|
67
58
|
version: '0'
|
68
|
-
segments:
|
69
|
-
- 0
|
70
|
-
hash: 3679480104141870157
|
71
59
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
-
none: false
|
73
60
|
requirements:
|
74
|
-
- -
|
61
|
+
- - '>='
|
75
62
|
- !ruby/object:Gem::Version
|
76
63
|
version: '0'
|
77
|
-
segments:
|
78
|
-
- 0
|
79
|
-
hash: 3679480104141870157
|
80
64
|
requirements: []
|
81
65
|
rubyforge_project:
|
82
|
-
rubygems_version: 1.
|
66
|
+
rubygems_version: 2.1.11
|
83
67
|
signing_key:
|
84
|
-
specification_version:
|
68
|
+
specification_version: 4
|
85
69
|
summary: LiqPAY billing API implementation in Ruby
|
86
70
|
test_files: []
|