zipMoney 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +4 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +287 -0
- data/Rakefile +13 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/zipMoney.rb +54 -0
- data/lib/zipMoney/api.rb +192 -0
- data/lib/zipMoney/api/cancel.rb +44 -0
- data/lib/zipMoney/api/capture.rb +44 -0
- data/lib/zipMoney/api/checkout.rb +52 -0
- data/lib/zipMoney/api/configure.rb +34 -0
- data/lib/zipMoney/api/query.rb +43 -0
- data/lib/zipMoney/api/quote.rb +54 -0
- data/lib/zipMoney/api/refund.rb +46 -0
- data/lib/zipMoney/api/settings.rb +16 -0
- data/lib/zipMoney/configuration.rb +49 -0
- data/lib/zipMoney/errors.rb +11 -0
- data/lib/zipMoney/express.rb +65 -0
- data/lib/zipMoney/request.rb +22 -0
- data/lib/zipMoney/resources.rb +71 -0
- data/lib/zipMoney/response.rb +68 -0
- data/lib/zipMoney/util.rb +53 -0
- data/lib/zipMoney/version.rb +3 -0
- data/lib/zipMoney/webhook.rb +67 -0
- data/zipMoney.gemspec +37 -0
- metadata +145 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Refund
|
3
|
+
include Request
|
4
|
+
|
5
|
+
attr_accessor :params
|
6
|
+
|
7
|
+
Struct.new("RefundParams", :reason, :refund_amount, :txn_id, :order_id, :quote_id, :order, :reference, :version, :metadata, :merchant_id, :merchant_key)
|
8
|
+
|
9
|
+
# Initializes a ZipMoney::Refund object
|
10
|
+
#
|
11
|
+
# Returns ZipMoney::Refund object
|
12
|
+
def initialize
|
13
|
+
@params = Struct::RefundParams.new
|
14
|
+
@params.order = Struct::Order.new
|
15
|
+
@params.metadata = Struct::Metadata.new
|
16
|
+
@params.version = Struct::Version.new
|
17
|
+
@params.order.detail = Array.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Performs the Refund api call on zipMoney endpoint
|
21
|
+
#
|
22
|
+
# Returns ZipMoney::Refund object
|
23
|
+
def do
|
24
|
+
validate
|
25
|
+
ZipMoney.api.refund(@params)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Performs the parameters validation
|
29
|
+
def validate
|
30
|
+
raise ArgumentError, "Params emtpy" if @params.nil?
|
31
|
+
@errors = []
|
32
|
+
@errors << 'reason must be provided' if @params.reason.nil?
|
33
|
+
@errors << 'refund_amount must be provided' if @params.refund_amount.nil?
|
34
|
+
@errors << 'txn_id must be provided' if @params.txn_id.nil?
|
35
|
+
@errors << 'order.id must be provided' if @params.order.id.nil?
|
36
|
+
@errors << 'order.total must be provided' if @params.order.total.nil?
|
37
|
+
@errors << 'order.shipping_value must be provided' if @params.order.shipping_value.nil?
|
38
|
+
@errors << 'order.tax must be provided' if @params.order.tax.nil?
|
39
|
+
@errors << 'order detail must be provided' if @params.order.detail.nil?
|
40
|
+
|
41
|
+
validate_item_details @params.order.detail
|
42
|
+
|
43
|
+
raise ZipMoney::RequestError.new("Following error(s) occurred while making request, please resolve them to make the request: #{@errors}") if @errors.any?
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Settings
|
3
|
+
include Request
|
4
|
+
|
5
|
+
attr_accessor :params
|
6
|
+
|
7
|
+
Struct.new("SettingsParams", :merchant_id, :merchant_key, :version, :metadata)
|
8
|
+
|
9
|
+
# Performs the Checkout api call on zipMoney endpoint
|
10
|
+
#
|
11
|
+
# Returns ZipMoney::Checkout object
|
12
|
+
def do
|
13
|
+
ZipMoney.api.settings()
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Configuration
|
3
|
+
|
4
|
+
API_VERSION = "1.0.1"
|
5
|
+
API_PLATFORM = "ruby"
|
6
|
+
API_NAME = "zipMoney Ruby SDK"
|
7
|
+
|
8
|
+
ENV_LIVE_API_URL = "https://api.zipmoney.com.au/v1/"
|
9
|
+
ENV_TEST_API_URL = "https://api.sandbox.zipmoney.com.au/v1/"
|
10
|
+
|
11
|
+
ATTRIBUTES = [
|
12
|
+
:merchant_id,
|
13
|
+
:merchant_key,
|
14
|
+
:environment,
|
15
|
+
]
|
16
|
+
|
17
|
+
attr_accessor *ATTRIBUTES
|
18
|
+
|
19
|
+
class << self
|
20
|
+
attr_accessor *ATTRIBUTES
|
21
|
+
|
22
|
+
# Checks if passed value is valid and assigns it true
|
23
|
+
#
|
24
|
+
# @param [env] Environment sandbox|live
|
25
|
+
#
|
26
|
+
# @return true|false
|
27
|
+
def environment=(env)
|
28
|
+
env = env.to_sym
|
29
|
+
raise ArgumentError, "#{env.inspect} is not a valid environment" unless [:sandbox, :live].include?(env)
|
30
|
+
@environment = env
|
31
|
+
end
|
32
|
+
|
33
|
+
# Checks if environment is sandbox
|
34
|
+
#
|
35
|
+
# @return true|false
|
36
|
+
def is_sandbox
|
37
|
+
environment.to_s == "sandbox"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Checks if passed merchant_id and merchant_key match with the one provided during setup
|
41
|
+
#
|
42
|
+
# @param [merchant_id] Merchant Id
|
43
|
+
# @param [merchant_key] Merchant Key
|
44
|
+
def credentials_valid(merchant_id,merchant_key)
|
45
|
+
raise ExpressError, "Invalid merchant credentials in the request" unless @merchant_id.to_i.eql?(merchant_id.to_i) && @merchant_key.to_s.eql?(merchant_key.to_s)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class ApiError < StandardError; end
|
3
|
+
class InvalidArgumentError < StandardError; end
|
4
|
+
class RequestError < StandardError; end
|
5
|
+
class ResponseError < StandardError; end
|
6
|
+
class WebHookError < StandardError; end
|
7
|
+
class WebHookRequestError < StandardError; end
|
8
|
+
class ExpressError < StandardError; end
|
9
|
+
class ExpressRequestError < StandardError; end
|
10
|
+
class ExpressResponseError < StandardError; end
|
11
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
module Express
|
3
|
+
attr_accessor :merchant_id, :merchant_key
|
4
|
+
|
5
|
+
ACTION_GET_QUOTE_DETAILS = 'quotedetails';
|
6
|
+
ACTION_GET_SHIPPING_METHODS = 'shippingmethods';
|
7
|
+
ACTION_CONFIRM_SHIPPING_METHOD = 'confirmshippingmethod';
|
8
|
+
ACTION_CONFIRM_ORDER = 'confirmorder';
|
9
|
+
ACTION_FINALISE_ORDER = 'finaliseorder';
|
10
|
+
ACTION_CANCEL_QUOTE = 'cancelquote';
|
11
|
+
|
12
|
+
# Process the express checkout action
|
13
|
+
#
|
14
|
+
# @param [action] Action
|
15
|
+
# @param [request] Express checkout request
|
16
|
+
# @param [block] Actions to be taken for respective actions
|
17
|
+
#
|
18
|
+
# Returns the response to the zipMoney Express Api
|
19
|
+
def self.process(action, request, &block)
|
20
|
+
raise ExpressRequestError, "Action empty" if action.nil?
|
21
|
+
raise ExpressRequestError, "Request empty" if request.nil?
|
22
|
+
request = Util.json_parse(request)
|
23
|
+
Configuration.credentials_valid(request["merchant_id"], request["merchant_key"])
|
24
|
+
if (block.arity > 0)
|
25
|
+
response = block.call(action, request)
|
26
|
+
raise ExpressResponseError, "No response provided" if response.nil?
|
27
|
+
puts send_response(response)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Appends api credentials to the express checkout response
|
32
|
+
#
|
33
|
+
# @param [response] response
|
34
|
+
def self.append_api_credentials(response)
|
35
|
+
response = Hash.new if !response.is_a?(Hash)
|
36
|
+
|
37
|
+
if response["merchant_id"] == nil
|
38
|
+
response["merchant_id"] = Configuration.merchant_id
|
39
|
+
end
|
40
|
+
|
41
|
+
if response["merchant_key"] == nil
|
42
|
+
response["merchant_key"] = Configuration.merchant_key
|
43
|
+
end
|
44
|
+
response
|
45
|
+
end
|
46
|
+
|
47
|
+
# Prepars the express checkout response
|
48
|
+
#
|
49
|
+
# @param [response] response
|
50
|
+
def self.prepare_response(response)
|
51
|
+
response = Util.json_parse(response)
|
52
|
+
append_api_credentials(response)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Prints the express checkout response
|
56
|
+
#
|
57
|
+
# @param [response] response
|
58
|
+
def self.send_response(response)
|
59
|
+
prepare_response(response).to_json
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
module Request
|
3
|
+
Struct.new("Order", :id, :tax, :shipping_value, :total, :detail)
|
4
|
+
Struct.new("Detail", :quantity, :name, :price, :description, :sku, :id, :category, :image_url)
|
5
|
+
Struct.new("Address",:first_name, :last_name, :line1, :line2, :country, :zip, :city, :state)
|
6
|
+
Struct.new("Consumer",:first_name, :last_name,:city, :phone, :gender, :dob, :email, :title)
|
7
|
+
Struct.new("Metadata",:order_reference, :attributes)
|
8
|
+
Struct.new("Version",:client, :platform)
|
9
|
+
Struct.new("ApiCredentials",:merchant_id, :merchant_key, :version)
|
10
|
+
|
11
|
+
attr_accessor :errors
|
12
|
+
|
13
|
+
def validate_item_details(order_items)
|
14
|
+
order_items.each_with_index do |item,index|
|
15
|
+
@errors << "order.detail[#{index}].id must be provided" if item.id.nil?
|
16
|
+
@errors << "order.detail[#{index}].name must be provided" if item.name.nil?
|
17
|
+
@errors << "order.detail[#{index}].quantity must be provided" if item.quantity.nil?
|
18
|
+
@errors << "order.detail[#{index}].price must be provided" if item.price.nil?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Resources
|
3
|
+
|
4
|
+
RESOURCE_SETTINGS = 'settings'
|
5
|
+
RESOURCE_CONFIGURE = 'configure'
|
6
|
+
RESOURCE_QUOTE = 'quote'
|
7
|
+
RESOURCE_CANCEL = 'cancel'
|
8
|
+
RESOURCE_REFUND = 'refund'
|
9
|
+
RESOURCE_CHECKOUT = 'checkout'
|
10
|
+
RESOURCE_QUERY = 'query'
|
11
|
+
RESOURCE_CAPTURE = 'capture'
|
12
|
+
RESOURCE_HEART_BEAT = 'Heartbeat'
|
13
|
+
|
14
|
+
class << self
|
15
|
+
# Checks if passed resource is valid and returns RestClient::Resource object
|
16
|
+
# configured with the passed resource and url
|
17
|
+
#
|
18
|
+
# @param [resource] endpoint resource
|
19
|
+
# @param [method] method get|post
|
20
|
+
# @param [query_string] query_string parameters
|
21
|
+
#
|
22
|
+
# @return RestClient::Resource object
|
23
|
+
def get(resource, method = :post, query_string = nil)
|
24
|
+
return false unless resource_exists(resource)
|
25
|
+
url = get_url(resource, (method == :get ? query_string : nil))
|
26
|
+
ssl_opts = {:verify_ssl => OpenSSL::SSL::VERIFY_PEER}
|
27
|
+
opts = {}
|
28
|
+
RestClient::Resource.new(url, opts.merge(ssl_opts))
|
29
|
+
end
|
30
|
+
|
31
|
+
# Checks if passed resource exists
|
32
|
+
#
|
33
|
+
# @param [resource] endpoint resource
|
34
|
+
#
|
35
|
+
# @return ZipMoney::Response object
|
36
|
+
def resource_exists(resource)
|
37
|
+
if resource.is_a?(String)
|
38
|
+
if self.constants.map{ |k| self.const_get(k).downcase }.include?resource
|
39
|
+
resource
|
40
|
+
end
|
41
|
+
else
|
42
|
+
raise ArgumentError, "#{resource} should be a string"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Builds the proper endpoint url with the given resource
|
47
|
+
#
|
48
|
+
# @param [resource] endpoint resource
|
49
|
+
# @param [query_string] query_string parameters
|
50
|
+
#
|
51
|
+
# @return String
|
52
|
+
def get_url(resource, query_string = nil)
|
53
|
+
if Configuration.is_sandbox
|
54
|
+
url = "#{Configuration::ENV_TEST_API_URL}"
|
55
|
+
else
|
56
|
+
url = "#{Configuration::ENV_LIVE_API_URL}"
|
57
|
+
end
|
58
|
+
|
59
|
+
url = url + resource
|
60
|
+
|
61
|
+
unless query_string.nil?
|
62
|
+
url = url + "?" +
|
63
|
+
query_string.map do |key, value|
|
64
|
+
"#{key}=#{value}"
|
65
|
+
end.join("&")
|
66
|
+
end
|
67
|
+
url
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Response
|
3
|
+
|
4
|
+
attr_accessor :_response , :_responseBody, :_responseHeader, :_statusCode
|
5
|
+
|
6
|
+
# Initializes a new api response object
|
7
|
+
#
|
8
|
+
# @param [response] response
|
9
|
+
#
|
10
|
+
# @return ZipMoney::Response object
|
11
|
+
def initialize(response)
|
12
|
+
raise ArgumentError, "Response doesnot exist" if ((response.nil? || response.empty?) && response.code.nil? && response.code.empty?)
|
13
|
+
@_response = response
|
14
|
+
@_statusCode = response.code
|
15
|
+
@_responseBody = response.body
|
16
|
+
end
|
17
|
+
|
18
|
+
# Converts the response body to Hash
|
19
|
+
#
|
20
|
+
# @return Hash
|
21
|
+
def toHash
|
22
|
+
raise ResponseError, "Response body doesnot exist" if @_responseBody.nil? || @_responseBody.empty?
|
23
|
+
JSON.parse(@_responseBody)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Converts the response body to Object
|
27
|
+
#
|
28
|
+
# @return OpenStruct
|
29
|
+
def toObject
|
30
|
+
raise ResponseError, "Response body doesnot exist" if @_responseBody.nil? || @_responseBody.empty?
|
31
|
+
responseObject = JSON.parse(@_responseBody, object_class: OpenStruct)
|
32
|
+
responseObject
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the redirect_url from the checkout and quote calls
|
36
|
+
#
|
37
|
+
# @return String
|
38
|
+
def getRedirectUrl
|
39
|
+
raise ArgumentError, "Response body doesnot exist" if @_responseBody.nil? || @_responseBody.empty?
|
40
|
+
resObj = toObject
|
41
|
+
return false if resObj.redirect_url.nil? || resObj.redirect_url.empty?
|
42
|
+
resObj.redirect_url
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the http status code
|
46
|
+
#
|
47
|
+
# @return Int
|
48
|
+
def getStatusCode
|
49
|
+
@_statusCode
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns if the api call was a success or failure
|
53
|
+
#
|
54
|
+
# @return true|false
|
55
|
+
def isSuccess
|
56
|
+
return @_statusCode == 200 || @_statusCode == 201? true : false
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns error string
|
60
|
+
#
|
61
|
+
# @return String
|
62
|
+
def getError
|
63
|
+
raise ArgumentError, "Response body doesnot exist" if @_responseBody.nil? || @_responseBody.empty?
|
64
|
+
resObj = toObject
|
65
|
+
resObj.Message
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
class Util
|
3
|
+
class << self
|
4
|
+
|
5
|
+
# Converts Struct objects to Hash
|
6
|
+
#
|
7
|
+
# @param [object] Struct Object
|
8
|
+
#
|
9
|
+
# @return Hash
|
10
|
+
def struct_to_hash(object)
|
11
|
+
hash = {}
|
12
|
+
object.to_h.each do |k,v|
|
13
|
+
if v.is_a?(Struct)
|
14
|
+
v = struct_to_hash(v)
|
15
|
+
hash[k] = v unless v.empty?
|
16
|
+
elsif v.is_a?(Array)
|
17
|
+
|
18
|
+
a = Array.new
|
19
|
+
v.each_with_index do |k1,v1|
|
20
|
+
v2 = struct_to_hash(k1)
|
21
|
+
a[v1] = v2 unless v2.empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
hash[k] = a
|
25
|
+
else
|
26
|
+
hash[k] = v unless v.nil?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
hash
|
30
|
+
end
|
31
|
+
|
32
|
+
# Converts Hash|Struct|OpenStruct objects to Hash
|
33
|
+
#
|
34
|
+
# @param [data] Json String
|
35
|
+
#
|
36
|
+
# @return data
|
37
|
+
def json_parse(data)
|
38
|
+
begin
|
39
|
+
data = JSON.parse(data)
|
40
|
+
rescue TypeError => e
|
41
|
+
if !data.is_a?(Hash) && !data.is_a?(Struct) && !data.is_a?(OpenStruct)
|
42
|
+
raise ArgumentError, "Invalid params provided"
|
43
|
+
end
|
44
|
+
rescue JSON::ParserError => e
|
45
|
+
if !data.is_a?(Hash) && !data.is_a?(Struct) && !data.is_a?(OpenStruct)
|
46
|
+
raise ArgumentError, "Invalid params provided"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
data
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module ZipMoney
|
2
|
+
module WebHook
|
3
|
+
attr_accessor :merchant_id, :merchant_key
|
4
|
+
|
5
|
+
EVENT_AUTH_SUCCESS = "authorise_succeeded"
|
6
|
+
EVENT_AUTH_FAIL = "authorise_failed"
|
7
|
+
EVENT_AUTH_REVIEW = "authorise_under_review"
|
8
|
+
EVENT_AUTH_DECLINED = "authorise_declined"
|
9
|
+
EVENT_CANCEL_SUCCESS = "cancel_succeeded"
|
10
|
+
EVENT_CANCEL_FAIL = "cancel_failed"
|
11
|
+
EVENT_CAPTURE_SUCCESS = "capture_succeeded"
|
12
|
+
EVENT_CAPTURE_FAIL = "capture_failed"
|
13
|
+
EVENT_REFUND_SUCCESS = "refund_succeeded"
|
14
|
+
EVENT_REFUND_FAIL = "refund_failed"
|
15
|
+
EVENT_ORDER_CANCELLED = "order_cancelled"
|
16
|
+
EVENT_CHARGE_SUCCESS = "charge_succeeded"
|
17
|
+
EVENT_CHARGE_FAIL = "charge_failed"
|
18
|
+
EVENT_CONFIG_UPDATE = "configuration_updated"
|
19
|
+
|
20
|
+
TYPE_SUBSCRIPTION_CONFIRMATION = "SubscriptionConfirmation"
|
21
|
+
TYPE_NOTIFICATION = "Notification"
|
22
|
+
|
23
|
+
# Process the webhook
|
24
|
+
#
|
25
|
+
# @param [request] WebHook's request
|
26
|
+
# @param [block] Actions to be taken for respective notifications
|
27
|
+
def self.process(request,&block)
|
28
|
+
raise WebHookRequestError, "Payload emtpy" if request.nil?
|
29
|
+
request = Util.json_parse(request)
|
30
|
+
if request["Type"] == TYPE_SUBSCRIPTION_CONFIRMATION
|
31
|
+
subscribe(request["SubscribeURL"])
|
32
|
+
elsif request["Type"] == TYPE_NOTIFICATION
|
33
|
+
process_notifications(request, &block)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# Process the webhook notifications
|
38
|
+
#
|
39
|
+
# @param [request] WebHook's request
|
40
|
+
# @param [block] Actions to be taken for respective notifications
|
41
|
+
def self.process_notifications(request, &block)
|
42
|
+
raise ArgumentError, "Invalid params provided" if request["Message"].nil?
|
43
|
+
message = Util.json_parse(request["Message"])
|
44
|
+
Configuration.credentials_valid(message["response"]["merchant_id"], message["response"]["merchant_key"])
|
45
|
+
raise ArgumentError, "Response empty" if message["response"].nil?
|
46
|
+
|
47
|
+
if (block.arity > 0)
|
48
|
+
block.call(message['type'], message["response"])
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Subscribes for the webhook notifications by calling the subscription url
|
53
|
+
#
|
54
|
+
# @param [request] WebHook's request
|
55
|
+
# @param [block] Actions to be taken for respective notifications
|
56
|
+
def self.subscribe(url)
|
57
|
+
raise WebHookError, "Url emtpy" if url.nil?
|
58
|
+
|
59
|
+
begin
|
60
|
+
response = RestClient.get(url)
|
61
|
+
rescue
|
62
|
+
raise WebHookError, "Unable to reach the subscription url #{url}" if response.nil?
|
63
|
+
end
|
64
|
+
response.code == 200 || response.code == 201
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|