apruve 0.9.0

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.
@@ -0,0 +1,116 @@
1
+ module Apruve
2
+
3
+ # Custom error class for rescuing from all API response-related Apruve errors
4
+ class Error < ::StandardError
5
+ attr_reader :response
6
+
7
+ # @param [Hash] response the decoded json response body
8
+ def initialize(response=nil)
9
+ @response = response
10
+ unless response.nil?
11
+ super error_message
12
+ # super 'Error!'
13
+ end
14
+ end
15
+
16
+ # @return [Hash]
17
+ def body
18
+ @body ||= begin
19
+ return {} unless response[:body]
20
+ Utils.indifferent_read_access(response[:body])
21
+ end
22
+ end
23
+
24
+ def error_message
25
+ # set_attrs
26
+ errors = body.fetch('errors', nil)
27
+ unless errors.nil?
28
+ error = errors[0][:error]
29
+ extra = error[:message] ? " -- #{error[:message]}" : ""
30
+ "#{self.class.name}(#{response[:status]}):: "\
31
+ "#{response[:method].to_s.upcase} #{response[:url].to_s}: "\
32
+ "#{error[:description]} #{extra}"
33
+ end
34
+ end
35
+ end
36
+
37
+ # General error class for non API response exceptions
38
+ class StandardError < Error
39
+ attr_reader :message
40
+ alias :error_message :message
41
+
42
+ # @param [String, nil] message a description of the exception
43
+ def initialize(message = nil)
44
+ @message = message
45
+ super(message)
46
+ end
47
+ end
48
+
49
+ # Raised when Apruve returns a 400 HTTP status code
50
+ class BadRequest < Error;
51
+ end
52
+
53
+ # Raised when Apruve returns a 401 HTTP status code
54
+ class Unauthorized < Error;
55
+ end
56
+
57
+ # Raised when Apruve returns a 403 HTTP status code
58
+ class Forbidden < Error;
59
+ end
60
+
61
+ # Raised when Apruve returns a 404 HTTP status code
62
+ class NotFound < Error;
63
+ end
64
+
65
+ # Raised when Apruve returns a 405 HTTP status code
66
+ class MethodNotAllowed < Error;
67
+ end
68
+
69
+ # Raised when Apruve returns a 406 HTTP status code
70
+ class AccessDenied < Error;
71
+ end
72
+
73
+ # Raised when Apruve returns a 409 HTTP status code
74
+ class Conflict < Error;
75
+ end
76
+
77
+ # Raised when Apruve returns a 410 HTTP status code
78
+ class Gone < Error;
79
+ end
80
+
81
+ # Raised when Apruve returns a 500 HTTP status code
82
+ class InternalServerError < Error;
83
+ end
84
+
85
+ # Raised when Apruve returns a 501 HTTP status code
86
+ class NotImplemented < Error;
87
+ end
88
+
89
+ # Raised when Apruve returns a 502 HTTP status code
90
+ class BadGateway < Error;
91
+ end
92
+
93
+ # Raised when Apruve returns a 503 HTTP status code
94
+ class ServiceUnavailable < Error;
95
+ end
96
+
97
+ # Raised when Apruve returns a 504 HTTP status code
98
+ class GatewayTimeout < Error;
99
+ end
100
+
101
+ # Raised when cannot connect to Apruve
102
+ class ServiceUnreachable < Error;
103
+ end
104
+
105
+ # Raised when we get a Faraday::ParseError
106
+ class ResponseUnreadable < Error;
107
+ end
108
+
109
+ # Raised when we haven't a clue
110
+ class UnknownError < Error;
111
+ end
112
+
113
+
114
+ # custom mapped exceptions
115
+ # class ValidationError < Error; end
116
+ end
@@ -0,0 +1,16 @@
1
+ module Apruve
2
+ # @api private
3
+ class FaradayErrorHandler < Faraday::Middleware
4
+ def call(env)
5
+ begin
6
+ @app.call(env)
7
+ rescue Faraday::ConnectionFailed
8
+ raise Apruve::ServiceUnreachable.new
9
+ rescue Faraday::ParsingError
10
+ raise Apruve::ResponseUnreadable.new
11
+ rescue Faraday::ClientError
12
+ raise Apruve::UnknownError.new
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ # $:.unshift(File.join(File.dirname(__FILE__), 'apruve', 'resources'))
2
+
3
+ require_relative 'resources/validation_error'
4
+ require_relative 'resources/apruve_object'
5
+ require_relative 'resources/payment_request'
6
+ require_relative 'resources/line_item'
7
+ require_relative 'resources/payment'
8
+ require_relative 'resources/payment_item'
9
+ require_relative 'resources/subscription'
10
+ require_relative 'resources/subscription_adjustment'
@@ -0,0 +1,44 @@
1
+ module Apruve
2
+ class ApruveObject
3
+ require 'json'
4
+
5
+ def initialize(args = {})
6
+ args.each do |k, v|
7
+ instance_variable_set("@#{k}".to_sym, v) unless v.nil?
8
+ end
9
+ end
10
+
11
+ def validate
12
+ # default implementation.
13
+ end
14
+
15
+ def to_hash
16
+ validate
17
+ hash = {}
18
+ instance_variables.each do |var|
19
+ if instance_variable_get(var).kind_of?(Array)
20
+ array = []
21
+ instance_variable_get(var).each { |aryvar| array.push(aryvar.to_hash) }
22
+ hash[var.to_s.delete('@')] = array
23
+ else
24
+ hash[var.to_s.delete('@')] = instance_variable_get(var)
25
+ end
26
+ end
27
+ hash.reject! { |k, v| v.nil? }
28
+ hash.reject! { |k, v| k == 'api_key' }
29
+ hash
30
+ end
31
+
32
+ def to_json(*a)
33
+ to_hash.to_json
34
+ end
35
+
36
+ def self.logger
37
+ Apruve.client.config[:logger]
38
+ end
39
+
40
+ def logger
41
+ Apruve.client.config[:logger]
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,13 @@
1
+ module Apruve
2
+ class LineItem < Apruve::ApruveObject
3
+ attr_accessor :id, :title, :amount_cents, :price_ea_cents, :quantity, :description,
4
+ :variant_info, :sku, :vendor, :view_product_url, :plan_code, :line_item_api_url,
5
+ :subscription_url
6
+
7
+ def validate
8
+ errors = []
9
+ errors << 'title must be set on line items' if title.nil?
10
+ raise Apruve::ValidationError.new(errors) if errors.length > 0
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,43 @@
1
+ module Apruve
2
+ class Payment < Apruve::ApruveObject
3
+ attr_accessor :id, :payment_request_id, :status, :status, :amount_cents, :currency, :merchant_notes,
4
+ :payment_items, :api_url, :view_url, :created_at, :updated_at
5
+
6
+ def self.find(payment_request_id, id)
7
+ response = Apruve.get("payment_requests/#{payment_request_id}/payments/#{id}")
8
+ Payment.new(response.body)
9
+ end
10
+
11
+ def initialize(params)
12
+ super
13
+ # hydrate payment items if appropriate
14
+ if @payment_items.nil?
15
+ @payment_items = []
16
+ elsif @payment_items.is_a?(Array) && @payment_items.first.is_a?(Hash)
17
+ hydrated_items = []
18
+ @payment_items.each do |item|
19
+ hydrated_items << Apruve::LineItem.new(item)
20
+ end
21
+ @payment_items = hydrated_items
22
+ end
23
+ @currency = Apruve.default_currency if currency.nil?
24
+ end
25
+
26
+ def validate
27
+ errors = []
28
+ errors << 'payment_request_id must be set' if payment_request_id.nil?
29
+ errors << 'amount_cents must be set' if amount_cents.nil?
30
+ raise Apruve::ValidationError.new(errors) if errors.length > 0
31
+ end
32
+
33
+ def save!
34
+ validate
35
+ response = Apruve.post("payment_requests/#{self.payment_request_id}/payments", self.to_json)
36
+ self.id = response.body['id']
37
+ self.status = response.body['status']
38
+ self.api_url = response.body['api_url']
39
+ self.view_url = response.body['view_url']
40
+ self.status
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,7 @@
1
+ module Apruve
2
+ class PaymentItem < Apruve::ApruveObject
3
+ attr_accessor :title, :amount_cents, :price_ea_cents, :quantity, :description, :variant_info, :sku,
4
+ :vendor, :view_product_url
5
+
6
+ end
7
+ end
@@ -0,0 +1,60 @@
1
+ module Apruve
2
+ class PaymentRequest < Apruve::ApruveObject
3
+ attr_accessor :id, :merchant_id, :merchant_order_id, :status, :amount_cents, :tax_cents,
4
+ :shipping_cents, :line_items, :api_url, :view_url, :created_at, :updated_at
5
+
6
+ def self.find(id)
7
+ response = Apruve.get("payment_requests/#{id}")
8
+ logger.debug response.body
9
+ PaymentRequest.new(response.body)
10
+ end
11
+
12
+ def self.finalize!(id)
13
+ response = Apruve.post("payment_requests/#{id}/finalize")
14
+ logger.debug response.body
15
+ response.body
16
+ end
17
+
18
+ def initialize(params)
19
+ super
20
+ # hydrate line items if appropriate
21
+ if @line_items.nil?
22
+ @line_items = []
23
+ elsif @line_items.is_a?(Array) && @line_items.first.is_a?(Hash)
24
+ hydrated_items = []
25
+ @line_items.each do |item|
26
+ hydrated_items << Apruve::LineItem.new(item)
27
+ end
28
+ @line_items = hydrated_items
29
+ end
30
+ end
31
+
32
+ def validate
33
+ errors = []
34
+ errors << 'merchant_id must be set' if merchant_id.nil?
35
+ raise Apruve::ValidationError.new(errors) if errors.length > 0
36
+ end
37
+
38
+ def value_string
39
+ token_string = to_hash.map do |k, v|
40
+ str = ''
41
+ if v.kind_of?(Array)
42
+ v.each do |item|
43
+ str = str + item.map{|q,r| r}.join
44
+ end
45
+ else
46
+ str = v
47
+ end
48
+ str
49
+ end
50
+ token_string.join
51
+ end
52
+
53
+ def secure_hash
54
+ if Apruve.client.api_key.nil?
55
+ raise 'api_key has not been set. Set it with Apruve.configure(api_key, environment, options)'
56
+ end
57
+ Digest::SHA256.hexdigest(Apruve.client.api_key+value_string)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ module Apruve
2
+ class Subscription < Apruve::LineItem
3
+ attr_accessor :id, :start_at, :next_charge_at, :last_charge_at, :end_at, :canceled_at
4
+
5
+ def self.find(id)
6
+ response = Apruve.get("subscriptions/#{id}")
7
+ logger.debug response.body
8
+ Subscription.new(response.body)
9
+ end
10
+
11
+ def update!
12
+ validate
13
+ response = Apruve.put("subscriptions/#{self.id}", self.to_json)
14
+ logger.debug response.body
15
+ nil
16
+ end
17
+
18
+ def cancel!
19
+ response = Apruve.post("subscriptions/#{self.id}/cancel")
20
+ logger.debug response.body
21
+ self.canceled_at = Time.parse(response.body['canceled_at']) unless response.body['canceled_at'].nil?
22
+ self.end_at = Time.parse(response.body['end_at']) unless response.body['end_at'].nil?
23
+ nil
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,33 @@
1
+ module Apruve
2
+ class SubscriptionAdjustment < Apruve::ApruveObject
3
+ attr_accessor :id, :subscription_id, :status, :title, :amount_cents, :price_ea_cents, :quantity, :description,
4
+ :variant_info, :sku, :vendor, :view_product_url
5
+
6
+ def self.find(subscription_id, id)
7
+ response = Apruve.get("subscriptions/#{subscription_id}/adjustments/#{id}")
8
+ logger.debug response.body
9
+ SubscriptionAdjustment.new(response.body)
10
+ end
11
+
12
+ def self.find_all(subscription_id)
13
+ response = Apruve.get("subscriptions/#{subscription_id}/adjustments")
14
+ logger.debug response.body
15
+ SubscriptionAdjustment.new(response.body)
16
+ end
17
+
18
+ def save!
19
+ validate
20
+ response = Apruve.post("subscriptions/#{self.subscription_id}/adjustments", self.to_json)
21
+ self.id = response.body['id']
22
+ self.status = response.body['status']
23
+ self.api_url = response.body['api_url']
24
+ self.status
25
+ end
26
+
27
+ def delete!
28
+ response = Apruve.delete("subscriptions/#{self.subscription_id}/adjustments/#{id}")
29
+ logger.debug response.body
30
+ nil
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ module Apruve
2
+ class ValidationError < StandardError
3
+ attr_accessor :errors
4
+ def initialize(errors)
5
+ @errors = errors
6
+ end
7
+
8
+ def message
9
+ @errors.to_s
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,39 @@
1
+ require 'faraday'
2
+ require_relative '../error'
3
+
4
+ # @api private
5
+ module Faraday
6
+
7
+ class Response::RaiseApruveError < Response::Middleware
8
+
9
+ HTTP_STATUS_CODES = {
10
+ 400 => Apruve::BadRequest,
11
+ 401 => Apruve::Unauthorized,
12
+ 403 => Apruve::Forbidden,
13
+ 404 => Apruve::NotFound,
14
+ 405 => Apruve::MethodNotAllowed,
15
+ 406 => Apruve::AccessDenied,
16
+ 409 => Apruve::Conflict,
17
+ 410 => Apruve::Gone,
18
+ 500 => Apruve::InternalServerError,
19
+ 501 => Apruve::NotImplemented,
20
+ 502 => Apruve::BadGateway,
21
+ 503 => Apruve::ServiceUnavailable,
22
+ 504 => Apruve::GatewayTimeout,
23
+ }
24
+
25
+ def on_complete(response)
26
+ status_code = response[:status].to_i
27
+ # if response.key? :body and response[:body] != nil and response[:body]['errors']
28
+ # category_code = response[:body]['errors'][0]['category_code']
29
+ # else
30
+ # category_code = nil
31
+ # end
32
+ error_class = HTTP_STATUS_CODES[status_code]
33
+ # error_class = CATEGORY_CODE_MAP[category_code] || HTTP_STATUS_CODES[status_code]
34
+ raise error_class.new(response) if error_class
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,11 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware/response_middleware'
3
+
4
+ module FaradayMiddleware
5
+
6
+ class ApruveParseJson < ParseJson
7
+ define_parser do |body|
8
+ ::JSON.parse body unless body.strip.empty? || body.include?('Not Found')
9
+ end
10
+ end
11
+ end