active_cart 0.0.6 → 0.0.7

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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.7
data/lib/active_cart.rb CHANGED
@@ -11,6 +11,8 @@ require 'order_total_collection'
11
11
  require 'cart'
12
12
  require 'acts_as_cart' if defined?(ActiveRecord)
13
13
 
14
+ require 'exceptions/out_of_stock'
15
+
14
16
  require 'storage_engines/memory'
15
17
  require 'items/memory_item'
16
18
 
@@ -13,10 +13,12 @@ module ActiveCart
13
13
  module ClassMethods
14
14
  # acts_as_cart - Turns an ActiveRecord model in to a cart. It can take a hash of options
15
15
  #
16
- # state_column: The database column that stores the persistent state machine state. Default: state
17
- # invoice_id_column: The column that stores the invoice id. Default: invoice_id
18
- # cart_items: The model that represents the items for this cart. Is associated as a has_many. Default: cart_items
19
- # order_totals: The model that represents order totals for this cart. It is associated as a has_many. Default: order_totals
16
+ # state_column: The database column that stores the persistent state machine state. Default: state
17
+ # invoice_id_column: The column that stores the invoice id. Default: invoice_id
18
+ # cart_items: The model that represents the items for this cart. Is associated as a has_many. Default: cart_items
19
+ # order_totals: The model that represents order totals for this cart. It is associated as a has_many. Default: order_totals
20
+ #
21
+ # Example
20
22
  #
21
23
  # class Cart < ActiveModel::Base
22
24
  # acts_as_cart
@@ -26,6 +28,14 @@ module ActiveCart
26
28
  #
27
29
  # You can create custom acts_as_state_machine (aasm) states and events after declaring acts_as_cart
28
30
  #
31
+ # NOTE: this is a STORAGE ENGINE, so you need to create it (by finding by id) then pass the result in to ActiveCart::Cart.new. It might look something like this
32
+ # (Most likely in ApplicationController):
33
+ #
34
+ # if session[:cart_id]
35
+ # engine = Cart.find(session[:cart_id])
36
+ # @cart = ActiveCart.new(engine) if engine
37
+ # end
38
+ #
29
39
  def acts_as_cart(options = {})
30
40
  cattr_accessor :aac_config
31
41
 
@@ -42,13 +52,46 @@ module ActiveCart
42
52
  #include AASM::Persistence::ActiveRecordPersistence
43
53
  include ActiveCart::CartStorage
44
54
 
55
+ #:nodoc
45
56
  def invoice_id
46
57
  read_attribute(self.aac_config[:invoice_id_column])
47
58
  end
48
59
 
60
+ #:nodoc
49
61
  def state
50
62
  read_attribute(self.aac_config[:state_column])
51
63
  end
64
+
65
+ #:nodoc
66
+ def find_cart_item(item)
67
+ self.send(:cart_items).find(:first, :conditions => [ 'original_id = ? AND original_type = ?', item.id, item.class.to_s ])
68
+ end
69
+
70
+ #:nodoc
71
+ def add_to_cart(item, quantity = 1)
72
+ cart_item = find_cart_item(item)
73
+ if cart_item
74
+ cart_item.quantity += quantity
75
+ cart_item.save!
76
+ else
77
+ cart_item = self.send(:cart_items).create!(self.aac_config[:cart_items].to_s.classify.constantize.new_from_item(item).attributes.merge(:quantity => quantity, :original_id => item.id, :original_type => item.class.to_s))
78
+ end
79
+ self.reload
80
+ end
81
+
82
+ #:nodoc
83
+ def remove_from_cart(item, quantity = 1)
84
+ cart_item = find_cart_item(item)
85
+ if cart_item
86
+ if cart_item.quantity - quantity > 0
87
+ cart_item.quantity = cart_item.quantity - quantity
88
+ cart_item.save!
89
+ else
90
+ cart_item.destroy
91
+ end
92
+ end
93
+ self.reload
94
+ end
52
95
  end
53
96
 
54
97
  aasm_column self.aac_config[:state_column]
@@ -80,6 +123,8 @@ module ActiveCart
80
123
  # acts_as_cart uses the 'original' polymorphic attribute to store a reference to the original Item object. The compound attribute gets nullified if the original Item gets
81
124
  # deleted.
82
125
  #
126
+ # When adding an item to a cart, you should pass in the actual concrete item, not the cart_item - the model will take care of the conversion.
127
+ #
83
128
  # For complex carts with multiple item types, you will probably need to use STI, as it's basically impossible to use a polymorphic relationship (If someone can
