parsbank 0.0.4 → 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 +150 -64
- data/lib/configuration.rb +3 -1
- 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 +130 -71
- 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 +35 -156
- data/lib/psp.json +84 -0
- data/lib/tmpl/_loader.html.erb +105 -0
- data/lib/tmpl/bank_list.html.erb +215 -0
- metadata +17 -47
- /data/lib/parsbank/{bsc-bitcoin/bsc-bitcoin.svg → binance/logo.svg} +0 -0
@@ -1,32 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Parsbank
|
2
|
-
class Zarinpal
|
3
|
-
attr_accessor :amount, :description, :email, :mobile, :merchant_id
|
4
|
+
class Zarinpal < Gates
|
5
|
+
attr_accessor :amount, :description, :email, :mobile, :merchant_id, :wsdl
|
4
6
|
attr_reader :response, :status, :status_message, :ref_id, :logo
|
5
7
|
|
6
8
|
def initialize(args = {})
|
7
|
-
@mobile = args.fetch(:mobile,
|
8
|
-
@email = args.fetch(:email,
|
9
|
+
@mobile = args.fetch(:mobile, '')
|
10
|
+
@email = args.fetch(:email, '')
|
9
11
|
@amount = args.fetch(:amount)
|
10
12
|
@description = args.fetch(:description, ' ')
|
11
13
|
@callback_url = args.fetch(:callback_url,
|
12
14
|
(default_config(:callback_url) || Parsbank.configuration.callback_url))
|
13
15
|
@merchant_id = args.fetch(:merchant_id, default_config(:merchant_id))
|
14
|
-
@wsdl =
|
16
|
+
@wsdl = create_rest_client
|
15
17
|
rescue KeyError => e
|
16
18
|
raise ArgumentError, "Missing required argument: #{e.message}"
|
17
19
|
end
|
18
20
|
|
19
|
-
def self.logo
|
20
|
-
file_path = "#{__dir__}/logo.svg"
|
21
|
-
return [404, { 'Content-Type' => 'text/plain' }, ['File not found']] unless File.exist?(file_path)
|
22
|
-
|
23
|
-
[
|
24
|
-
200,
|
25
|
-
{ 'Content-Type' => 'image/svg+xml' },
|
26
|
-
File.open(file_path, 'r')
|
27
|
-
]
|
28
|
-
end
|
29
|
-
|
30
21
|
def validate(response = nil)
|
31
22
|
@response = response[:payment_request_response] || response[:payment_verification_response] || response
|
32
23
|
@ref_id = @response[:authority]
|
@@ -45,61 +36,99 @@ module Parsbank
|
|
45
36
|
end
|
46
37
|
|
47
38
|
def call
|
48
|
-
response =
|
49
|
-
|
50
|
-
|
51
|
-
|
39
|
+
response = @wsdl.call
|
40
|
+
|
41
|
+
Rails.logger.info "Received response with status: #{response.status}, body: #{response.body.inspect}"
|
42
|
+
|
43
|
+
if response.valid?
|
44
|
+
validate(response.body)
|
45
|
+
else
|
46
|
+
@valid = false
|
47
|
+
Rails.logger.error "POST request to #{BASE_URL}/#{endpoint} failed with status: #{response.status}, error: #{response.body.inspect}"
|
48
|
+
raise "API request failed with status #{response.status}: #{response.body}"
|
49
|
+
end
|
50
|
+
rescue Faraday::ConnectionFailed => e
|
51
|
+
Rails.logger.error "Connection failed: #{e.message}"
|
52
|
+
raise "Connection to API failed: #{e.message}"
|
53
|
+
rescue Faraday::TimeoutError => e
|
54
|
+
Rails.logger.error "Request timed out: #{e.message}"
|
55
|
+
raise "API request timed out: #{e.message}"
|
56
|
+
rescue StandardError => e
|
57
|
+
Rails.logger.error "An error occurred: #{e.message}"
|
58
|
+
raise "An unexpected error occurred: #{e.message}"
|
59
|
+
|
60
|
+
JSON.parse response.body
|
61
|
+
|
62
|
+
if response[:success]
|
63
|
+
validate(response[:body])
|
64
|
+
else
|
65
|
+
{ status: :nok, message: begin
|
66
|
+
response[:error]
|
67
|
+
rescue StandardError
|
68
|
+
response
|
69
|
+
end }
|
70
|
+
end
|
52
71
|
end
|
53
72
|
|
54
|
-
def redirect_form
|
55
|
-
|
73
|
+
def redirect_form(ref_id)
|
74
|
+
javascript_tag = <<-JS
|
56
75
|
<script type='text/javascript' charset='utf-8'>
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
function postRefId(refIdValue) {
|
77
|
+
var form = document.createElement('form');
|
78
|
+
form.setAttribute('method', 'POST');
|
79
|
+
form.setAttribute('action', 'https://www.zarinpal.com/pg/StartPay/' + refIdValue);
|
80
|
+
form.setAttribute('target', '_self');
|
81
|
+
var hiddenField = document.createElement('input');
|
82
|
+
hiddenField.setAttribute('name', 'RefId');
|
83
|
+
hiddenField.setAttribute('value', refIdValue);
|
84
|
+
form.appendChild(hiddenField);
|
85
|
+
document.body.appendChild(form);
|
86
|
+
form.submit();
|
87
|
+
document.body.removeChild(form);
|
88
|
+
}
|
89
|
+
postRefId('#{ref_id}');
|
90
|
+
</script>
|
91
|
+
JS
|
92
|
+
|
93
|
+
redirect_loaders do
|
94
|
+
"#{javascript_tag}#{I18n.t('actions.redirect_to_gate')}"
|
95
|
+
end
|
75
96
|
end
|
76
97
|
|
77
98
|
private
|
78
99
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
logger: Rails.logger,
|
90
|
-
log_level: (Parsbank.configuration.debug ? :debug : :fatal)
|
100
|
+
def create_rest_client
|
101
|
+
Parsbank::Restfull.new(
|
102
|
+
endpoint: default_config(:endpoint) || 'https://payment.zarinpal.com/pg/v4/payment',
|
103
|
+
action: 'request.json',
|
104
|
+
headers: {
|
105
|
+
'Content-Type' => 'application/json'
|
106
|
+
},
|
107
|
+
request_message: build_request_message,
|
108
|
+
http_method: :post,
|
109
|
+
response_type: :json
|
91
110
|
)
|
111
|
+
|
112
|
+
|
92
113
|
end
|
93
114
|
|
115
|
+
def deep_clean(hash)
|
116
|
+
hash.reject do |_, value|
|
117
|
+
(value.is_a?(Hash) && deep_clean(value).empty?) || value.nil? || value == ""
|
118
|
+
end.transform_values do |v|
|
119
|
+
v.is_a?(Hash) ? deep_clean(v) : v
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
94
124
|
def build_request_message
|
95
|
-
{
|
96
|
-
'
|
97
|
-
'
|
98
|
-
'
|
99
|
-
'
|
100
|
-
'
|
101
|
-
|
102
|
-
}
|
125
|
+
deep_clean({
|
126
|
+
'merchant_id' => @merchant_id,
|
127
|
+
'metadata' => {'mobile' => @mobile, 'email' => @email,'order_id'=> ''},
|
128
|
+
'amount' => @amount,
|
129
|
+
'description' => @description,
|
130
|
+
'callback_url' => @callback_url
|
131
|
+
})
|
103
132
|
end
|
104
133
|
|
105
134
|
def perform_validation
|
data/lib/parsbank/zibal/zibal.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'faraday'
|
4
4
|
require 'faraday_middleware'
|
5
5
|
module Parsbank
|
6
|
-
class Zibal
|
6
|
+
class Zibal < Gates
|
7
7
|
attr_accessor :amount, :description, :email, :mobile, :merchant, :callbackUrl, :orderId, :allowedCards, :ledgerId,
|
8
8
|
:nationalCode, :checkMobileWithCard
|
9
9
|
|
@@ -25,17 +25,6 @@ module Parsbank
|
|
25
25
|
raise ArgumentError, "Missing required argument: #{e.message}"
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.logo
|
29
|
-
file_path = "#{__dir__}/logo.svg"
|
30
|
-
return [404, { 'Content-Type' => 'text/plain' }, ['File not found']] unless File.exist?(file_path)
|
31
|
-
|
32
|
-
[
|
33
|
-
200,
|
34
|
-
{ 'Content-Type' => 'image/svg+xml' },
|
35
|
-
File.open(file_path, 'r')
|
36
|
-
]
|
37
|
-
end
|
38
|
-
|
39
28
|
def validate(response = nil)
|
40
29
|
@response = response
|
41
30
|
@ref_id = @response['trackId']
|
@@ -55,8 +44,6 @@ module Parsbank
|
|
55
44
|
|
56
45
|
def call
|
57
46
|
create_rest_client
|
58
|
-
rescue Savon::Error => e
|
59
|
-
raise "SOAP request failed: #{e.message}"
|
60
47
|
end
|
61
48
|
|
62
49
|
def redirect_form
|
@@ -84,10 +71,6 @@ module Parsbank
|
|
84
71
|
|
85
72
|
private
|
86
73
|
|
87
|
-
def default_config(key)
|
88
|
-
Parsbank.load_secrets_yaml[self.class.name.split('::').last.downcase][key.to_s]
|
89
|
-
end
|
90
|
-
|
91
74
|
def create_rest_client
|
92
75
|
connection = Parsbank::Restfull.new(
|
93
76
|
endpoint: default_config(:endpoint) || 'https://gateway.zibal.ir',
|
data/lib/parsbank.rb
CHANGED
@@ -1,101 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'yaml'
|
4
|
-
require '
|
4
|
+
require 'uri'
|
5
|
+
require 'erb'
|
6
|
+
require 'i18n'
|
7
|
+
require 'active_support'
|
5
8
|
require 'parsbank/version'
|
9
|
+
require 'db_setup'
|
6
10
|
require 'parsbank/restfull'
|
7
|
-
require 'parsbank/
|
11
|
+
require 'parsbank/soap'
|
12
|
+
require 'parsbank/gates'
|
13
|
+
require 'parsbank/binance/binance'
|
8
14
|
require 'parsbank/mellat/mellat'
|
9
15
|
require 'parsbank/zarinpal/zarinpal'
|
10
16
|
require 'parsbank/zibal/zibal'
|
17
|
+
require 'parsbank/nobitex/nobitex'
|
11
18
|
require 'configuration'
|
19
|
+
require 'parsbank/transaction_request'
|
20
|
+
require 'parsbank/transaction_verify'
|
12
21
|
|
13
|
-
# Main Module
|
14
22
|
module Parsbank
|
15
23
|
class Error < StandardError; end
|
16
24
|
|
17
|
-
$SUPPORTED_PSP = [
|
18
|
-
'asanpardakht': {
|
19
|
-
'name': 'Asan Pardakht CO.',
|
20
|
-
'website': 'http://asanpardakht.ir',
|
21
|
-
'tags': %w[iranian-psp ir rial]
|
22
|
-
},
|
23
|
-
'damavand': {
|
24
|
-
'name': 'Electronic Card Damavand CO.',
|
25
|
-
'website': 'http://ecd-co.ir',
|
26
|
-
'tags': %w[iranian-psp ir rial]
|
27
|
-
},
|
28
|
-
'mellat': {
|
29
|
-
'name': 'Behpardakht Mellat CO.',
|
30
|
-
'website': 'http://behpardakht.com',
|
31
|
-
'tags': %w[iranian-psp ir rial]
|
32
|
-
},
|
33
|
-
'pep': {
|
34
|
-
'name': 'Pasargad CO.',
|
35
|
-
'website': 'http://pep.co.ir',
|
36
|
-
'tags': %w[iranian-psp ir rial]
|
37
|
-
},
|
38
|
-
|
39
|
-
'sep': {
|
40
|
-
'name': 'Saman Bank CO.',
|
41
|
-
'website': 'http://sep.ir',
|
42
|
-
'tags': %w[iranian-psp ir rial]
|
43
|
-
},
|
44
|
-
'pna': {
|
45
|
-
'name': 'Pardakht Novin Arian CO.',
|
46
|
-
'website': 'http://pna.co.ir',
|
47
|
-
'tags': %w[iranian-psp ir rial]
|
48
|
-
},
|
49
|
-
'pec': {
|
50
|
-
'name': 'Parsian Bank CO.',
|
51
|
-
'website': 'http://pec.ir',
|
52
|
-
'tags': %w[iranian-psp ir rial]
|
53
|
-
},
|
54
|
-
|
55
|
-
'sadad': {
|
56
|
-
'name': 'Sadad Bank CO.',
|
57
|
-
'website': 'http://sadadco.com',
|
58
|
-
'tags': %w[iranian-psp ir rial]
|
59
|
-
},
|
60
|
-
'sayan': {
|
61
|
-
'name': 'Sayan Card CO.',
|
62
|
-
'website': 'http://sayancard.ir',
|
63
|
-
'tags': %w[iranian-psp ir rial]
|
64
|
-
},
|
65
|
-
|
66
|
-
'fanava': {
|
67
|
-
'name': 'Fan Ava Card CO.',
|
68
|
-
'website': 'http://fanavacard.com',
|
69
|
-
'tags': %w[iranian-psp ir rial]
|
70
|
-
},
|
71
|
-
'kiccc': {
|
72
|
-
'name': 'IranKish CO.',
|
73
|
-
'website': 'http://kiccc.com',
|
74
|
-
'tags': %w[iranian-psp ir rial]
|
75
|
-
},
|
76
|
-
|
77
|
-
'sepehr': {
|
78
|
-
'name': 'Sepehr Bank CO.',
|
79
|
-
'website': 'http://www.sepehrpay.com',
|
80
|
-
'tags': %w[iranian-psp ir rial]
|
81
|
-
},
|
82
|
-
|
83
|
-
'zarinpal': {
|
84
|
-
'name': 'Zarinpal',
|
85
|
-
'website': 'http://www.sepehrpay.com',
|
86
|
-
'tags': %w[iranian-psp ir rial]
|
87
|
-
},
|
88
|
-
'zibal': {
|
89
|
-
'name': 'Zibal',
|
90
|
-
'website': 'http://zibal.ir',
|
91
|
-
'tags': %w[iranian-psp ir rial]
|
92
|
-
},
|
93
|
-
'bscbitcoin': {
|
94
|
-
'name': 'Binance Bitcoin',
|
95
|
-
'website': 'https://bitcoin.org',
|
96
|
-
'tags': %w[btc bitcoin binance bsc crypto]
|
97
|
-
}
|
98
|
-
]
|
99
25
|
class << self
|
100
26
|
attr_accessor :configuration
|
101
27
|
end
|
@@ -105,6 +31,10 @@ module Parsbank
|
|
105
31
|
yield configuration
|
106
32
|
end
|
107
33
|
|
34
|
+
def self.supported_psp
|
35
|
+
JSON.parse(File.read(File.join(__dir__, 'psp.json')))
|
36
|
+
end
|
37
|
+
|
108
38
|
def self.gateways_list
|
109
39
|
load_secrets_yaml
|
110
40
|
end
|
@@ -113,71 +43,32 @@ module Parsbank
|
|
113
43
|
load_secrets_yaml.select { |_, value| value['enabled'] }
|
114
44
|
end
|
115
45
|
|
46
|
+
def self.initialize_in_rails
|
47
|
+
return unless defined?(Rails)
|
116
48
|
|
117
|
-
|
118
|
-
|
119
|
-
bank = args.fetch(:bank, 'random-irr-gates')
|
120
|
-
description = args.fetch(:description, '')
|
121
|
-
|
122
|
-
selected_bank = available_gateways_list.select { |k| k == bank }
|
123
|
-
raise "Bank not enabled or not exists on bank_secrets.yml: #{bank}" unless selected_bank.present?
|
124
|
-
|
125
|
-
default_callback = Parsbank.configuration.callback_url + "&bank_name=#{bank}"
|
126
|
-
|
127
|
-
case bank
|
128
|
-
when 'mellat'
|
129
|
-
mellat_klass = Parsbank::Mellat.new(
|
130
|
-
amount: amount,
|
131
|
-
additional_data: description,
|
132
|
-
callback_url: selected_bank['mellat']['callback_url'] || default_callback,
|
133
|
-
orderId: rand(1...9999)
|
134
|
-
)
|
135
|
-
mellat_klass.call
|
136
|
-
result = mellat_klass.redirect_form
|
137
|
-
|
138
|
-
when 'zarinpal'
|
139
|
-
zarinpal_klass = Parsbank::Zarinpal.new(
|
140
|
-
amount: amount,
|
141
|
-
additional_data: description,
|
142
|
-
callback_url: selected_bank['zarinpal']['callback_url'] || default_callback
|
143
|
-
)
|
144
|
-
zarinpal_klass.call
|
145
|
-
result = zarinpal_klass.redirect_form
|
146
|
-
|
147
|
-
when 'zibal'
|
148
|
-
Parsbank::Zibal.new(
|
149
|
-
amount: amount,
|
150
|
-
additional_data: description,
|
151
|
-
callback_url: selected_bank['zibal']['callback_url'] || default_callback
|
152
|
-
)
|
153
|
-
zarinpal_klass.call
|
154
|
-
result = zarinpal_klass.redirect_form
|
155
|
-
when 'bscbitcoin'
|
156
|
-
bscbitcoin_klass = Parsbank::BscBitcoin.new(
|
157
|
-
additional_data: description
|
158
|
-
)
|
159
|
-
result = bscbitcoin_klass.generate_payment_address(amount: amount)
|
49
|
+
ActiveSupport.on_load(:after_initialize) do
|
50
|
+
Parsbank.initialize!
|
160
51
|
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.initialize!
|
55
|
+
I18n.load_path += Dir.glob(File.join(__dir__, 'locales', '*.yml'))
|
56
|
+
I18n.available_locales = %i[en fa]
|
57
|
+
I18n.enforce_available_locales = false
|
161
58
|
|
162
|
-
|
59
|
+
Parsbank::DBSetup.establish_connection
|
163
60
|
end
|
164
61
|
|
165
62
|
def self.load_secrets_yaml
|
166
63
|
# Load the YAML file specified by the secrets_path
|
167
64
|
secrets = YAML.load_file(Parsbank.configuration.secrets_path)
|
168
|
-
|
169
|
-
unless secrets.is_a?(Hash)
|
170
|
-
raise "Error: Invalid format in #{Parsbank.configuration.secrets_path}. Expected a hash of bank secrets."
|
171
|
-
end
|
172
|
-
|
173
|
-
supported_banks = $SUPPORTED_PSP[0].keys
|
65
|
+
raise "Error: Invalid format in #{Parsbank.configuration.secrets_path}." unless secrets.is_a?(Hash)
|
174
66
|
|
175
67
|
secrets.each_key do |bank_key|
|
176
|
-
unless
|
177
|
-
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(', ')}"
|
178
70
|
end
|
179
71
|
end
|
180
|
-
|
181
72
|
secrets
|
182
73
|
rescue Errno::ENOENT
|
183
74
|
raise "Error: Secrets file not found at #{Parsbank.configuration.secrets_path}."
|
@@ -185,23 +76,11 @@ module Parsbank
|
|
185
76
|
raise "Error: YAML syntax issue in #{Parsbank.configuration.secrets_path}: #{e.message}"
|
186
77
|
end
|
187
78
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
end
|
193
|
-
|
194
|
-
private
|
195
|
-
def self.render_bank_list_item(bank)
|
196
|
-
bank_klass=Object.const_get("Parsbank::#{bank.capitalize}")
|
197
|
-
status, headers, body = bank_klass.logo rescue nil
|
198
|
-
<<~HTML
|
199
|
-
<li class='parsbank_radio_wrapper #{bank}_wrapper'>
|
200
|
-
|
201
|
-
<input type='radio' id='#{bank}' name='bank' value='#{bank}' />
|
202
|
-
<label for='#{bank}'>#{File.read(body) rescue ''} #{bank.upcase}</label>
|
203
|
-
</li>
|
204
|
-
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
|
205
83
|
end
|
206
|
-
|
207
84
|
end
|
85
|
+
|
86
|
+
Parsbank.initialize_in_rails
|
data/lib/psp.json
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
{
|
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"]
|
83
|
+
}
|
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>
|