Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Reverted changes to API configuration.

Cleaned up formatting and whitespace.
  • Loading branch information...
commit c0be7968191470bb8ed5198ffa2b5aab78316f89 1 parent 9e8df50
@tylerhunt authored
View
50 lib/remit.rb
@@ -8,6 +8,8 @@
require 'erb'
require 'rubygems'
+
+gem 'relax', '0.0.6'
require 'relax'
require 'remit/common'
@@ -76,36 +78,29 @@ class API < Relax::Service
include UnsubscribeForCallerNotification
include WriteOffDebt
- attr_reader :pipeline
+ API_ENDPOINT = 'https://fps.amazonaws.com/'.freeze
+ API_SANDBOX_ENDPOINT = 'https://fps.sandbox.amazonaws.com/'.freeze
+ PIPELINE_URL = 'https://authorize.payments.amazon.com/cobranded-ui/actions/start'.freeze
+ PIPELINE_SANDBOX_URL = 'https://authorize.payments-sandbox.amazon.com/cobranded-ui/actions/start'.freeze
+ API_VERSION = Date.new(2007, 1, 8).to_s.freeze
+ SIGNATURE_VERSION = 1.freeze
+
attr_reader :access_key
- attr_reader :secret_key
-
-
- path = File.expand_path "#{RAILS_ROOT}/config/amazon_fps.yml" # Should generate amazon_fps.yml file on install
- h = YAML.load_file path rescue raise "No config file round at /config/amazon_fps.yml!"
- config = h[RAILS_ENV].symbolize_keys
- # set default params and set AWS keys
- ACCESS_KEY = config[:access_key]
- SECRET_ACCESS_KEY = config[:secret_access_key]
- ENDPOINT = config[:endpoint]
- RETURN_BASE = config[:return_base]
- PIPELINE = config[:pipeline]
- SANDBOX = config[:sandbox]
- API_VERSION = config[:version]
- SIGNATURE_VERSION = 1
-
- def initialize
- super(ENDPOINT)
- @pipeline = PIPELINE
- @access_key = ACCESS_KEY
- @secret_key = SECRET_ACCESS_KEY
- end
+ attr_reader :secret_key
+ attr_reader :pipeline_url
- private
+ def initialize(access_key, secret_key, sandbox=false)
+ @access_key = access_key
+ @secret_key = secret_key
+ @pipeline_url = sandbox ? PIPELINE_SANDBOX_URL : PIPELINE_URL
- def new_query(query = {})
+ super(sandbox ? API_SANDBOX_ENDPOINT : API_ENDPOINT)
+ end
+
+ def new_query(query={})
SignedQuery.new(@endpoint, @secret_key, query)
end
+ private :new_query
def default_query
new_query({
@@ -115,19 +110,24 @@ def default_query
:Timestamp => Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
})
end
+ private :default_query
def query(request)
query = super
query[:Signature] = sign(query)
query
end
+ private :query
def sign(values)
keys = values.keys.sort { |a, b| a.to_s.downcase <=> b.to_s.downcase }
+
signature = keys.inject('') do |signature, key|
signature += key.to_s + values[key].to_s
end
+
Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @secret_key, signature)).strip
end
+ private :sign
end
end
View
17 lib/remit/common.rb
@@ -11,21 +11,21 @@ def self.action(name)
parameter :action, :value => name
end
- protected
-
def convert_key(key)
key.to_s.gsub(/(^|_)(.)/) { $2.upcase }.to_sym
end
+ protected :convert_key
end
class BaseResponse < Relax::Response
- def node_name(name, namespace = nil)
+ def node_name(name, namespace=nil)
super(name.to_s.gsub(/(^|_)(.)/) { $2.upcase }, namespace)
end
end
class Response < BaseResponse
parameter :request_id
+
attr_accessor :status
attr_accessor :errors
@@ -48,27 +48,26 @@ def successful?
@status == ResponseStatus::SUCCESS
end
- def node_name(name, namespace = nil)
+ def node_name(name, namespace=nil)
super(name.to_s.split('/').collect{ |tag|
tag.gsub(/(^|_)(.)/) { $2.upcase }
}.join('/'), namespace)
end
-
end
class SignedQuery < Relax::Query
- def initialize(uri, secret_key, query = {})
+ def initialize(uri, secret_key, query={})
super(query)
@uri = URI.parse(uri.to_s)
@secret_key = secret_key
end
def sign
- delete_if { |key, value| key == :awsSignature }
+ delete(:awsSignature)
store(:awsSignature, Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest::SHA1.new, @secret_key, "#{@uri.path}?#{to_s(false)}".gsub('%20', '+'))).strip)
end
- def to_s(signed = true)
+ def to_s(signed=true)
sign if signed
super()
end
@@ -76,10 +75,12 @@ def to_s(signed = true)
class << self
def parse(uri, secret_key, query_string)
query = self.new(uri, secret_key)
+
query_string.split('&').each do |parameter|
key, value = parameter.split('=', 2)
query[key] = unescape_value(value)
end
+
query
end
end
View
20 lib/remit/data_types.rb
@@ -8,12 +8,12 @@ class Amount < BaseResponse
parameter :currency_code
parameter :amount, :type => :float
end
-
+
class TemporaryDeclinePolicy < BaseResponse
parameter :temporary_decline_policy_type
parameter :implicit_retry_timeout_in_mins
end
-
+
class DescriptorPolicy < BaseResponse
parameter :soft_descriptor_type
parameter :CS_number_of
@@ -90,14 +90,14 @@ class TransactionResponse < BaseResponse
parameter :status
parameter :status_detail
parameter :new_sender_token_usage, :type => TokenUsageLimit
-
+
%w(reserved success failure initiated reinitiated temporary_decline).each do |status_name|
define_method("#{status_name}?") do
self.status == Remit::TransactionStatus.const_get(status_name.sub('_', '').upcase)
end
end
end
-
+
class TransactionStatus
RESERVED = 'Reserved'
SUCCESS = 'Success'
@@ -113,7 +113,7 @@ class TokenType
RECURRING = 'Recurring'
UNRESTRICTED = 'Unrestricted'
end
-
+
class PipelineName
SINGLE_USE = 'SingleUse'
MULTI_USE = 'MultiUse'
@@ -122,7 +122,7 @@ class PipelineName
SETUP_PREPAID = 'SetupPrepaid'
SETUP_POSTPAID = 'SetupPostpaid'
end
-
+
class PipelineStatusCode
CALLER_EXCEPTION = 'CE' # problem with your code
SYSTEM_ERROR = 'SE' # system error, try again
@@ -135,24 +135,24 @@ class PipelineStatusCode
INVALID_CALLER = 'NM' # you are not a valid 3rd party caller to the transaction
SUCCESS_RECIPIENT_TOKEN_INSTALLED = 'SR'
end
-
+
module RequestTypes
class Amount < Remit::Request
parameter :amount
parameter :currency_code
end
-
+
class TemporaryDeclinePolicy < Remit::Request
parameter :temporary_decline_policy_type
parameter :implicit_retry_timeout_in_mins
end
-
+
class DescriptorPolicy < Remit::Request
parameter :soft_descriptor_type
parameter :CS_number_of
end
end
-
+
class Operation
PAY = "Pay"
REFUND = "Refund"
View
28 lib/remit/error_codes.rb
@@ -1,27 +1,29 @@
-# scraped and categorized from http://docs.amazonwebservices.com/AmazonFPS/2007-01-08/FPSDeveloperGuide/index.html?ErrorCodesTable.html
-# you can use these categories to specify default error handling in your application such as asking users to retry or sending an exception email.
+# Scraped and categorized from http://docs.amazonwebservices.com/AmazonFPS/\
+# 2007-01-08/FPSDeveloperGuide/index.html?ErrorCodesTable.html. You can use
+# these categories to specify default error handling in your application such
+# as asking users to retry or sending an exception email.
module Remit::ErrorCodes
- class << self
+ class << self
def sender_error?(code)
SENDER.include? code.to_sym
end
-
+
def recipient_error?(code)
RECIPIENT.include? code.to_sym
end
-
+
def caller_error?(code)
CALLER.include?(code.to_sym)
end
-
+
def amazon_error?(code)
AMAZON.include? code.to_sym
end
-
+
def api_error?(code)
API.include? code.to_sym
end
-
+
def unknown_error?(code)
UNKNOWN.include? code.to_sym
end
@@ -43,7 +45,7 @@ def unknown_error?(code)
:UnverifiedBankAccount, # A verified bank account should be used for this transaction
:UnverifiedEmailAddress_Sender, # The sender account must have a verified e-mail address for this payment
]
-
+
RECIPIENT = [
:InactiveAccount_Recipient, # The recipient's account is in suspended or closed state.
:InvalidAccountState_Recipient, # Recipient account cannot participate in the transaction
@@ -54,7 +56,7 @@ def unknown_error?(code)
:UnverifiedAccount_Recipient, # The recipient's account must have a verified bank account or a credit card before this transaction can be initiated.
:UnverifiedEmailAddress_Recipient, # The recipient account must have a verified e-mail address for receiving payments.
]
-
+
CALLER = [
:InactiveAccount_Caller, # The caller's account is in suspended or closed state.
:InvalidAccountState_Caller, # The caller account cannot participate in the transaction
@@ -62,11 +64,11 @@ def unknown_error?(code)
:TokenNotActive_Caller, # The caller token is canceled.
:UnverifiedEmailAddress_Caller, # The caller account must have a verified e-mail address
]
-
+
AMAZON = [
:InternalError # A retriable error that happens due to some transient problem in the system.
]
-
+
# bad syntax or logic
API = [
:AmountOutOfRange, # The transaction amount is more than the allowed range.
@@ -106,7 +108,7 @@ def unknown_error?(code)
:TokenUsageError, # The token usage limit is exceeded.
:UsageNotDefined, # For a multi-use token or a recurring token the usage limits are not specified in the GateKeeper text.
]
-
+
# these errors don't specify who is at fault
UNKNOWN = [
:InvalidAccountState, # The account is either suspended or closed. Payment instructions cannot be installed on this account.
View
11 lib/remit/get_pipeline.rb
@@ -33,12 +33,11 @@ def parameters #:nodoc:
attr_reader :api
parameter :pipeline_name
- parameter :return_URL
+ parameter :return_url
parameter :caller_key
- def initialize(api, pipeline, options)
+ def initialize(api, options)
@api = api
- @pipeline = pipeline
options.each do |k,v|
self.send("#{k}=", v)
@@ -46,7 +45,7 @@ def initialize(api, pipeline, options)
end
def url
- uri = URI.parse(@pipeline)
+ uri = URI.parse(@api.pipeline_url)
query = {}
self.class.parameters.each do |p|
@@ -61,7 +60,7 @@ def url
# Remove any unused optional parameters
query.reject! { |key, value| value.nil? }
- uri.query = SignedQuery.new(@api.pipeline, @api.secret_key, query).to_s
+ uri.query = SignedQuery.new(@api.pipeline_url, @api.secret_key, query).to_s
uri.to_s
end
end
@@ -173,7 +172,7 @@ def get_postpaid_pipeline(options)
end
def get_pipeline(pipeline_subclass, options)
- pipeline = pipeline_subclass.new(self, @pipeline, {
+ pipeline = pipeline_subclass.new(self, {
:caller_key => @access_key
}.merge(options))
end
View
10 spec/spec_helper.rb
@@ -9,7 +9,7 @@ def remit
describe 'a successful response', :shared => true do
it 'should return success' do
- @response.status.should eql('Success')
+ @response.status.should == 'Success'
end
it 'should not have any errors' do
@@ -25,16 +25,12 @@ def remit
it "is not successful" do
@response.should_not be_successful
end
-
+
it "has a request id" do
@response.request_id.should_not be_empty
end
-
+
it "has errors" do
@response.errors.should_not be_empty
end
end
-
-
-
-
View
50 spec/units/get_pipeline_spec.rb
@@ -3,7 +3,7 @@
describe 'A pipeline', :shared => true do
before do
@pipeline_options = {
- :return_URL => 'http://example.com/'
+ :return_url => 'http://example.com/'
}
end
@@ -32,10 +32,10 @@
it 'should ignore unused parameters' do
uri = URI.parse(@pipeline.url)
query = Relax::Query.parse(uri)
-
+
query[:paymentReason].should be_nil
end
-
+
it 'should have the right name' do
@pipeline.pipeline_name.should == Remit::PipelineName::SINGLE_USE
end
@@ -43,24 +43,24 @@
describe 'A multi-use pipeline' do
it_should_behave_like 'A pipeline'
-
+
before do
@pipeline_options.merge!({
:transaction_amount => 10,
:caller_reference => 'N2PCBEIA5864E27EL7C86PJL1FGUGPBL61QTJJM5GQK265SPEN8ZKIJPMQARDVJK',
:recipient_token_list => 'N5PCME5A5Q6FE2QEB7CD64JLGFTUGXBE61HTCJMGGAK2R5IPEQ8EKIVP3QAVD7JP'
})
-
+
@pipeline = remit.get_multi_use_pipeline(@pipeline_options)
end
-
+
it 'should ignore unused parameters' do
uri = URI.parse(@pipeline.url)
query = Relax::Query.parse(uri)
-
+
query[:paymentReason].should be_nil
end
-
+
it 'should have the right name' do
@pipeline.pipeline_name.should == Remit::PipelineName::MULTI_USE
end
@@ -68,11 +68,11 @@
describe 'A recipient pipeline' do
it_should_behave_like 'A pipeline'
-
+
before do
@validity_start = Time.now + (3600 * 24) # 1 day from now
@validity_expiry = Time.now + (2600 * 24 * 180) # ~6 months from now
-
+
@pipeline_options.merge!({
:validity_start => @validity_start,
:validity_expiry => @validity_expiry,
@@ -80,14 +80,14 @@
:max_variable_fee => '0.25',
:recipient_pays_fee => true
})
-
+
@pipeline = remit.get_recipient_pipeline(@pipeline_options)
end
-
+
it 'should have the recipient pay marketplace fees' do
@pipeline.url.should match(/recipientPaysFee=true/)
end
-
+
it 'should have the right name' do
@pipeline.pipeline_name.should == Remit::PipelineName::RECIPIENT
end
@@ -100,7 +100,7 @@
@validity_start = Time.now + (3600 * 24) # 1 day from now
@validity_expiry = Time.now + (3600 * 24 * 180) # ~6 months from now
@recurring_period = '1 Month'
-
+
@pipeline_options.merge!({
:validity_start => @validity_start,
:validity_expiry => @validity_expiry,
@@ -109,32 +109,32 @@
:caller_reference => 'N2PCBEIA5864E27EL7C86PJL1FGUGPBL61QTJJM5GQK265SPEN8ZKIJPMQARDVJK',
:recipient_token => 'N5PCME5A5Q6FE2QEB7CD64JLGFTUGXBE61HTCJMGGAK2R5IPEQ8EKIVP3QAVD7JP'
})
-
+
@pipeline = remit.get_recurring_use_pipeline(@pipeline_options)
end
it 'should convert times to seconds from epoch' do
uri = URI.parse(@pipeline.url)
query = Relax::Query.parse(uri)
-
+
@validity_start.to_i.to_s.should == query[:validityStart]
@validity_expiry.to_i.to_s.should == query[:validityExpiry]
end
-
+
it 'should allow time in seconds' do
options = @pipeline_options.merge({
:validity_start => @validity_start.to_i,
:validity_expiry => @validity_expiry.to_i
})
@pipeline = remit.get_recurring_use_pipeline(options)
-
+
uri = URI.parse(@pipeline.url)
query = Relax::Query.parse(uri)
-
+
@validity_start.to_i.to_s.should == query[:validityStart]
@validity_expiry.to_i.to_s.should == query[:validityExpiry]
end
-
+
it 'should have the right name' do
@pipeline.pipeline_name.should == Remit::PipelineName::RECURRING
end
@@ -142,23 +142,23 @@
describe 'A postpaid pipeline' do
it_should_behave_like 'A pipeline'
-
+
before do
@credit_limit = 100
@global_amount_limit = 100
-
+
@pipeline_options.merge!({
:credit_limit => @credit_limit,
:global_amount_limit => @global_amount_limit
})
-
+
@pipeline = remit.get_postpaid_pipeline(@pipeline_options)
end
-
+
it 'should create a PostpaidPipeline' do
@pipeline.class.should == Remit::GetPipeline::PostpaidPipeline
end
-
+
it 'should have the right name' do
@pipeline.pipeline_name.should == Remit::PipelineName::SETUP_POSTPAID
end
View
22 spec/units/get_results_spec.rb
@@ -3,9 +3,9 @@
describe "the GetResults API" do
describe "a successful response" do
it_should_behave_like 'a successful response'
-
+
before do
- doc = <<-EXML
+ doc = <<-XML
<?xml version=\"1.0\"?>
<ns3:GetResultsResponse xmlns:ns3=\"http://fps.amazonaws.com/doc/2007-01-08/\">
<TransactionResults>
@@ -18,27 +18,29 @@
<Status>Success</Status>
<RequestId>f89727ba-9ff6-4ca8-87a3-0fd6c9de6b95:0</RequestId>
</ns3:GetResultsResponse>
- EXML
-
+ XML
+
@response = Remit::GetResults::Response.new(doc)
end
-
+
it "has one result" do
@response.number_pending.should == 1
@response.transaction_results.size == "1"
end
-
+
describe "the result" do
- before { @result = @response.transaction_results.first }
-
+ before do
+ @result = @response.transaction_results.first
+ end
+
it "references a previous transaction" do
@result.transaction_id.should == "abc123"
end
-
+
it "references a pay transaction" do
@result.operation_type.should == 'Pay'
end
-
+
it "reports the transaction's new status" do
@result.transaction_status.should == 'Success'
end
View
34 spec/units/ipn_request_spec.rb
@@ -1,34 +1,32 @@
require File.dirname(__FILE__) + '/units_helper'
describe 'an IPN request' do
-
before(:each) do
@request_params = {
- "action" => "notice",
- "buyerName" => "Fps Buyer",
- "callerReference" => "4-8-1-3.5",
- "controller" => "amazon_fps/ipn",
+ "action" => "notice",
+ "buyerName" => "Fps Buyer",
+ "callerReference" => "4-8-1-3.5",
+ "controller" => "amazon_fps/ipn",
"operation" => "PAY",
- "paymentMethod" => "CC",
- "recipientEmail" => "recipient@email.url",
- "recipientName" => "Fps Business",
- "signature" => "DA7ZbuQaBDt2/+Mty9XweJyqI1E=",
- "status" => "SUCCESS",
- "transactionAmount" => "USD 3.50",
- "transactionDate" => "1224687134",
+ "paymentMethod" => "CC",
+ "recipientEmail" => "recipient@email.url",
+ "recipientName" => "Fps Business",
+ "signature" => "DA7ZbuQaBDt2/+Mty9XweJyqI1E=",
+ "status" => "SUCCESS",
+ "transactionAmount" => "USD 3.50",
+ "transactionDate" => "1224687134",
"transactionId" => "13KIGL9RC25853BGPPOS2VSKBKF2JERR3HO"
}
@request = Remit::IpnRequest.new(@request_params, 'THISISMYTESTKEY')
end
-
+
it 'should be a valid request' do
@request.should be_valid
end
-
+
it 'should pass through access to given parameters' do
- @request.status.should eql('SUCCESS')
- @request.operation.should eql('PAY')
- @request.transactionId.should eql('13KIGL9RC25853BGPPOS2VSKBKF2JERR3HO')
+ @request.status.should == 'SUCCESS'
+ @request.operation.should == 'PAY'
+ @request.transactionId.should == '13KIGL9RC25853BGPPOS2VSKBKF2JERR3HO'
end
-
end
View
62 spec/units/pay_spec.rb
@@ -3,61 +3,61 @@
describe "the Pay API" do
describe "a successful response" do
it_should_behave_like 'a successful response'
-
+
before do
- doc = <<-EXML
- <ns3:PayResponse xmlns:ns3="http://fps.amazonaws.com/doc/2007-01-08/">
- <ns3:TransactionResponse>
- <TransactionId>abc123</TransactionId>
- <Status>Initiated</Status>
- </ns3:TransactionResponse>
- <Status>Success</Status>
- <RequestId>foo</RequestId>
- </ns3:PayResponse>
- EXML
-
+ doc = <<-XML
+ <ns3:PayResponse xmlns:ns3="http://fps.amazonaws.com/doc/2007-01-08/">
+ <ns3:TransactionResponse>
+ <TransactionId>abc123</TransactionId>
+ <Status>Initiated</Status>
+ </ns3:TransactionResponse>
+ <Status>Success</Status>
+ <RequestId>foo</RequestId>
+ </ns3:PayResponse>
+ XML
+
@response = Remit::Pay::Response.new(doc)
end
-
+
it "has a transaction response" do
@response.transaction_response.should_not be_nil
end
-
+
it "has a transaction id" do
@response.transaction_response.transaction_id.should == 'abc123'
end
-
+
it "has a transaction status" do
@response.transaction_response.status.should == 'Initiated'
end
-
+
it "has status shortcuts" do
@response.transaction_response.should be_initiated
end
end
-
+
describe "for a failed request" do
it_should_behave_like 'a failed response'
-
+
before do
- doc = <<-EXML
- <ns3:PayResponse xmlns:ns3=\"http://fps.amazonaws.com/doc/2007-01-08/\">
- <Status>Failure</Status>
- <Errors>
+ doc = <<-XML
+ <ns3:PayResponse xmlns:ns3=\"http://fps.amazonaws.com/doc/2007-01-08/\">
+ <Status>Failure</Status>
<Errors>
- <ErrorType>Business</ErrorType>
- <IsRetriable>false</IsRetriable>
- <ErrorCode>InvalidParams</ErrorCode>
- <ReasonText>callerTokenId can not be empty</ReasonText>
+ <Errors>
+ <ErrorType>Business</ErrorType>
+ <IsRetriable>false</IsRetriable>
+ <ErrorCode>InvalidParams</ErrorCode>
+ <ReasonText>callerTokenId can not be empty</ReasonText>
+ </Errors>
</Errors>
- </Errors>
- <RequestId>7966a2d9-5ce9-4902-aefc-b01d254c931a:0</RequestId>
- </ns3:PayResponse>
- EXML
+ <RequestId>7966a2d9-5ce9-4902-aefc-b01d254c931a:0</RequestId>
+ </ns3:PayResponse>
+ XML
@response = Remit::Pay::Response.new(doc)
end
-
+
it "has error details" do
error = @response.errors.first
error.should be_kind_of(Remit::ServiceError)
Please sign in to comment.
Something went wrong with that request. Please try again.