servicemerchant 0.1.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.
- data/MIT-LICENSE.txt +20 -0
- data/README.txt +231 -0
- data/Rakefile +122 -0
- data/demo.rb +69 -0
- data/recurring_billing/lib/am_extensions.rb +1 -0
- data/recurring_billing/lib/am_extensions/paypal_extension.rb +170 -0
- data/recurring_billing/lib/dependencies.rb +14 -0
- data/recurring_billing/lib/gateways.rb +5 -0
- data/recurring_billing/lib/gateways/authorize_net.rb +103 -0
- data/recurring_billing/lib/gateways/paypal.rb +124 -0
- data/recurring_billing/lib/recurring_billing.rb +130 -0
- data/recurring_billing/lib/recurring_billing.rdoc +87 -0
- data/recurring_billing/lib/utils.rb +81 -0
- data/recurring_billing/test/fixtures.yml +33 -0
- data/recurring_billing/test/remote/authorize_net_test.rb +36 -0
- data/recurring_billing/test/remote/paypal_test.rb +46 -0
- data/recurring_billing/test/remote/recurring_billing_test.rb +41 -0
- data/recurring_billing/test/test_helper.rb +153 -0
- data/recurring_billing/test/unit/authorize_net_gateway_class_test.rb +42 -0
- data/recurring_billing/test/unit/paypal_gateway_class_test.rb +23 -0
- data/recurring_billing/test/unit/recurring_billing_gateway_class_test.rb +35 -0
- data/recurring_billing/test/unit/utils_test.rb +17 -0
- data/subscription_management/Rakefile +29 -0
- data/subscription_management/lib/models/subscription.rb +9 -0
- data/subscription_management/lib/models/subscription_profile.rb +4 -0
- data/subscription_management/lib/subscription_management.rb +326 -0
- data/subscription_management/samples/backpack.yml +101 -0
- data/subscription_management/samples/basecamp.yml +71 -0
- data/subscription_management/samples/brainkeeper.yml +90 -0
- data/subscription_management/samples/campfire.yml +74 -0
- data/subscription_management/samples/clickandpledge.yml +24 -0
- data/subscription_management/samples/demo.rb +19 -0
- data/subscription_management/samples/elm.yml +174 -0
- data/subscription_management/samples/freshbooks.yml +78 -0
- data/subscription_management/samples/highrise.yml +100 -0
- data/subscription_management/samples/presets.yml +10 -0
- data/subscription_management/samples/tariff.outline.yml +0 -0
- data/subscription_management/samples/taxes.yml +21 -0
- data/subscription_management/subscription_management.rb +7 -0
- data/subscription_management/tasks/schema.rb +50 -0
- data/subscription_management/test/connection.rb +10 -0
- data/subscription_management/test/remote/subscription_management_test.rb +112 -0
- data/subscription_management/test/test_helper.rb +84 -0
- data/subscription_management/test/unit/subscription_management_test.rb +40 -0
- data/tracker/README +12 -0
- data/tracker/Rakefile +40 -0
- data/tracker/db/migrations/empty-directory +0 -0
- data/tracker/demo.rb +12 -0
- data/tracker/lib/models/recurring_payment_profile.rb +134 -0
- data/tracker/lib/models/transaction.rb +19 -0
- data/tracker/lib/recurring_billing_extension.rb +103 -0
- data/tracker/lib/recurring_billing_extension.rdoc +34 -0
- data/tracker/tasks/schema.rb +66 -0
- data/tracker/test/connection.rb +10 -0
- data/tracker/test/recurring_payment_profile.rb +35 -0
- data/tracker/test/remote/authorize_net_test.rb +68 -0
- data/tracker/test/remote/paypal_test.rb +115 -0
- data/tracker/test/test_helper.rb +87 -0
- data/tracker/test/unit/recurring_payment_profile_test.rb +62 -0
- data/tracker/tracker.rb +10 -0
- data/vendor/money-1.7.1/MIT-LICENSE +20 -0
- data/vendor/money-1.7.1/README +75 -0
- data/vendor/money-1.7.1/lib/bank/no_exchange_bank.rb +9 -0
- data/vendor/money-1.7.1/lib/bank/variable_exchange_bank.rb +30 -0
- data/vendor/money-1.7.1/lib/money.rb +29 -0
- data/vendor/money-1.7.1/lib/money/core_extensions.rb +26 -0
- data/vendor/money-1.7.1/lib/money/money.rb +209 -0
- data/vendor/money-1.7.1/lib/support/cattr_accessor.rb +57 -0
- metadata +153 -0
@@ -0,0 +1,87 @@
|
|
1
|
+
This class provides unified API to access remote payment gateways.
|
2
|
+
|
3
|
+
== Quick overview
|
4
|
+
=== Creating a gateway accessor
|
5
|
+
There are two options to get an instance of an accessor for required gateway. First is to use get_instance method:
|
6
|
+
options = {:gateway => :authorize_net, :login => 'MyLogin', :password => 'MyPassword'}
|
7
|
+
gateway = RecurringBilling::RecurringBillingGateway.get_instance(options)
|
8
|
+
which basically is an alias for the second method, directly calling
|
9
|
+
the constructor of RecurringBilling::AuthorizeNetGateway (or any other RecurringBillingGateway descendant):
|
10
|
+
gateway = RecurringBilling::AuthorizeNetGateway({:login => 'MyLogin', :password => 'MyPassword'})
|
11
|
+
First method is recommended to be used for more flexibility.
|
12
|
+
|
13
|
+
=== Common options for RecurringBilling methods
|
14
|
+
It should be self-explanatory that every recurring payment itself has many parameters - those parameters have to be specified
|
15
|
+
when the payment is created and updated on remote gateway as well. Within the API, these are grouped for convenience into four groups
|
16
|
+
that have become the input parameters for create and update methods:
|
17
|
+
- Amount
|
18
|
+
- Card
|
19
|
+
- Payment Options
|
20
|
+
- Recurring Options
|
21
|
+
|
22
|
+
<b>Amount</b>(amount) is the object of Money class, which includes both amount and currency of the payment.
|
23
|
+
|
24
|
+
<b>Card</b>(card) is the object of ActiveMerchant::Billing::CreditCard representing the credit card that is charged during recurring payments
|
25
|
+
|
26
|
+
<b>Payment Options</b>(payment_options) are a hash of:
|
27
|
+
- :subscription_name - +string+ containing the reference name for the subscription
|
28
|
+
- :billing_address - +hash+ containing subscriber's billing address (see ActiveMerchant for more info on structure)
|
29
|
+
- :order - +hash+ containing merchant's info about order, like invoice ID (see ActiveMerchant for more info on structure)
|
30
|
+
- :taxes_amount_included - +boolean+ declaring if taxes are included in payment amount or not
|
31
|
+
This set of options contains information of merchant.
|
32
|
+
|
33
|
+
<b>Recurring Options</b>(payment_options) are a hash of:
|
34
|
+
- :start_date - +Date+ object, date of the first billing occurrence
|
35
|
+
- :interval - +string+ of <tt>(0.5|d+)\s*(d|w|m|y)/</tt> template that shows time between two consecutive billing occurrences
|
36
|
+
- :end_date - +Date+ object representing date after which there are no more billing occurrences
|
37
|
+
- :occurrences - positive +integer+ showing number of billing occurrences. Either this or :end_date should be specified
|
38
|
+
- :trial_days - positive +integer+ showing number of days of free trial
|
39
|
+
This set of options declares settings of payment recurring occurrences.
|
40
|
+
|
41
|
+
=== Creating a remote payment
|
42
|
+
Once gateway is created, payments could be made. The whole idea is very simple - prepare parameters and use the
|
43
|
+
create method of an instance:
|
44
|
+
amount = Money.us_dollar(100) # $1 USD
|
45
|
+
card = ActiveMerchant::Billing::CreditCard.new({
|
46
|
+
:number => '4242424242424242',
|
47
|
+
:month => 9,
|
48
|
+
:year => Time.now.year + 1,
|
49
|
+
:first_name => 'Name',
|
50
|
+
:last_name => 'Lastname',
|
51
|
+
:verification_value => '123',
|
52
|
+
:type => 'visa'
|
53
|
+
}) # Some random credit card
|
54
|
+
payment_options = {
|
55
|
+
:subscription_name => 'Random subscription',
|
56
|
+
:order => {:invoice_number => 'ODMX31337'}
|
57
|
+
}
|
58
|
+
recurring_options = {
|
59
|
+
:start_date => Date.today,
|
60
|
+
:occurrences => 10,
|
61
|
+
:interval => '10d'
|
62
|
+
}
|
63
|
+
billing_id = gateway.create(amount, card, payment_options, recurring_options)
|
64
|
+
You may then check the result of recurring payment creation by accessing last_response:
|
65
|
+
response = gateway.last_response
|
66
|
+
print response.inspect
|
67
|
+
Exact structure of last_response return value is defined in respective ActiveMerchant module. Most common
|
68
|
+
uses of last_response query are:
|
69
|
+
unless response.success? # succeed-failed check
|
70
|
+
print response.message # get message retrieved from remote gateway
|
71
|
+
...
|
72
|
+
Last response is changed whenever create, update, inquiry or delete methods are called.
|
73
|
+
|
74
|
+
=== Updating and canceling a remote payment
|
75
|
+
To update the settings of recurring payment on gateway, just call the update method of an instance.
|
76
|
+
new_amount = Money.us_dollar(150) # $1.5 USD
|
77
|
+
success = gateway.update(billing_id, new_amount, nil, {}, {}) # or just gateway.update(new_amount)
|
78
|
+
Please note that acceptable update parameters vary with gateway. Correctness of parameters for update is
|
79
|
+
checked via protected correct_update? method.
|
80
|
+
|
81
|
+
Recurring payment may be cancelled via delete method:
|
82
|
+
success = gateway.delete(billing_id)
|
83
|
+
|
84
|
+
=== Inquiring gateway on payment status
|
85
|
+
In order to inquire remote gateway on status of given subscription, inquiry method of an instance should be used:
|
86
|
+
result = gateway.inquiry(billing_id)
|
87
|
+
The result structure varies from gateway to gateway.
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# This module contains common functions that ServiceMerchant uses.
|
2
|
+
module Utils
|
3
|
+
#Counts nubmer of months between two dates
|
4
|
+
#
|
5
|
+
# 2008/1/1, 2007/12/31 => 1
|
6
|
+
# 2008/9/10, 2009/10/20 => 13
|
7
|
+
# ETC
|
8
|
+
def months_between(date1, date2)
|
9
|
+
if date1 > date2
|
10
|
+
recent_date = date1.to_date
|
11
|
+
past_date = date2.to_date
|
12
|
+
else
|
13
|
+
recent_date = date2.to_date
|
14
|
+
past_date = date1.to_date
|
15
|
+
end
|
16
|
+
years_diff = recent_date.year - past_date.year
|
17
|
+
months_diff = recent_date.month - past_date.month + ((recent_date.day >= past_date.day) ? 0 : -1)
|
18
|
+
if months_diff < 0
|
19
|
+
months_diff = 12 + months_diff
|
20
|
+
years_diff -= 1
|
21
|
+
end
|
22
|
+
return years_diff*12 + months_diff
|
23
|
+
end
|
24
|
+
|
25
|
+
# Parses given INTERVAL string into hash.
|
26
|
+
#
|
27
|
+
# Sample use:
|
28
|
+
# "1w" => {:length => 1, :unit => :w }
|
29
|
+
# "0.5 m" => {:length => 0.5, :unit => :m }
|
30
|
+
# "10 d" => {:length => 10, :unit => :d }
|
31
|
+
# "3y" => {:length => 3, :unit => :y }
|
32
|
+
# "0.25 w" => ArgumentError
|
33
|
+
# "2 x" => ArgumentError
|
34
|
+
def parse_interval(interval)
|
35
|
+
if (interval =~ /^(\d+|0\.5)\s*(d|w|m|y)$/i)
|
36
|
+
return $1 == '0.5' ? 0.5 : $1.to_i, $2.downcase.to_sym
|
37
|
+
end
|
38
|
+
raise ArgumentError, "Invalid value format for payment interval: #{interval}"
|
39
|
+
end
|
40
|
+
|
41
|
+
# Returns number of payment occurrences between END_DATE and START_DATE with INTERVAL frequency.
|
42
|
+
#
|
43
|
+
# INTERVAL should be given in the same format parse_interval uses. END_DATE and START_DATE should be either Date or DateTime.
|
44
|
+
# Returned number includes initial payment.
|
45
|
+
#
|
46
|
+
# Sample use:
|
47
|
+
# [Date.today(), '1 w', Date.today()+18] => 3
|
48
|
+
# [DateTime.new(2008, 09, 20), '1y', DateTime.new(2009, 09, 19)] => 1
|
49
|
+
def get_occurrences(start_date, interval, end_date)
|
50
|
+
|
51
|
+
start_date = Date.new(start_date.year,start_date.month,start_date.mday)
|
52
|
+
end_date = Date.new(end_date.year,end_date.month,end_date.mday)
|
53
|
+
raise ArgumentError, "Start date (#{start_date}) should be less than or equal to end date (#{end_date})" if (start_date>end_date)
|
54
|
+
|
55
|
+
i_length, i_unit = parse_interval(interval)
|
56
|
+
|
57
|
+
if i_length == 0.5 && ![:m, :y].include?(i_unit)
|
58
|
+
raise ArgumentError, "Semi- interval is not supported to this units (#{i_unit.to_s})"
|
59
|
+
end
|
60
|
+
|
61
|
+
new_interval = case i_unit
|
62
|
+
when :d then {:length=>i_length, :unit=>:days}
|
63
|
+
when :w then {:length=>i_length*7, :unit=>:days}
|
64
|
+
when :m then {:length=>i_length, :unit=>:months}
|
65
|
+
when :y then {:length=>i_length*12, :unit=>:months}
|
66
|
+
end
|
67
|
+
|
68
|
+
if new_interval[:unit] == :days
|
69
|
+
new_occurrences = 1 + ((end_date - start_date)/new_interval[:length]).to_i
|
70
|
+
elsif new_interval[:unit] == :months
|
71
|
+
new_occurrences = 1 + (months_between(end_date, start_date)/new_interval[:length]).to_i
|
72
|
+
end
|
73
|
+
return new_occurrences
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns midnight of specified DateTime object (as DateTime).
|
77
|
+
def get_midnight(datetime_x)
|
78
|
+
DateTime.new(datetime_x.year,datetime_x.month,datetime_x.mday)
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# This file has all of the ActiveMerchant test account credentials.
|
2
|
+
# Many gateways do not offer publicly available test accounts. In
|
3
|
+
# order to make testing the gateways easy you can copy this file to
|
4
|
+
# your home directory as the file ~/.active_merchant/fixtures.yml
|
5
|
+
# You can then place your own test account credentials in your local
|
6
|
+
# copy of the file.
|
7
|
+
#
|
8
|
+
# If the login is numeric, ensure that you place quotes around it.
|
9
|
+
# Leading zeros will be lost when YAML parses the file if you don't.
|
10
|
+
#
|
11
|
+
# Paste any required PEM certificates after the pem key.
|
12
|
+
#
|
13
|
+
authorize_net:
|
14
|
+
gateway: authorize_net
|
15
|
+
login: 6zz6m5N4Et
|
16
|
+
password: 9V9wUv6Yd92t27t5
|
17
|
+
is_test: true
|
18
|
+
|
19
|
+
# You can use either your API PEM file or API signature with PayPal.
|
20
|
+
paypal_certificate:
|
21
|
+
gateway: paypal
|
22
|
+
login: LOGIN
|
23
|
+
password: PASSWORD
|
24
|
+
subject:
|
25
|
+
pem: |--
|
26
|
+
PASTE YOUR PEM FILE HERE
|
27
|
+
|
28
|
+
paypal:
|
29
|
+
gateway: paypal
|
30
|
+
login: a.lebe_1220380924_biz_api1.list.ru
|
31
|
+
password: 1220380928
|
32
|
+
signature: An5ns1Kso7MWUdW4ErQKJJJ4qi4-ABavC-ayabELBOsjVjsDpfMCgJRN
|
33
|
+
is_test: true
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class AuthorizeNetGatewayRemoteTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
credentials = fixtures(:authorize_net)
|
7
|
+
assert @gw = RecurringBilling::AuthorizeNetGateway.new(credentials.update({:is_test => true}))
|
8
|
+
assert_equal @gw.name, 'Authorize.net'
|
9
|
+
@card = credit_card()
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_crud_recurring_payment
|
13
|
+
payment_options = {
|
14
|
+
:subscription_name => 'Test Subscription 1337',
|
15
|
+
:order => {:invoice_number => '407933'}
|
16
|
+
}
|
17
|
+
recurring_options = {
|
18
|
+
:start_date => Date.today + 1,
|
19
|
+
:end_date => Date.today + 290,
|
20
|
+
:interval => '1m'
|
21
|
+
}
|
22
|
+
|
23
|
+
billing_id = @gw.create(Money.us_dollar(15), @card, payment_options, recurring_options)
|
24
|
+
print "Create:\n"
|
25
|
+
print @gw.last_response.inspect
|
26
|
+
payment_options[:order] = {:invoice_number => '407934'}
|
27
|
+
@gw.update(billing_id, Money.us_dollar(16), @card, payment_options, nil)
|
28
|
+
print "\nUpdate:\n"
|
29
|
+
print @gw.last_response.inspect
|
30
|
+
@gw.delete(billing_id)
|
31
|
+
print "\nDelete:\n"
|
32
|
+
print @gw.last_response.inspect
|
33
|
+
assert true
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class PaypalGatewayRemoteTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
cred = fixtures(:paypal)
|
7
|
+
assert @gw = RecurringBilling::PaypalGateway.new(cred.update({:is_test=>true}))
|
8
|
+
assert_equal @gw.name, 'PayPal Website Payments Pro (US)'
|
9
|
+
@card = credit_card()
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_crud_recurring_payment
|
13
|
+
payment_options = {
|
14
|
+
:subscription_name => 'Test Subscription 1337',
|
15
|
+
:order => {:invoice_number => '407933'}
|
16
|
+
}
|
17
|
+
recurring_options = {
|
18
|
+
:start_date => Date.today + 1,
|
19
|
+
:end_date => Date.today + 290,
|
20
|
+
:interval => '1m'
|
21
|
+
}
|
22
|
+
|
23
|
+
print "\nCreate:\n"
|
24
|
+
billing_id = @gw.create(Money.us_dollar(15), @card, payment_options=payment_options, recurring_options=recurring_options)
|
25
|
+
print @gw.last_response.inspect
|
26
|
+
payment_options[:order] = {:invoice_number => '407934'}
|
27
|
+
assert @gw.last_response.success?
|
28
|
+
|
29
|
+
print "\n\nUpdate:\n"
|
30
|
+
@gw.update(billing_id, Money.us_dollar(16), @card, payment_options=payment_options)
|
31
|
+
print @gw.last_response.inspect
|
32
|
+
assert @gw.last_response.success?
|
33
|
+
|
34
|
+
print "\n\nInquiry:\n"
|
35
|
+
result = @gw.inquiry(billing_id)
|
36
|
+
print @gw.last_response.inspect
|
37
|
+
print "\n\n", result.inspect
|
38
|
+
assert @gw.last_response.success?
|
39
|
+
|
40
|
+
print "\n\nDelete:\n"
|
41
|
+
@gw.delete(billing_id)
|
42
|
+
print @gw.last_response.inspect
|
43
|
+
assert @gw.last_response.success?
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
class RecurringBillingRemoteTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@card = credit_card()
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform_generic_test(gateway)
|
10
|
+
random_invoice = "%06d" % rand(999999)
|
11
|
+
payment_options = {
|
12
|
+
:subscription_name => 'Test Subscription 1337',
|
13
|
+
:order => {:invoice_number => random_invoice}
|
14
|
+
}
|
15
|
+
recurring_options = {
|
16
|
+
:start_date => Date.today + 1,
|
17
|
+
:end_date => Date.today + 290,
|
18
|
+
:interval => '1m'
|
19
|
+
}
|
20
|
+
credentials = fixtures(gateway)
|
21
|
+
assert gw = RecurringBilling::RecurringBillingGateway.get_instance(credentials)
|
22
|
+
|
23
|
+
billing_id = gw.create(Money.us_dollar(15), @card, payment_options, recurring_options)
|
24
|
+
assert gw.last_response.success?
|
25
|
+
new_random_invoice = "%06d" % rand(999999)
|
26
|
+
payment_options[:order] = {:invoice_number => new_random_invoice}
|
27
|
+
gw.update(billing_id, Money.us_dollar(16), @card, payment_options, {})
|
28
|
+
assert gw.last_response.success?
|
29
|
+
gw.delete(billing_id)
|
30
|
+
assert gw.last_response.success?
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_paypal
|
34
|
+
perform_generic_test(:paypal)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_authorize_net
|
38
|
+
perform_generic_test(:authorize_net)
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
require 'active_merchant'
|
6
|
+
|
7
|
+
require File.dirname(__FILE__) + '/../lib/gateways'
|
8
|
+
|
9
|
+
# Turn off invalid certificate crashes
|
10
|
+
require 'openssl'
|
11
|
+
silence_warnings do
|
12
|
+
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
|
13
|
+
end
|
14
|
+
|
15
|
+
ActiveMerchant::Billing::Base.mode = :test
|
16
|
+
|
17
|
+
module RecurringBilling
|
18
|
+
module Assertions
|
19
|
+
def assert_field(field, value)
|
20
|
+
clean_backtrace do
|
21
|
+
assert_equal value, @helper.fields[field]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Allows the testing of you to check for negative assertions:
|
26
|
+
#
|
27
|
+
# # Instead of
|
28
|
+
# assert !something_that_is_false
|
29
|
+
#
|
30
|
+
# # Do this
|
31
|
+
# assert_false something_that_should_be_false
|
32
|
+
#
|
33
|
+
# An optional +msg+ parameter is available to help you debug.
|
34
|
+
def assert_false(boolean, message = nil)
|
35
|
+
message = build_message message, '<?> is not false or nil.', boolean
|
36
|
+
|
37
|
+
clean_backtrace do
|
38
|
+
assert_block message do
|
39
|
+
not boolean
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# A handy little assertion to check for a successful response:
|
45
|
+
#
|
46
|
+
# # Instead of
|
47
|
+
# assert_success response
|
48
|
+
#
|
49
|
+
# # DRY that up with
|
50
|
+
# assert_success response
|
51
|
+
#
|
52
|
+
# A message will automatically show the inspection of the response
|
53
|
+
# object if things go wrong.
|
54
|
+
def assert_success(response)
|
55
|
+
clean_backtrace do
|
56
|
+
assert response.success?, "Response failed: #{response.inspect}"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# The negative of +assert_success+
|
61
|
+
def assert_failure(response)
|
62
|
+
clean_backtrace do
|
63
|
+
assert_false response.success?, "Response expected to fail: #{response.inspect}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def assert_valid(validateable)
|
68
|
+
clean_backtrace do
|
69
|
+
assert validateable.valid?, "Expected to be valid"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def assert_not_valid(validateable)
|
74
|
+
clean_backtrace do
|
75
|
+
assert_false validateable.valid?, "Expected to not be valid"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def clean_backtrace(&block)
|
81
|
+
yield
|
82
|
+
rescue Test::Unit::AssertionFailedError => e
|
83
|
+
path = File.expand_path(__FILE__)
|
84
|
+
raise Test::Unit::AssertionFailedError, e.message, e.backtrace.reject { |line| File.expand_path(line) =~ /#{path}/ }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
module Test
|
90
|
+
module Unit
|
91
|
+
class TestCase
|
92
|
+
|
93
|
+
include RecurringBilling::Assertions
|
94
|
+
include Utils
|
95
|
+
|
96
|
+
DEFAULT_CREDENTIALS = File.dirname(__FILE__) + '/fixtures.yml'
|
97
|
+
|
98
|
+
private
|
99
|
+
def credit_card(number = '4242424242424242', options = {})
|
100
|
+
defaults = {
|
101
|
+
:number => number,
|
102
|
+
:month => 9,
|
103
|
+
:year => Time.now.year + 1,
|
104
|
+
:first_name => 'John',
|
105
|
+
:last_name => 'Doe',
|
106
|
+
:verification_value => '123',
|
107
|
+
:type => 'visa'
|
108
|
+
}.update(options)
|
109
|
+
|
110
|
+
ActiveMerchant::Billing::CreditCard.new(defaults)
|
111
|
+
end
|
112
|
+
|
113
|
+
def address(options = {})
|
114
|
+
{
|
115
|
+
:name => 'John Doe',
|
116
|
+
:address1 => '1234 My Street',
|
117
|
+
:address2 => 'Apt 1',
|
118
|
+
:company => 'Widgets Inc',
|
119
|
+
:city => 'Ottawa',
|
120
|
+
:state => 'ON',
|
121
|
+
:zip => 'K1C2N6',
|
122
|
+
:country => 'CA',
|
123
|
+
:phone => '(555)555-5555'
|
124
|
+
}.update(options)
|
125
|
+
end
|
126
|
+
|
127
|
+
def all_fixtures
|
128
|
+
@@fixtures ||= load_fixtures
|
129
|
+
end
|
130
|
+
|
131
|
+
def fixtures(key)
|
132
|
+
data = all_fixtures[key] || raise(StandardError, "No fixture data was found for '#{key}'")
|
133
|
+
|
134
|
+
data.dup
|
135
|
+
end
|
136
|
+
|
137
|
+
def load_fixtures
|
138
|
+
file = DEFAULT_CREDENTIALS
|
139
|
+
yaml_data = YAML.load(File.read(file))
|
140
|
+
symbolize_keys(yaml_data)
|
141
|
+
|
142
|
+
yaml_data
|
143
|
+
end
|
144
|
+
|
145
|
+
def symbolize_keys(hash)
|
146
|
+
return unless hash.is_a?(Hash)
|
147
|
+
|
148
|
+
hash.symbolize_keys!
|
149
|
+
hash.each{|k,v| symbolize_keys(v)}
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|