paysto-rails 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/paysto-rails.svg)](http://badge.fury.io/rb/paysto-rails)
|
3
3
|
[![Code Climate](https://codeclimate.com/github/fbandrey/paysto-rails/badges/gpa.svg)](https://codeclimate.com/github/fbandrey/paysto-rails)
|
4
4
|
[![Dependency Status](https://gemnasium.com/fbandrey/paysto-rails.svg)](https://gemnasium.com/fbandrey/paysto-rails)
|
5
|
+
[![security](https://hakiri.io/github/fbandrey/paysto-rails/master.svg)](https://hakiri.io/github/fbandrey/paysto-rails/master)
|
6
|
+
[![Inline docs](http://inch-ci.org/github/fbandrey/paysto-rails.png?branch=master)](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
|