radiant-shop_discounts-extension 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.DS_Store +0 -0
  2. data/.gitignore +1 -0
  3. data/README +3 -0
  4. data/Rakefile +138 -0
  5. data/VERSION +1 -0
  6. data/app/controllers/admin/shop/discounts/discountables_controller.rb +44 -0
  7. data/app/controllers/admin/shop/discounts_controller.rb +64 -0
  8. data/app/models/form_discount.rb +39 -0
  9. data/app/models/shop_discount.rb +37 -0
  10. data/app/models/shop_discountable.rb +64 -0
  11. data/app/views/admin/shop/discounts/edit.html.haml +11 -0
  12. data/app/views/admin/shop/discounts/edit/_foot.html.haml +16 -0
  13. data/app/views/admin/shop/discounts/edit/_form.html.haml +15 -0
  14. data/app/views/admin/shop/discounts/edit/_head.html.haml +4 -0
  15. data/app/views/admin/shop/discounts/edit/_inputs.html.haml +2 -0
  16. data/app/views/admin/shop/discounts/edit/_meta.html.haml +8 -0
  17. data/app/views/admin/shop/discounts/edit/_parts.html.haml +9 -0
  18. data/app/views/admin/shop/discounts/edit/_popups.html.haml +4 -0
  19. data/app/views/admin/shop/discounts/edit/buttons/_browse_categories.html.haml +1 -0
  20. data/app/views/admin/shop/discounts/edit/buttons/_browse_products.html.haml +1 -0
  21. data/app/views/admin/shop/discounts/edit/inputs/_amount.html.haml +3 -0
  22. data/app/views/admin/shop/discounts/edit/inputs/_code.html.haml +3 -0
  23. data/app/views/admin/shop/discounts/edit/inputs/_name.html.haml +3 -0
  24. data/app/views/admin/shop/discounts/edit/meta/_finish.html.haml +5 -0
  25. data/app/views/admin/shop/discounts/edit/meta/_start.html.haml +5 -0
  26. data/app/views/admin/shop/discounts/edit/parts/_categories.html.haml +3 -0
  27. data/app/views/admin/shop/discounts/edit/parts/_products.html.haml +3 -0
  28. data/app/views/admin/shop/discounts/edit/popups/_browse_categories.html.haml +6 -0
  29. data/app/views/admin/shop/discounts/edit/popups/_browse_products.html.haml +6 -0
  30. data/app/views/admin/shop/discounts/edit/shared/_category.html.haml +11 -0
  31. data/app/views/admin/shop/discounts/edit/shared/_product.html.haml +12 -0
  32. data/app/views/admin/shop/discounts/index.html.haml +13 -0
  33. data/app/views/admin/shop/discounts/index/_discount.html.haml +13 -0
  34. data/app/views/admin/shop/discounts/index/_foot.html.haml +5 -0
  35. data/app/views/admin/shop/discounts/index/_head.html.haml +2 -0
  36. data/app/views/admin/shop/discounts/index/buttons/_new_discount.html.haml +1 -0
  37. data/app/views/admin/shop/discounts/new.html.haml +11 -0
  38. data/app/views/admin/shop/discounts/remove.html.haml +12 -0
  39. data/config/locales/en.yml +17 -0
  40. data/config/routes.rb +17 -0
  41. data/cucumber.yml +1 -0
  42. data/db/migrate/20101015162137_setup_shop_discounts.rb +30 -0
  43. data/features/support/env.rb +16 -0
  44. data/features/support/paths.rb +14 -0
  45. data/lib/shop_discounts/models/discountable.rb +14 -0
  46. data/lib/shop_discounts/models/product.rb +20 -0
  47. data/lib/shop_discounts/models/purchaseable.rb +33 -0
  48. data/lib/shop_discounts/tags/cart.rb +18 -0
  49. data/lib/shop_discounts/tags/item.rb +30 -0
  50. data/lib/tasks/shop_discounts_extension_tasks.rake +55 -0
  51. data/public/javascripts/admin/extensions/shop/discounts/edit.js +76 -0
  52. data/public/stylesheets/sass/admin/extensions/shop/discounts/edit.sass +125 -0
  53. data/radiant-shop_discounts-extension.gemspec +124 -0
  54. data/shop_discounts_extension.rb +31 -0
  55. data/spec/controllers/admin/shop/discounts/discountables_controller_spec.rb +72 -0
  56. data/spec/controllers/admin/shop/discounts_controller_spec.rb +81 -0
  57. data/spec/datasets/forms_discount.rb +24 -0
  58. data/spec/datasets/shop_discountables.rb +22 -0
  59. data/spec/datasets/shop_discounts.rb +34 -0
  60. data/spec/lib/shop_discounts/models/discountable_spec.rb +114 -0
  61. data/spec/lib/shop_discounts/models/purchaseable_spec.rb +55 -0
  62. data/spec/lib/shop_discounts/tags/item_spec.rb +96 -0
  63. data/spec/models/form_discount_spec.rb +63 -0
  64. data/spec/models/shop_category_spec.rb +19 -0
  65. data/spec/models/shop_discount_spec.rb +130 -0
  66. data/spec/models/shop_line_item_spec.rb +15 -0
  67. data/spec/models/shop_product_spec.rb +40 -0
  68. data/spec/spec.opts +3 -0
  69. data/spec/spec_helper.rb +23 -0
  70. metadata +161 -0
