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.
Files changed (63) hide show
  1. data/.gitignore +12 -0
  2. data/Changelog.md +38 -0
  3. data/Gemfile +2 -0
  4. data/MIT-LICENSE +19 -0
  5. data/README.md +88 -0
  6. data/Rakefile +10 -0
  7. data/lib/merchant_sidekick.rb +45 -0
  8. data/lib/merchant_sidekick/active_merchant/credit_card_payment.rb +117 -0
  9. data/lib/merchant_sidekick/active_merchant/gateways/authorize_net_gateway.rb +26 -0
  10. data/lib/merchant_sidekick/active_merchant/gateways/base.rb +29 -0
  11. data/lib/merchant_sidekick/active_merchant/gateways/bogus_gateway.rb +19 -0
  12. data/lib/merchant_sidekick/active_merchant/gateways/paypal_gateway.rb +43 -0
  13. data/lib/merchant_sidekick/addressable/address.rb +400 -0
  14. data/lib/merchant_sidekick/addressable/addressable.rb +353 -0
  15. data/lib/merchant_sidekick/buyer.rb +99 -0
  16. data/lib/merchant_sidekick/gateway.rb +81 -0
  17. data/lib/merchant_sidekick/install.rb +19 -0
  18. data/lib/merchant_sidekick/invoice.rb +179 -0
  19. data/lib/merchant_sidekick/line_item.rb +128 -0
  20. data/lib/merchant_sidekick/migrations/addressable.rb +47 -0
  21. data/lib/merchant_sidekick/migrations/billing.rb +100 -0
  22. data/lib/merchant_sidekick/migrations/shopping_cart.rb +28 -0
  23. data/lib/merchant_sidekick/money.rb +38 -0
  24. data/lib/merchant_sidekick/order.rb +244 -0
  25. data/lib/merchant_sidekick/payment.rb +59 -0
  26. data/lib/merchant_sidekick/purchase_invoice.rb +180 -0
  27. data/lib/merchant_sidekick/purchase_order.rb +350 -0
  28. data/lib/merchant_sidekick/railtie.rb +7 -0
  29. data/lib/merchant_sidekick/sales_invoice.rb +56 -0
  30. data/lib/merchant_sidekick/sales_order.rb +122 -0
  31. data/lib/merchant_sidekick/sellable.rb +88 -0
  32. data/lib/merchant_sidekick/seller.rb +93 -0
  33. data/lib/merchant_sidekick/shopping_cart/cart.rb +225 -0
  34. data/lib/merchant_sidekick/shopping_cart/line_item.rb +152 -0
  35. data/lib/merchant_sidekick/version.rb +3 -0
  36. data/merchant_sidekick.gemspec +37 -0
  37. data/spec/address_spec.rb +153 -0
  38. data/spec/addressable_spec.rb +250 -0
  39. data/spec/buyer_spec.rb +203 -0
  40. data/spec/cart_line_item_spec.rb +58 -0
  41. data/spec/cart_spec.rb +213 -0
  42. data/spec/config/merchant_sidekick.yml +10 -0
  43. data/spec/credit_card_payment_spec.rb +175 -0
  44. data/spec/fixtures/addresses.yml +97 -0
  45. data/spec/fixtures/line_items.yml +18 -0
  46. data/spec/fixtures/orders.yml +24 -0
  47. data/spec/fixtures/payments.yml +17 -0
  48. data/spec/fixtures/products.yml +12 -0
  49. data/spec/fixtures/users.yml +11 -0
  50. data/spec/gateway_spec.rb +136 -0
  51. data/spec/invoice_spec.rb +79 -0
  52. data/spec/line_item_spec.rb +65 -0
  53. data/spec/order_spec.rb +85 -0
  54. data/spec/payment_spec.rb +14 -0
  55. data/spec/purchase_invoice_spec.rb +70 -0
  56. data/spec/purchase_order_spec.rb +191 -0
  57. data/spec/sales_invoice_spec.rb +58 -0
  58. data/spec/sales_order_spec.rb +107 -0
  59. data/spec/schema.rb +28 -0
  60. data/spec/sellable_spec.rb +34 -0
  61. data/spec/seller_spec.rb +201 -0
  62. data/spec/spec_helper.rb +255 -0
  63. metadata +201 -0