84
129
  # suggest a better way, I'm all ears). That said, there is no easy way to model complex carts, so I'll leave this as an exercise for the reader.
85
130
  #
@@ -132,6 +177,16 @@ module ActiveCart
132
177
  read_attribute(self.aaci_config[:price_column])
133
178
  end
134
179
  end
180
+
181
+ # Creates a new cart_item item for the passed in concrete item
182
+ #
183
+ # The default copies all the common attributes from the passed in item to new cart_item (Except id). Override it if you want to do something special.
184
+ #
185
+ def new_from_item(item)
186
+ cart_item = self.new
187
+ item.class.columns.each { |col| cart_item.send((col.to_s + "=").to_sym, item.send(col)) if cart_item.respond_to?((col.to_s + "=").to_sym) }
188
+ cart_item
189
+ end
135
190
 
136
191
  belongs_to self.aaci_config[:cart], :foreign_key => self.aaci_config[:foreign_key]
137
192
  belongs_to :original, :polymorphic => true
@@ -0,0 +1,4 @@
1
+ module ActiveCart
2
+ class OutOfStock < StandardError
3
+ end
4
+ end
data/test/blueprints.rb CHANGED
@@ -6,11 +6,17 @@ Cart.blueprint do
6
6
  state { 'shopping' }
7
7
  end
8
8
 
9
+ Item.blueprint do
10
+ name { Faker::Lorem.words(2).join(' ') }
11
+ price { (rand(9999) + 1).to_i / 100 }
12
+ end
13
+
9
14
  CartItem.blueprint do
10
15
  cart { Cart.make }
11
16
  name { Faker::Lorem.words(2).join(' ') }
12
17
  quantity { rand(10).to_i }
13
18
  price { (rand(9999) + 1).to_i / 100 }
19
+ original { Item.make }
14
20
  end
15
21
 
16
22
  OrderTotal.blueprint do
@@ -0,0 +1,2 @@
1
+ class Item < ActiveRecord::Base
2
+ end
data/test/schema.rb CHANGED
@@ -5,6 +5,11 @@ ActiveRecord::Schema.define :version => 0 do
5
5
  t.string :dummy # Not needed in real carts - used sa a dummy field for testing
6
6
  end
7
7
 
8
+ create_table :items, :force => true do |t|
9
+ t.string :name
10
+ t.float :price
11
+ end
12
+
8
13
  create_table :cart_items, :force => true do |t|
9
14
  t.integer :cart_id
10
15
  t.string :name
data/test/test_helper.rb CHANGED
@@ -34,6 +34,7 @@ require 'active_cart/acts_as_cart'
34
34
  load(File.dirname(__FILE__) + '/schema.rb')
35
35
 
36
36
  require 'fixtures/cart'
37
+ require 'fixtures/item'
37
38
  require 'fixtures/cart_item'
38
39
  require 'fixtures/order_total'
39
40
  require 'blueprints'
@@ -350,5 +350,114 @@ class ActsAsCartTest < ActiveSupport::TestCase
350
350
  end
351
351
  end
352
352
  end
