paysto-rails 1.0.1 → 1.0.2
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 +8 -8
- data/README.md +12 -14
- data/lib/generators/paysto/install_generator.rb +5 -1
- data/lib/generators/paysto/models_generator.rb +4 -1
- data/lib/generators/templates/config/paysto.rb +11 -3
- data/lib/generators/templates/models/invoice.rb +8 -1
- data/lib/paysto/base.rb +39 -20
- data/lib/paysto/controller.rb +8 -1
- data/lib/paysto/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NzRjM2IyMzliNGYwNjdhOGMyM2I1YmMyY2RhMzYwZDU0MzhjYWE5Yw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MDZjZDZhMzQxMDZmMDUzZmQ2MDA4YmMzMTQ3ZjQwMGE5YmMxNTFmMg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NmQwMmU0MDBhZWFjZDJiNjBiNTNmOTc4NzRhNDFkNjliZDRlNDRkM2RmNWM3
|
10
|
+
MzhmNWRlMjRhM2RiMDYyYWQyMzJmMmU5ZTc3NTA3YjcxOTQ1Yjc4YmVmMjdm
|
11
|
+
MTY0OWU5NDFmZWEwMTgzMmU1OTFkY2FmODAzOGZiZDkwNDZlOWQ=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OTA3NzQ3Zjk5MTFlMmRiOTcyMTAzNWRhZTVhZjM2MTBkNjMxYjE5MTVhYjAx
|
14
|
+
ZDVlZDY3MWJlNDE1NjA1NTI5M2FjOTI4MDM2ZDc1MmU3ZTlkOWU0ZGE1ZmFh
|
15
|
+
MGI1NGMzNGJlN2ExYTIwMzkxOTFlMDg3ZGYyMjY2Y2VkMzJiNzk=
|
data/README.md
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
[](http://badge.fury.io/rb/paysto-rails)
|
3
3
|
[](https://codeclimate.com/github/fbandrey/paysto-rails)
|
4
4
|
[](https://gemnasium.com/fbandrey/paysto-rails)
|
5
|
+
[](https://hakiri.io/github/fbandrey/paysto-rails/master)
|
6
|
+
[](http://inch-ci.org/github/fbandrey/paysto-rails)
|
5
7
|
|
6
|
-
This is first implementation for passing payments through [Paysto](https://paysto.com) gateway.
|
7
|
-
|
8
|
-
It works only with «[onlineMerchant](https://paysto.com/ru/products/onlineMerchant)», if you know what I mean. :)
|
8
|
+
This is first implementation for passing payments through [Paysto](https://paysto.com) gateway. It works only with «[onlineMerchant](https://paysto.com/ru/products/onlineMerchant)».
|
9
9
|
|
10
10
|
## Installation
|
11
11
|
|
@@ -65,35 +65,33 @@ In the simple case only what you should to do:
|
|
65
65
|
|
66
66
|
That's all.
|
67
67
|
|
68
|
-
Now you may customize models as you want, associate it with users or anything else...
|
69
|
-
|
70
|
-
For more information check [payment workflow](https://github.com/fbandrey/paysto-rails/wiki/Payment-workflow) wiki.
|
71
|
-
|
72
68
|
## Usage
|
73
69
|
|
74
|
-
You have 3 models and 1 controller now if you did everything right before. Check models and extend them with logic
|
70
|
+
You have 3 models and 1 controller now if you did everything right before. Check models and extend them with logic or associations, which you need in your application.
|
75
71
|
|
76
|
-
Controller by default [extended with concern](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb) and
|
72
|
+
Controller by default [extended with concern](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb) and contains all necessary methods:
|
77
73
|
```
|
78
74
|
class PaystoController < ApplicationController
|
79
75
|
include Paysto::Controller
|
80
76
|
end
|
81
77
|
```
|
82
|
-
But you may override methods
|
78
|
+
But you may override methods as you want. For example, if you want to redirect user to custom URL when payment is passed:
|
83
79
|
```
|
84
80
|
class PaystoController < ApplicationController
|
85
81
|
include Paysto::Controller
|
86
82
|
|
87
83
|
def success
|
88
84
|
flash[:success] = I18n.t('paysto.success')
|
89
|
-
redirect_to
|
85
|
+
redirect_to any_custom_payments_path
|
90
86
|
end
|
91
87
|
end
|
92
88
|
```
|
93
89
|
|
94
|
-
Also you can customize [check](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb#L9) or [callback](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb#L18) methods using Paysto module as you want, but
|
90
|
+
Also you can customize [check](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb#L9) or [callback](https://github.com/fbandrey/paysto-rails/blob/master/lib/paysto/controller.rb#L18) methods using Paysto module as you want, but do it only if you know what's going on there.
|
91
|
+
|
92
|
+
Check [payment workflow](https://github.com/fbandrey/paysto-rails/wiki/Payment-workflow) wiki for more information.
|
95
93
|
|
96
|
-
|
94
|
+
#### Paysto methods
|
97
95
|
|
98
96
|
```Paysto.balance``` – current balance in Paysto.
|
99
97
|
|
@@ -109,7 +107,7 @@ Also you can customize [check](https://github.com/fbandrey/paysto-rails/blob/mas
|
|
109
107
|
|
110
108
|
```Paysto.md5_valid?(params)``` – check whether the MD5 sign is valid.
|
111
109
|
|
112
|
-
```Paysto.pay_till``` – timestamp string in Paysto format.
|
110
|
+
```Paysto.pay_till``` – timestamp string for payment expiration in Paysto format.
|
113
111
|
|
114
112
|
```Paysto.real_amount(amount)``` – real income amount without Paysto tax.
|
115
113
|
|
@@ -4,6 +4,7 @@ module Paysto
|
|
4
4
|
class InstallGenerator < Rails::Generators::Base
|
5
5
|
source_root File.expand_path('../../templates', __FILE__)
|
6
6
|
|
7
|
+
# Extend routes.rb with required routes.
|
7
8
|
def add_paysto_routes
|
8
9
|
paysto_route = <<-PAYSTO_ROUTES
|
9
10
|
namespace :paysto do
|
@@ -14,18 +15,21 @@ PAYSTO_ROUTES
|
|
14
15
|
route paysto_route
|
15
16
|
end
|
16
17
|
|
18
|
+
# Copy general Paysto config.
|
17
19
|
def copy_config
|
18
20
|
template 'config/paysto.rb', 'config/initializers/paysto.rb'
|
19
21
|
end
|
20
22
|
|
23
|
+
# Copy RU and EN locale files.
|
21
24
|
def copy_locale
|
22
25
|
template 'config/paysto.en.yml', 'config/locales/paysto.en.yml'
|
23
26
|
template 'config/paysto.ru.yml', 'config/locales/paysto.ru.yml'
|
24
27
|
end
|
25
28
|
|
29
|
+
# Copy default Paysto controller.
|
26
30
|
def copy_controller
|
27
31
|
template 'controllers/paysto_controller.rb', 'app/controllers/paysto_controller.rb'
|
28
32
|
end
|
29
33
|
|
30
34
|
end
|
31
|
-
end
|
35
|
+
end
|
@@ -6,6 +6,7 @@ module Paysto
|
|
6
6
|
include Rails::Generators::Migration
|
7
7
|
source_root File.expand_path('../../templates', __FILE__)
|
8
8
|
|
9
|
+
# Migration timestamp.
|
9
10
|
def self.next_migration_number(dirname)
|
10
11
|
if ActiveRecord::Base.timestamped_migrations
|
11
12
|
Time.new.utc.strftime("%Y%m%d%H%M%S")
|
@@ -14,14 +15,16 @@ module Paysto
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
# Create migration with required tables.
|
17
19
|
def create_migration_file
|
18
20
|
migration_template 'migration.rb', 'db/migrate/create_paysto_tables.rb'
|
19
21
|
end
|
20
22
|
|
23
|
+
# Render configured models.
|
21
24
|
def copy_models
|
22
25
|
template 'models/payment.rb', "app/models/#{Paysto.payment_class_name.underscore}.rb"
|
23
26
|
template 'models/invoice.rb', "app/models/#{Paysto.invoice_class_name.underscore}.rb"
|
24
27
|
template 'models/invoice_notification.rb', "app/models/#{Paysto.invoice_notification_class_name.underscore}.rb"
|
25
28
|
end
|
26
29
|
end
|
27
|
-
end
|
30
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
Paysto.setup do |config|
|
2
2
|
|
3
|
-
# === Put your Paysto credentials here
|
3
|
+
# === Put your real Paysto credentials here.
|
4
4
|
config.id = 'SECRET-ID'
|
5
5
|
config.secret = 'SECRET-KEY'
|
6
6
|
config.description = 'CUSTOM-DESCRIPTION-FOR-PAYMENTS'
|
7
7
|
|
8
|
+
# === Paysto URLs.
|
8
9
|
config.urls = {
|
9
10
|
payment: 'https://paysto.com/ru/pay',
|
10
11
|
currencies: 'https://paysto.com/api/Common/Currency',
|
@@ -12,6 +13,7 @@ Paysto.setup do |config|
|
|
12
13
|
payments_list: 'https://paysto.com/api/Payment/GetList'
|
13
14
|
}
|
14
15
|
|
16
|
+
# === Paysto server IPs.
|
15
17
|
config.ips = [
|
16
18
|
'66.226.72.66',
|
17
19
|
'66.226.74.225',
|
@@ -20,10 +22,16 @@ Paysto.setup do |config|
|
|
20
22
|
'66.226.74.228'
|
21
23
|
]
|
22
24
|
|
23
|
-
# === Payments tax of your tariff plan in Paysto
|
25
|
+
# === Payments tax of your tariff plan in Paysto. Default onlineMerchant "All inclusive" is 5%.
|
24
26
|
config.tax = 0.05
|
25
27
|
|
26
|
-
# ===
|
28
|
+
# === Minimal Paysto tax for each payment. Default: 10.
|
29
|
+
config.min_tax = 10
|
30
|
+
|
31
|
+
# === Payments expiration. Default: 1.day.
|
32
|
+
config.expiration = 1.day
|
33
|
+
|
34
|
+
# === Customize model names as you want before they are will be generated.
|
27
35
|
config.payment_class_name = 'Payment'
|
28
36
|
config.invoice_class_name = 'Invoice'
|
29
37
|
config.invoice_notification_class_name = 'InvoiceNotification'
|
@@ -8,18 +8,22 @@ class <%= Paysto.invoice_class_name %> < ActiveRecord::Base
|
|
8
8
|
|
9
9
|
validates :amount, presence: true
|
10
10
|
|
11
|
+
# 'Success' code for different gateways.
|
11
12
|
SUCCESS_STATES = {
|
12
13
|
'paysto' => 'RES_PAID'
|
13
14
|
}
|
14
15
|
|
16
|
+
# Create <%= Paysto.invoice_notification_class_name %> with details.
|
15
17
|
def notify(params, gateway)
|
16
18
|
self.<%= Paysto.invoice_notification_class_name.underscore.pluralize %>.create(pay_data: info_by_gateway(params, gateway))
|
17
19
|
end
|
18
20
|
|
21
|
+
# Check whether the <%= Paysto.invoice_class_name.underscore %> is should be paid.
|
19
22
|
def need_to_be_paid?(gateway, payment_status, amount)
|
20
23
|
!paid? && (payment_status == SUCCESS_STATES[gateway.to_s]) && (self.amount.to_f == amount.to_f)
|
21
24
|
end
|
22
25
|
|
26
|
+
# Create <%= Paysto.payment_class_name %> record.
|
23
27
|
def create_<%= Paysto.payment_class_name.underscore %>(payment_method, gateway_code, real_amount = nil)
|
24
28
|
self.<%= Paysto.payment_class_name.underscore %> = <%= Paysto.payment_class_name %>.new(amount: self.amount,
|
25
29
|
real_amount: real_amount,
|
@@ -32,12 +36,15 @@ class <%= Paysto.invoice_class_name %> < ActiveRecord::Base
|
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
39
|
+
# Whether the <%= Paysto.invoice_class_name.underscore %> is paid.
|
35
40
|
def paid?
|
36
41
|
!!paid_at
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
46
|
+
# Payment details string.
|
47
|
+
# You could extend this method for another gateways.
|
41
48
|
def info_by_gateway(_params, _gateway)
|
42
49
|
_keys = case _gateway
|
43
50
|
when :paysto
|
@@ -51,4 +58,4 @@ class <%= Paysto.invoice_class_name %> < ActiveRecord::Base
|
|
51
58
|
end.join(';')
|
52
59
|
end
|
53
60
|
|
54
|
-
end
|
61
|
+
end
|
data/lib/paysto/base.rb
CHANGED
@@ -7,96 +7,115 @@ module Paysto
|
|
7
7
|
:urls,
|
8
8
|
:ips,
|
9
9
|
:tax,
|
10
|
+
:min_tax,
|
11
|
+
:expiration,
|
10
12
|
:payment_class_name,
|
11
13
|
:invoice_class_name,
|
12
14
|
:invoice_notification_class_name
|
13
15
|
|
14
16
|
class << self
|
15
17
|
|
18
|
+
# Configuring module.
|
16
19
|
def setup
|
17
20
|
yield self
|
18
21
|
end
|
19
22
|
|
23
|
+
# Payment class.
|
20
24
|
def payment_class
|
21
25
|
@@payment_class_name.constantize
|
22
26
|
end
|
23
27
|
|
28
|
+
# Invoice class.
|
24
29
|
def invoice_class
|
25
30
|
@@invoice_class_name.constantize
|
26
31
|
end
|
27
32
|
|
33
|
+
# InvoiceNotification class.
|
28
34
|
def invoice_notification_class
|
29
35
|
@@invoice_notification_class_name.constantize
|
30
36
|
end
|
31
37
|
|
38
|
+
# List of available pay methods according to your tariff plan.
|
32
39
|
def currencies
|
33
|
-
https_request_to
|
40
|
+
https_request_to @@urls[:currencies], base_params
|
34
41
|
end
|
35
42
|
|
43
|
+
# Your current balance in Paysto.
|
36
44
|
def balance
|
37
|
-
https_request_to
|
45
|
+
https_request_to @@urls[:balance], base_params
|
38
46
|
end
|
39
47
|
|
48
|
+
# Returns array of payments with details between dates.
|
49
|
+
# +from+ – from date.
|
50
|
+
# +to+ – to date.
|
40
51
|
def get_payments(from, to)
|
41
|
-
p = { 'PAYSTO_SHOP_ID' =>
|
52
|
+
p = { 'PAYSTO_SHOP_ID' => @@id,
|
42
53
|
'FROM' => from.strftime('%Y%m%d%H%M'),
|
43
54
|
'TO' => to.strftime('%Y%m%d%H%M') }
|
44
55
|
p.merge!('PAYSTO_MD5' => generate_md5(p))
|
45
56
|
|
46
|
-
res = https_request_to(
|
57
|
+
res = https_request_to(@@urls[:payments_list], p)
|
47
58
|
CSV.parse(res)
|
48
59
|
end
|
49
60
|
|
61
|
+
# Returns payment type or 'common' by default.
|
62
|
+
# +invoice_id+ – invoice ID of payment.
|
63
|
+
# +time+ – estimated payment execution time.
|
50
64
|
def get_payment_type(invoice_id, time = Time.zone.now)
|
51
|
-
_type = 'common'
|
52
65
|
_payments = get_payments(time.utc - 30.minutes, time.utc + 5.minutes)
|
53
66
|
if _payments.present?
|
54
67
|
p = _payments.select{|_p| _p[2].eql?(invoice_id.to_s)}.first
|
55
68
|
_type = p[7] if p
|
56
69
|
end
|
57
|
-
_type
|
70
|
+
_type || 'common'
|
58
71
|
end
|
59
72
|
|
73
|
+
# Check whether the invoice is valid.
|
60
74
|
def invoice_valid?(invoice)
|
61
|
-
invoice && invoice.
|
75
|
+
invoice && invoice.send("#{@@payment_class_name.underscore}_id").blank? && invoice.paid_at.blank?
|
62
76
|
end
|
63
77
|
|
78
|
+
# Check whether the IP is permitted.
|
64
79
|
def ip_valid?(ip)
|
65
|
-
|
80
|
+
@@ips.include?(ip)
|
66
81
|
end
|
67
82
|
|
83
|
+
# Check whether the MD5 sign is valid.
|
68
84
|
def md5_valid?(p)
|
69
|
-
|
85
|
+
except_keys = ['action', 'controller', 'PAYSTO_MD5']
|
86
|
+
generate_md5(p.reject{|k,v| except_keys.include?(k)}) == p['PAYSTO_MD5']
|
70
87
|
end
|
71
88
|
|
89
|
+
# Timestamp string in Paysto format for payments expiration.
|
72
90
|
def pay_till
|
73
|
-
(Time.zone.now +
|
91
|
+
(Time.zone.now + @@expiration).utc.strftime('%Y%m%d%H%M')
|
74
92
|
end
|
75
93
|
|
94
|
+
# Real income value without Paysto tax for any amount which you want to calculate.
|
95
|
+
# +str+ – amount string or numeric, does not matter.
|
76
96
|
def real_amount(str)
|
77
97
|
amount = str.to_f
|
78
|
-
_tax = amount *
|
79
|
-
_tax =
|
98
|
+
_tax = amount * @@tax
|
99
|
+
_tax = @@min_tax if _tax < @@min_tax
|
80
100
|
amount - _tax
|
81
101
|
end
|
82
102
|
|
83
103
|
private
|
84
104
|
|
105
|
+
# Generating MD5 sign according with received params.
|
85
106
|
def generate_md5(p = {}, upcase = true)
|
86
107
|
hash_str = p.to_a.sort_by{|pair| pair.first.downcase}.map{|pair| pair.join('=')}.join('&')
|
87
|
-
md5 = Digest::MD5.hexdigest("#{hash_str}&#{
|
88
|
-
|
89
|
-
md5.upcase
|
90
|
-
else
|
91
|
-
md5
|
92
|
-
end
|
108
|
+
md5 = Digest::MD5.hexdigest("#{hash_str}&#{@@secret}")
|
109
|
+
upcase ? md5.upcase : md5
|
93
110
|
end
|
94
111
|
|
112
|
+
# Base set of params for requests.
|
95
113
|
def base_params
|
96
|
-
p = { 'PAYSTO_SHOP_ID' =>
|
114
|
+
p = { 'PAYSTO_SHOP_ID' => @@id }
|
97
115
|
p.merge!('PAYSTO_MD5' => generate_md5(p))
|
98
116
|
end
|
99
117
|
|
118
|
+
# Performing an HTTPS request.
|
100
119
|
def https_request_to(url, params)
|
101
120
|
uri = URI.parse(url)
|
102
121
|
req = Net::HTTP::Post.new(uri.path)
|
@@ -110,4 +129,4 @@ module Paysto
|
|
110
129
|
end
|
111
130
|
|
112
131
|
end
|
113
|
-
end
|
132
|
+
end
|
data/lib/paysto/controller.rb
CHANGED
@@ -3,9 +3,12 @@ module Paysto
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
+
# Some callbacks does not requires verifications.
|
6
7
|
skip_before_filter :verify_authenticity_token, only: [:callback, :check]
|
7
8
|
end
|
8
9
|
|
10
|
+
# First step of payment workflow: Invoice, IP and MD5 verification.
|
11
|
+
# Render invoice ID if everything right or anything else if not.
|
9
12
|
def check
|
10
13
|
invoice = Paysto.invoice_class.find_by_id(params['PAYSTO_INVOICE_ID'])
|
11
14
|
if Paysto.invoice_valid?(invoice) && Paysto.ip_valid?(request.remote_ip) && Paysto.md5_valid?(params)
|
@@ -15,6 +18,8 @@ module Paysto
|
|
15
18
|
end
|
16
19
|
end
|
17
20
|
|
21
|
+
# Second step of payment workflow: Payment creation.
|
22
|
+
# Render invoice ID if everything right or anything else if not.
|
18
23
|
def callback
|
19
24
|
invoice = Paysto.invoice_class.find_by_id(params['PAYSTO_INVOICE_ID'])
|
20
25
|
if invoice && invoice.need_to_be_paid?(:paysto, params['PAYSTO_REQUEST_MODE'], params['PAYSTO_SUM']) && Paysto.ip_valid?(request.remote_ip) && Paysto.md5_valid?(params)
|
@@ -26,15 +31,17 @@ module Paysto
|
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
34
|
+
# Success callback.
|
29
35
|
def success
|
30
36
|
flash[:success] = I18n.t('paysto.success')
|
31
37
|
redirect_to root_path
|
32
38
|
end
|
33
39
|
|
40
|
+
# Fail callback.
|
34
41
|
def fail
|
35
42
|
flash[:alert] = I18n.t('paysto.fail')
|
36
43
|
redirect_to root_path
|
37
44
|
end
|
38
45
|
|
39
46
|
end
|
40
|
-
end
|
47
|
+
end
|
data/lib/paysto/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paysto-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrey Baiburin
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|