merchant_sidekick 0.4.2
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/.gitignore +12 -0
- data/Changelog.md +38 -0
- data/Gemfile +2 -0
- data/MIT-LICENSE +19 -0
- data/README.md +88 -0
- data/Rakefile +10 -0
- data/lib/merchant_sidekick.rb +45 -0
- data/lib/merchant_sidekick/active_merchant/credit_card_payment.rb +117 -0
- data/lib/merchant_sidekick/active_merchant/gateways/authorize_net_gateway.rb +26 -0
- data/lib/merchant_sidekick/active_merchant/gateways/base.rb +29 -0
- data/lib/merchant_sidekick/active_merchant/gateways/bogus_gateway.rb +19 -0
- data/lib/merchant_sidekick/active_merchant/gateways/paypal_gateway.rb +43 -0
- data/lib/merchant_sidekick/addressable/address.rb +400 -0
- data/lib/merchant_sidekick/addressable/addressable.rb +353 -0
- data/lib/merchant_sidekick/buyer.rb +99 -0
- data/lib/merchant_sidekick/gateway.rb +81 -0
- data/lib/merchant_sidekick/install.rb +19 -0
- data/lib/merchant_sidekick/invoice.rb +179 -0
- data/lib/merchant_sidekick/line_item.rb +128 -0
- data/lib/merchant_sidekick/migrations/addressable.rb +47 -0
- data/lib/merchant_sidekick/migrations/billing.rb +100 -0
- data/lib/merchant_sidekick/migrations/shopping_cart.rb +28 -0
- data/lib/merchant_sidekick/money.rb +38 -0
- data/lib/merchant_sidekick/order.rb +244 -0
- data/lib/merchant_sidekick/payment.rb +59 -0
- data/lib/merchant_sidekick/purchase_invoice.rb +180 -0
- data/lib/merchant_sidekick/purchase_order.rb +350 -0
- data/lib/merchant_sidekick/railtie.rb +7 -0
- data/lib/merchant_sidekick/sales_invoice.rb +56 -0
- data/lib/merchant_sidekick/sales_order.rb +122 -0
- data/lib/merchant_sidekick/sellable.rb +88 -0
- data/lib/merchant_sidekick/seller.rb +93 -0
- data/lib/merchant_sidekick/shopping_cart/cart.rb +225 -0
- data/lib/merchant_sidekick/shopping_cart/line_item.rb +152 -0
- data/lib/merchant_sidekick/version.rb +3 -0
- data/merchant_sidekick.gemspec +37 -0
- data/spec/address_spec.rb +153 -0
- data/spec/addressable_spec.rb +250 -0
- data/spec/buyer_spec.rb +203 -0
- data/spec/cart_line_item_spec.rb +58 -0
- data/spec/cart_spec.rb +213 -0
- data/spec/config/merchant_sidekick.yml +10 -0
- data/spec/credit_card_payment_spec.rb +175 -0
- data/spec/fixtures/addresses.yml +97 -0
- data/spec/fixtures/line_items.yml +18 -0
- data/spec/fixtures/orders.yml +24 -0
- data/spec/fixtures/payments.yml +17 -0
- data/spec/fixtures/products.yml +12 -0
- data/spec/fixtures/users.yml +11 -0
- data/spec/gateway_spec.rb +136 -0
- data/spec/invoice_spec.rb +79 -0
- data/spec/line_item_spec.rb +65 -0
- data/spec/order_spec.rb +85 -0
- data/spec/payment_spec.rb +14 -0
- data/spec/purchase_invoice_spec.rb +70 -0
- data/spec/purchase_order_spec.rb +191 -0
- data/spec/sales_invoice_spec.rb +58 -0
- data/spec/sales_order_spec.rb +107 -0
- data/spec/schema.rb +28 -0
- data/spec/sellable_spec.rb +34 -0
- data/spec/seller_spec.rb +201 -0
- data/spec/spec_helper.rb +255 -0
- metadata +201 -0
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe MerchantSidekick::SalesInvoice do
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@buyer = users(:sam)
|
7
|
+
@seller = users(:sally)
|
8
|
+
@product = products(:widget)
|
9
|
+
@invoice = MerchantSidekick::SalesInvoice.new(
|
10
|
+
:net_amount => Money.new(2995, 'USD'),
|
11
|
+
:tax_amount => Money.new(0, 'USD'),
|
12
|
+
:gross_amount => Money.new(2995, 'USD'),
|
13
|
+
:buyer => @buyer,
|
14
|
+
:seller => @seller
|
15
|
+
)
|
16
|
+
|
17
|
+
# addresses
|
18
|
+
@sally_billing = @invoice.build_origin_address(addresses(:sally_billing).content_attributes)
|
19
|
+
@sam_billing = @invoice.build_billing_address(addresses(:sam_billing).content_attributes)
|
20
|
+
@sam_shipping = @invoice.build_shipping_address(addresses(:sam_shipping).content_attributes)
|
21
|
+
|
22
|
+
# line items and add
|
23
|
+
@line_item = MerchantSidekick::LineItem.new(
|
24
|
+
:order => nil,
|
25
|
+
:invoice => @invoice,
|
26
|
+
:sellable => @product,
|
27
|
+
:tax_rate => 0
|
28
|
+
)
|
29
|
+
@line_item.should_not be_nil
|
30
|
+
@invoice.line_items.push(@line_item)
|
31
|
+
|
32
|
+
# credit card
|
33
|
+
@credit_card = valid_credit_card
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should cash" do
|
37
|
+
transaction do
|
38
|
+
lambda {
|
39
|
+
payment = @invoice.cash("success@test.tst")
|
40
|
+
payment.should be_success
|
41
|
+
payment.position.should == 1
|
42
|
+
@invoice.current_state.should == :paid
|
43
|
+
}.should change(MerchantSidekick::Payment, :count).by(1)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should not cash" do
|
48
|
+
transaction do
|
49
|
+
lambda {
|
50
|
+
payment = @invoice.cash("error@error.tst")
|
51
|
+
payment.should_not be_success
|
52
|
+
payment.position.should == 1
|
53
|
+
@invoice.current_state.should == :payment_declined
|
54
|
+
}.should change(MerchantSidekick::Payment, :count).by(1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe MerchantSidekick::SalesOrder, "with valid account" do
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@sam = users(:sam)
|
7
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
8
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
9
|
+
|
10
|
+
@user = @sally = users(:sally)
|
11
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
12
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
13
|
+
|
14
|
+
@product = products(:widget)
|
15
|
+
@order = @sally.sell_to @sam, @product
|
16
|
+
@account = "pass@test.tst"
|
17
|
+
|
18
|
+
# ActiveMerchant::Billing::Base.mode = :test
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return a payment" do
|
22
|
+
transaction do
|
23
|
+
@order.cash(@account).should be_instance_of(MerchantSidekick::ActiveMerchant::CreditCardPayment)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should return success" do
|
28
|
+
transaction do
|
29
|
+
@order.cash(@account).should be_success
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should be set to state pending" do
|
34
|
+
transaction do
|
35
|
+
@order.cash(@account)
|
36
|
+
@order.should be_approved
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should have a valid invoice" do
|
41
|
+
transaction do
|
42
|
+
@order.cash(@account)
|
43
|
+
@order.invoice.should_not be_nil
|
44
|
+
@order.invoice_id.should_not be_nil
|
45
|
+
@order.invoice.should be_instance_of(MerchantSidekick::SalesInvoice)
|
46
|
+
@order.invoice.should be_paid
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should set payment amount equal to order amount" do
|
51
|
+
transaction do
|
52
|
+
@order.cash(@account).amount.should == @order.total
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should have corret addresses" do
|
57
|
+
transaction do
|
58
|
+
@order.origin_address.to_s.should_not be_blank
|
59
|
+
@order.origin_address.to_s.should == @sally.billing_address.to_s
|
60
|
+
|
61
|
+
@order.billing_address.to_s.should_not be_blank
|
62
|
+
@order.billing_address.to_s.should == @sam.billing_address.to_s
|
63
|
+
|
64
|
+
@order.shipping_address.to_s.should_not be_blank
|
65
|
+
@order.shipping_address.to_s.should == @sam.shipping_address.to_s
|
66
|
+
|
67
|
+
@order.cash(@account).should be_success
|
68
|
+
|
69
|
+
@order.invoice.origin_address.to_s.should_not be_blank
|
70
|
+
@order.invoice.origin_address.to_s.should == @sally.billing_address.to_s
|
71
|
+
|
72
|
+
@order.invoice.billing_address.to_s.should_not be_blank
|
73
|
+
@order.invoice.billing_address.to_s.should == @sam.billing_address.to_s
|
74
|
+
|
75
|
+
@order.invoice.shipping_address.to_s.should_not be_blank
|
76
|
+
@order.invoice.shipping_address.to_s.should == @sam.shipping_address.to_s
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe MerchantSidekick::SalesOrder, "with invalid account" do
|
81
|
+
|
82
|
+
def setup
|
83
|
+
@sam = users(:sam)
|
84
|
+
@product = products(:widget)
|
85
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
86
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
87
|
+
|
88
|
+
@user = @sally = users(:sally)
|
89
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
90
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
91
|
+
|
92
|
+
@order = @sally.sell_to @sam, @product
|
93
|
+
@payment = @order.cash 'error@error.tst'
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should initialize and save the order and invoice" do
|
97
|
+
transaction do
|
98
|
+
@order.should be_is_a(MerchantSidekick::SalesOrder)
|
99
|
+
@order.should_not be_new_record
|
100
|
+
@order.invoice.should be_payment_declined
|
101
|
+
@order.should be_created
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
data/spec/schema.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require "merchant_sidekick/migrations/addressable"
|
2
|
+
require "merchant_sidekick/migrations/billing"
|
3
|
+
require "merchant_sidekick/migrations/shopping_cart"
|
4
|
+
|
5
|
+
CreateMerchantSidekickAddressableTables.up
|
6
|
+
CreateMerchantSidekickBillingTables.up
|
7
|
+
CreateMerchantSidekickShoppingCartTables.up
|
8
|
+
|
9
|
+
ActiveRecord::Schema.define :version => 0 do
|
10
|
+
create_table :addressables, :force => true do |t|
|
11
|
+
t.column :name, :string
|
12
|
+
t.column :type, :string
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table :products, :force => true do |t|
|
16
|
+
t.column :title, :string
|
17
|
+
t.column :description, :text
|
18
|
+
t.column :type, :string
|
19
|
+
t.column :price_cents, :integer, :null => false, :default => 0
|
20
|
+
t.column :price_currency, :string, :null => false, :default => "USD"
|
21
|
+
end
|
22
|
+
|
23
|
+
create_table :users, :force => true do |t|
|
24
|
+
t.column :name, :string
|
25
|
+
t.column :email, :string
|
26
|
+
t.column :type, :string
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe "A sellable model" do
|
4
|
+
|
5
|
+
it "should have a price" do
|
6
|
+
lambda { Product.new.should.respond_to?(:price) }.should_not raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have many line_items" do
|
10
|
+
lambda { Product.new.line_items.should == [] }.should_not raise_error
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have many orders" do
|
14
|
+
lambda { Product.new.orders.should == [] }.should_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "A sellable with money" do
|
20
|
+
|
21
|
+
it "should have a currency accessor" do
|
22
|
+
lambda {
|
23
|
+
Product.new.should.respond_to?(:price_cents)
|
24
|
+
Product.new.should.respond_to?(:price_currency)
|
25
|
+
Product.new.price_currency.should == "USD"
|
26
|
+
Product.new.currency.should == ::Money::Currency.wrap("USD")
|
27
|
+
}.should_not raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should have a currency as string accessor" do
|
31
|
+
lambda { Product.new.currency_as_string.should == "USD" }.should_not raise_error
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
data/spec/seller_spec.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
require File.expand_path("../spec_helper", __FILE__)
|
2
|
+
|
3
|
+
describe "A seller's model" do
|
4
|
+
|
5
|
+
it "should be able to sell" do
|
6
|
+
SellingUser.new.should respond_to(:sell)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be able to sell" do
|
10
|
+
SellingUser.new.should respond_to(:sell_to)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have many orders" do
|
14
|
+
lambda { SellingUser.new.orders(true).first }.should_not raise_error
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should have many invoices" do
|
18
|
+
lambda { SellingUser.new.invoices(true).first }.should_not raise_error
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should have many sales orders" do
|
22
|
+
lambda { SellingUser.new.sales_orders(true).first }.should_not raise_error
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have many sales invoices" do
|
26
|
+
lambda { SellingUser.new.sales_invoices(true).first }.should_not raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "A seller sells a product" do
|
32
|
+
|
33
|
+
def setup
|
34
|
+
@sally = users(:sally)
|
35
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
36
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
37
|
+
@sam = users(:sam)
|
38
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
39
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
40
|
+
@product = products(:widget)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create a new order" do
|
44
|
+
transaction do
|
45
|
+
lambda do
|
46
|
+
order = @sally.sell_to @sam, @product
|
47
|
+
order.should be_an_instance_of(MerchantSidekick::SalesOrder)
|
48
|
+
order.buyer.should == @sam
|
49
|
+
order.should be_valid
|
50
|
+
order.save!
|
51
|
+
end.should change(MerchantSidekick::Order, :count)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should build sales order :to option" do
|
56
|
+
transaction do
|
57
|
+
lambda do
|
58
|
+
order = @sally.sell @product, :to => @sam
|
59
|
+
order.should be_an_instance_of(MerchantSidekick::SalesOrder)
|
60
|
+
order.seller.should == @sally
|
61
|
+
order.buyer.should == @sam
|
62
|
+
order.should be_valid
|
63
|
+
order.save!
|
64
|
+
end.should change(MerchantSidekick::Order, :count)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should add to seller's orders" do
|
69
|
+
transaction do
|
70
|
+
order = @sally.sell_to(@sam, @product)
|
71
|
+
order.save!
|
72
|
+
@sally.orders.last.should == order
|
73
|
+
@sally.sales_orders.last.should == order
|
74
|
+
order.seller.should == @sally
|
75
|
+
order.buyer.should == @sam
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should create line items" do
|
80
|
+
transaction do
|
81
|
+
order = @sally.sell_to(@sam, @product)
|
82
|
+
order.line_items.size.should == 1
|
83
|
+
order.line_items.first.sellable.should == @product
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should set line item amount to sellable price" do
|
88
|
+
transaction do
|
89
|
+
order = @sally.sell_to @sam, @product
|
90
|
+
order.line_items.first.amount.should == @product.price
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should set line item amount to 0 if sellable does not have a price" do
|
95
|
+
transaction do
|
96
|
+
@product.price = 0
|
97
|
+
order = @sally.sell_to @sam, @product
|
98
|
+
order.line_items.first.amount.should == 0.to_money
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should ignore blank sellables" do
|
103
|
+
transaction do
|
104
|
+
order = @sally.sell_to @sam, @product, nil
|
105
|
+
order.line_items.size.should == 1
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "A seller selling multiple products" do
|
112
|
+
|
113
|
+
def setup
|
114
|
+
@sally = users(:sally)
|
115
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
116
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
117
|
+
@sam = users(:sam)
|
118
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
119
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
120
|
+
@products = [products(:widget), products(:knob)]
|
121
|
+
@order = @sally.sell_to @sam, @products
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should create line items for each sellable" do
|
125
|
+
transaction do
|
126
|
+
lambda { @order.save! }.should change(MerchantSidekick::LineItem, :count).by(2)
|
127
|
+
@order.should have(2).line_items
|
128
|
+
@order.line_items.map(&:sellable).should == @products
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe "A seller selling a cart" do
|
134
|
+
|
135
|
+
def setup
|
136
|
+
@sally = users(:sally)
|
137
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
138
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
139
|
+
@sam = users(:sam)
|
140
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
141
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
142
|
+
@products = [products(:widget), products(:knob)]
|
143
|
+
@order = @sally.sell_to @sam, @products
|
144
|
+
@cart = MerchantSidekick::ShoppingCart::Cart.new
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should sell one cart" do
|
148
|
+
transaction do
|
149
|
+
@cart.add(@products)
|
150
|
+
@cart.total.to_s.should == "33.94"
|
151
|
+
order = @sally.sell_to @sam, @cart
|
152
|
+
order.total.to_s.should == "33.94"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should sell multipe carts" do
|
157
|
+
transaction do
|
158
|
+
cart1 = MerchantSidekick::ShoppingCart::Cart.new
|
159
|
+
cart2 = MerchantSidekick::ShoppingCart::Cart.new
|
160
|
+
|
161
|
+
cart1.add(@products.first)
|
162
|
+
cart2.add(@products.last)
|
163
|
+
order = @sally.sell_to @sam, cart1, cart2
|
164
|
+
order.total.to_s.should == "33.94"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
describe "A seller selling no product" do
|
172
|
+
|
173
|
+
def setup
|
174
|
+
@sally = users(:sally)
|
175
|
+
@sally_billing = @sally.create_billing_address(addresses(:sally_billing).content_attributes)
|
176
|
+
@sally_shipping = @sally.create_shipping_address(addresses(:sally_shipping).content_attributes)
|
177
|
+
@sam = users(:sam)
|
178
|
+
@sam_billing = @sam.create_billing_address(addresses(:sam_billing).content_attributes)
|
179
|
+
@sam_shipping = @sam.create_shipping_address(addresses(:sam_shipping).content_attributes)
|
180
|
+
@product = products(:widget)
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should raise an error as sell is a protected method" do
|
184
|
+
transaction do
|
185
|
+
lambda { @sally.sell(@product) }.should raise_error(NoMethodError)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should raise an error for there is no sellable" do
|
190
|
+
transaction do
|
191
|
+
lambda { @sally.sell_to(@sam) }.should raise_error(ArgumentError)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
it "should raise an error for no sellable" do
|
196
|
+
transaction do
|
197
|
+
lambda { @sally.sell_to(@sam, []) }.should raise_error(ArgumentError)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,255 @@
|
|
1
|
+
require "bundler/setup"
|
2
|
+
require "rspec"
|
3
|
+
require "active_record"
|
4
|
+
require "active_support"
|
5
|
+
require "sqlite3"
|
6
|
+
require "merchant_sidekick"
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
# config.use_transactional_fixtures = true
|
10
|
+
# config.use_instantiated_fixtures = false
|
11
|
+
# config.fixture_path = File.dirname(__FILE__) + '/fixtures'
|
12
|
+
end
|
13
|
+
|
14
|
+
# If you want to see the ActiveRecord log, invoke the tests using `rake test LOG=true`
|
15
|
+
if ENV["LOG"]
|
16
|
+
require "logger"
|
17
|
+
ActiveRecord::Base.logger = Logger.new($stdout)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Provide basic Rails methods for testing purposes
|
21
|
+
unless defined?(Rails)
|
22
|
+
module Rails
|
23
|
+
extend self
|
24
|
+
def env; "test"; end
|
25
|
+
def root; Pathname.new(File.expand_path("..", __FILE__)); end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
|
30
|
+
ActiveRecord::Migration.verbose = false
|
31
|
+
|
32
|
+
require "schema"
|
33
|
+
at_exit {ActiveRecord::Base.connection.disconnect!}
|
34
|
+
|
35
|
+
Money.default_currency = Money::Currency.wrap("USD")
|
36
|
+
|
37
|
+
#--- Sudo fixtures
|
38
|
+
|
39
|
+
def transaction
|
40
|
+
ActiveRecord::Base.connection.transaction do
|
41
|
+
send(:setup) if respond_to?(:setup)
|
42
|
+
yield
|
43
|
+
raise ActiveRecord::Rollback
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def users(key, options = {})
|
48
|
+
values = YAML::load_file(File.expand_path("../fixtures/users.yml", __FILE__))
|
49
|
+
(values[key.to_s]["type"] || "User").constantize.create! values[key.to_s].merge(options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def products(key, options = {})
|
53
|
+
values = YAML::load_file(File.expand_path("../fixtures/products.yml", __FILE__))
|
54
|
+
(values[key.to_s]["type"] || "Product").constantize.create! values[key.to_s].merge(options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def addresses(key, options = {})
|
58
|
+
values = YAML::load_file(File.expand_path("../fixtures/addresses.yml", __FILE__))
|
59
|
+
(values[key.to_s]["type"] || "MerchantSidekick::Addressable::Address").constantize.create! values[key.to_s].merge(options)
|
60
|
+
end
|
61
|
+
|
62
|
+
def orders(key, options = {})
|
63
|
+
values = YAML::load_file(File.expand_path("../fixtures/orders.yml", __FILE__))
|
64
|
+
(values[key.to_s]["type"] || "MerchantSidekick::Order").constantize.create! values[key.to_s].merge(options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def payments(key, options = {})
|
68
|
+
values = YAML::load_file(File.expand_path("../fixtures/payments.yml", __FILE__))
|
69
|
+
(values[key.to_s]["type"] || "MerchantSidekick::Payment").constantize.create! values[key.to_s].merge(options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def line_items(key, options = {})
|
73
|
+
values = YAML::load_file(File.expand_path("../fixtures/line_items.yml", __FILE__))
|
74
|
+
(values[key.to_s]["type"] || "MerchantSidekick::LineItem").constantize.create! values[key.to_s].merge(options)
|
75
|
+
end
|
76
|
+
|
77
|
+
#--- MerchantSidekick::Addressable test models
|
78
|
+
|
79
|
+
class MerchantSidekick::Addressable::Address
|
80
|
+
# extends to_s to add name for testing purposes
|
81
|
+
def to_s_with_name
|
82
|
+
name = []
|
83
|
+
name << self.first_name
|
84
|
+
name << self.middle_name if MerchantSidekick::Addressable::Address.middle_name?
|
85
|
+
name << self.last_name
|
86
|
+
name = name.reject(&:blank?).join(" ")
|
87
|
+
[name, to_s_without_name].reject(&:blank?).join(", ")
|
88
|
+
end
|
89
|
+
alias_method_chain :to_s, :name
|
90
|
+
end
|
91
|
+
|
92
|
+
class Addressable < ActiveRecord::Base; end
|
93
|
+
|
94
|
+
class HasOneSingleAddressModel < Addressable
|
95
|
+
has_address
|
96
|
+
end
|
97
|
+
|
98
|
+
class HasManySingleAddressModel < Addressable
|
99
|
+
has_addresses
|
100
|
+
end
|
101
|
+
|
102
|
+
class HasOneMultipleAddressModel < Addressable
|
103
|
+
has_address :billing, :shipping
|
104
|
+
end
|
105
|
+
|
106
|
+
class HasManyMultipleAddressModel < Addressable
|
107
|
+
has_addresses :billing, :shipping
|
108
|
+
end
|
109
|
+
|
110
|
+
def valid_address_attributes(attributes = {})
|
111
|
+
{
|
112
|
+
:first_name => "George",
|
113
|
+
:last_name => "Bush",
|
114
|
+
:gender => 'm',
|
115
|
+
:street => "100 Washington St.",
|
116
|
+
:postal_code => "95065",
|
117
|
+
:city => "Santa Cruz",
|
118
|
+
:province_code => "CA",
|
119
|
+
:province => "California",
|
120
|
+
:company_name => "Exxon",
|
121
|
+
:phone => "+1 831 123-4567",
|
122
|
+
:mobile => "+1 831 223-4567",
|
123
|
+
:fax => "+1 831 323-4567",
|
124
|
+
:country_code => "US",
|
125
|
+
:country => "United States of America"
|
126
|
+
}.merge(MerchantSidekick::Addressable::Address.middle_name? ? { :middle_name => "W." } : {}).merge(attributes)
|
127
|
+
end
|
128
|
+
|
129
|
+
#--- MerchantSidekick generic test models
|
130
|
+
|
131
|
+
class Product < ActiveRecord::Base
|
132
|
+
money :price, :cents => :price_cents, :currency => :price_currency
|
133
|
+
acts_as_sellable
|
134
|
+
|
135
|
+
# TODO weird cart serialization workaround
|
136
|
+
def target; true; end
|
137
|
+
end
|
138
|
+
|
139
|
+
class ProductWithNameAndSku < Product
|
140
|
+
def name; "A beautiful name"; end
|
141
|
+
def sku; "PR1234"; end
|
142
|
+
def description; "Wonderful name!"; end
|
143
|
+
def taxable; true; end
|
144
|
+
end
|
145
|
+
|
146
|
+
class ProductWithTitleAndNumber < Product
|
147
|
+
def title; "A beautiful title"; end
|
148
|
+
def number; "PR1234"; end
|
149
|
+
def description; "Wonderful title!"; end
|
150
|
+
def new_record?; true; end
|
151
|
+
end
|
152
|
+
|
153
|
+
class ProductWithCopy < Product
|
154
|
+
def copy_name(options={}); "customized name"; end
|
155
|
+
def copy_item_number(options = {}); "customized item number"; end
|
156
|
+
def copy_description(options = {}); "customized description"; end
|
157
|
+
def copy_price(options = {}); Money.new(9999, "USD"); end
|
158
|
+
end
|
159
|
+
|
160
|
+
class User < ActiveRecord::Base
|
161
|
+
has_address :billing, :shipping
|
162
|
+
end
|
163
|
+
|
164
|
+
# TODO rename to just "Buyer"
|
165
|
+
class BuyingUser < User
|
166
|
+
acts_as_buyer
|
167
|
+
end
|
168
|
+
|
169
|
+
# TODO rename to just "Seller"
|
170
|
+
class SellingUser < User
|
171
|
+
acts_as_seller
|
172
|
+
end
|
173
|
+
|
174
|
+
#--- MerchantSidekick shopping cart
|
175
|
+
|
176
|
+
def valid_cart_line_item_attributes(attributes = {})
|
177
|
+
{:quantity => 5}.merge(attributes)
|
178
|
+
end
|
179
|
+
|
180
|
+
#--- ActiveMerchant related helpers
|
181
|
+
|
182
|
+
def valid_credit_card_attributes(attributes = {})
|
183
|
+
{
|
184
|
+
:number => "1", #"4242424242424242",
|
185
|
+
:first_name => "Claudio",
|
186
|
+
:last_name => "Almende",
|
187
|
+
:month => "8",
|
188
|
+
:year => "#{ Time.now.year + 1 }",
|
189
|
+
:verification_value => '123',
|
190
|
+
:type => 'visa'
|
191
|
+
}.merge(attributes)
|
192
|
+
end
|
193
|
+
|
194
|
+
def invalid_credit_card_attributes(attributes = {})
|
195
|
+
{
|
196
|
+
:first_name => "Bad",
|
197
|
+
:last_name => "Boy",
|
198
|
+
:month => "8",
|
199
|
+
:year => Time.now.year + 1,
|
200
|
+
:number => "2",
|
201
|
+
:type => "bogus"
|
202
|
+
}.merge(attributes)
|
203
|
+
end
|
204
|
+
|
205
|
+
def credit_card(options={})
|
206
|
+
ActiveMerchant::Billing::CreditCard.new(valid_credit_card_attributes(options))
|
207
|
+
end
|
208
|
+
|
209
|
+
def valid_credit_card(options={})
|
210
|
+
credit_card(valid_credit_card_attributes(options))
|
211
|
+
end
|
212
|
+
|
213
|
+
def invalid_credit_card(options={})
|
214
|
+
credit_card(invalid_credit_card_attributes(options))
|
215
|
+
end
|
216
|
+
|
217
|
+
module ActiveMerchant
|
218
|
+
module Billing
|
219
|
+
class BogusGateway < Gateway
|
220
|
+
|
221
|
+
# Transfers money to one or multiple recipients (bulk transfer).
|
222
|
+
#
|
223
|
+
# Overloaded activemerchant bogus gateways to support transfers, similar
|
224
|
+
# to Paypal Website Payments Pro functionality.
|
225
|
+
#
|
226
|
+
# E.g.
|
227
|
+
#
|
228
|
+
# @gateway.transfer 1000, "bob@example.com",
|
229
|
+
# :subject => "The money I owe you", :note => "Sorry, it's coming in late."
|
230
|
+
#
|
231
|
+
# gateway.transfer [1000, 'fred@example.com'],
|
232
|
+
# [2450, 'wilma@example.com', :note => 'You will receive an extra payment on March 24.'],
|
233
|
+
# [2000, 'barney@example.com'],
|
234
|
+
# :subject => "Salary January.", :note => "Thanks for your hard work."
|
235
|
+
|
236
|
+
def transfer(money, paypal_account, options={})
|
237
|
+
if paypal_account == 'fail@error.tst'
|
238
|
+
Response.new(false, FAILURE_MESSAGE, {:paid_amount => money.to_s, :error => FAILURE_MESSAGE },:test => true)
|
239
|
+
elsif paypal_account == 'error@error.tst'
|
240
|
+
raise Error, ERROR_MESSAGE
|
241
|
+
elsif /[\w-]+(?:\.[\w-]+)*@(?:[\w-]+\.)+[a-zA-Z]{2,7}$/i.match(paypal_account)
|
242
|
+
Response.new(true, SUCCESS_MESSAGE, {:paid_amount => money.to_s}, :test => true)
|
243
|
+
else
|
244
|
+
raise Error, ERROR_MESSAGE
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
ActiveMerchant::Billing::Base.mode = :test
|
253
|
+
ActiveMerchant::Billing::CreditCard.require_verification_value = true
|
254
|
+
|
255
|
+
MerchantSidekick::default_gateway = :bogus_gateway
|