@@ -0,0 +1,152 @@
1
+ # MerchantSidekick::ShoppingCart::LineItem duplicates the actual purchasable product upon putting a product into a cart.
2
+ # This is necessary, because we want to maintain order information even after the product
3
+ # might have already been removed from the system.
4
+ #
5
+ # This class copies many of the product attributes, because product rows usually undergo
6
+ # constant changes (description, price, etc.), while the cart_line_item will remain unchanged
7
+ # during its lifetime.
8
+ module MerchantSidekick
9
+ module ShoppingCart
10
+ class LineItem < ActiveRecord::Base
11
+ self.table_name = "cart_line_items"
12
+
13
+ attr_accessor :options
14
+
15
+ belongs_to :product, :polymorphic => true
16
+ money :unit_price, :cents => "cents", :currency => "currency"
17
+ acts_as_sellable
18
+
19
+ validates_presence_of :product
20
+
21
+ def options=(some_options={})
22
+ @options = some_options.to_hash
23
+ end
24
+
25
+ def options
26
+ @options || {}
27
+ end
28
+
29
+ def product_with_price=(a_product)
30
+ if a_product && (a_product.respond_to?(:price) || a_product.respond_to?(:copy_price))
31
+ self[:taxable] = if a_product.respond_to?(:taxable?)
32
+ a_product.send(:taxable?)
33
+ elsif a_product.respond_to?(:taxable)
34
+ a_product.send(:taxable)
35
+ else
36
+ false
37
+ end
38
+ self[:unit] = a_product.respond_to?(:unit) ? a_product.unit.to_s : 'piece'
39
+ self[:pieces] = a_product.respond_to?(:pieces) ? a_product.pieces : 1,
40
+
41
+ # name from product copy_name method, name or title column
42
+ self[:name] = if a_product.respond_to?(:copy_name)
43
+ a_product.send(:copy_name, self.options)
44
+ elsif a_product.respond_to?(:title)
45
+ a_product.send(:title)
46
+ elsif a_product.respond_to?(:name)
47
+ a_product.send(:name)
48
+ else
49
+ 'No name'
50
+ end
51
+
52
+ # item_number from product copy_iten_number method, sku or number column
53
+ self[:item_number] = if a_product.respond_to?(:copy_item_number)
54
+ a_product.send(:copy_item_number, self.options)
55
+ elsif a_product.respond_to?(:sku)
56
+ a_product.send(:sku)
57
+ elsif a_product.respond_to?(:number)
58
+ a_product.send(:number)
59
+ else
60
+ a_product.id unless a_product.new_record?
61
+ end
62
+
63
+ # description from product copy_description or description column
64
+ self[:description] = if a_product.respond_to?(:copy_description)
65
+ a_product.send(:copy_description, self.options)
66
+ elsif a_product.respond_to?(:description)
67
+ a_product.send(:description)
68
+ else
69
+ 'No description'
70
+ end
71
+
72
+ # unit price
73
+ product_unit_price = if a_product.respond_to?(:copy_price)
74
+ a_product.send(:copy_price, self.options)
75
+ else
76
+ a_product.send(:price)
77
+ end
78
+ product_unit_price = ::Money.new(1, self.currency || 'USD') + product_unit_price - ::Money.new(1, self.currency || 'USD')
79
+ self.unit_price = product_unit_price
80
+ end
81
+ self.product_without_price = a_product
82
+ end
83
+ alias_method_chain :product=, :price
84
+
85
+ # overwrites from taxable? from acts_as_sellable
86
+ # Important! don't change this to is_taxable?, rather alias it!
87
+ def taxable?
88
+ self.taxable
89
+ end
90
+ alias_method :is_taxable?, :taxable?
91
+
92
+ # overwrites from price_is_net? from product
93
+ def price_is_net?
94
+ if self.product
95
+ return self.product.send(:price_is_net?) if self.product.respond_to?(:price_is_net?)
96
+ end
97
+ true
98
+ end
99
+
100
+ # overwrites from price_is_gross? from acts_as_sellable
101
+ def price_is_gross?
102
+ !price_is_net?
103
+ end
104
+
105
+ # Returns a product name and sets the title attribute
106
+ def name
107
+ self[:name]
108
+ end
109
+
110
+ # returns or sets the item number based on the product's
111
+ # SKU, number, or id
112
+ def item_number
113
+ self[:item_number]
114
+ end
115
+
116
+ # Make the unit a symbol
117
+ # getter
118
+ def unit
119
+ self[:unit].to_s.empty? ? :piece : self[:unit].to_sym
120
+ end
121
+
122
+ # Make the unit a symbol
123
+ # setter
124
+ def unit=(a_unit)
125
+ self[:unit] = a_unit.to_s
126
+ end
127
+
128
+ # total price = unit_price * quantity
129
+ # unit_price is defined as money!
130
+ def total_amount
131
+ self.unit_price * (self.quantity || 1)
132
+ end
133
+ alias_method :price, :total_amount
134
+ # alias_method :total_price, :total_amount
135
+
136
+ # Price per piece
137
+ # Example:
138
+ # 12 bottles (pieces) of a unit price of $45.00 per box (unit price)
139
+ # is a per piece price of $3.75
140
+ def price_per_piece
141
+ self.unit_price / (self.pieces || 1) if self.unit_price
142
+ end
143
+
144
+ # Returns a localized description text
145
+ # e.g. "12 months subscription for $74 ($5.95 per month)"
146
+ def description
147
+ self[:description]
148
+ end
149
+
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,3 @@
1
+ module MerchantSidekick
2
+ VERSION = "0.4.2"
3
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require File.expand_path("../lib/merchant_sidekick/version", __FILE__)
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "merchant_sidekick"
8
+ s.version = MerchantSidekick::VERSION
9
+ s.authors = ["Juergen Fesslmeier"]
10
+ s.email = ["jfesslmeier@gmail.com"]
11
+ s.homepage = ""
12
+ s.summary = "A light-weight E-commerce plugin."
13
+ s.rubyforge_project = "merchant_sidekick"
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_dependency "activerecord", ">= 3.1.0"
19
+ s.add_dependency "money"
20
+ s.add_dependency "acts_as_list"
21
+ s.add_dependency "aasm"
22
+ s.add_dependency "activemerchant"
23
+
24
+ s.add_development_dependency "rspec", "~> 2.7.0"
25
+ s.add_development_dependency "sqlite3"
26
+ s.add_development_dependency "rake"
27
+
28
+ s.description = <<-EOM
29
+ EOM
30
+
31
+ s.post_install_message = <<-EOM
32
+ NOTE: This is an experimental port of the original MerchantSidekick plugin.
33
+
34
+ https://github.com/chinshr/merchant_sidekick/README.md
35
+ EOM
36
+
37
+ end
@@ -0,0 +1,153 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe MerchantSidekick::Addressable::Address, "should handle default columns" do
4
+ it "should have default class attr columns assigned" do
5
+ MerchantSidekick::Addressable::Address.street_address_column.should == :street
6
+ MerchantSidekick::Addressable::Address.city_column.should == :city
7
+ MerchantSidekick::Addressable::Address.postal_code_column.should == :postal_code
8
+ MerchantSidekick::Addressable::Address.province_column.should == :province
9
+ MerchantSidekick::Addressable::Address.province_code_column.should == :province_code
10
+ MerchantSidekick::Addressable::Address.country_column.should == :country
11
+ MerchantSidekick::Addressable::Address.country_code_column.should == :country_code
12
+ MerchantSidekick::Addressable::Address.gender_column.should == :gender
13
+ MerchantSidekick::Addressable::Address.first_name_column.should == :first_name
14
+ MerchantSidekick::Addressable::Address.middle_name_column.should == false
15
+ MerchantSidekick::Addressable::Address.last_name_column.should == :last_name
16
+ end
17
+ end
18
+
19
+ describe MerchantSidekick::Addressable::Address, "with address members" do
20
+
21
+ before(:each) do
22
+ @address = MerchantSidekick::Addressable::Address.new(valid_address_attributes(:addressable => Addressable.create))
23
+ end
24
+
25
+ it "should create an address" do
26
+ @address.should_not == nil
27
+ @address.first_name.should == "George"
28
+ @address.firstname.should == "George"
29
+ @address.middle_name.should == "W." if @address.middle_name?
30
+ @address.last_name.should == "Bush"
31
+ @address.lastname.should == "Bush"
32
+ end
33
+
34
+ it "should handle street and address_line" do
35
+ @address.street.should == "100 Washington St."
36
+ @address.address_line_1.should == "100 Washington St."
37
+ end
38
+
39
+ it "should add address_line_2 properly" do
40
+ @address.street.should == "100 Washington St."
41
+ @address.address_line_2 = "Suite 1234"
42
+ @address.address_line_2.should == "Suite 1234"
43
+ @address.street.should == "100 Washington St.\nSuite 1234"
44
+ end
45
+
46
+ it "should address_line_1 and address_line_2 properly" do
47
+ @address.street = ''
48
+ @address.address_line_1 = "100 Enterprise Way"
49
+ @address.address_line_2 = "Office Square 15"
50
+
51
+ @address.address_line_1.should == "100 Enterprise Way"
52
+ @address.address_line_2.should == "Office Square 15"
53
+ @address.street.should == "100 Enterprise Way\nOffice Square 15"
54
+ end
55
+
56
+ it "should have a valid name" do
57
+ if @address.middle_name?
58
+ @address.name.should == "George W. Bush"
59
+ else
60
+ @address.name.should == "George Bush"
61
+ end
62
+ end
63
+
64
+ it "should have a valid salutation and name" do
65
+ if @address.middle_name?
66
+ @address.salutation_and_name.should == "Mr George W. Bush"
67
+ else
68
+ @address.salutation_and_name.should == "Mr George Bush"
69
+ end
70
+ end
71
+
72
+ it "should stringify address fields" do
73
+ # full
74
+ @address.to_s.should == "George Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
75
+
76
+ # sparse
77
+ @address = MerchantSidekick::Addressable::Address.new(
78
+ :street => "100 Sunshine Blvd.",
79
+ :postal_code => '95066',
80
+ :city => 'Scotts Valley',
81
+ :province_code => 'CA',
82
+ :country_code => 'US'
83
+ )
84
+ @address.to_s.should == "100 Sunshine Blvd., Scotts Valley, CA, 95066, US"
85
+ end
86
+
87
+ it "should return a name" do
88
+ @address.name.should == 'George Bush'
89
+ end
90
+
91
+ it "should return nil if names are nil" do
92
+ @address = MerchantSidekick::Addressable::Address.new
93
+ @address.name.should be_nil
94
+ end
95
+
96
+ it "should convert to active merchant address attributes" do
97
+ @address = MerchantSidekick::Addressable::Address.new(valid_address_attributes(
98
+ :addressable => Addressable.create,
99
+ :street => "100 Sunshine Blvd.\nSuite 7"
100
+ ))
101
+ merchant = @address.to_merchant_attributes
102
+ merchant[:name].should == "George Bush"
103
+ merchant[:address1].should == "100 Sunshine Blvd."
104
+ merchant[:address2].should == "Suite 7"
105
+ merchant[:city].should == "Santa Cruz"
106
+ merchant[:state].should == "CA"
107
+ merchant[:country].should == "US"
108
+ merchant[:zip].should == "95065"
109
+ merchant[:phone].should == "+1 831 123-4567"
110
+ end
111
+
112
+ it "should work with gender" do
113
+ @address.should be_gender # funny :-)
114
+ @address.gender = :male
115
+ @address.gender.should == 'm'
116
+ @address.should be_is_gender_male
117
+ @address.gender = :female
118
+ @address.gender.should == 'f'
119
+ @address.gender = 'm'
120
+ @address.gender.should == 'm'
121
+ @address.gender = 'f'
122
+ @address.gender.should == 'f'
123
+ end
124
+
125
+ it "should return a province or a province code" do
126
+ address = MerchantSidekick::Addressable::Address.new(:province => "California", :province_code => "CA" )
127
+ address.province_or_province_code.should == "California"
128
+
129
+ address = MerchantSidekick::Addressable::Address.new(:province_code => "CA" )
130
+ address.province_or_province_code.should == "CA"
131
+
132
+ address = MerchantSidekick::Addressable::Address.new(:province => "", :province_code => "CA" )
133
+ address.province_or_province_code.should == "CA"
134
+
135
+ address = MerchantSidekick::Addressable::Address.new
136
+ address.province_or_province_code.should be_nil
137
+ end
138
+
139
+ it "should return a country or a country code" do
140
+ address = MerchantSidekick::Addressable::Address.new(:country => 'Germany', :country_code => 'DE')
141
+ address.country_or_country_code.should == "Germany"
142
+
143
+ address = MerchantSidekick::Addressable::Address.new(:country_code => 'DE')
144
+ address.country_or_country_code.should == "DE"
145
+
146
+ address = MerchantSidekick::Addressable::Address.new(:country => '', :country_code => 'DE')
147
+ address.country_or_country_code.should == "DE"
148
+
149
+ address = MerchantSidekick::Addressable::Address.new
150
+ address.country_or_country_code.should be_nil
151
+ end
152
+
153
+ end
@@ -0,0 +1,250 @@
1
+ require File.expand_path("../spec_helper", __FILE__)
2
+
3
+ describe HasOneSingleAddressModel, "new" do
4
+
5
+ before(:each) do
6
+ MerchantSidekick::Addressable::Address.middle_name_column = false
7
+ @addressable = HasOneSingleAddressModel.new
8
+ @address = @addressable.build_address valid_address_attributes
9
+ end
10
+
11
+ it "should have an addressable for address" do
12
+ @address.addressable.should_not be_nil
13
+ @address.addressable.should == @addressable
14
+ end
15
+
16
+ end
17
+
18
+ describe HasOneSingleAddressModel, "create" do
19
+
20
+ before(:each) do
21
+ MerchantSidekick::Addressable::Address.middle_name_column = false
22
+ @addressable = HasOneSingleAddressModel.create
23
+ @address = @addressable.create_address valid_address_attributes
24
+ end
25
+
26
+ it "should have a single address" do
27
+ @addressable.address.should_not be_nil
28
+ @addressable.address.to_s.should == "George Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
29
+ end
30
+
31
+ end
32
+
33
+ describe HasManySingleAddressModel do
34
+
35
+ before(:each) do
36
+ MerchantSidekick::Addressable::Address.middle_name_column = false
37
+ @addressable = HasManySingleAddressModel.create
38
+ @address = @addressable.addresses.create valid_address_attributes
39
+ end
40
+
41
+ it "should hold at least one" do
42
+ @addressable.addresses.should_not be_empty
43
+ @addressable.addresses.size.should == 1
44
+ end
45
+
46
+ it "should add more addresses" do
47
+ @addressable.addresses.create valid_address_attributes(
48
+ :first_name => "Barbara", :last_name => "Bush"
49
+ )
50
+ @addressable.addresses.create valid_address_attributes(
51
+ :first_name => "Tom", :last_name => "Bush"
52
+ )
53
+ @addressable.addresses.size.should == 3
54
+ @addressable.addresses[0].to_s.should == "George Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
55
+ @addressable.addresses[1].to_s.should == "Barbara Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
56
+ @addressable.addresses[2].to_s.should == "Tom Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
57
+ end
58
+
59
+ end
60
+
61
+ describe HasOneMultipleAddressModel do
62
+
63
+ before(:each) do
64
+ MerchantSidekick::Addressable::Address.middle_name_column = false
65
+ @addressable = HasOneMultipleAddressModel.create
66
+ @billing_address = @addressable.create_billing_address valid_address_attributes(:first_name => "Bill")
67
+ @shipping_address = @addressable.create_shipping_address valid_address_attributes(:first_name => "Ship")
68
+ end
69
+
70
+ it "should have a valid billing address" do
71
+ @addressable.billing_address.should_not be_nil
72
+ @addressable.billing_address.type.should == "BillingAddress"
73
+ @addressable.billing_address.kind.should == :billing
74
+ @addressable.billing_address.to_s.should == "Bill Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
75
+ end
76
+
77
+ it "should populate addressable of an address instance with create" do
78
+ @addressable.billing_address.addressable.should == @addressable
79
+ end
80
+
81
+ it "should populate addressable of an address instance with build on an existing" do
82
+ @invoice = HasOneMultipleAddressModel.create
83
+ @invoice.build_billing_address(valid_address_attributes(:first_name => "Bill"))
84
+ @invoice.billing_address.should_not be_nil
85
+ @invoice.billing_address.addressable.should == @invoice
86
+ end
87
+
88
+ it "should populate addressable of an address instance with create on an existing" do
89
+ @invoice = HasOneMultipleAddressModel.create
90
+ @invoice.create_billing_address(valid_address_attributes(:first_name => "Bill"))
91
+ @invoice.billing_address.should_not be_nil
92
+ @invoice.billing_address.addressable.should == @invoice
93
+ end
94
+
95
+ it "should populate addressable of an address instance with build on a new" do
96
+ @invoice = HasOneMultipleAddressModel.new
97
+ @invoice.build_billing_address(valid_address_attributes(:first_name => "Bill"))
98
+ @invoice.billing_address.should_not be_nil
99
+ @invoice.billing_address.addressable.should == @invoice
100
+ end
101
+
102
+ it "should build_shipping_address" do
103
+ customer = HasOneMultipleAddressModel.create
104
+ address = customer.build_shipping_address valid_address_attributes
105
+ customer.shipping_address.should == address
106
+ customer.shipping_address.addressable.should == customer
107
+ end
108
+
109
+ it "should create_shipping_address" do
110
+ addressable = HasOneMultipleAddressModel.create
111
+ lambda {
112
+ address = addressable.create_shipping_address valid_address_attributes
113
+ addressable.shipping_address.should == address
114
+ addressable.shipping_address.addressable.should == addressable
115
+ }.should change(MerchantSidekick::Addressable::Address, :count)
116
+ end
117
+
118
+ it "should have a valid shipping address" do
119
+ @addressable.shipping_address.should_not be_nil
120
+ @addressable.shipping_address.should be_shipping
121
+ @addressable.shipping_address.to_s.should == "Ship Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
122
+ end
123
+
124
+ it "should assign a new shipping address" do
125
+ save_billing_address = @addressable.billing_address
126
+ @addressable.billing_address = BillingAddress.new valid_address_attributes(
127
+ :first_name => "New Billing"
128
+ )
129
+ @addressable.save
130
+ @addressable.reload
131
+ save_billing_address.to_s.should_not == @addressable.billing_address
132
+ save_billing_address.id.should_not == @addressable.billing_address.id
133
+ @addressable.billing_address.first_name.should == "New Billing"
134
+ end
135
+
136
+ it "should find_addresses" do
137
+ #@addressable.addresses.first.should == @billing_address
138
+
139
+ address = @addressable.find_addresses(:first, :billing)
140
+ address.should == @billing_address
141
+ end
142
+
143
+ it "should find_billing_address" do
144
+ address = @addressable.find_billing_address
145
+ address.should == @billing_address
146
+
147
+ address = @addressable.find_billing_address :conditions => @billing_address.content_attributes
148
+ address.should == @billing_address
149
+ end
150
+
151
+ it "should find_default_shipping_address and default_shipping_address" do
152
+ @addressable.find_default_shipping_address.should == @shipping_address
153
+ @addressable.default_shipping_address.should == @shipping_address
154
+ end
155
+
156
+
157
+ it "should find_or_build_shipping_address" do
158
+ # take existing shipping address
159
+ lambda {
160
+ existing_address = @addressable.find_or_build_shipping_address(
161
+ @shipping_address.content_attributes
162
+ )
163
+ }.should_not change(MerchantSidekick::Addressable::Address, :count)
164
+
165
+ # new shipping addresss
166
+ #lambda {
167
+ new_address = @addressable.find_or_build_shipping_address(valid_address_attributes(
168
+ :first_name => "New shipping address")
169
+ )
170
+ new_address.should be_new_record
171
+ new_address.should be_shipping
172
+ new_address.first_name.should == "New shipping address"
173
+ new_address.save
174
+ #}.should change(MerchantSidekick::Addressable::Address, :count)
175
+ end
176
+
177
+ it "should find_billing_address_or_clone_from" do
178
+ # billing address exists, don't clone
179
+ address = @addressable.find_billing_address_or_clone_from :shipping
180
+ address.should be_instance_of(BillingAddress)
181
+ address.should == @billing_address
182
+ address.street.should == @billing_address.street
183
+
184
+ # destroy billing address
185
+ lambda {
186
+ @addressable.billing_address.destroy
187
+ @addressable.reload
188
+ @addressable.billing_address.should == nil
189
+ }.should change(MerchantSidekick::Addressable::Address, :count)
190
+
191
+ # clone from new instance
192
+ shipping_address = ShippingAddress.new valid_address_attributes(
193
+ :first_name => "Another Shipping Address"
194
+ )
195
+ lambda {
196
+ cloned_address = @addressable.find_billing_address_or_clone_from shipping_address
197
+ cloned_address.should be_instance_of(BillingAddress)
198
+ cloned_address.should be_billing
199
+ cloned_address.first_name.should == "Another Shipping Address"
200
+ @addressable.save
201
+ }.should change(MerchantSidekick::Addressable::Address, :count)
202
+
203
+ # destroy billing address
204
+ @addressable.billing_address.destroy
205
+ @addressable.reload
206
+
207
+ # clone from attributes
208
+ shipping_address = ShippingAddress.new valid_address_attributes(
209
+ :first_name => "Yet Another Shipping Address"
210
+ )
211
+ lambda {
212
+ cloned_address = @addressable.find_billing_address_or_clone_from shipping_address.content_attributes
213
+ cloned_address.should be_instance_of(BillingAddress)
214
+ cloned_address.should be_billing
215
+ cloned_address.first_name.should == "Yet Another Shipping Address"
216
+ @addressable.save
217
+ }.should change(MerchantSidekick::Addressable::Address, :count)
218
+ end
219
+
220
+ end
221
+
222
+ describe HasManyMultipleAddressModel do
223
+
224
+ before(:each) do
225
+ MerchantSidekick::Addressable::Address.middle_name_column = false
226
+ @addressable = HasManyMultipleAddressModel.create
227
+ @billing_address = @addressable.billing_addresses.create valid_address_attributes(:first_name => "Bill")
228
+ @shipping_address = @addressable.shipping_addresses.create valid_address_attributes(:first_name => "Ship")
229
+ end
230
+
231
+ it "should have at least one valid billing addresses" do
232
+ @addressable.billing_addresses.should_not be_empty
233
+ @addressable.addresses.size.should == 2
234
+ @addressable.billing_addresses.size.should == 1
235
+ @addressable.billing_addresses.first.should be_billing
236
+ @addressable.billing_addresses.first.should_not be_shipping
237
+ @addressable.billing_addresses.first.to_s.should == "Bill Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
238
+ end
239
+
240
+ it "should have at least one valid shipping addresses" do
241
+ @addressable.shipping_addresses.should_not be_empty
242
+ @addressable.addresses.size.should == 2
243
+ @addressable.shipping_addresses.size.should == 1
244
+ @addressable.shipping_addresses.first.should be_shipping
245
+ @addressable.shipping_addresses.first.should_not be_billing
246
+ @addressable.shipping_addresses.first.to_s.should == "Ship Bush, 100 Washington St., Santa Cruz, California, 95065, United States of America"
247
+ end
248
+
249
+ end
250
+