safecharge 0.0.3

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ff76ed515bb382871847edfff75a3338adb50cbe
4
+ data.tar.gz: 1abce3e38d9783c534ae44b8a511768f4a44ba0b
5
+ SHA512:
6
+ metadata.gz: 207c9507b761fd53c213796c29bef229582d769c283bb162952c8798dde2707a0308fd8386f2f31637bfd1bb49ae33d34dc46355b0fda5f2d1f3770b1a296b68
7
+ data.tar.gz: d1204ea21290be3e93365297a2bc23f251884e52e3274f2024c3c9899d10341be942b8cadf0495d7b7b45a327df6e30a5a95536a58c8b4e5592c16f8b6f65e65
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in safecharge.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Interactive Gaming Entertainment Pty Ltd
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # Safecharge
2
+
3
+ A simple Ruby wrapper for the SafeCharge PPP Payment API v 3.0.0 (Revised July 2011), as well as
4
+ the SafeCharge Web Cashier API v1.0 (Revised July 2013).
5
+
6
+ ## Status
7
+
8
+ This project is under active development right now, and not suitable for use.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'safecharge'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install safecharge
23
+
24
+ ## Usage
25
+
26
+ ### Public Payment Page
27
+
28
+ The SafeCharge PPP system provides a simple means for merchants to integrate credit card
29
+ payments into their site, without worrying about having to capture their customers'
30
+ credit card details.
31
+
32
+ It works like this:
33
+
34
+ Step 1) Your website provides a way for customers to choose the items they wish to buy,
35
+ say via a shopping basket, or similar.
36
+
37
+ Collate an array of items with the following information
38
+
39
+ items = [
40
+ {
41
+ 'name' => 'bat',
42
+ 'number' => 'sku54321',
43
+ 'amount' => 25,
44
+ 'quantity' => 1
45
+ },
46
+ {
47
+ 'name' => 'ball',
48
+ 'number' => 'sku12345',
49
+ 'amount' => 15,
50
+ 'quantity' => 2
51
+ }
52
+ ]
53
+
54
+ and insert that items array into an array of params like so
55
+
56
+ params = {
57
+ 'total_amount' => 55,
58
+ 'currency' => 'USD',
59
+ 'items' => items
60
+ }
61
+
62
+ Note you must supply the following environment variables for this API to work.
63
+
64
+ SAFECHARGE_SECRET_KEY, SAFECHARGE_MERCHANT_ID, SAFECHARGE_MERCHANT_SITE_ID
65
+
66
+ These will have been provided to you by Safecharge.
67
+
68
+ Step 2) You offer a `checkout` button that links to the following url.
69
+
70
+ `url = Safecharge.request_url(params)`
71
+
72
+ Step 3) The SafeCharge system will redirect the user to the Public Payment Page
73
+ and there they will enter in their credit card and other payment details as needed.
74
+ When the user confirms their payment, the Safecharge system authenticates it and
75
+ redirects the user to either a 'success', 'failure' or 'back' page. The back page
76
+ is used if the user suspends the payment processing by clicking on their browser's
77
+ back button.
78
+
79
+ ### Web Cashier
80
+
81
+ The Safecharge Web Cashier extends the standard Public Payment Page with paramaters that
82
+ allow you to register and identify customers in SafeCharge's system, and enable you to
83
+ change the deposit amounts within limits you define.
84
+
85
+ It works like this:
86
+
87
+ Step 1) Your website provides a way for customers to choose the items they wish to buy,
88
+ say via a shopping basket, or similar.
89
+
90
+ Collate an array of items with the following information
91
+
92
+ items = [
93
+ {
94
+ 'name' => 'deposit',
95
+ 'number' => 'something',
96
+ 'amount' => 0,
97
+ 'quantity' => 1,
98
+ 'open_amount' => 'true',
99
+ 'min_amount' => 10.0,
100
+ 'max_amount' => 1000.0,
101
+ },
102
+ ]
103
+
104
+ and insert that items array into an array of params like so
105
+
106
+ params = {
107
+ 'total_amount' => 55,
108
+ 'currency' => 'USD',
109
+ 'items' => items,
110
+ 'user_token' => 'auto', # or 'register'
111
+ 'user_token_id' => 'player_id'
112
+ }
113
+
114
+ Note you must supply the following environment variables for this API to work.
115
+
116
+ SAFECHARGE_SECRET_KEY, SAFECHARGE_MERCHANT_ID, SAFECHARGE_MERCHANT_SITE_ID
117
+
118
+ These will have been provided to you by Safecharge.
119
+
120
+ Step 2) You offer a `checkout` button that links to the following url.
121
+
122
+ `url = Safecharge.wc_request_url(params)`
123
+
124
+ Step 3) The SafeCharge system will redirect the user to the WebCashier Page
125
+ and there they will enter in their credit card and other payment details as needed.
126
+ When the user confirms their payment, the Safecharge system authenticates it and
127
+ redirects the user to either a 'success', 'failure' or 'back' page. The back page
128
+ is used if the user suspends the payment processing by clicking on their browser's
129
+ back button.
130
+
131
+ ## Contributing
132
+
133
+ 1. Fork it
134
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
135
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
136
+ 4. Push to the branch (`git push origin my-new-feature`)
137
+ 5. Create new Pull Request
data/lib/safecharge.rb ADDED
@@ -0,0 +1,147 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "safecharge/version"
5
+ require "safecharge/constants"
6
+ require "safecharge/request"
7
+ require "safecharge/wc_request"
8
+ require "safecharge/response"
9
+
10
+ # The Safecharge PPP system provides a simple means for merchants to integrate credit card
11
+ # payments into their site, without worrying about having to capture their customers'
12
+ # credit card details.
13
+ #
14
+ # It works like this:
15
+ #
16
+ # Step 1) Your website provides a way for customers to choose the items they wish to buy,
17
+ # say via a shopping basket, or similar.
18
+ #
19
+ # Collate an array of items with the following information
20
+ #
21
+ # items = [
22
+ # {
23
+ # 'name' => 'bat',
24
+ # 'number' => 'sku54321',
25
+ # 'amount' => 25,
26
+ # 'quantity' => 1
27
+ # },
28
+ # {
29
+ # 'name' => 'ball',
30
+ # 'number' => 'sku12345',
31
+ # 'amount' => 15,
32
+ # 'quantity' => 2
33
+ # }
34
+ # ]
35
+ #
36
+ # and insert that items array into an array of params like so
37
+ #
38
+ # params = {
39
+ # 'total_amount' => 55,
40
+ # 'currency' => 'USD',
41
+ # 'items' => items
42
+ # }
43
+ #
44
+ # Note you must supply the following environment variables for this API to work.
45
+ #
46
+ # SAFECHARGE_SECRET_KEY, SAFECHARGE_MERCHANT_ID, SAFECHARGE_MERCHANT_SITE_ID
47
+ #
48
+ # These will have been provided to you by Safecharge.
49
+ #
50
+ # Step 2) You offer a 'checkout' button that links to the following url.
51
+ #
52
+ # url = Safecharge.request_url(params)
53
+ #
54
+ # Step 3) The Safecharge system will redirect the user to the Public Payment Page
55
+ # and there they will enter in their credit card and other payment details as needed.
56
+ # When the user confirms their payment, the Safecharge system authenticates it and
57
+ # redirects the user to either a 'success', 'failure' or 'back' page. The back page
58
+ # is used if the user suspends the payment processing by clicking on their browser's
59
+ # back button.
60
+ # Whichever page is returned, it will incude parameters from the server
61
+ # which can be decoded into a valid Response object by your server.
62
+ #
63
+ # response = Safecharge.parse_response
64
+ #
65
+ # TODO: finish these docs
66
+ #
67
+ module Safecharge
68
+
69
+ # define errors and exceptions.
70
+ class SafechargeError < RuntimeError
71
+ end
72
+ class InternalException < SafechargeError
73
+ end
74
+ class ValidationException < SafechargeError
75
+ end
76
+
77
+ # module level method to get the redirection URL given some params.
78
+ # you must explicitly set the mode to 'live' to generate the production URL.
79
+ def self.request_url(params = {}, mode = 'test')
80
+ result = nil
81
+ url = ''
82
+ case mode
83
+ when 'test'
84
+ url = Safecharge::Constants::SERVER_TEST
85
+ when 'live'
86
+ url = Safecharge::Constants::SERVER_LIVE
87
+ else
88
+ raise ArgumentError, "Invalid request mode #{mode}"
89
+ end
90
+
91
+ begin
92
+ request = Safecharge::Request.new(url, params)
93
+ return request.full_url
94
+
95
+ rescue InternalException => e
96
+ puts "Caught Internal Exception: #{e.message}"
97
+ puts e.backtrace
98
+ raise RuntimeError, "Internal server error. Please try again later."
99
+
100
+ rescue ValidationException => e
101
+ puts "Caught Validation Exception: #{e.message}"
102
+ puts e.backtrace
103
+ raise RuntimeError, "Validation error: #{e.message} Fix your data and retry."
104
+
105
+ rescue SafechargeError => e
106
+ puts "Caught General Safecharge Error: #{e.message}"
107
+ puts e.backtrace
108
+ raise RuntimeError, "Undocumented Internal error: #{e.message}"
109
+ end
110
+ end
111
+
112
+ # module level method to get the redirection URL given some params.
113
+ # you must explicitly set the mode to 'live' to generate the production URL.
114
+ def self.wc_request_url(params = {}, mode = 'test')
115
+ result = nil
116
+ url = ''
117
+ case mode
118
+ when 'test'
119
+ url = Safecharge::Constants::SERVER_TEST
120
+ when 'live'
121
+ url = Safecharge::Constants::SERVER_LIVE
122
+ else
123
+ raise ArgumentError, "Invalid request mode #{mode}"
124
+ end
125
+
126
+ begin
127
+ request = Safecharge::WcRequest.new(url, params)
128
+ return request.full_url
129
+
130
+ rescue InternalException => e
131
+ puts "Caught Internal Exception: #{e.message}"
132
+ puts e.backtrace
133
+ raise RuntimeError, "Internal server error. Please try again later."
134
+
135
+ rescue ValidationException => e
136
+ puts "Caught Validation Exception: #{e.message}"
137
+ puts e.backtrace
138
+ raise RuntimeError, "Validation error: #{e.message} Fix your data and retry."
139
+
140
+ rescue SafechargeError => e
141
+ puts "Caught General Safecharge Error: #{e.message}"
142
+ puts e.backtrace
143
+ raise RuntimeError, "Undocumented Internal error: #{e.message}"
144
+ end
145
+ end
146
+
147
+ end
@@ -0,0 +1,44 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ module Safecharge
5
+ class Constants
6
+ API_VERSION = '3.0.0'
7
+
8
+ SERVER_TEST = ENV['SAFECHARGE_SERVER_TEST'] # provided by SafeCharge
9
+ SERVER_LIVE = ENV['SAFECHARGE_SERVER_LIVE'] # provided by SafeCharge
10
+
11
+ SECRET_KEY = ENV['SAFECHARGE_SECRET_KEY'] # provided by SafeCharge
12
+ MERCHANT_ID = ENV['SAFECHARGE_MERCHANT_ID'] # provided by SafeCharge
13
+ MERCHANT_SITE_ID = ENV['SAFECHARGE_MERCHANT_SITE_ID'] # provided by SafeCharge
14
+ MERCHANT_3D_SITE_ID = ENV['SAFECHARGE_MERCHANT_3D_SITE_ID'] # provided by SafeCharge
15
+
16
+ SG_CLIENT_PASSWORD = ENV['SAFECHARGE_SG_CLIENT_PASSWORD'] # provided by SafeCharge
17
+ SG_3D_CLIENT_PASSWORD = ENV['SAFECHARGE_SG_3D_CLIENT_PASSWORD'] # provided by SafeCharge
18
+
19
+ CPANEL_PASSWORD = ENV['SAFECHARGE_CPANEL_PASSWORD'] # provided by SafeCharge
20
+
21
+ APPROVED = 'APPROVED'
22
+ DECLINED = 'DECLINED'
23
+ ERROR = 'ERROR'
24
+ BANK_ERROR = 'BANK_ERROR'
25
+ INVALID_LOGIN = 'INVALID_LOGIN'
26
+ INVALID_IP = 'INVALID_IP'
27
+ TIMEOUT = 'TIMEOUT'
28
+ UNKNOWN_ERROR = 'UNKNOWN_ERROR'
29
+
30
+ CURRENCIES = [
31
+ 'GBP', 'EUR', 'USD', 'HKD', 'YEN', 'AUD', 'CAD',
32
+ 'NOK', 'ZAR', 'SEK', 'CHF', 'NIS', 'MXN', 'RUB'
33
+ ]
34
+ # REQUEST_TYPE_AUTH = 'Auth'
35
+ # REQUEST_TYPE_SETTLE = 'Settle'
36
+ # REQUEST_TYPE_SALE = 'Sale'
37
+ # REQUEST_TYPE_CREDIT = 'Credit'
38
+ # REQUEST_TYPE_VOID = 'Void'
39
+ # REQUEST_TYPE_AVS = 'AVSOnly'
40
+
41
+ DEFAULT_ENCODING = 'utf-8'
42
+ DEFAULT_CURRENCY_CODE = 'EUR'
43
+ end
44
+ end
@@ -0,0 +1,187 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "safecharge"
5
+ require "safecharge/constants"
6
+
7
+ module Safecharge
8
+ class Request
9
+ attr_accessor :mode, :params, :items, :url, :full_url
10
+
11
+ ALLOWED_FIELDS = {
12
+ 'currency' => {:required => true, :type => 'currency_code'},
13
+ 'customData' => {:required => false, :type => 'string', length: 255},
14
+ 'customSiteName' => {:required => false, :type => 'string', length: 50},
15
+ 'discount' => {:required => false, :type => 'currency'},
16
+ 'encoding' => {:required => false, :type => 'string', length: 20},
17
+ 'error_url' => {:required => false, :type => 'string', length: 300},
18
+ 'handling' => {:required => false, :type => 'currency'},
19
+ 'invoice_id' => {:required => false, :type => 'string', length: 400},
20
+ 'merchant_id' => {:required => true, :type => 'int'},
21
+ 'merchant_site_id' => {:required => true, :type => 'int'},
22
+ 'merchant_unique_id' => {:required => false, :type => 'string', length: 64},
23
+ 'merchantLocale' => {:required => false, :type => 'string', length: 5},
24
+ 'payment_method' => {:required => false, :type => 'string', length: 256},
25
+ 'pending_url' => {:required => false, :type => 'string', length: 300},
26
+ 'productId' => {:required => false, :type => 'string', length: 50},
27
+ 'shipping' => {:required => false, :type => 'currency'},
28
+ 'skip_billing_tab' => {:required => false, :type => 'boolstring'},
29
+ 'skip_review_tab' => {:required => false, :type => 'boolstring'},
30
+ 'success_url' => {:required => false, :type => 'string', length: 300},
31
+ 'total_amount' => {:required => true, :type => 'currency'},
32
+ 'total_tax' => {:required => false, :type => 'percent'},
33
+ 'userid' => {:required => false, :type => 'string', length: 50},
34
+ 'version' => {:required => true, :type => 'string', length: 10},
35
+ 'webMasterId' => {:required => false, :type => 'string', length: 255}
36
+
37
+ } # 'time_stamp', 'numberofitems' and 'checksum' are inserted after validation.
38
+
39
+ ALLOWED_ITEM_FIELDS = {
40
+ 'name' => {:required => true, :type => 'string', length: 400},
41
+ 'number' => {:required => true, :type => 'string', length: 400},
42
+ 'amount' => {:required => true, :type => 'currency'},
43
+ 'quantity' => {:required => true, :type => 'int'},
44
+ 'discount' => {:required => false, :type => 'percent'},
45
+ 'shipping' => {:required => false, :type => 'currency'},
46
+ 'handling' => {:required => false, :type => 'currency'}
47
+
48
+ }
49
+
50
+ DEFAULT_PARAMS = {
51
+ 'merchant_id' => Safecharge::Constants::MERCHANT_ID,
52
+ 'merchant_site_id' => Safecharge::Constants::MERCHANT_SITE_ID,
53
+ 'currency' => Safecharge::Constants::DEFAULT_CURRENCY_CODE,
54
+ 'version' => Safecharge::Constants::API_VERSION,
55
+ 'encoding' => Safecharge::Constants::DEFAULT_ENCODING
56
+ }
57
+
58
+ def initialize(url, params = {})
59
+ raise ArgumentError, "missing url" if url == nil || url.empty?
60
+ if url === Safecharge::Constants::SERVER_TEST
61
+ self.mode = 'test'
62
+ elsif url === Safecharge::Constants::SERVER_LIVE
63
+ self.mode = 'live'
64
+ else
65
+ raise ArgumentError, "invalid url #{url}"
66
+ end
67
+ self.url = url
68
+ self.full_url = url
69
+ core_params, items, extracted_items = self.extract_items(params)
70
+ raise ValidationException, "Missing array of Items." if items == nil || items.empty?
71
+ self.items = items
72
+ self.params = DEFAULT_PARAMS.merge(core_params)
73
+ self.validate_parameters(self.params)
74
+ items.each {|i| self.validate_parameters(i, self.class::ALLOWED_ITEM_FIELDS)}
75
+ self.params.merge!(extracted_items)
76
+ self.params.merge!({'numberofitems' => items.size,
77
+ 'time_stamp' => Time.now.utc.strftime("%Y-%m-%d.%H:%M:%S")})
78
+ self.params.merge!({'checksum' => calculate_checksum})
79
+ self.construct_url
80
+ end
81
+
82
+ protected
83
+
84
+ def extract_items(params)
85
+ items = params.delete('items')
86
+ return params, nil, nil if items == nil
87
+ keyed_items = {}
88
+ items.each_with_index do |item, i|
89
+ item.keys.each do |key|
90
+ new_key = "item_#{key}_#{i+1}"
91
+ keyed_items[new_key] = item[key]
92
+ end
93
+ end
94
+ return params, items, keyed_items
95
+ end
96
+
97
+ def validate_parameters(params, against = self.class::ALLOWED_FIELDS)
98
+ self.validate_fields(params, against)
99
+ self.validate_no_extra_fields(params, against)
100
+ end
101
+
102
+ def validate_fields(params, against = self.class::ALLOWED_FIELDS)
103
+ against.each do |name, meta|
104
+ required = (meta[:required] === true)
105
+ # Check that all required parameters are present
106
+ if required && !params.keys.include?(name)
107
+ raise ValidationException, "Parameter #{name} is required, but missing from #{params.keys}"
108
+ end
109
+ if params.keys.include? name
110
+ p = params[name]
111
+ if p != nil
112
+ # Check the type of the value
113
+ correct_type = false
114
+ case meta[:type]
115
+ when 'boolstring'
116
+ correct_type = p.is_a?(String) && ['True', 'False'].include?(p)
117
+ when 'string'
118
+ correct_type = p.is_a? String
119
+ raise ValidationException, sprintf("Value '%s' in field '%s' is too long.", p, name) if p.size > meta[:length]
120
+ when 'currency_code'
121
+ correct_type = p.is_a? String
122
+ when 'currency'
123
+ correct_type = p.is_a?(Float) || p.is_a?(Integer)
124
+ when 'percent'
125
+ correct_type = p.is_a?(Float) || p.is_a?(Integer)
126
+ when 'int'
127
+ correct_type = p.is_a? Integer
128
+ end
129
+
130
+ if !correct_type
131
+ raise ValidationException, sprintf("Value '%s' in field '%s' is not of expected type '%s'", p, name, meta[:type])
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ def validate_no_extra_fields(params, against = self.class::ALLOWED_FIELDS)
139
+ allowed_fields = against.keys
140
+ params.each do |key, value|
141
+ raise InternalException, "Field #{key} is not supported" if !allowed_fields.include?(key)
142
+ end
143
+ end
144
+
145
+ def calculate_checksum
146
+ codes = [Safecharge::Constants::SECRET_KEY,
147
+ self.params['merchant_id'],
148
+ self.params['currency'],
149
+ self.params['total_amount']]
150
+ self.items.each do |item|
151
+ codes << item['name']
152
+ codes << item['amount']
153
+ codes << item['quantity']
154
+ end
155
+ codes << self.params['time_stamp']
156
+ s = codes.join('')
157
+ return Digest::MD5.hexdigest(s)
158
+ end
159
+
160
+ def construct_url
161
+ uri = URI(self.url)
162
+ uri.query = URI.encode_www_form(self.params)
163
+ self.full_url = uri.to_s
164
+ return uri
165
+ end
166
+
167
+ # def calculate_item_total
168
+ # # item_amount_N - item_discount_N + item_shipping_N + item_handling_N) * item_quantity_N
169
+ # return 0.0 if self.items == nil || self.items.empty?
170
+ # result = 0
171
+ # self.items.each {|i| result += (i['amount'] +
172
+ # i['shipping'] +
173
+ # i['handling'] -
174
+ # i['discount']) * i['quantity']}
175
+ # return result
176
+ # end
177
+ #
178
+ # def calculate_total_with_tax
179
+ # # calculatedTotalAmount+=shipping+handling-discount
180
+ # tot = calculate_item_total +
181
+ # self.fields['shipping'] +
182
+ # self.fields['handling'] - self.fields['discount']
183
+ # return tot, tot * ( self.fields['total_tax'] / 100)
184
+ # end
185
+
186
+ end
187
+ end
@@ -0,0 +1,58 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "safecharge"
5
+ require "safecharge/constants"
6
+
7
+ module Safecharge
8
+ class Response
9
+ attr_accessor :params
10
+
11
+ ALLOWED_FIELDS = [
12
+ 'Status', 'totalAmount', 'TransactionID', 'ClientUniqueID', 'ErrCode',
13
+ 'ExErrCode', 'AuthCode', 'Reason', 'Token', 'ReasonCode',
14
+ 'advanceResponseChecksum', 'ECI',
15
+ 'nameOnCard', 'currency',
16
+ 'total_discount', 'total_handling', 'total_shipping', 'total_tax',
17
+ 'customData', 'merchant_unique_id', 'merchant_site_id',
18
+ 'requestVersion', 'message', 'Error', 'PPP_TransactionID', 'UserID',
19
+ 'ProductID', 'ppp_status', 'merchantLocale', 'unknownParameters', 'webMasterId'
20
+ ]
21
+
22
+ def initialize(incoming_encoded_params = nil)
23
+ self.params = self.decode(incoming_encoded_params)
24
+ end
25
+
26
+ def decode(param_string)
27
+ #todo write this.
28
+ return {}
29
+ end
30
+
31
+ def self.code(err, exerr)
32
+ return Safecharge::Constants::APPROVED if err == 0 && exerr == 0
33
+ return Safecharge::Constants::DECLINED if err == -1 && exerr == 0
34
+ # pending? see p 22 of the spec
35
+ return Safecharge::Constants::ERROR if err == -1100 && exerr > 0
36
+ # could be more specific. see p 22 of the spec for exerr codes
37
+ return Safecharge::Constants::BANK_ERROR if err < 0 && exerr != 0
38
+ return Safecharge::Constants::INVALID_LOGIN if err == -1001
39
+ return Safecharge::Constants::INVALID_IP if err == -1005
40
+ return Safecharge::Constants::TIMEOUT if err == -1203
41
+ return Safecharge::Constants::UNKNOWN_ERROR
42
+ end
43
+
44
+ protected
45
+
46
+ def calculate_checksum
47
+ codes = [Safecharge::Constants::SECRET_KEY,
48
+ self.params['totalAmount'],
49
+ self.params['currency'],
50
+ self.params['responseTimeStamp'],
51
+ self.params['PPP_TransactionID'],
52
+ self.params['Status'],
53
+ self.params['productId']]
54
+ s = codes.join('')
55
+ return Digest::MD5.hexdigest(s)
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,6 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ module Safecharge
5
+ VERSION = "0.0.3"
6
+ end
@@ -0,0 +1,79 @@
1
+ #!/user/bin/env ruby
2
+ #coding: utf-8
3
+
4
+ require "safecharge"
5
+ require "safecharge/constants"
6
+
7
+ module Safecharge
8
+ class WcRequest < Request
9
+
10
+ ALLOWED_FIELDS = {
11
+ 'currency' => {:required => true, :type => 'currency_code'},
12
+ 'customData' => {:required => false, :type => 'string', length: 255},
13
+ 'customSiteName' => {:required => false, :type => 'string', length: 50},
14
+ 'discount' => {:required => false, :type => 'currency'},
15
+ 'encoding' => {:required => false, :type => 'string', length: 20},
16
+ 'error_url' => {:required => false, :type => 'string', length: 300},
17
+ 'handling' => {:required => false, :type => 'currency'},
18
+ 'invoice_id' => {:required => false, :type => 'string', length: 400},
19
+ 'merchant_id' => {:required => true, :type => 'int'},
20
+ 'merchant_site_id' => {:required => true, :type => 'int'},
21
+ 'merchant_unique_id' => {:required => false, :type => 'string', length: 64},
22
+ 'merchantLocale' => {:required => false, :type => 'string', length: 5},
23
+ 'payment_method' => {:required => false, :type => 'string', length: 256},
24
+ 'pending_url' => {:required => false, :type => 'string', length: 300},
25
+ 'productId' => {:required => false, :type => 'string', length: 50},
26
+ 'shipping' => {:required => false, :type => 'currency'},
27
+ 'skip_billing_tab' => {:required => false, :type => 'boolstring'},
28
+ 'skip_review_tab' => {:required => false, :type => 'boolstring'},
29
+ 'success_url' => {:required => false, :type => 'string', length: 300},
30
+ 'total_amount' => {:required => true, :type => 'currency'},
31
+ 'total_tax' => {:required => false, :type => 'percent'},
32
+ 'userid' => {:required => false, :type => 'string', length: 50},
33
+ 'version' => {:required => true, :type => 'string', length: 10},
34
+ 'webMasterId' => {:required => false, :type => 'string', length: 255},
35
+ 'user_token' => {:required => false, :type => 'string', length: 8}, # register or auto
36
+ 'user_token_id' => {:required => true, :type => 'string', length: 45}
37
+
38
+ } # 'time_stamp', 'numberofitems' and 'checksum' are inserted after validation.
39
+
40
+ ALLOWED_ITEM_FIELDS = {
41
+ 'name' => {:required => true, :type => 'string', length: 400},
42
+ 'number' => {:required => true, :type => 'string', length: 400},
43
+ 'amount' => {:required => true, :type => 'currency'},
44
+ 'quantity' => {:required => true, :type => 'int'},
45
+ 'discount' => {:required => false, :type => 'percent'},
46
+ 'shipping' => {:required => false, :type => 'currency'},
47
+ 'handling' => {:required => false, :type => 'currency'},
48
+ 'open_amount' => {:required => false, :type => 'boolstring'},
49
+ 'min_amount' => {:required => false, :type => 'currency'},
50
+ 'max_amount' => {:required => false, :type => 'currency'}
51
+ }
52
+
53
+ def initialize(url, params = {})
54
+ super(url, params)
55
+ end
56
+
57
+ protected
58
+
59
+ def calculate_checksum
60
+ codes = [Safecharge::Constants::SECRET_KEY,
61
+ self.params['merchant_id'],
62
+ self.params['currency'],
63
+ self.params['total_amount']]
64
+ self.items.each do |item|
65
+ codes << item['name']
66
+ codes << item['amount']
67
+ codes << item['quantity']
68
+ codes << item['open_amount']
69
+ codes << item['min_amount']
70
+ codes << item['max_amount']
71
+ end
72
+ codes << self.params['user_token_id']
73
+ codes << self.params['time_stamp']
74
+ s = codes.join('')
75
+ return Digest::MD5.hexdigest(s)
76
+ end
77
+
78
+ end
79
+ end
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'safecharge/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "safecharge"
8
+ spec.version = Safecharge::VERSION
9
+ spec.authors = ["Dave Sag"]
10
+ spec.email = ["davesag@gmail.com"]
11
+ spec.description = "Implements all of the features of the SafeCharge API."
12
+ spec.summary = "A Ruby Wrapper for the SafeCharge API"
13
+ spec.homepage = "http://cv.davesag.com/"
14
+ spec.license = "MIT"
15
+ spec.date = Time.now.utc.strftime("%Y-%m-%d")
16
+
17
+ spec.files = `git ls-files`.split($/) - %w(.rspec .gitignore Rakefile) - `git ls-files test_data`.split($/) - `git ls-files spec`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ # spec.add_dependency "ox", "~> 2.0.5"
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ spec.add_development_dependency "rspec", "~> 2.6"
26
+ spec.add_development_dependency "dotenv"
27
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: safecharge
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ platform: ruby
6
+ authors:
7
+ - Dave Sag
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-09-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '2.6'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '2.6'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dotenv
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Implements all of the features of the SafeCharge API.
70
+ email:
71
+ - davesag@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - Gemfile
77
+ - LICENSE.txt
78
+ - README.md
79
+ - lib/safecharge.rb
80
+ - lib/safecharge/constants.rb
81
+ - lib/safecharge/request.rb
82
+ - lib/safecharge/response.rb
83
+ - lib/safecharge/version.rb
84
+ - lib/safecharge/wc_request.rb
85
+ - safecharge.gemspec
86
+ homepage: http://cv.davesag.com/
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ post_install_message:
91
+ rdoc_options: []
92
+ require_paths:
93
+ - lib
94
+ required_ruby_version: !ruby/object:Gem::Requirement
95
+ requirements:
96
+ - - '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ required_rubygems_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ requirements: []
105
+ rubyforge_project:
106
+ rubygems_version: 2.0.7
107
+ signing_key:
108
+ specification_version: 4
109
+ summary: A Ruby Wrapper for the SafeCharge API
110
+ test_files: []