payzilla 0.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.
Files changed (52) hide show
  1. data/.gitignore +23 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE +23 -0
  5. data/README.md +82 -0
  6. data/Rakefile +4 -0
  7. data/init.rb +1 -0
  8. data/lib/encoding/converter.rb +5 -0
  9. data/lib/payzilla/config.rb +224 -0
  10. data/lib/payzilla/gateways/akado.rb +59 -0
  11. data/lib/payzilla/gateways/beeline.rb +205 -0
  12. data/lib/payzilla/gateways/cyberplat.rb +97 -0
  13. data/lib/payzilla/gateways/dummy.rb +72 -0
  14. data/lib/payzilla/gateways/gorod.rb +80 -0
  15. data/lib/payzilla/gateways/mailru.rb +56 -0
  16. data/lib/payzilla/gateways/matrix.rb +66 -0
  17. data/lib/payzilla/gateways/megafon.rb +120 -0
  18. data/lib/payzilla/gateways/mts.rb +200 -0
  19. data/lib/payzilla/gateways/osmp.rb +85 -0
  20. data/lib/payzilla/gateways/rapida.rb +127 -0
  21. data/lib/payzilla/gateways/skylink.rb +105 -0
  22. data/lib/payzilla/gateways/webmoney.rb +102 -0
  23. data/lib/payzilla/gateways/yamoney.rb +93 -0
  24. data/lib/payzilla/gateways/yota.rb +63 -0
  25. data/lib/payzilla/gateways.rb +173 -0
  26. data/lib/payzilla/payment.rb +161 -0
  27. data/lib/payzilla/revision.rb +18 -0
  28. data/lib/payzilla/transports/http.rb +62 -0
  29. data/lib/payzilla/utils/string_file.rb +14 -0
  30. data/lib/payzilla/version.rb +3 -0
  31. data/lib/payzilla.rb +19 -0
  32. data/lib/string.rb +12 -0
  33. data/payzilla.gemspec +33 -0
  34. data/schemas/.gitkeep +0 -0
  35. data/schemas/beeline.wsdl +538 -0
  36. data/spec/lib/payzilla/gateways/akado_spec.rb +31 -0
  37. data/spec/lib/payzilla/gateways/beeline_spec.rb +52 -0
  38. data/spec/lib/payzilla/gateways/cyberplat_spec.rb +44 -0
  39. data/spec/lib/payzilla/gateways/gorod_spec.rb +36 -0
  40. data/spec/lib/payzilla/gateways/mailru_spec.rb +24 -0
  41. data/spec/lib/payzilla/gateways/matrix_spec.rb +35 -0
  42. data/spec/lib/payzilla/gateways/megafon_spec.rb +45 -0
  43. data/spec/lib/payzilla/gateways/mts_spec.rb +55 -0
  44. data/spec/lib/payzilla/gateways/osmp_spec.rb +30 -0
  45. data/spec/lib/payzilla/gateways/rapida_spec.rb +48 -0
  46. data/spec/lib/payzilla/gateways/skylink_spec.rb +39 -0
  47. data/spec/lib/payzilla/gateways/webmoney_spec.rb +38 -0
  48. data/spec/lib/payzilla/gateways/yamoney_spec.rb +31 -0
  49. data/spec/lib/payzilla/gateways/yota_spec.rb +30 -0
  50. data/spec/spec_helper.rb +9 -0
  51. data/spec/support/config_stub.rb +7 -0
  52. metadata +236 -0
