parsbank 0.0.5 → 0.0.8
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 +4 -4
- data/README.md +5 -3
- data/lib/db_setup.rb +103 -0
- data/lib/locales/en.yml +18 -0
- data/lib/locales/fa.yml +19 -0
- data/lib/parsbank/{bsc-bitcoin/bsc-bitcoin.rb → binance/binance.rb} +2 -1
- data/lib/parsbank/gates.rb +16 -0
- data/lib/parsbank/mellat/logo.svg +1 -0
- data/lib/parsbank/mellat/mellat.rb +2 -6
- data/lib/parsbank/nobitex/logo.svg +6 -0
- data/lib/parsbank/nobitex/nobitex.rb +1 -15
- data/lib/parsbank/restfull.rb +35 -23
- data/lib/parsbank/soap.rb +106 -0
- data/lib/parsbank/transaction_request.rb +134 -0
- data/lib/parsbank/transaction_verify.rb +135 -0
- data/lib/parsbank/version.rb +1 -1
- data/lib/parsbank/zarinpal/logo.svg +1 -1
- data/lib/parsbank/zarinpal/zarinpal.rb +89 -60
- data/lib/parsbank/zibal/zibal.rb +1 -18
- data/lib/parsbank.rb +25 -185
- data/lib/psp.json +82 -76
- data/lib/tmpl/_loader.html.erb +105 -0
- data/lib/tmpl/bank_list.html.erb +215 -0
- metadata +15 -18
- /data/lib/parsbank/{bsc-bitcoin/bsc-bitcoin.svg → binance/logo.svg} +0 -0
data/lib/parsbank.rb
CHANGED
@@ -1,23 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yaml'
|
4
|
-
require 'savon'
|
5
4
|
require 'uri'
|
5
|
+
require 'erb'
|
6
|
+
require 'i18n'
|
6
7
|
require 'active_support'
|
7
8
|
require 'parsbank/version'
|
9
|
+
require 'db_setup'
|
8
10
|
require 'parsbank/restfull'
|
9
|
-
require 'parsbank/
|
11
|
+
require 'parsbank/soap'
|
12
|
+
require 'parsbank/gates'
|
13
|
+
require 'parsbank/binance/binance'
|
10
14
|
require 'parsbank/mellat/mellat'
|
11
15
|
require 'parsbank/zarinpal/zarinpal'
|
12
16
|
require 'parsbank/zibal/zibal'
|
17
|
+
require 'parsbank/nobitex/nobitex'
|
13
18
|
require 'configuration'
|
19
|
+
require 'parsbank/transaction_request'
|
20
|
+
require 'parsbank/transaction_verify'
|
14
21
|
|
15
|
-
# Main Module
|
16
22
|
module Parsbank
|
17
23
|
class Error < StandardError; end
|
18
24
|
|
19
|
-
$SUPPORTED_PSP = JSON.parse(File.read(File.join(__dir__, 'psp.json')))
|
20
|
-
|
21
25
|
class << self
|
22
26
|
attr_accessor :configuration
|
23
27
|
end
|
@@ -27,6 +31,10 @@ module Parsbank
|
|
27
31
|
yield configuration
|
28
32
|
end
|
29
33
|
|
34
|
+
def self.supported_psp
|
35
|
+
JSON.parse(File.read(File.join(__dir__, 'psp.json')))
|
36
|
+
end
|
37
|
+
|
30
38
|
def self.gateways_list
|
31
39
|
load_secrets_yaml
|
32
40
|
end
|
@@ -35,7 +43,6 @@ module Parsbank
|
|
35
43
|
load_secrets_yaml.select { |_, value| value['enabled'] }
|
36
44
|
end
|
37
45
|
|
38
|
-
|
39
46
|
def self.initialize_in_rails
|
40
47
|
return unless defined?(Rails)
|
41
48
|
|
@@ -45,169 +52,23 @@ module Parsbank
|
|
45
52
|
end
|
46
53
|
|
47
54
|
def self.initialize!
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
puts "\033[31mParsBank ERROR: database_url not set, Transaction history not stored on database\033[0m"
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def self.establish_connection
|
56
|
-
database_url = Parsbank.configuration.database_url
|
57
|
-
model = Parsbank.configuration.model
|
58
|
-
raise "DATABASE_URL environment variable is not set" if database_url.nil?
|
59
|
-
|
60
|
-
supported_databases = {
|
61
|
-
'postgresql' => 'pg',
|
62
|
-
'mysql2' => 'mysql2',
|
63
|
-
'sqlite3' => 'sqlite3',
|
64
|
-
'nulldb' => 'nulldb'
|
65
|
-
}.freeze
|
66
|
-
|
67
|
-
uri = URI.parse(database_url)
|
68
|
-
|
69
|
-
gem_name = supported_databases[uri.scheme]
|
70
|
-
unless gem_name
|
71
|
-
raise "Unsupported database adapter: #{uri.scheme}. Supported adapters: #{supported_databases.keys.join(', ')}"
|
72
|
-
end
|
73
|
-
|
74
|
-
begin
|
75
|
-
require gem_name
|
76
|
-
rescue LoadError
|
77
|
-
raise "Missing required gem for #{uri.scheme}. Please add `gem '#{gem_name}'` to your Gemfile."
|
78
|
-
end
|
79
|
-
|
80
|
-
begin
|
81
|
-
ActiveRecord::Base.establish_connection(database_url)
|
82
|
-
unless ActiveRecord::Base.connection.table_exists?(model.tableize)
|
83
|
-
puts 'Create Transaction Table'
|
84
|
-
ActiveRecord::Base.connection.create_table model.tableize do |t|
|
85
|
-
t.string :gateway
|
86
|
-
t.string :amount
|
87
|
-
t.string :unit
|
88
|
-
t.string :track_id
|
89
|
-
t.string :local_id
|
90
|
-
t.string :ip
|
91
|
-
t.integer :user_id
|
92
|
-
t.integer :cart_id
|
93
|
-
t.text :description
|
94
|
-
t.string :callback_url
|
95
|
-
t.text :gateway_verify_response
|
96
|
-
t.text :gateway_response
|
97
|
-
t.string :status
|
98
|
-
t.timestamps
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
unless Object.const_defined?(model)
|
103
|
-
Object.const_set(model, Class.new(ActiveRecord::Base) do
|
104
|
-
self.table_name = model.tableize
|
105
|
-
end)
|
106
|
-
end
|
107
|
-
|
108
|
-
rescue => e
|
109
|
-
raise "Failed to connect to the database: #{e.message}"
|
110
|
-
end
|
55
|
+
I18n.load_path += Dir.glob(File.join(__dir__, 'locales', '*.yml'))
|
56
|
+
I18n.available_locales = %i[en fa]
|
57
|
+
I18n.enforce_available_locales = false
|
111
58
|
|
112
|
-
|
113
|
-
|
114
|
-
def self.redirect_to_gateway(args = {})
|
115
|
-
bank = args.fetch(:bank, available_gateways_list.keys.sample)
|
116
|
-
selected_bank = available_gateways_list.select { |k| k == bank }
|
117
|
-
unless selected_bank.present?
|
118
|
-
raise "Bank not enabled or not exists in #{Parsbank.configuration.secrets_path}: #{bank}"
|
119
|
-
end
|
120
|
-
|
121
|
-
description = args.fetch(:description)
|
122
|
-
default_callback = "#{selected_bank[bank.to_s]['callback_url'] || Parsbank.configuration.callback_url}&bank_name=#{bank}"
|
123
|
-
|
124
|
-
crypto_amount = args.fetch(:crypto_amount, nil)
|
125
|
-
fiat_amount = args.fetch(:fiat_amount, nil)
|
126
|
-
real_amount = args.fetch(:real_amount, nil)
|
127
|
-
|
128
|
-
if crypto_amount.nil? && fiat_amount.nil? && real_amount.nil?
|
129
|
-
raise 'Amount fileds is emptey: crypto_amount OR fiat_amount OR real_amount'
|
130
|
-
end
|
131
|
-
|
132
|
-
if $SUPPORTED_PSP[bank]['tags'].include?('crypto') && crypto_amount.nil? && real_amount.nil?
|
133
|
-
raise "#{bank} needs crypto_amount or real_amount"
|
134
|
-
end
|
135
|
-
|
136
|
-
if $SUPPORTED_PSP[bank]['tags'].include?('rial') && fiat_amount.nil? && real_amount.nil?
|
137
|
-
raise "#{bank} needs fiat_amount or real_amount"
|
138
|
-
end
|
139
|
-
|
140
|
-
transaction = Object.const_get(Parsbank.configuration.model).create(
|
141
|
-
description: description,
|
142
|
-
amount: fiat_amount || crypto_amount,
|
143
|
-
gateway: bank,
|
144
|
-
callback_url: default_callback,
|
145
|
-
status: 'start',
|
146
|
-
user_id: args.fetch(:user_id, nil),
|
147
|
-
cart_id: args.fetch(:cart_id, nil),
|
148
|
-
local_id: args.fetch(:local_id, nil),
|
149
|
-
ip: args.fetch(:ip, nil)
|
150
|
-
) if Parsbank.configuration.database_url.present?
|
151
|
-
|
152
|
-
case bank
|
153
|
-
when 'mellat'
|
154
|
-
mellat_klass = Parsbank::Mellat.new(
|
155
|
-
amount: fiat_amount,
|
156
|
-
additional_data: description,
|
157
|
-
callback_url: default_callback,
|
158
|
-
orderId: transaction.id
|
159
|
-
)
|
160
|
-
mellat_klass.call
|
161
|
-
transaction.update!(gateway_response: mellat_klass.response, unit: 'irr')
|
162
|
-
result = mellat_klass.redirect_form
|
163
|
-
|
164
|
-
when 'zarinpal'
|
165
|
-
zarinpal_klass = Parsbank::Zarinpal.new(
|
166
|
-
amount: fiat_amount,
|
167
|
-
additional_data: description,
|
168
|
-
callback_url: default_callback
|
169
|
-
)
|
170
|
-
zarinpal_klass.call
|
171
|
-
transaction.update!(gateway_response: zarinpal_klass.response,track_id: zarinpal_klass.ref_id, unit: 'irt') if transaction.present?
|
172
|
-
result = zarinpal_klass.redirect_form
|
173
|
-
|
174
|
-
when 'zibal'
|
175
|
-
Parsbank::Zibal.new(
|
176
|
-
amount: fiat_amount,
|
177
|
-
additional_data: description,
|
178
|
-
callback_url: default_callback
|
179
|
-
)
|
180
|
-
zarinpal_klass.call
|
181
|
-
result = zarinpal_klass.redirect_form
|
182
|
-
when 'bscbitcoin'
|
183
|
-
bscbitcoin_klass = Parsbank::BscBitcoin.new(
|
184
|
-
additional_data: description
|
185
|
-
)
|
186
|
-
convert_real_amount_to_assets if crypto_amount.nil? && args.key?(:real_amount)
|
187
|
-
result = bscbitcoin_klass.generate_payment_address(amount: amount)
|
188
|
-
transaction.update!(gateway_response: result, unit: 'bitcoin') if transaction.present?
|
189
|
-
|
190
|
-
end
|
191
|
-
|
192
|
-
result
|
59
|
+
Parsbank::DBSetup.establish_connection
|
193
60
|
end
|
194
61
|
|
195
62
|
def self.load_secrets_yaml
|
196
63
|
# Load the YAML file specified by the secrets_path
|
197
64
|
secrets = YAML.load_file(Parsbank.configuration.secrets_path)
|
198
|
-
|
199
|
-
unless secrets.is_a?(Hash)
|
200
|
-
raise "Error: Invalid format in #{Parsbank.configuration.secrets_path}. Expected a hash of bank secrets."
|
201
|
-
end
|
202
|
-
|
203
|
-
supported_banks = $SUPPORTED_PSP.keys
|
65
|
+
raise "Error: Invalid format in #{Parsbank.configuration.secrets_path}." unless secrets.is_a?(Hash)
|
204
66
|
|
205
67
|
secrets.each_key do |bank_key|
|
206
|
-
unless
|
207
|
-
raise "#{bank_key.capitalize} in #{Parsbank.configuration.secrets_path} is not supported by ParsBank. \nSupported Banks: #{
|
68
|
+
unless supported_psp.keys.include?(bank_key.to_s)
|
69
|
+
raise "#{bank_key.capitalize} in #{Parsbank.configuration.secrets_path} is not supported by ParsBank. \nSupported Banks: #{supported_psp.keys.join(', ')}"
|
208
70
|
end
|
209
71
|
end
|
210
|
-
|
211
72
|
secrets
|
212
73
|
rescue Errno::ENOENT
|
213
74
|
raise "Error: Secrets file not found at #{Parsbank.configuration.secrets_path}."
|
@@ -215,32 +76,11 @@ module Parsbank
|
|
215
76
|
raise "Error: YAML syntax issue in #{Parsbank.configuration.secrets_path}: #{e.message}"
|
216
77
|
end
|
217
78
|
|
218
|
-
def self.gateways_list_shortcode
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
def self.render_bank_list_item(bank)
|
224
|
-
bank_klass = Object.const_get("Parsbank::#{bank.capitalize}")
|
225
|
-
_, _, body = begin
|
226
|
-
bank_klass.logo
|
227
|
-
rescue StandardError
|
228
|
-
nil
|
229
|
-
end
|
230
|
-
<<~HTML
|
231
|
-
<li class='parsbank_radio_wrapper #{bank}_wrapper'>
|
232
|
-
#{' '}
|
233
|
-
<input type='radio' id='#{bank}' name='bank' value='#{bank}' />
|
234
|
-
<label for='#{bank}'>#{begin
|
235
|
-
File.read(body)
|
236
|
-
rescue StandardError
|
237
|
-
''
|
238
|
-
end} #{bank.upcase}</label>
|
239
|
-
</li>
|
240
|
-
HTML
|
79
|
+
def self.gateways_list_shortcode(args = {})
|
80
|
+
ERB.new(File.read(File.join(__dir__, 'tmpl', 'bank_list.html.erb'))).result(binding).gsub(/(?:\n\r?|\r\n?)/, '').gsub(/>\s+</, '><').gsub(
|
81
|
+
/\s+/, ' '
|
82
|
+
).strip
|
241
83
|
end
|
242
84
|
end
|
243
85
|
|
244
|
-
|
245
|
-
|
246
|
-
Parsbank.initialize_in_rails
|
86
|
+
Parsbank.initialize_in_rails
|
data/lib/psp.json
CHANGED
@@ -1,78 +1,84 @@
|
|
1
1
|
{
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
2
|
+
"asanpardakht": {
|
3
|
+
"name": "Asan Pardakht CO.",
|
4
|
+
"website": "http://asanpardakht.ir",
|
5
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
6
|
+
},
|
7
|
+
"damavand": {
|
8
|
+
"name": "Electronic Card Damavand CO.",
|
9
|
+
"website": "http://ecd-co.ir",
|
10
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
11
|
+
},
|
12
|
+
"mellat": {
|
13
|
+
"name": "Behpardakht Mellat CO.",
|
14
|
+
"website": "http://behpardakht.com",
|
15
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
16
|
+
},
|
17
|
+
"pep": {
|
18
|
+
"name": "Pasargad CO.",
|
19
|
+
"website": "http://pep.co.ir",
|
20
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
21
|
+
},
|
22
|
+
"sep": {
|
23
|
+
"name": "Saman Bank CO.",
|
24
|
+
"website": "http://sep.ir",
|
25
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
26
|
+
},
|
27
|
+
"pna": {
|
28
|
+
"name": "Pardakht Novin Arian CO.",
|
29
|
+
"website": "http://pna.co.ir",
|
30
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
31
|
+
},
|
32
|
+
"pec": {
|
33
|
+
"name": "Parsian Bank CO.",
|
34
|
+
"website": "http://pec.ir",
|
35
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
36
|
+
},
|
37
|
+
"sadad": {
|
38
|
+
"name": "Sadad Bank CO.",
|
39
|
+
"website": "http://sadadco.com",
|
40
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
41
|
+
},
|
42
|
+
"sayan": {
|
43
|
+
"name": "Sayan Card CO.",
|
44
|
+
"website": "http://sayancard.ir",
|
45
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
46
|
+
},
|
47
|
+
"fanava": {
|
48
|
+
"name": "Fan Ava Card CO.",
|
49
|
+
"website": "http://fanavacard.com",
|
50
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
51
|
+
},
|
52
|
+
"kiccc": {
|
53
|
+
"name": "IranKish CO.",
|
54
|
+
"website": "http://kiccc.com",
|
55
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
56
|
+
},
|
57
|
+
"sepehr": {
|
58
|
+
"name": "Sepehr Bank CO.",
|
59
|
+
"website": "http://www.sepehrpay.com",
|
60
|
+
"tags": ["iranian-psp", "ir", "rial"]
|
61
|
+
},
|
62
|
+
"zarinpal": {
|
63
|
+
"name": "Zarinpal",
|
64
|
+
"website": "http://www.sepehrpay.com",
|
65
|
+
"tags": ["iranian-psp", "irt", "rial"]
|
66
|
+
},
|
67
|
+
"zibal": {
|
68
|
+
"name": "Zibal",
|
69
|
+
"website": "http://zibal.ir",
|
70
|
+
"tags": ["iranian-psp", "irt", "rial"]
|
71
|
+
},
|
72
|
+
"binance": {
|
73
|
+
"name": "Binance",
|
74
|
+
"website": "https://binance.com",
|
75
|
+
"support_coins": ["btc", "usdt"],
|
76
|
+
"tags": ["btc", "bitcoin", "binance", "bsc", "crypto"]
|
77
|
+
},
|
78
|
+
"nobitex": {
|
79
|
+
"name": "Nobitex",
|
80
|
+
"website": "https://nobitex.ir",
|
81
|
+
"support_coins": ["btc", "usdt"],
|
82
|
+
"tags": ["btc", "bitcoin", "nobitex", "bsc", "crypto"]
|
77
83
|
}
|
78
|
-
|
84
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
<html>
|
2
|
+
|
3
|
+
<head>
|
4
|
+
<title>Loading...</title>
|
5
|
+
<meta http-equiv='cache-control' content='max-age=0' />
|
6
|
+
<meta http-equiv='cache-control' content='no-cache' />
|
7
|
+
<meta http-equiv='expires' content='0' />
|
8
|
+
<meta http-equiv='expires' content='Tue, 18 May 1998 1:00:00 GMT' />
|
9
|
+
<meta http-equiv='pragma' content='no-cache' />
|
10
|
+
<meta charset='utf-8'>
|
11
|
+
<meta content='width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' name='viewport'>
|
12
|
+
<meta content='#da532c' name='msapplication-TileColor'>
|
13
|
+
<meta name='theme-color' content='#ffffff'>
|
14
|
+
<meta name='author' content='ParsBank Gem'>
|
15
|
+
<meta name="robots" content="noindex,nofollow,noarchive" />
|
16
|
+
<style>
|
17
|
+
body {
|
18
|
+
text-align: center;
|
19
|
+
background: #5052bc;
|
20
|
+
margin-top: 50vh;
|
21
|
+
color: white;
|
22
|
+
line-height: 5rem;
|
23
|
+
}
|
24
|
+
|
25
|
+
.loader {
|
26
|
+
width: 16px;
|
27
|
+
display: block;
|
28
|
+
margin: auto;
|
29
|
+
height: 16px;
|
30
|
+
position: relative;
|
31
|
+
left: -32px;
|
32
|
+
border-radius: 50%;
|
33
|
+
color: #fff;
|
34
|
+
background: currentColor;
|
35
|
+
box-shadow: 32px 0, -32px 0, 64px 0;
|
36
|
+
z-index: -1;
|
37
|
+
}
|
38
|
+
|
39
|
+
.loader::after {
|
40
|
+
content: '';
|
41
|
+
position: absolute;
|
42
|
+
left: -32px;
|
43
|
+
top: 0;
|
44
|
+
width: 16px;
|
45
|
+
height: 16px;
|
46
|
+
border-radius: 10px;
|
47
|
+
background: #FF3D00;
|
48
|
+
animation: move 3s linear infinite alternate;
|
49
|
+
}
|
50
|
+
|
51
|
+
@keyframes move{
|
52
|
+
|
53
|
+
0%,
|
54
|
+
5% {
|
55
|
+
left: -32px;
|
56
|
+
width: 16px;
|
57
|
+
}
|
58
|
+
|
59
|
+
15%,
|
60
|
+
20% {
|
61
|
+
left: -32px;
|
62
|
+
width: 48px;
|
63
|
+
}
|
64
|
+
|
65
|
+
30%,
|
66
|
+
35% {
|
67
|
+
left: 0px;
|
68
|
+
width: 16px;
|
69
|
+
}
|
70
|
+
|
71
|
+
45%,
|
72
|
+
50% {
|
73
|
+
left: 0px;
|
74
|
+
width: 48px;
|
75
|
+
}
|
76
|
+
|
77
|
+
60%,
|
78
|
+
65% {
|
79
|
+
left: 32px;
|
80
|
+
width: 16px;
|
81
|
+
}
|
82
|
+
|
83
|
+
75%,
|
84
|
+
80% {
|
85
|
+
left: 32px;
|
86
|
+
width: 48px;
|
87
|
+
}
|
88
|
+
|
89
|
+
95%,
|
90
|
+
100% {
|
91
|
+
left: 64px;
|
92
|
+
width: 16px;
|
93
|
+
}
|
94
|
+
</style>
|
95
|
+
</head>
|
96
|
+
|
97
|
+
<body>
|
98
|
+
<span class='loader'></span>
|
99
|
+
|
100
|
+
|
101
|
+
<%= yield %>
|
102
|
+
|
103
|
+
</body>
|
104
|
+
|
105
|
+
</html>
|