liqpay 0.0.1 → 0.1.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.
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
-