micah-remit 0.0.5

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 (47) hide show
  1. data/LICENSE +20 -0
  2. data/README.markdown +91 -0
  3. data/lib/remit.rb +135 -0
  4. data/lib/remit/common.rb +88 -0
  5. data/lib/remit/data_types.rb +164 -0
  6. data/lib/remit/error_codes.rb +118 -0
  7. data/lib/remit/get_pipeline.rb +189 -0
  8. data/lib/remit/ipn_request.rb +49 -0
  9. data/lib/remit/operations/cancel_subscription_and_refund.rb +23 -0
  10. data/lib/remit/operations/cancel_token.rb +18 -0
  11. data/lib/remit/operations/discard_results.rb +18 -0
  12. data/lib/remit/operations/fund_prepaid.rb +31 -0
  13. data/lib/remit/operations/get_account_activity.rb +60 -0
  14. data/lib/remit/operations/get_account_balance.rb +29 -0
  15. data/lib/remit/operations/get_all_credit_instruments.rb +18 -0
  16. data/lib/remit/operations/get_all_prepaid_instruments.rb +18 -0
  17. data/lib/remit/operations/get_debt_balance.rb +23 -0
  18. data/lib/remit/operations/get_outstanding_debt_balance.rb +22 -0
  19. data/lib/remit/operations/get_payment_instruction.rb +21 -0
  20. data/lib/remit/operations/get_prepaid_balance.rb +23 -0
  21. data/lib/remit/operations/get_results.rb +27 -0
  22. data/lib/remit/operations/get_token_by_caller.rb +19 -0
  23. data/lib/remit/operations/get_token_usage.rb +18 -0
  24. data/lib/remit/operations/get_tokens.rb +20 -0
  25. data/lib/remit/operations/get_total_prepaid_liability.rb +22 -0
  26. data/lib/remit/operations/get_transaction.rb +42 -0
  27. data/lib/remit/operations/install_payment_instruction.rb +22 -0
  28. data/lib/remit/operations/pay.rb +35 -0
  29. data/lib/remit/operations/refund.rb +37 -0
  30. data/lib/remit/operations/reserve.rb +30 -0
  31. data/lib/remit/operations/retry_transaction.rb +18 -0
  32. data/lib/remit/operations/settle.rb +20 -0
  33. data/lib/remit/operations/settle_debt.rb +30 -0
  34. data/lib/remit/operations/subscribe_for_caller_notification.rb +18 -0
  35. data/lib/remit/operations/unsubscribe_for_caller_notification.rb +17 -0
  36. data/lib/remit/operations/write_off_debt.rb +28 -0
  37. data/lib/remit/pipeline_response.rb +52 -0
  38. data/spec/integrations/get_account_activity_spec.rb +36 -0
  39. data/spec/integrations/get_tokens_spec.rb +38 -0
  40. data/spec/integrations/integrations_helper.rb +8 -0
  41. data/spec/spec_helper.rb +36 -0
  42. data/spec/units/get_pipeline_spec.rb +165 -0
  43. data/spec/units/get_results_spec.rb +49 -0
  44. data/spec/units/ipn_request_spec.rb +32 -0
  45. data/spec/units/pay_spec.rb +133 -0
  46. data/spec/units/units_helper.rb +4 -0
  47. metadata +120 -0
