servicemerchant 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|