liqpay 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,5 @@
1
1
  *.gem
2
2
  .bundle
3
+ .rvmrc
3
4
  Gemfile.lock
4
5
  pkg/*
data/README.md CHANGED
@@ -1,3 +1,122 @@
1
1
  # LiqPAY
2
2
 
3
- This Ruby gem implements the [LiqPAY](http://liqpay.com) billing system API.
3
+ This Ruby gem implements the [LiqPAY](http://liqpay.com) billing system.
4
+
5
+ As of now it only covers the [Liq&Buy 1.2 API](https://liqpay.com/?do=pages&p=cnb12), which is used to accept credit card payments on your site.
6
+
7
+ ## Installation
8
+
9
+ Include the [liqpay gem](https://rubygems.org/gems/liqpay) in your app.
10
+
11
+ ## Configuration
12
+
13
+ The recommended way is setting the `Liqpay.default_options` hash somewhere in
14
+ your initializers.
15
+
16
+ You MUST supply the `merchant_id` and `merchant_signature` options, that are
17
+ provided by LiqPAY when you sign up.
18
+
19
+ ## Processing payments through Liq&Buy
20
+
21
+ ### General flow
22
+
23
+ 1. User initiates the payment process; you redirect him to LiqPAY via POST, providing necessary parameters to set up the payment's amount and description
24
+
25
+ 2. Users completes payment through LiqPAY.
26
+
27
+ 3. LiqPAY redirects the user to the URL you specified.
28
+
29
+ 4. You validate the response against your secret signature.
30
+
31
+ 5. If the payment was successful: You process the payment on your side.
32
+
33
+ 6. If the payment was cancelled: You cancel the operation.
34
+
35
+ So, LiqPAY is pretty simple, it does no server-to-server validation, just a
36
+ browser-driven flow.
37
+
38
+ ### Implementation in Rails
39
+
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'
45
+
46
+ 1. Create a `Liqpay::Request` object
47
+
48
+ The required options are: the amount and currency of the payment, and an
49
+ "order ID".
50
+
51
+ The "order ID" is just a random string that you will use to
52
+ identify the payment after it has been completed. If you have an `Order`
53
+ model (I suggest that you should), pass its ID. If not, it can be a random
54
+ string stored in the session, or whatever, but *it must be unique*.
55
+
56
+ @liqpay_request = Liqpay::Request.new(
57
+ :amount => '999.99',
58
+ :currency => 'UAH',
59
+ :order_id => '123',
60
+ :description => 'Some Product',
61
+ :result_url => liqpay_payment_url
62
+ )
63
+
64
+ **Note that this does not do anything permanent.** No saves to the database, no
65
+ requests to LiqPAY.
66
+
67
+
68
+
69
+ 2. Put a payment button somewhere
70
+
71
+ As you need to make a POST request, there is definitely going to be a form somewhere.
72
+
73
+ To output a form consisting of a single "Pay with LiqPAY" button, do
74
+
75
+ <%=liqpay_button @liqpay_request %>
76
+
77
+ Or:
78
+
79
+ <%=liqpay_button @liqpay_request, :title => "Pay now!" %>
80
+
81
+ Or:
82
+
83
+ <%=liqpay_button @liqpay_request do %>
84
+ <%=link_to 'Pay now!', '#', :onclick => 'document.forms[0].submit();' %>
85
+ <% end %>
86
+
87
+ 3. Set up a receiving endpoint.
88
+
89
+ # config/routes.rb
90
+ post '/liqpay_payment' => 'payments#liqpay_payment'
91
+
92
+ # app/controllers/payments_controller.rb
93
+ class PaymentsController < ApplicationController
94
+ # Skipping forgery protection here is important
95
+ protect_from_forgery :except => :liqpay_payment
96
+
97
+ def liqpay_payment
98
+ @liqpay_response = Liqpay::Response.new(params)
99
+
100
+ if @liqpay_response.success?
101
+ # check that order_id is valid
102
+ # check that amount matches
103
+ # handle success
104
+ else
105
+ # handle error
106
+ end
107
+ rescue Liqpay::InvalidResponse
108
+ # handle error
109
+ end
110
+ end
111
+
112
+ That's about it.
113
+
114
+ ### Security considerations
115
+
116
+ * Check that amount from response matches the expected amount;
117
+ * check that the order id is valid;
118
+ * check that the order isn't completed yet (to avoid replay attacks);
119
+
120
+ - - -
121
+
122
+ 2012 Leonid Shevtsov
@@ -2,9 +2,11 @@ require 'liqpay/version'
2
2
  require 'liqpay/request'
3
3
  require 'liqpay/response'
4
4
 
5
+ require 'liqpay/railtie' if defined?(Rails)
6
+
5
7
  module Liqpay
6
- API_VERSION = '1.2'
7
- ENDPOINT_URL = 'https://www.liqpay.com/?do=clickNbuy'
8
+ LIQBUY_API_VERSION = '1.2'
9
+ LIQBUY_ENDPOINT_URL = 'https://www.liqpay.com/?do=clickNbuy'
8
10
  SUPPORTED_CURRENCIES = %w(UAH USD EUR RUR)
9
11
 
10
12
  @default_options = {}
@@ -0,0 +1,26 @@
1
+ module Liqpay
2
+ module LiqpayHelper
3
+ # Displays a form to send a payment request to LiqPay
4
+ #
5
+ # You can either pass in a block, that SHOULD render a submit button (or not, if you plan to submit the form otherwise), or
6
+ # let the helper create a simple submit button for you.
7
+ #
8
+ # liqpay_request - an instance of Liqpay::Request
9
+ # options - currently accepts two options
10
+ # id - the ID of the form being created (`liqpay_form` by default)
11
+ # title - text on the submit button (`Pay with LiqPay` by default); not used if you pass in a block
12
+ def liqpay_button(liqpay_request, options={}, &block)
13
+ id = options.fetch(:id, 'liqpay_form')
14
+ title = options.fetch(:title, 'Pay with LiqPAY')
15
+ content_tag(:form, :id => id, :action => Liqpay::LIQBUY_ENDPOINT_URL, :method => :post) do
16
+ result = hidden_field_tag(:operation_xml, liqpay_request.encoded_xml)+hidden_field_tag(:signature, liqpay_request.signature)
17
+ if block_given?
18
+ result += yield
19
+ else
20
+ result += submit_tag(title, :name => nil)
21
+ end
22
+ result
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ require 'liqpay/liqpay_helper'
2
+
3
+ module Liqpay
4
+ class Railtie < Rails::Railtie
5
+ ActionView::Base.send :include, Liqpay::LiqpayHelper
6
+ end
7
+ end
@@ -2,7 +2,31 @@ require 'base64'
2
2
 
3
3
  module Liqpay
4
4
  class Request < BaseOperation
5
- attr_accessor :result_url, :server_url, :order_id, :amount, :currency, :description, :default_phone, :pay_way, :goods_id, :exp_time
5
+ # REQUIRED Amount of payment (Float), in :currency
6
+ attr_accessor :amount
7
+ # REQUIRED Currency of payment - one of `Liqpay::SUPPORTED_CURRENCIES`
8
+ attr_accessor :currency
9
+ # REQUIRED Arbitrary but unique ID
10
+ attr_accessor :order_id
11
+ # RECOMMENDED URL that the user will be redirected to after payment
12
+ attr_accessor :result_url
13
+ # RECOMMENDED URL that'll receive the order details in the background.
14
+ attr_accessor :server_url
15
+ # RECOMMENDED Description to be displayed to the user
16
+ attr_accessor :description
17
+ # Phone number to be suggested to the user
18
+ #
19
+ # LiqPAY requires users to provide a phone number before payment.
20
+ # If you know the user's phone number, you can provide it so he
21
+ # doesn't have to enter it manually.
22
+ attr_accessor :default_phone
23
+ # Method of payment. One or more (comma-separated) of:
24
+ # card - by card
25
+ # liqpay - by liqpay account
26
+ attr_accessor :pay_way
27
+
28
+ attr_accessor :exp_time
29
+ attr_accessor :goods_id
6
30
 
7
31
  def initialize(options={})
8
32
  super(options)
@@ -36,7 +60,7 @@ module Liqpay
36
60
  validate! unless @kamikaze
37
61
  Nokogiri::XML::Builder.new { |xml|
38
62
  xml.request {
39
- xml.version Liqpay::API_VERSION
63
+ xml.version Liqpay::LIQBUY_API_VERSION
40
64
  xml.merchant_id merchant_id
41
65
  xml.result_url result_url
42
66
  xml.server_url server_url
@@ -3,13 +3,33 @@ require 'nokogiri'
3
3
 
4
4
  module Liqpay
5
5
  class Response < BaseOperation
6
+ SUCCESS_STATUSES = %w(success wait_secure)
7
+
6
8
  attr_reader :encoded_xml, :signature, :xml
7
9
 
8
10
  ATTRIBUTES = %w(merchant_id order_id amount currency description status code transaction_id pay_way sender_phone goods_id pays_count)
9
- ATTRIBUTES.each do |attr|
11
+ %w(merchant_id order_id amount currency description status code transaction_id pay_way sender_phone goods_id pays_count).each do |attr|
10
12
  attr_reader attr
11
13
  end
12
14
 
15
+ # Amount of payment. MUST match the requested amount
16
+ attr_reader :amount
17
+ # Currency of payment. MUST match the requested currency
18
+ attr_reader :currency
19
+ # Status of payment. One of '
20
+ # failure
21
+ # success
22
+ # wait_secure - success, but the card wasn't known to the system
23
+ attr_reader :status
24
+ # Error code
25
+ attr_reader :code
26
+ # LiqPAY's internal transaction ID
27
+ attr_reader :transaction_id
28
+ # Chosen method of payment
29
+ attr_reader :pay_way
30
+ # Payer's phone
31
+ attr_reader :sender_phone
32
+
13
33
  def initialize(options = {})
14
34
  super(options)
15
35
 
@@ -19,6 +39,11 @@ module Liqpay
19
39
  decode!
20
40
  end
21
41
 
42
+ # Returns true, if the transaction was successful
43
+ def success?
44
+ SUCCESS_STATUSES.include? self.status
45
+ end
46
+
22
47
  private
23
48
  def decode!
24
49
  @xml = Base64.decode64(@encoded_xml)
@@ -1,3 +1,3 @@
1
1
  module Liqpay
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -7,7 +7,7 @@ Gem::Specification.new do |s|
7
7
  s.version = Liqpay::VERSION
8
8
  s.authors = ["Leonid Shevtsov"]
9
9
  s.email = ["leonid@shevtsov.me"]
10
- s.homepage = "http://leonid.shevtsov.me/en/liqpay"
10
+ s.homepage = "https://github.com/leonid-shevtsov/liqpay"
11
11
  s.summary = %q{LiqPAY billing API implementation in Ruby}
12
12
  s.description = %q{LiqPAY billing API implementation in Ruby}
13
13
 
metadata CHANGED
@@ -1,90 +1,74 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: liqpay
3
- version: !ruby/object:Gem::Version
4
- hash: 29
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
5
  prerelease:
6
- segments:
7
- - 0
8
- - 0
9
- - 1
10
- version: 0.0.1
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Leonid Shevtsov
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-09-03 00:00:00 +03:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-01-27 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: nokogiri
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70327090826000 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 3
30
- segments:
31
- - 0
32
- version: "0"
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
33
22
  type: :runtime
34
- version_requirements: *id001
23
+ prerelease: false
24
+ version_requirements: *70327090826000
35
25
  description: LiqPAY billing API implementation in Ruby
36
- email:
26
+ email:
37
27
  - leonid@shevtsov.me
38
28
  executables: []
39
-
40
29
  extensions: []
41
-
42
30
  extra_rdoc_files: []
43
-
44
- files:
31
+ files:
45
32
  - .gitignore
46
33
  - Gemfile
47
34
  - README.md
48
35
  - Rakefile
49
36
  - lib/liqpay.rb
50
37
  - lib/liqpay/base_operation.rb
38
+ - lib/liqpay/liqpay_helper.rb
39
+ - lib/liqpay/railtie.rb
51
40
  - lib/liqpay/request.rb
52
41
  - lib/liqpay/response.rb
53
42
  - lib/liqpay/version.rb
54
43
  - liqpay.gemspec
55
- has_rdoc: true
56
- homepage: http://leonid.shevtsov.me/en/liqpay
44
+ homepage: https://github.com/leonid-shevtsov/liqpay
57
45
  licenses: []
58
-
59
46
  post_install_message:
60
47
  rdoc_options: []
61
-
62
- require_paths:
48
+ require_paths:
63
49
  - lib
64
- required_ruby_version: !ruby/object:Gem::Requirement
50
+ required_ruby_version: !ruby/object:Gem::Requirement
65
51
  none: false
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- hash: 3
70
- segments:
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ segments:
71
57
  - 0
72
- version: "0"
73
- required_rubygems_version: !ruby/object:Gem::Requirement
58
+ hash: 3173392958928029467
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
60
  none: false
75
- requirements:
76
- - - ">="
77
- - !ruby/object:Gem::Version
78
- hash: 3
79
- segments:
61
+ requirements:
62
+ - - ! '>='
63
+ - !ruby/object:Gem::Version
64
+ version: '0'
65
+ segments:
80
66
  - 0
81
- version: "0"
67
+ hash: 3173392958928029467
82
68
  requirements: []
83
-
84
69
  rubyforge_project:
85
- rubygems_version: 1.6.2
70
+ rubygems_version: 1.8.11
86
71
  signing_key:
87
72
  specification_version: 3
88
73
  summary: LiqPAY billing API implementation in Ruby
89
74
  test_files: []
90
-