@@ -0,0 +1,118 @@
1
+ # Scraped and categorized from http://docs.amazonwebservices.com/AmazonFPS/\
2
+ # 2007-01-08/FPSDeveloperGuide/index.html?ErrorCodesTable.html. You can use
3
+ # these categories to specify default error handling in your application such
4
+ # as asking users to retry or sending an exception email.
5
+ module Remit::ErrorCodes
6
+ class << self
7
+ def sender_error?(code)
8
+ SENDER.include? code.to_sym
9
+ end
10
+
11
+ def recipient_error?(code)
12
+ RECIPIENT.include? code.to_sym
13
+ end
14
+
15
+ def caller_error?(code)
16
+ CALLER.include?(code.to_sym)
17
+ end
18
+
19
+ def amazon_error?(code)
20
+ AMAZON.include? code.to_sym
21
+ end
22
+
23
+ def api_error?(code)
24
+ API.include? code.to_sym
25
+ end
26
+
27
+ def unknown_error?(code)
28
+ UNKNOWN.include? code.to_sym
29
+ end
30
+ end
31
+
32
+ SENDER = [
33
+ :InactiveAccount_Sender, # The sender's account is in suspended or closed state.
34
+ :InactiveInstrument, # The payment instrument used for this transaction is no longer active.
35
+ :InstrumentExpired, # The prepaid or the postpaid instrument has expired.
36
+ :InstrumentNotActive, # The prepaid or postpaid instrument used in the transaction is not active.
37
+ :InvalidAccountState_Sender, # Sender account cannot participate in the transaction.
38
+ :InvalidInstrumentForAccountType, # The sender account can use only credit cards
39
+ :InvalidInstrumentState, # The prepaid or credit instrument should be active
40
+ :InvalidTokenId_Sender, # The send token specified is either invalid or canceled or the token is not active.
41
+ :PaymentInstrumentNotCC, # The payment method specified in the transaction is not a credit card. You can only use a credit card for this transaction.
42
+ :PaymentInstrumentMissing, # There needs to be a payment instrument defined in the token which defines the payment method.
43
+ :TokenNotActive_Sender, # The sender token is canceled.
44
+ :UnverifiedAccount_Sender, # The sender's account must have a verified U.S. credit card or a verified U.S bank account before this transaction can be initiated
45
+ :UnverifiedBankAccount, # A verified bank account should be used for this transaction
46
+ :UnverifiedEmailAddress_Sender, # The sender account must have a verified e-mail address for this payment
47
+ ]
48
+
49
+ RECIPIENT = [
50
+ :InactiveAccount_Recipient, # The recipient's account is in suspended or closed state.
51
+ :InvalidAccountState_Recipient, # Recipient account cannot participate in the transaction
52
+ :InvalidRecipientRoleForAccountType, # The recipient account is not allowed to receive payments
53
+ :InvalidRecipientForCCTransaction, # This account cannot receive credit card payments.
54
+ :InvalidTokenId_Recipient, # The recipient token specified is either invalid or canceled.
55
+ :TokenNotActive_Recipient, # The recipient token is canceled.
56
+ :UnverifiedAccount_Recipient, # The recipient's account must have a verified bank account or a credit card before this transaction can be initiated.
57
+ :UnverifiedEmailAddress_Recipient, # The recipient account must have a verified e-mail address for receiving payments.
58
+ ]
59
+
60
+ CALLER = [
61
+ :InactiveAccount_Caller, # The caller's account is in suspended or closed state.
62
+ :InvalidAccountState_Caller, # The caller account cannot participate in the transaction
63
+ :InvalidTokenId_Caller, # The caller token specified is either invalid or canceled or the specified token is not active.
64
+ :TokenNotActive_Caller, # The caller token is canceled.
65
+ :UnverifiedEmailAddress_Caller, # The caller account must have a verified e-mail address
66
+ ]
67
+
68
+ AMAZON = [
69
+ :InternalError # A retriable error that happens due to some transient problem in the system.
70
+ ]
71
+
72
+ # bad syntax or logic
73
+ API = [
74
+ :AmountOutOfRange, # The transaction amount is more than the allowed range.
75
+ :BadRule, # One of the GK constructs is not well defined
76
+ :CannotSpecifyUsageForSingleUseToken, # Token usages cannot be specified for a single use token.
77
+ :ConcurrentModification, # A retriable error can happen due to concurrent modification of data by two processes.
78
+ :DuplicateRequest, # A different request associated with this caller reference already exists.
79
+ :IncompatibleTokens, # The transaction could not be completed because the tokens have incompatible payment instructions.
80
+ :InstrumentAccessDenied, # The external calling application is not the recipient for this postpaid or prepaid instrument. The caller should be the liability holder
81
+ :InvalidCallerReference, # The CallerReferece does not have a token associated with it.
82
+ :InvalidDateRange, # The end date specified is before the start date or the start date is in the future.
83
+ :InvalidEvent, # The event specified was not subscribed using the SubscribeForCallerNotification operation.
84
+ :InvalidParams, # One or more parameters in the request is invalid.
85
+ :InvalidPaymentInstrument, # The payment method used in the transaction is invalid.
86
+ :InvalidPaymentMethod, # Payment method specified in the GK construct is invalid.
87
+ :InvalidSenderRoleForAccountType, # This token cannot be used for this operation.
88
+ :InvalidTokenId, # The token that you are trying to cancel was not installed by you.
89
+ :InvalidTokenType, # Invalid operation performed on the token. Example, getting the token usage information on a single use token.
90
+ :InvalidTransactionId, # The specified transaction could not be found or the caller did not execute the transaction or this is not a Pay or Reserve call.
91
+ :InvalidTransactionState, # The transaction is not completed or it has been temporarily failed.
92
+ :InvalidUsageDuration, # The duration cannot be less than one hour.
93
+ :InvalidUsageLimitCount, # The usage count is null or empty.
94
+ :InvalidUsageStartTime, # The start time specified for the token is not valid.
95
+ :InvalidUsageType, # The usage type specified is invalid.
96
+ :OriginalTransactionIncomplete, # The original transaction is still in progress.
97
+ :OriginalTransactionFailed, # The original transaction has failed
98
+ :PaymentMethodNotDefined, # Payment method is not defined in the transaction.
99
+ :RefundAmountExceeded, # The refund amount is more than the refundable amount.
100
+ :SameTokenIdUsedMultipleTimes, # This token is already used in earlier transactions.
101
+ :SenderNotOriginalRecipient, # The sender in the refund transaction is not the recipient of the original transaction.
102
+ :SettleAmountGreaterThanReserveAmount, # The amount being settled is greater than the reserved amount.
103
+ :TransactionDenied, # This transaction is not allowed.
104
+ :TransactionExpired, # Returned when the Caller attempts to explicitly retry a transaction that is temporarily declined and is in queue for implicit retry.
105
+ :TransactionFullyRefundedAlready, # The complete refund for this transaction is already completed
106
+ :TransactionTypeNotRefundable, # You cannot refund this transaction.
107
+ :TokenAccessDenied, # Permission is denied to cancel the token.
108
+ :TokenUsageError, # The token usage limit is exceeded.
109
+ :UsageNotDefined, # For a multi-use token or a recurring token the usage limits are not specified in the GateKeeper text.
110
+ ]
111
+
112
+ # these errors don't specify who is at fault
113
+ UNKNOWN = [
114
+ :InvalidAccountState, # The account is either suspended or closed. Payment instructions cannot be installed on this account.
115
+ :InsufficientBalance, # The sender, caller, or recipient's account balance has insufficient funds to complete the transaction.
116
+ :AccountLimitsExceeded, # The spending or the receiving limit on the account is exceeded
117
+ ]
118
+ end
@@ -0,0 +1,189 @@
1
+ require 'erb'
2
+
3
+ require 'remit/common'
4
+
5
+ module Remit
6
+ module GetPipeline
7
+ class Pipeline
8
+ @parameters = []
9
+ attr_reader :parameters
10
+
11
+ class << self
12
+ # Create the parameters hash for the subclass.
13
+ def inherited(subclass) #:nodoc:
14
+ subclass.instance_variable_set('@parameters', [])
15
+ end
16
+
17
+ def parameter(name)
18
+ attr_accessor name
19
+ @parameters << name
20
+ end
21
+
22
+ def convert_key(key)
23
+ key.to_s.gsub(/_(.)/) { $1.upcase }.to_sym
24
+ end
25
+
26
+ # Returns a hash of all of the parameters for this request, including
27
+ # those that are inherited.
28
+ def parameters #:nodoc:
29
+ (superclass.respond_to?(:parameters) ? superclass.parameters : []) + @parameters
30
+ end
31
+ end
32
+
33
+ attr_reader :api
34
+
35
+ parameter :pipeline_name
36
+ parameter :return_url
37
+ parameter :caller_key
38
+ parameter :version
39
+ parameter :address_name
40
+ parameter :address_line_1
41
+ parameter :address_line_2
42
+ parameter :city
43
+ parameter :state
44
+ parameter :zip
45
+ parameter :country
46
+ parameter :phone_number
47
+
48
+ def initialize(api, options)
49
+ @api = api
50
+
51
+ options.each do |k,v|
52
+ self.send("#{k}=", v)
53
+ end
54
+ end
55
+
56
+ def url
57
+ uri = URI.parse(@api.pipeline_url)
58
+
59
+ query = {}
60
+ self.class.parameters.each do |p|
61
+ val = self.send(p)
62
+
63
+ # Convert Time values to seconds from Epoch
64
+ val = val.to_i if val.is_a?(Time)
65
+
66
+ query[self.class.convert_key(p.to_s)] = val
67
+ end
68
+
69
+ # Remove any unused optional parameters
70
+ query.reject! { |key, value| value.nil? || (value.is_a?(String) && value.empty?) }
71
+
72
+ uri.query = SignedQuery.new(@api.pipeline_url, @api.secret_key, query).to_s
73
+ uri.to_s
74
+ end
75
+ end
76
+
77
+ class SingleUsePipeline < Pipeline
78
+ parameter :caller_reference
79
+ parameter :payment_reason
80
+ parameter :payment_method
81
+ parameter :transaction_amount
82
+ parameter :recipient_token
83
+
84
+ def pipeline_name
85
+ Remit::PipelineName::SINGLE_USE
86
+ end
87
+ end
88
+
89
+ class MultiUsePipeline < Pipeline
90
+ parameter :caller_reference
91
+ parameter :payment_reason
92
+ parameter :recipient_token_list
93
+ parameter :amount_type
94
+ parameter :transaction_amount
95
+ parameter :validity_start
96
+ parameter :validity_expiry
97
+ parameter :payment_method
98
+ parameter :global_amount_limit
99
+ parameter :usage_limit_type_1
100
+ parameter :usage_limit_period_1
101
+ parameter :usage_limit_value_1
102
+ parameter :usage_limit_type_2
103
+ parameter :usage_limit_period_2
104
+ parameter :usage_limit_value_2
105
+ parameter :is_recipient_cobranding
106
+
107
+ def pipeline_name
108
+ Remit::PipelineName::MULTI_USE
109
+ end
110
+ end
111
+
112
+ class RecipientPipeline < Pipeline
113
+ parameter :caller_reference
114
+ parameter :validity_start # Time or seconds from Epoch
115
+ parameter :validity_expiry # Time or seconds from Epoch
116
+ parameter :payment_method
117
+ parameter :recipient_pays_fee
118
+ parameter :caller_reference_refund
119
+ parameter :max_variable_fee
120
+ parameter :max_fixed_fee
121
+
122
+ def pipeline_name
123
+ Remit::PipelineName::RECIPIENT
124
+ end
125
+ end
126
+
127
+ class RecurringUsePipeline < Pipeline
128
+ parameter :caller_reference
129
+ parameter :payment_reason
130
+ parameter :recipient_token
131
+ parameter :transaction_amount
132
+ parameter :validity_start # Time or seconds from Epoch
133
+ parameter :validity_expiry # Time or seconds from Epoch
134
+ parameter :payment_method
135
+ parameter :recurring_period
136
+
137
+ def pipeline_name
138
+ Remit::PipelineName::RECURRING
139
+ end
140
+ end
141
+
142
+ class PostpaidPipeline < Pipeline
143
+ parameter :caller_reference_sender
144
+ parameter :caller_reference_settlement
145
+ parameter :payment_reason
146
+ parameter :payment_method
147
+ parameter :validity_start # Time or seconds from Epoch
148
+ parameter :validity_expiry # Time or seconds from Epoch
149
+ parameter :credit_limit
150
+ parameter :global_amount_limit
151
+ parameter :usage_limit_type1
152
+ parameter :usage_limit_period1
153
+ parameter :usage_limit_value1
154
+ parameter :usage_limit_type2
155
+ parameter :usage_limit_period2
156
+ parameter :usage_limit_value2
157
+
158
+ def pipeline_name
159
+ Remit::PipelineName::SETUP_POSTPAID
160
+ end
161
+ end
162
+
163
+ def get_single_use_pipeline(options)
164
+ self.get_pipeline(SingleUsePipeline, options)
165
+ end
166
+
167
+ def get_multi_use_pipeline(options)
168
+ self.get_pipeline(MultiUsePipeline, options)
169
+ end
170
+
171
+ def get_recipient_pipeline(options)
172
+ self.get_pipeline(RecipientPipeline, options)
173
+ end
174
+
175
+ def get_recurring_use_pipeline(options)
176
+ self.get_pipeline(RecurringUsePipeline, options)
177
+ end
178
+
179
+ def get_postpaid_pipeline(options)
180
+ self.get_pipeline(PostpaidPipeline, options)
181
+ end
182
+
183
+ def get_pipeline(pipeline_subclass, options)
184
+ pipeline = pipeline_subclass.new(self, {
185
+ :caller_key => @access_key
186
+ }.merge(options))
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,49 @@
1
+ require 'base64'
2
+ require 'openssl/digest'
3
+
4
+ module Remit
5
+ # Encapsulates the logic for IPN request validation and attribute retrieval.
6
+ #
7
+ # Note: if your responses from Amazon are not validating, please pass the
8
+ # :version parameter to your original CBUI request.
9
+ class IpnRequest
10
+ # Signature key name used by AmazonFPS IPNs
11
+ SIGNATURE_KEY = 'signature'
12
+
13
+ # +params+ should be your controllers request parameters.
14
+ def initialize(params, secret_key)
15
+ raise ArgumentError, "Expected the request params hash, received: #{params.inspect}" unless params.kind_of?(Hash)
16
+ @params = strip_keys_from(params, 'action', 'controller')
17
+ @supplied_signature = @params.delete(SIGNATURE_KEY)
18
+ @secret_key = secret_key
19
+ end
20
+
21
+ def valid?
22
+ return false unless @supplied_signature
23
+ generate_signature_for(@params) == @supplied_signature
24
+ end
25
+
26
+ def method_missing(method, *args) #:nodoc:
27
+ if @params.has_key?(method.to_s)
28
+ @params[method.to_s]
29
+ else
30
+ super(method, *args)
31
+ end
32
+ end
33
+
34
+ def generate_signature_for(params)
35
+ query = params.sort_by { |k,v| k.downcase }
36
+ digest = OpenSSL::Digest::Digest.new('sha1')
37
+ hmac = OpenSSL::HMAC.digest(digest, @secret_key, query.to_s)
38
+ encoded = Base64.encode64(hmac).chomp
39
+ end
40
+ private :generate_signature_for
41
+
42
+ def strip_keys_from(params, *ignore_keys)
43
+ parsed = params.dup
44
+ ignore_keys.each { |key| parsed.delete(key) }
45
+ parsed
46
+ end
47
+ private :strip_keys_from
48
+ end
49
+ end
@@ -0,0 +1,23 @@
1
+ require 'remit/common'
2
+
3
+ # Note: This is a special FPS action used by Amazon SimplePay
4
+ # See more here: http://docs.amazonwebservices.com/AmazonSimplePay/latest/ASPAdvancedUserGuide/
5
+ module Remit
6
+ module CancelSubscriptionAndRefund
7
+ class Request < Remit::Request
8
+ action :CancelSubscriptionAndRefund
9
+ parameter :caller_reference, :required => true
10
+ parameter :cancel_reason
11
+ parameter :refund_amount, :type => Remit::RequestTypes::Amount
12
+ parameter :subscription_id, :required => true
13
+ end
14
+
15
+ class Response < Remit::Response
16
+ parameter :refund_transaction_id
17
+ end
18
+
19
+ def cancel_subscription_and_refund(request = Request.new)
20
+ call(request, Response)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ require 'remit/common'
2
+
3
+ module Remit
4
+ module CancelToken
5
+ class Request < Remit::Request
6
+ action :CancelToken
7
+ parameter :token_id, :required => true
8
+ parameter :reason_text
9
+ end
10
+
11
+ class Response < Remit::Response
12
+ end
13
+
14
+ def cancel_token(request = Request.new)
15
+ call(request, Response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'remit/common'
2
+
3
+ module Remit
4
+ module DiscardResults
5
+ class Request < Remit::Request
6
+ action :DiscardResults
7
+ parameter :transaction_ids, :required => true
8
+ end
9
+
10
+ class Response < Remit::Response
11
+ parameter :discard_errors
12
+ end
13
+
14
+ def discard_results(request = Request.new)
15
+ call(request, Response)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ require 'remit/common'
2
+
3
+ module Remit
4
+ module FundPrepaid
5
+ class Request < Remit::Request
6
+ action :FundPrepaid
7
+ parameter :transaction_ids
8
+ parameter :caller_description
9
+ parameter :caller_reference, :required => true
10
+ parameter :caller_token_id, :required => true
11
+ parameter :charge_fee_to, :required => true
12
+ parameter :funding_amount, :type => Remit::RequestTypes::Amount, :required => true
13
+ parameter :meta_data
14
+ parameter :prepaid_instrument_id, :required => true
15
+ parameter :recipient_description
16
+ parameter :recipient_reference
17
+ parameter :sender_description
18
+ parameter :sender_reference
19
+ parameter :sender_token_id, :required => true
20
+ parameter :transaction_date
21
+ end
22
+
23
+ class Response < Remit::Response
24
+ parameter :transaction_response, :type => TransactionResponse
25
+ end
26
+
27
+ def fund_prepaid(request = Request.new)
28
+ call(request, Response)
29
+ end
30
+ end
31
+ end