@@ -0,0 +1,24 @@
1
+ class FormsDiscountDataset < Dataset::Base
2
+
3
+ uses :pages, :shop_discounts, :forms
4
+
5
+ helpers do
6
+ def mock_valid_form_discount_request
7
+ @form = forms(:checkout)
8
+ @form[:extensions] = {
9
+ :add_discount => {
10
+ :extension => 'discount',
11
+ :process => 'add'
12
+ }
13
+ }
14
+ @data = {
15
+ :discount => {
16
+ :code => shop_discounts(:ten_percent).code
17
+ }
18
+ }
19
+
20
+ @request.session = { :shop_order => @order.id }
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,22 @@
1
+ class ShopDiscountablesDataset < Dataset::Base
2
+
3
+ uses :shop_discounts, :shop_products, :shop_categories
4
+
5
+ def load
6
+ create_record :shop_discountables, :ten_percent_bread,
7
+ :discount_id => shop_discounts(:ten_percent).id,
8
+ :discounted_id => shop_categories(:bread).id,
9
+ :discounted_type => 'ShopCategory'
10
+
11
+ create_record :shop_discountables, :five_percent_bread,
12
+ :discount_id => shop_discounts(:five_percent).id,
13
+ :discounted_id => shop_categories(:bread).id,
14
+ :discounted_type => 'ShopCategory'
15
+
16
+ create_record :shop_discountables, :five_percent_crusty_bread,
17
+ :discount_id => shop_discounts(:five_percent).id,
18
+ :discounted_id => shop_products(:crusty_bread).id,
19
+ :discounted_type => 'ShopProduct'
20
+ end
21
+
22
+ end
@@ -0,0 +1,34 @@
1
+ class ShopDiscountsDataset < Dataset::Base
2
+
3
+ def load
4
+ create_record :shop_discounts, :ten_percent,
5
+ :name => 'ten percent',
6
+ :code => '10pcoff',
7
+ :amount => 10.00
8
+
9
+ create_record :shop_discounts, :five_percent,
10
+ :name => 'five percent',
11
+ :code => '5pcoff',
12
+ :amount => 5.00
13
+
14
+ create_record :shop_discounts, :one_percent,
15
+ :name => 'one percent',
16
+ :code => '1pcoff',
17
+ :amount => 1.00,
18
+ :starts_at => nil,
19
+ :finishes_at => nil
20
+
21
+ create_record :shop_discounts, :hundred_percent,
22
+ :name => 'hundred',
23
+ :code => 'hundred',
24
+ :amount => 100
25
+
26
+ create_record :shop_discounts, :invalid,
27
+ :name => 'invalid',
28
+ :code => 'invalid',
29
+ :amount => 100,
30
+ :starts_at => Time.now - 5.days,
31
+ :finishes_at => Time.now - 2.days
32
+ end
33
+
34
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ShopDiscountable do
4
+
5
+ dataset :shop_discountables, :shop_line_items
6
+
7
+ before(:each) do
8
+ @discount = shop_discounts(:ten_percent)
9
+ end
10
+
11
+ describe 'validations' do
12
+ before :each do
13
+ @discountable = shop_discountables(:ten_percent_bread)
14
+ end
15
+
16
+ context 'discount' do
17
+ it 'should require' do
18
+ @discountable.discount = nil
19
+ @discountable.valid?.should === false
20
+ end
21
+ end
22
+
23
+ context 'discounted' do
24
+ it 'should require' do
25
+ @discountable.discounted = nil
26
+ @discountable.valid?.should === false
27
+ end
28
+ it 'should be unique to the class' do
29
+ @other = ShopDiscountable.new(:discount => @discount, :discounted => @discountable.discounted)
30
+ @other.valid?.should === false
31
+
32
+ @other.discounted = shop_categories(:milk)
33
+ @other.valid?.should === true
34
+ end
35
+ end
36
+ end
37
+
38
+ describe 'category and product hooks' do
39
+ describe '#create' do
40
+ before :each do
41
+ @discount = shop_discounts(:one_percent)
42
+ @category = shop_categories(:milk)
43
+
44
+ discountable = @discount.discountables.create(:discounted => @category)
45
+ end
46
+ it 'should assign the category to the discount' do
47
+ @discount.categories.include?(@category).should be_true
48
+ end
49
+ it 'should assign the products to that category' do
50
+ @discount.products.should_not be_empty
51
+ @discount.products.should === @category.products
52
+ end
53
+ end
54
+
55
+ describe '#destroy' do
56
+ before :each do
57
+ @discount = shop_discounts(:one_percent)
58
+ @category = shop_categories(:milk)
59
+
60
+ discountable = @discount.discountables.create(:discounted => @category)
61
+ discountable.destroy
62
+ end
63
+ it 'should remove the category to the discount' do
64
+ @discount.categories.include?(@category).should be_false
65
+ end
66
+ it 'should remove the products of that category' do
67
+ @category.products.each do |p|
68
+ @discount.products.include?(p).should be_false
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ describe 'order and line_item hooks' do
75
+ before :each do
76
+ @discount = shop_discounts(:one_percent)
77
+ @order = shop_orders(:several_items)
78
+ @line_item_one = shop_orders(:several_items).line_items.first
79
+ @line_item_two = shop_orders(:several_items).line_items.last
80
+
81
+ # Creates a discount for the items product
82
+ @discount.discountables.create(:discounted_id => @line_item_one.item.id, :discounted_type => @line_item_one.item.class.name)
83
+ end
84
+ describe '#create' do
85
+ before :each do
86
+ discountable = @discount.discountables.create(:discounted => @order)
87
+ end
88
+ it 'should assign the category to the discount' do
89
+ @discount.orders.include?(@order).should be_true
90
+ end
91
+ it 'should assign only the items with discounted products to that category' do
92
+ @discount.line_items.should_not be_empty
93
+ @discount.line_items.include?(@line_item_one).should be_true
94
+ @discount.line_items.include?(@line_item_two).should be_false
95
+ end
96
+ end
97
+
98
+ describe '#destroy' do
99
+ before :each do
100
+ discountable = @discount.discountables.create(:discounted => @order)
101
+ discountable.destroy
102
+ end
103
+ it 'should remove the category to the discount' do
104
+ @discount.orders.include?(@order).should be_false
105
+ end
106
+ it 'should remove the products of that category' do
107
+ @order.line_items.each do |p|
108
+ @discount.line_items.include?(p).should be_false
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec/spec_helper'
2
+
3
+ #
4
+ # Tests for image model extensions
5
+ #
6
+ describe ShopDiscounts::Models::Purchaseable do
7
+
8
+ dataset :shop_line_items, :shop_discounts
9
+
10
+ before :each do
11
+ ShopDiscountable.create(:discount => shop_discounts(:ten_percent), :discounted => shop_line_items(:one))
12
+ end
13
+
14
+ describe '#value' do
15
+ it 'it should return the price of the items' do
16
+ shop_line_items(:one).value.should === shop_line_items(:one).item.price
17
+ end
18
+ end
19
+
20
+ describe '#discount' do
21
+ context 'single discount' do
22
+ it 'should return the value of that discount as a percentage' do
23
+ shop_line_items(:one).discount.should === (shop_discounts(:ten_percent).amount * 0.01)
24
+ end
25
+ end
26
+ context 'multiple discounts' do
27
+ before :each do
28
+ ShopDiscountable.create(:discount => shop_discounts(:five_percent), :discounted => shop_line_items(:one))
29
+ end
30
+ it 'should attach all discounts to the item' do
31
+ shop_line_items(:one).discount.should == 0.15
32
+ end
33
+ end
34
+ context 'too many discounts' do
35
+ before :each do
36
+ ShopDiscountable.create(:discount => shop_discounts(:hundred_percent), :discounted => shop_line_items(:one))
37
+ end
38
+ it 'should return a capped discount amount' do
39
+ shop_line_items(:one).discount.should == 1
40
+ end
41
+ end
42
+ end
43
+
44
+ describe '#discounted' do
45
+ it 'should return how much has been taken off the product' do
46
+ shop_line_items(:one).discounted.should === (shop_line_items(:one).item.price * 0.1)
47
+ end
48
+ end
49
+
50
+ describe '#price' do
51
+ it 'should return the discounted price of the product' do
52
+ shop_line_items(:one).price.should === (shop_line_items(:one).value - shop_line_items(:one).discounted)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,96 @@
1
+ require 'spec/spec_helper'
2
+
3
+ #
4
+ # Test for ShopDiscounts Item Tag Extensions
5
+ #
6
+ describe ShopDiscounts::Tags::Item do
7
+
8
+ dataset :pages, :shop_orders, :shop_line_items, :shop_discounts
9
+
10
+ it 'should describe these tags' do
11
+ ShopDiscounts::Tags::Item.tags.sort.should == [
12
+ 'shop:cart:item:value',
13
+ 'shop:cart:item:discount',
14
+ 'shop:cart:item:if_discounted',
15
+ 'shop:cart:item:unless_discounted'].sort
16
+ end
17
+
18
+ context 'page tags' do
19
+
20
+ before :all do
21
+ @page = pages(:home)
22
+ end
23
+
24
+ before :each do
25
+ @line_item = shop_line_items(:one)
26
+ shop_discounts(:ten_percent).discountables.create(:discounted => @line_item)
27
+ mock(Shop::Tags::Helpers).current_line_item(anything) { @line_item }
28
+ end
29
+
30
+ describe '<r:shop:cart:item:value />' do
31
+ it 'should return the value of the item' do
32
+ tag = %{<r:shop:cart:item:value />}
33
+ exp = Shop::Tags::Helpers.currency(@line_item.value)
34
+
35
+ @page.should render(tag).as(exp)
36
+ end
37
+ end
38
+
39
+ describe '<r:shop:cart:item:discount />' do
40
+ it 'should return the markdown of the item' do
41
+ tag = %{<r:shop:cart:item:discount />}
42
+ exp = Shop::Tags::Helpers.currency(@line_item.discount)
43
+
44
+ @page.should render(tag).as(exp)
45
+ end
46
+ end
47
+
48
+ describe '<r:shop:cart:item:if_discounted />' do
49
+ context 'item is discounted' do
50
+ it 'should expand' do
51
+ tag = %{<r:shop:cart:item:if_discounted>success</r:shop:cart:item:if_discounted>}
52
+ exp = %{success}
53
+
54
+ @page.should render(tag).as(exp)
55
+ end
56
+ end
57
+
58
+ context 'item is not discounted' do
59
+ before :each do
60
+ @line_item.discounts.delete_all
61
+ end
62
+ it 'should not expand' do
63
+ tag = %{<r:shop:cart:item:if_discounted>failure</r:shop:cart:item:if_discounted>}
64
+ exp = %{}
65
+
66
+ @page.should render(tag).as(exp)
67
+ end
68
+ end
69
+ end
70
+
71
+ describe '<r:shop:cart:item:unless_discounted />' do
72
+ context 'item is not discounted' do
73
+ before :each do
74
+ @line_item.discounts.delete_all
75
+ end
76
+ it 'should expand' do
77
+ tag = %{<r:shop:cart:item:unless_discounted>success</r:shop:cart:item:unless_discounted>}
78
+ exp = %{success}
79
+
80
+ @page.should render(tag).as(exp)
81
+ end
82
+ end
83
+
84
+ context 'item is discounted' do
85
+ it 'should not expand' do
86
+ tag = %{<r:shop:cart:item:unless_discounted>failure</r:shop:cart:item:unless_discounted>}
87
+ exp = %{}
88
+
89
+ @page.should render(tag).as(exp)
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe FormDiscount do
4
+
5
+ dataset :forms_discount, :shop_discounts, :pages
6
+
7
+ before :each do
8
+ mock_page_with_request_and_data
9
+ end
10
+
11
+ describe '#create' do
12
+ before :each do
13
+ login_as :customer
14
+ @order = shop_orders(:several_items)
15
+ end
16
+ context 'add' do
17
+ before :each do
18
+ mock_valid_form_discount_request
19
+ end
20
+ context 'valid discount' do
21
+ before :each do
22
+ @discount = FormDiscount.new(@form, @page, @form[:extensions][:add_discount])
23
+ @result = @discount.create
24
+ end
25
+ it 'should add the discount to the order' do
26
+ shop_orders(:several_items).discounts.first(:conditions => { :code => '10pcoff' }).should_not be_nil
27
+ end
28
+ it 'should return true for result[:add]' do
29
+ @result[:add].should be_true
30
+ end
31
+ end
32
+ context 'invalid discount' do
33
+ before :each do
34
+ @data[:discount][:code] = 'invalid'
35
+ end
36
+ it 'should not add the discount to the order' do
37
+ shop_orders(:several_items).discounts.first(:conditions => { :code => 'invalid' }).should be_nil
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'remove' do
43
+ before :each do
44
+ discountable = shop_discounts(:ten_percent).discountables.create(:discounted_id => @order.id, :discounted_type => @order.class.name)
45
+
46
+ mock_valid_form_discount_request
47
+ @form[:extensions][:add_discount][:process] = 'remove'
48
+ @data[:discountable] = { :id => discountable.id }
49
+
50
+ @discount = FormDiscount.new(@form, @page, @form[:extensions][:add_discount])
51
+ @result = @discount.create
52
+ end
53
+ it 'should remove the discount from the order' do
54
+ shop_orders(:several_items).discounts.include?(shop_discounts(:ten_percent)).should be_false
55
+ end
56
+ it 'should return true for result[:remove]' do
57
+ @result[:remove].should be_true
58
+ end
59
+ end
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ShopCategory do
4
+
5
+ dataset :shop_categories
6
+
7
+ before :each do
8
+ @category = shop_categories(:bread)
9
+ end
10
+
11
+ it 'should have many discountables' do
12
+ @category.discountables.is_a?(Array).should be_true
13
+ end
14
+
15
+ it 'should have many discounts' do
16
+ @category.discounts.is_a?(Array).should be_true
17
+ end
18
+
19
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec/spec_helper'
2
+
3
+ describe ShopDiscount do
4
+
5
+ dataset :shop_discounts, :shop_products, :shop_orders
6
+
7
+ describe 'scope' do
8
+ before :each do
9
+ @valid = ShopDiscount.all_including_invalid(:conditions => { :code => '10pcoff'}).first
10
+ @invalid = ShopDiscount.all_including_invalid(:conditions => { :code => 'invalid'}).first
11
+ end
12
+ context 'all' do
13
+ it 'should not return invalid by default' do
14
+ ShopDiscount.all.include?(@valid).should be_true
15
+ ShopDiscount.all.include?(@invalid).should be_false
16
+ end
17
+ end
18
+ context 'all_including_invalid' do
19
+ it 'should return all including invalid' do
20
+ ShopDiscount.all_including_invalid.include?(@valid).should be_true
21
+ ShopDiscount.all_including_invalid.include?(@invalid).should be_true
22
+ end
23
+ end
24
+ end
25
+
26
+ describe 'validations' do
27
+ before :each do
28
+ @discount = shop_discounts(:ten_percent)
29
+ end
30
+
31
+ context 'name' do
32
+ it 'should require' do
33
+ @discount.name = nil
34
+ @discount.valid?.should === false
35
+ end
36
+ it 'should be unique' do
37
+ @other = shop_discounts(:five_percent)
38
+ @other.name = @discount.name
39
+ @other.valid?.should === false
40
+ end
41
+ end
42
+
43
+ context 'code' do
44
+ it 'should require' do
45
+ @discount.code = nil
46
+ @discount.valid?.should === false
47
+ end
48
+ it 'should be unique' do
49
+ @other = shop_discounts(:five_percent)
50
+ @other.code = @discount.code
51
+ @other.valid?.should === false
52
+ end
53
+ end
54
+
55
+ context 'amount' do
56
+ it 'should require' do
57
+ @discount.amount = nil
58
+ @discount.valid?.should === false
59
+ end
60
+ it 'should be numerical' do
61
+ @discount.amount = 'failure'
62
+ @discount.valid?.should === false
63
+ end
64
+ end
65
+ end
66
+
67
+ describe 'relationships' do
68
+ before :each do
69
+ @discount = shop_discounts(:five_percent)
70
+ end
71
+ context 'categories' do
72
+ before :each do
73
+ @bread = shop_categories(:bread)
74
+ end
75
+ it 'should have many' do
76
+ @discount.discountables.create(:discounted => @bread)
77
+ @discount.categories.include?(@bread).should === true
78
+ end
79
+ context '#for' do
80
+ before :each do
81
+ @discount.discountables.create(:discounted => shop_categories(:bread))
82
+ @discount.discountables.create(:discounted => shop_categories(:milk))
83
+ @discount.discountables.create(:discounted => shop_products(:crusty_bread))
84
+ @discount.discountables.create(:discounted => shop_products(:full_milk))
85
+ end
86
+ it 'should return result of only that type' do
87
+ discountables = @discount.discountables.for('ShopCategory')
88
+ discountables.each do |d|
89
+ d.discounted.is_a?(ShopCategory).should === true
90
+ end
91
+ end
92
+ it 'should return result of only that type regardless of string format' do
93
+ discountables = @discount.discountables.for('Shop_category')
94
+ discountables.each do |d|
95
+ d.discounted.is_a?(ShopCategory).should === true
96
+ end
97
+
98
+ discountables = @discount.discountables.for('shop_category')
99
+ discountables.each do |d|
100
+ d.discounted.is_a?(ShopCategory).should === true
101
+ end
102
+
103
+ discountables = @discount.discountables.for('ShopProduct')
104
+ discountables.each do |d|
105
+ d.discounted.is_a?(ShopProduct).should === true
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ describe '#available_categories' do
113
+ before :each do
114
+ @discount = shop_discounts(:ten_percent)
115
+ end
116
+ it 'should return all categories minus its own' do
117
+ @discount.available_categories.should === ShopCategory.all - @discount.categories
118
+ end
119
+ end
120
+
121
+ describe '#available_products' do
122
+ before :each do
123
+ @discount = shop_discounts(:ten_percent)
124
+ end
125
+ it 'should return all products minus its own' do
126
+ @discount.available_products.should === ShopProduct.all - @discount.products
127
+ end
128
+ end
129
+
130
+ end