353
+
354
+ context 'add to cart' do
355
+ should 'add an item to the cart if the cart is empty' do
356
+ assert @cart.empty?
357
+ item = Item.make
358
+ @cart.add_to_cart(item)
359
+ assert_equal 1, @cart.size
360
+ assert_equal 1, @cart[0].quantity
361
+ assert_equal 1, @cart.quantity
362
+ assert_equal CartItem, @cart[0].class
363
+ assert_equal item.id, @cart[0].original.id
364
+ end
365
+
366
+ should 'increase the item quantity if the same item is added to the cart again' do
367
+ assert @cart.empty?
368
+ item = Item.make
369
+ @cart.add_to_cart(item)
370
+ assert_equal 1, @cart.size
371
+ assert_equal 1, @cart[0].quantity
372
+
373
+ item_2 = Item.find(item.id) # Has the same id, is the same as item
374
+ @cart.add_to_cart(item_2)
375
+ assert_equal 1, @cart.size
376
+ assert_equal 2, @cart[0].quantity
377
+ assert_equal 2, @cart.quantity
378
+ assert_equal CartItem, @cart[0].class
379
+ assert_equal item.id, @cart[0].original.id
380
+ end
381
+
382
+ should 'increase the item quantity by the supplied number if the same item is add to the cart again and a quantity is supplied' do
383
+ assert @cart.empty?
384
+ item = Item.make
385
+ @cart.add_to_cart(item)
386
+ assert_equal 1, @cart.size
387
+ assert_equal 1, @cart[0].quantity
388
+
389
+ item_2 = Item.find(item.id) # Has the same id, is the same as item
390
+ @cart.add_to_cart(item_2, 10)
391
+ assert_equal 1, @cart.size
392
+ assert_equal 11, @cart[0].quantity
393
+ assert_equal 11, @cart.quantity
394
+ end
395
+
396
+ should 'add another item to the cart' do
397
+ assert @cart.empty?
398
+ item = Item.make
399
+ @cart.add_to_cart(item)
400
+ assert_equal 1, @cart.size
401
+ assert_equal 1, @cart[0].quantity
402
+
403
+ item_2 = Item.make
404
+ @cart.add_to_cart(item_2, 10)
405
+ assert_equal 2, @cart.size
406
+ assert_equal 1, @cart[0].quantity
407
+ assert_equal 10, @cart[1].quantity
408
+ assert_equal 11, @cart.quantity
409
+ assert_equal CartItem, @cart[0].class
410
+ assert_equal item.id, @cart[0].original.id
411
+ assert_equal CartItem, @cart[1].class
412
+ assert_equal item_2.id, @cart[1].original.id
413
+ end
414
+ end
415
+
416
+ context 'remove_from_cart' do
417
+ should 'remove the quantity supplied from the cart' do
418
+ item = Item.make
419
+ @cart.add_to_cart(item, 10)
420
+ assert_equal 1, @cart.size
421
+ assert_equal 10, @cart.quantity
422
+
423
+ @cart.remove_from_cart(item)
424
+ assert_equal 1, @cart.size
425
+ assert_equal 9, @cart.quantity
426
+ end
427
+
428
+ should 'remove the item from the cart if the quantity to be removed is equal to the number in cart' do
429
+ item = Item.make
430
+ @cart.add_to_cart(item, 10)
431
+ assert_equal 1, @cart.size
432
+ assert_equal 10, @cart.quantity
433
+
434
+ @cart.remove_from_cart(item, 10)
435
+ assert_equal 0, @cart.size
436
+ end
437
+
438
+ should 'remove the item from the cart if the quantity to be removed is greater than the number in cart' do
439
+ item = Item.make
440
+ @cart.add_to_cart(item, 10)
441
+ assert_equal 1, @cart.size
442
+ assert_equal 10, @cart.quantity
443
+
444
+ @cart.remove_from_cart(item, 11)
445
+ assert_equal 0, @cart.size
446
+
447
+ assert_not_nil Item.find(item.id)
448
+ end
449
+
450
+ should "simply return if the item doesn't exist in the cart" do
451
+ item = Item.make
452
+ @cart.add_to_cart(item, 10)
453
+ assert_equal 1, @cart.size
454
+ assert_equal 10, @cart.quantity
455
+
456
+ item_2 = Item.make
457
+ @cart.remove_from_cart(item_2, 10)
458
+ assert_equal 1, @cart.size
459
+ assert_equal 10, @cart.quantity
460
+ end
461
+ end
353
462
  end
354
463
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_cart
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Myles Eftos
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-02-28 00:00:00 +08:00
12
+ date: 2010-03-01 00:00:00 +08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -95,9 +95,11 @@ files:
95
95
  - lib/active_cart/order_total.rb
96
96
  - lib/active_cart/order_total_collection.rb
97
97
  - lib/active_cart/storage_engines/memory.rb
98
+ - lib/exceptions/out_of_stock.rb
98
99
  - test/blueprints.rb
99
100
  - test/fixtures/cart.rb
100
101
  - test/fixtures/cart_item.rb
102
+ - test/fixtures/item.rb
101
103
  - test/fixtures/order_total.rb
102
104
  - test/mocks/test_cart_storage.rb
103
105
  - test/mocks/test_item.rb
@@ -152,6 +154,7 @@ test_files:
152
154
  - test/fixtures/cart_item.rb
153
155
  - test/fixtures/order_total.rb
154
156
  - test/fixtures/cart.rb
157
+ - test/fixtures/item.rb
155
158
  - test/blueprints.rb
156
159
  - test/test_helper.rb
157
160
  - test/performance/browsing_test.rb