@@ -0,0 +1,173 @@
1
+ require 'rexml/document'
2
+
3
+ module Payzilla
4
+ module Gateways
5
+ class Gateway
6
+ attr_accessor :config
7
+ attr_accessor :logger
8
+ attr_accessor :revision_page_size
9
+
10
+ # Creates gateway instance
11
+ #
12
+ # @param [Config] config the Payzilla::Config object
13
+ # @param [String] log path to config file
14
+ def initialize(config, log=nil)
15
+ @config = config
16
+
17
+ if defined?(Rails) && Rails.root.join('log/gateways').directory?
18
+ log ||= Rails.root.join("log/gateways/#{@config.keyword}.log")
19
+ end
20
+
21
+ if !log.respond_to?(:info)
22
+ @logger = Logger.new log.to_s, 2
23
+ @logger.level = Logger::DEBUG
24
+ @logger.level = @config.debug_level if @config.respond_to?(:debug_level)
25
+ @logger.formatter = Logger::Formatter.new
26
+ end
27
+
28
+ @revision_page_size = 5000
29
+ end
30
+
31
+ # Register some settings
32
+ #
33
+ # @param [Array] list list of strings, which are settings, defined in Payzilla::Config instance with appendix "setting_"
34
+ def self.register_settings(list)
35
+ @available_settings = list
36
+ end
37
+
38
+ # Register some attachments
39
+ #
40
+ # @param [Array] list list of strings, which are attachments, defined in Payzilla::Config instance with appendix "attachment_"
41
+ def self.register_attachments(list)
42
+ @available_attachments = list
43
+ end
44
+
45
+ # Register some switches
46
+ #
47
+ # @param [Array] list list of strings, which are switches, defined in Payzilla::Config instance with appendix "switch_"
48
+ def self.register_switches(list)
49
+ @available_switches = list
50
+ end
51
+
52
+ def self.require_payment_fields(list)
53
+ @required_payment_fields = list
54
+ end
55
+
56
+ def self.required_payment_fields
57
+ @required_payment_fields || []
58
+ end
59
+
60
+ # Show registered settings
61
+ #
62
+ # @return [Array] an array with registered settings
63
+ def self.available_settings
64
+ @available_settings || []
65
+ end
66
+
67
+ # Show registered attachments
68
+ #
69
+ # @return [Array] an array with registered attachments
70
+ def self.available_attachments
71
+ @available_attachments || []
72
+ end
73
+
74
+ # Show registered switches
75
+ #
76
+ # @return [Array] an array with registered switches
77
+ def self.available_switches
78
+ @available_switches || []
79
+ end
80
+
81
+ # Check if gateway requires revision
82
+ #
83
+ # @return [Boolean]
84
+ def requires_revision?
85
+ self.class.requires_revision?
86
+ end
87
+
88
+ # Check if gateway requires revision
89
+ #
90
+ # @return [Boolean]
91
+ def self.requires_revision?
92
+ @requires_revision == true
93
+ end
94
+
95
+ # Require gateway revision
96
+ def self.requires_revision
97
+ @requires_revision = true
98
+ end
99
+
100
+ # Check if gateway can list providers
101
+ def can_list_providers?
102
+ self.class.can_list_providers?
103
+ end
104
+
105
+ # Check if gateway can list providers
106
+ def self.can_list_providers?
107
+ @can_list_providers == true
108
+ end
109
+
110
+ # Set that Gateway can set providers
111
+ def self.can_list_providers
112
+ @can_list_providers = true
113
+ end
114
+
115
+ # Send revision to carrier
116
+ #
117
+ # @param [Revision] revision an object, created from Payzilla::Revision
118
+ # @return [String] error code
119
+ def revise(revision)
120
+ send_revision revision, generate_revision(revision)[1]
121
+ end
122
+
123
+ protected
124
+
125
+ # Paginate payments to avoid memory leaks in case of very lagre number of payments
126
+ #
127
+ # @param [Payment] payments payments, that you want to revise
128
+ # @param args that you need to generate request body
129
+ # @param block some block, that make operations with args
130
+ def paginate_payments(payments, *args, &block)
131
+ totals = {
132
+ :count => 0,
133
+ :enrolled_sum => 0,
134
+ :paid_sum => 0
135
+ }
136
+
137
+ if payments.respond_to?(:limit)
138
+ pages = (payments.count.to_f / revision_page_size.to_f).ceil
139
+
140
+ pages.times do |p|
141
+ slice = payments.offset(p*revision_page_size).limit(revision_page_size)
142
+
143
+ yield slice, *args
144
+
145
+ totals[:count] += slice.count
146
+ totals[:enrolled_sum] += slice.map{|x| x.enrolled_amount}.inject(:+)
147
+ totals[:paid_sum] += slice.map{|x| x.paid_amount}.inject(:+)
148
+ end
149
+ else
150
+ yield payments, *args
151
+
152
+ totals[:count] = payments.count
153
+ totals[:enrolled_sum] = payments.map{|x| x.enrolled_amount}.inject(:+)
154
+ totals[:paid_sum] = payments.map{|x| x.paid_amount}.inject(:+)
155
+ end
156
+
157
+ totals
158
+ end
159
+
160
+ # Generates XML dump. Usialy used for logging
161
+ #
162
+ # @param [String] text with XML response or request
163
+ # @return [String] ready to use in logging stringified XML
164
+ def dump_xml(text)
165
+ xml = ""
166
+ doc = REXML::Document.new(text)
167
+ doc.write(xml, 1)
168
+ xml = "XML DUMP\n#{'-'*30}\n#{xml}\n#{'-'*30}"
169
+ xml
170
+ end
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,161 @@
1
+ module Payzilla
2
+ class Payment
3
+
4
+ # @!attribute id
5
+ # Paymen identifier
6
+ #
7
+ # Used by:
8
+ # * Akado
9
+ # * Beeline
10
+ # * Cyberplat
11
+ # * Mailru
12
+ # * Matrix
13
+ # * Megafon
14
+ # * MTS
15
+ # * OSMP
16
+ # * Rapida
17
+ # * Skylink
18
+ # * Webmoney
19
+ # * Yamoney
20
+ # * Yota
21
+ # @note Should be unique for each paymet (For example current time plus some salt)
22
+ #
23
+ # @!attribute account
24
+ # Account, which you need to replenish
25
+ #
26
+ # Used by:
27
+ # * Akado
28
+ # * Beeline
29
+ # * Cyberplat
30
+ # * Matrix
31
+ # * Megafon
32
+ # * MTS
33
+ # * OSMP
34
+ # * Skylink
35
+ # * Yamoney
36
+ # * Yota
37
+ #
38
+ # @!attribute created_at
39
+ # Paymend creatiton date
40
+ #
41
+ # Used by:
42
+ # * Akado. Format: YYYY-MM-DD HH24:MI:SS by Moscow local time
43
+ # * Beeline
44
+ # * Matrix. Format: YYYY-MM-DD HH24:MI:SS by Moscow local time
45
+ # * Megafon
46
+ # * MTS
47
+ # * Skylink
48
+ # * Yota. Format: YYYY-MM-DDTHH24:MI:SS by Moscow local time
49
+ # @note If in this list format is missing, than you can use default DateTime.now without any formating
50
+ #
51
+ # @!attribute enrolled_amount
52
+ # Amount of money, that client will recieve
53
+ #
54
+ # Used by:
55
+ # * Akado. Format: 100.00
56
+ # * Beeline
57
+ # * Cyberplat
58
+ # * Mailru
59
+ # * Matrix
60
+ # * Megafon
61
+ # * MTS. Format: 100.00
62
+ # * OSMP
63
+ # * Rapida
64
+ # * Skylink
65
+ # * Webmoney
66
+ # * Yamoney
67
+ # @note Missing format in this list mens, that you should use integer value without coins
68
+ #
69
+ # @!attribute paid_amount
70
+ # Amount of money, that client put into kiosk
71
+ #
72
+ # Used by:
73
+ # * Beeline
74
+ # * OSMP
75
+ # * Skylink
76
+ #
77
+ # @!attribute discount_card
78
+ # Client's discount card
79
+ #
80
+ # Used by:
81
+ # * Beeline _optional_
82
+ #
83
+ # @!attribute subagent_id
84
+ # Subagent identifier
85
+ #
86
+ # Used by:
87
+ # * Beeline. _optional_
88
+ #
89
+ # @!attribute fields
90
+ # Additional params, that can be passed into payment
91
+ #
92
+ # Used by:
93
+ # * Cyberplat
94
+ # * Rapida
95
+ # * Webmoney
96
+ # * phone - account, you need to pay to
97
+ # * purse - currency
98
+ # * name - your name
99
+ # * passport_serie
100
+ # * passport_date
101
+ #
102
+ # @!attribute agent_id
103
+ # Agent identifier
104
+ #
105
+ # Used by:
106
+ # * Cyberplat
107
+ #
108
+ # @!attribute terminal_id
109
+ # Terminal identifier
110
+ #
111
+ # Used by:
112
+ # * Cyberplat
113
+ # * MTS
114
+ # * Rapida
115
+ #
116
+ # @!attribute gateway_payment_id
117
+ # Gateway payment idetifier. You can get it by parsing response of check method
118
+ #
119
+ # Used by:
120
+ # * Matrix
121
+ # * MTS
122
+ #
123
+ # @!attribute gateway_provider_id
124
+ # Gateway provider identifier
125
+ #
126
+ # Used by:
127
+ # * MTS
128
+ # * OSMP
129
+ # * Rapida
130
+ #
131
+ # @!attribute commision_amount
132
+ # Amount of commision, that would be subtracted from enrolled amount
133
+ #
134
+ # Used by:
135
+ # * Rapida
136
+ #
137
+ # @!attribute payment_type
138
+ # Chose payment type. On the left side is 'what you want', and on the right - what you should pass
139
+ # * Cash | self::TYPE_CASH
140
+ # * Inner card | self::TYPE_INNER_CARD
141
+ # * Foreign card | self::TYPE_FOREIGN_CARD
142
+ # * Bank account | self::TYPE_IBANK
143
+ # * Account | self::TYPE_ACCOUNT
144
+ attr_accessor :id, :account, :created_at, :enrolled_amount,
145
+ :paid_amount, :terminal_id, :gateway_provider_id,
146
+ :discount_card, :subagent_id, :agent_id, :fields,
147
+ :commission_amount, :payment_type
148
+
149
+ TYPE_CASH = 0
150
+ TYPE_INNER_CARD = 1
151
+ TYPE_FOREIGN_CARD = 2
152
+ TYPE_IBANK = 3
153
+ TYPE_ACCOUNT = 4
154
+
155
+ def initialize(args={})
156
+ payment_type = self::TYPE_CASH
157
+
158
+ args.each{|k,v| send "#{k}=", v}
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,18 @@
1
+ module Payzilla
2
+ class Revision
3
+
4
+ # @!attribute payments
5
+ # Array of instances of Payzilla::Payment
6
+ #
7
+ # @!attribute date
8
+ # Simple date instance, for example Date.today
9
+ #
10
+ # @!attribute id
11
+ # Some unique revision identifier
12
+ attr_accessor :payments, :date, :id
13
+
14
+ def initialize(args={})
15
+ args.each{|k,v| send "#{k}=", v}
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,62 @@
1
+ require 'rest-client'
2
+
3
+ module Payzilla
4
+ module Transports
5
+ module HTTP
6
+ # Generate new RestClient resource
7
+ #
8
+ # @param [String] url carrier's server url
9
+ # @param [Hash] attributes additional attributes such as ssl certificate and keys
10
+ # @return [RestClient::Resource] resource, where you can send payment data with GET or POST methods
11
+ def resource(url, attributes)
12
+ RestClient::Resource.new url, attributes
13
+ end
14
+
15
+ # Send data via GET method
16
+ #
17
+ # @param [String] url carrier's server url
18
+ # @param [Hash] params data, which would be sent
19
+ # @param [Hash] attributes additional attributes such as ssl certificate and keys
20
+ # @return [String] server response
21
+ def get(url, params, attributes={})
22
+ logger.info "GET #{url}: #{params.inspect}" unless logger.blank?
23
+ logger.debug attributes.inspect unless logger.blank?
24
+ resource(url, attributes).get(:params => params).to_s
25
+ end
26
+
27
+ # Send data via POST method
28
+ #
29
+ # @param [String] url carrier's server url
30
+ # @param [Hash] params data, which would be sent
31
+ # @param [Hash] attributes additional attributes such as ssl certificate and keys
32
+ # @return [String] server response
33
+ def post(url, params, attributes={}, headers={})
34
+ logger.info "POST #{url}: #{params.inspect}" unless logger.blank?
35
+ logger.debug attributes.inspect unless logger.blank?
36
+ resource(url, attributes).post(params, headers).to_s
37
+ end
38
+
39
+ # Prepare SSL data to be sent
40
+ #
41
+ # @param [File] cert certificate file, that you should use to access to secure host
42
+ # @param [File] key key file, that you need to use to access to secure host
43
+ # @param [String] password password that used to read encrypted key file
44
+ # @param [File] ca certificate authority file, if it is needed
45
+ def ssl(cert, key, password, ca=false)
46
+ ssl = {
47
+ :ssl_client_cert => OpenSSL::X509::Certificate.new(File.read cert.path),
48
+ :verify_ssl => OpenSSL::SSL::VERIFY_NONE
49
+ }
50
+
51
+ unless password.blank?
52
+ ssl[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(key.path), password)
53
+ else
54
+ ssl[:ssl_client_key] = OpenSSL::PKey::RSA.new(File.read(key.path))
55
+ end
56
+ ssl[:ssl_ca_file] = ca.path unless ca.blank?
57
+
58
+ ssl
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,14 @@
1
+ require 'stringio'
2
+
3
+ module Payzilla
4
+ module Utils
5
+ class StringFile < StringIO
6
+ attr_accessor :path
7
+
8
+ def initialize(filename, content)
9
+ self.path = filename
10
+ super content
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module Payzilla
2
+ VERSION = "0.0.2"
3
+ end
data/lib/payzilla.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'payzilla/version'
2
+ require 'payzilla/payment'
3
+ require 'payzilla/revision'
4
+ require 'payzilla/gateways'
5
+ require 'payzilla/transports/http'
6
+ require 'payzilla/utils/string_file'
7
+ require 'encoding/converter.rb' if RUBY_PLATFORM =~ /java/
8
+ require 'string.rb'
9
+
10
+ Dir["#{File.dirname(__FILE__)}/payzilla/gateways/*.rb"].each do |gateway|
11
+ begin
12
+ require gateway
13
+ rescue Exception => e
14
+ puts "WARNING: #{File.basename(gateway)} was not loaded: #{e}"
15
+ end
16
+ end
17
+
18
+ module Payzilla
19
+ end
data/lib/string.rb ADDED
@@ -0,0 +1,12 @@
1
+ String.class_eval do
2
+ # Changes case of the string into lowerCamelCase.
3
+ #
4
+ # @return [String] in lowerCamelCase style.
5
+ def lower_camelcase
6
+ str = dup
7
+ str.gsub!(/\/(.?)/) { "::#{$1.upcase}" }
8
+ str.gsub!(/(?:_+|-+)([a-z])/) { $1.upcase }
9
+ str.gsub!(/(\A|\s)([A-Z])/) { $1 + $2.downcase }
10
+ str
11
+ end
12
+ end
data/payzilla.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'payzilla/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "payzilla"
8
+ gem.version = Payzilla::VERSION
9
+ gem.authors = ["Boris Staal", "Vasilij Melnychuck"]
10
+ gem.email = ["boris@roundlake.ru", "v.melnychuck@roundlake.ru"]
11
+ gem.description = %q{Payzilla}
12
+ gem.summary = %q{Payzilla}
13
+ gem.homepage = ""
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_dependency 'rake'
21
+ gem.add_dependency 'json'
22
+ gem.add_dependency 'rest-client'
23
+ gem.add_dependency 'crack'
24
+ gem.add_dependency 'savon'
25
+ gem.add_dependency 'cyberplat_pki'
26
+ gem.add_dependency 'webmoney', '0.0.15.pre'
27
+ gem.add_dependency 'gyoku'
28
+ gem.add_dependency 'gpgme-ffi'
29
+
30
+ ['pry', 'rspec'].each do |dep|
31
+ gem.add_development_dependency(dep)
32
+ end
33
+ end
data/schemas/.gitkeep ADDED
File without changes