active_cart 0.0.6 → 0.0.7

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