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,4 @@
1
+ %h1
2
+ = @page_title
3
+ - @buttons.each do |button|
4
+ = render :partial => "admin/shop/discounts/edit/buttons/#{button}"
@@ -0,0 +1,2 @@
1
+ - @inputs.each do |input|
2
+ = render :partial => "admin/shop/discounts/edit/inputs/#{input}", :locals => { :f => f }
@@ -0,0 +1,8 @@
1
+ - if @meta.present?
2
+ .drawer
3
+ .drawer_contents#attributes
4
+ %table.fieldset
5
+ - @meta.each do |meta|
6
+ = render :partial => "admin/shop/discounts/edit/meta/#{meta}", :locals => { :f => f }
7
+ .drawer_handle
8
+ %a.toggle{:href=>'#attributes', :rel=>"toggle[attributes]", :class=>"#{(meta_errors? ? 'less' : 'more')}"}= meta_label
@@ -0,0 +1,9 @@
1
+ #tab_control
2
+ #tabs.tabs
3
+ #tab_toolbar
4
+ #pages.pages
5
+ = hidden_field_tag 'page_part_index_field' #important
6
+ - @parts.each do |part|
7
+ .page{:id => "product_page_#{part}", 'data-caption'=>h(part)}
8
+ .part{:id => "product_part_#{part}"}
9
+ = render :partial => "admin/shop/discounts/edit/parts/#{part}", :locals => { :f => f }
@@ -0,0 +1,4 @@
1
+ #popups
2
+ - @popups.each do |popup|
3
+ .popup{ :id => "#{popup}_popup"}
4
+ = render :partial => "admin/shop/discounts/edit/popups/#{popup}"
@@ -0,0 +1 @@
1
+ = link_to t('browse_categories'), '#browse_categories_popup', :class => 'popup button'
@@ -0,0 +1 @@
1
+ = link_to t('browse_products'), '#browse_products_popup', :class => 'popup button'
@@ -0,0 +1,3 @@
1
+ %p.title
2
+ = f.label :amount, t('amount')
3
+ = f.text_field :amount, :class => 'textbox', :maxlenth => 255
@@ -0,0 +1,3 @@
1
+ %p.title
2
+ = f.label :code, t('code')
3
+ = f.text_field :code, :class => 'textbox', :maxlenth => 255
@@ -0,0 +1,3 @@
1
+ %p.title
2
+ = f.label :name, t('name')
3
+ = f.text_field :name, :class => 'textbox', :maxlenth => 255
@@ -0,0 +1,5 @@
1
+ %tr
2
+ %th.label
3
+ = f.label :finishes_at, t('finishes')
4
+ %td.field
5
+ = f.text_field :finishes_at, :class => 'date'
@@ -0,0 +1,5 @@
1
+ %tr
2
+ %th.label
3
+ = f.label :starts_at, t('starts')
4
+ %td.field
5
+ = f.text_field :starts_at, :class => 'date'
@@ -0,0 +1,3 @@
1
+ %ul#discount_categories.categories.discounteds
2
+ - @shop_discount.discountables.for('ShopCategory').each do |category|
3
+ = render :partial => 'admin/shop/discounts/edit/shared/category', :locals => { :category => category }
@@ -0,0 +1,3 @@
1
+ %ul#discount_products.products.discounteds
2
+ - @shop_discount.discountables.for('ShopProduct').each do |product|
3
+ = render :partial => 'admin/shop/discounts/edit/shared/product', :locals => { :product => product }
@@ -0,0 +1,6 @@
1
+ %h3.title Browse Categories
2
+
3
+ %ul#available_categories.availables
4
+ = render :partial => '/admin/shop/discounts/edit/shared/category', :collection => @shop_discount.available_categories
5
+
6
+ %a#browse_categories_popup_close.close{ :href => '#browse_categories_popup_close' }
@@ -0,0 +1,6 @@
1
+ %h3.title Browse Products
2
+
3
+ %ul#available_products.availables
4
+ = render :partial => '/admin/shop/discounts/edit/shared/product', :collection => @shop_discount.available_products
5
+
6
+ %a#browse_products_popup_close.close{ :href => '#browse_products_popup_close' }
@@ -0,0 +1,11 @@
1
+ - discounted_type = category.class.to_s
2
+ - discounted_id = discounted_type == "ShopCategory" ? category.id : category.discounted_id
3
+ - discountable_id = discounted_type == "ShopCategory" ? nil : category.id
4
+ - success_element = discounted_type == "ShopCategory" ? 'discount_categories' : 'available_categories'
5
+ - class_type = discounted_type == "ShopCategory" ? "available" : "discounted"
6
+
7
+ %li.category{:class => "discountable #{class_type} category", :id => "#{discounted_type}_#{category.id}", :'data-discounted_id' => discounted_id, :'data-discounted_type' => discounted_type, :'data-discounted_type_human' => 'Category', :'data-discountable_id' => discountable_id, :'data-success_element' => success_element }
8
+ %span.name= truncate((category.name rescue category.discounted.name), 30, '...')
9
+ %span.handle= (category.handle rescue category.discounted.handle)
10
+ .actions
11
+ %span.delete
@@ -0,0 +1,12 @@
1
+ - discounted_type = product.class.to_s
2
+
3
+ - discounted_id = discounted_type == "ShopProduct" ? product.id : product.discounted_id
4
+ - discountable_id = discounted_type == "ShopProduct" ? nil : product.id
5
+ - success_element = discounted_type == "ShopProduct" ? 'discount_products' : 'available_products'
6
+ - class_type = discounted_type == "ShopProduct" ? "available" : "discounted"
7
+
8
+ %li.product{:class => "discountable #{class_type} product", :id => "#{class_type}_#{product.id}", :'data-discounted_id' => discounted_id, :'data-discounted_type' => discounted_type, :'data-discounted_type_human' => 'Product', :'data-discountable_id' => discountable_id, :'data-success_element' => success_element }
9
+ %span.name= truncate((product.name rescue product.discounted.name), 30, '...')
10
+ %span.sku= (product.sku rescue product.discounted.sku)
11
+ .actions
12
+ %span.delete
@@ -0,0 +1,13 @@
1
+ - @page_title = t('discounts') + ' - ' + default_page_title
2
+
3
+ .outset
4
+
5
+ #head.min
6
+ = render :partial => '/admin/shop/discounts/index/head'
7
+
8
+ #discounts_map.map
9
+ %ul#discounts
10
+ = render :partial => '/admin/shop/discounts/index/discount', :collection => @shop_discounts
11
+
12
+ #actions
13
+ = render :partial => '/admin/shop/discounts/index/foot'
@@ -0,0 +1,13 @@
1
+ %li.discount.object{:id => "discount_#{discount.id}", :'data-id' => discount.id}
2
+ .attributes
3
+ %span.name.attribute
4
+ - render_region :body do |body|
5
+ - body.name do
6
+ %span.name.attribute= link_to discount.name, [:edit_admin, discount]
7
+ - body.code do
8
+ %span.code.attribute= discount.code
9
+ - body.amount do
10
+ %span.amount.attribute= discount.amount
11
+ - body.modify do
12
+ .modify
13
+ %span.remove= link_to t('remove'), [:remove_admin, discount]
@@ -0,0 +1,5 @@
1
+ %ul
2
+ - render_region :foot do |foot|
3
+ - foot.buttons do
4
+ - @buttons.each do |button|
5
+ %li= render :partial => "admin/shop/discounts/index/buttons/#{button}"
@@ -0,0 +1,2 @@
1
+ - render_region :head do |head|
2
+ - nil
@@ -0,0 +1 @@
1
+ = link_to image('plus') + " " + t("add_discount"), new_admin_shop_discount_path
@@ -0,0 +1,11 @@
1
+ - @page_title = t('new_discount')
2
+
3
+ - render_region :main do |main|
4
+ - main.head do
5
+ = render 'admin/shop/discounts/edit/head'
6
+
7
+ - main.popups do
8
+ = render 'admin/shop/discounts/edit/popups'
9
+
10
+ - main.form do
11
+ = render 'admin/shop/discounts/edit/form'
@@ -0,0 +1,12 @@
1
+ %h1
2
+ = t('remove_discount')
3
+
4
+ %p
5
+ = t('text.remove_discount.warning')
6
+
7
+ - form_for [:admin, @shop_discount.becomes(ShopDiscount)], :html => {:method => :delete, 'data-onsubmit_status'=>"Removing Discount…"} do
8
+
9
+ %p.buttons
10
+ %input.button{:type=>"submit", :value => t('delete_discount') }/
11
+ = t('or')
12
+ = link_to t('cancel'), admin_shop_discounts_path
@@ -0,0 +1,17 @@
1
+ ---
2
+ en:
3
+ shop discounts: Shop Discounts
4
+ discounts: Discounts
5
+ add_discount: Add Discount
6
+ new_discount: New Discount
7
+ browse_products: Browse Products
8
+ browse_categories: Browse Categories
9
+ amount: Amount
10
+ code: Code
11
+ starts: Starts On
12
+ finishes: Finishes On
13
+ remove_discount: Remove Discount
14
+ text:
15
+ remove_discount:
16
+ warning: Removing a discount is irreversible
17
+ delete_discount: Delete Discount
data/config/routes.rb ADDED
@@ -0,0 +1,17 @@
1
+ ActionController::Routing::Routes.draw do |map|
2
+
3
+
4
+ map.namespace :admin do |admin|
5
+ admin.namespace :shop, :member => { :remove => :get } do |shop|
6
+ shop.resources :products, :except => :new, :collection => { :sort => :put } do |product|
7
+ product.resources :discounts, :controller => 'products/discounts', :only => [ :create, :destroy]
8
+ product.resources :discount_templates,:controller => 'products/discount_templates', :only => [ :update ]
9
+ end
10
+
11
+ shop.resources :discounts, :member => { :remove => :get } do |discounts|
12
+ discounts.resources :discountables, :controller => 'discounts/discountables', :only => [:create,:destroy]
13
+ end
14
+ end
15
+ end
16
+
17
+ end
data/cucumber.yml ADDED
@@ -0,0 +1 @@
1
+ default: --format progress features --tags ~@proposed,~@in_progress
@@ -0,0 +1,30 @@
1
+ class SetupShopDiscounts < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "shop_discountables", :force => true do |t|
4
+ t.integer "discount_id"
5
+ t.integer "discounted_id"
6
+ t.string "discounted_type"
7
+ t.integer "created_by"
8
+ t.datetime "created_at"
9
+ t.integer "updated_by"
10
+ t.datetime "updated_at"
11
+ end
12
+
13
+ create_table "shop_discounts", :force => true do |t|
14
+ t.string "name"
15
+ t.string "code"
16
+ t.decimal "amount"
17
+ t.datetime "starts_at"
18
+ t.datetime "finishes_at"
19
+ t.integer "created_by"
20
+ t.integer "updated_by"
21
+ t.datetime "created_at"
22
+ t.datetime "updated_at"
23
+ end
24
+ end
25
+
26
+ def self.down
27
+ remove_table "shop_discountables"
28
+ remove_table "shop_discounts"
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ # Sets up the Rails environment for Cucumber
2
+ ENV["RAILS_ENV"] = "test"
3
+ # Extension root
4
+ extension_env = File.expand_path(File.dirname(__FILE__) + '/../../../../../config/environment')
5
+ require extension_env+'.rb'
6
+
7
+ Dir.glob(File.join(RADIANT_ROOT, "features", "**", "*.rb")).each {|step| require step}
8
+
9
+ Cucumber::Rails::World.class_eval do
10
+ include Dataset
11
+ datasets_directory "#{RADIANT_ROOT}/spec/datasets"
12
+ Dataset::Resolver.default = Dataset::DirectoryResolver.new("#{RADIANT_ROOT}/spec/datasets", File.dirname(__FILE__) + '/../../spec/datasets', File.dirname(__FILE__) + '/../datasets')
13
+ self.datasets_database_dump_path = "#{Rails.root}/tmp/dataset"
14
+
15
+ # dataset :shop_discounts
16
+ end
@@ -0,0 +1,14 @@
1
+ def path_to(page_name)
2
+ case page_name
3
+
4
+ when /the homepage/i
5
+ root_path
6
+
7
+ when /login/i
8
+ login_path
9
+ # Add more page name => path mappings here
10
+
11
+ else
12
+ raise "Can't find mapping from \"#{page_name}\" to a path."
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module ShopDiscounts
2
+ module Models
3
+ module Discountable
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ has_many :discountables, :class_name => 'ShopDiscountable', :foreign_key => :discounted_id
8
+ has_many :discounts, :class_name => 'ShopDiscount', :through => :discountables
9
+ end
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,20 @@
1
+ module ShopDiscounts
2
+ module Models
3
+ module Product
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+ after_create :assign_discounts
8
+
9
+ # Assigns discounts based off categories discounts
10
+ def assign_discounts
11
+ category.discounts.each do |discount|
12
+ ShopDiscountable.create(:discount => discount, :discounted => self)
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,33 @@
1
+ module ShopDiscounts
2
+ module Models
3
+ module Purchaseable
4
+
5
+ def self.included(base)
6
+ base.class_eval do
7
+
8
+ def discount
9
+ discount = BigDecimal.new('0.00')
10
+ discounts.map { |d| discount += d.amount }
11
+
12
+ # Maximum discount is 100%
13
+ discount = [discount,100.0].min
14
+
15
+ # Convert to a percentage
16
+ discount * 0.01
17
+ end
18
+
19
+ def discounted
20
+ (value * discount)
21
+ end
22
+
23
+ alias_method :value, :price
24
+ def price
25
+ result = BigDecimal.new('0.00')
26
+ result = value - discounted
27
+ end
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,18 @@
1
+ module ShopDiscounts
2
+ module Tags
3
+ module Cart
4
+ include Radiant::Taggable
5
+
6
+ [:value, :markdown].each do |symbol|
7
+ desc %{ outputs the #{symbol} of the current cart item }
8
+ tag "shop:cart:#{symbol}" do |tag|
9
+ attr = tag.attr.symbolize_keys
10
+ order = tag.locals.shop_order
11
+
12
+ Shop::Tags::Helpers.currency(order.send(symbol),attr)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,30 @@
1
+ module ShopDiscounts
2
+ module Tags
3
+ module Item
4
+ include Radiant::Taggable
5
+ [:value, :discount].each do |symbol|
6
+ desc %{ outputs the #{symbol} of the current cart item }
7
+ tag "shop:cart:item:#{symbol}" do |tag|
8
+ attr = tag.attr.symbolize_keys
9
+ item = tag.locals.shop_line_item
10
+
11
+ Shop::Tags::Helpers.currency(item.send(symbol),attr)
12
+ end
13
+ end
14
+
15
+ desc %{ expands if the item has a discount}
16
+ tag "shop:cart:item:if_discounted" do |tag|
17
+ item = tag.locals.shop_line_item
18
+
19
+ tag.expand if item.price != item.value
20
+ end
21
+
22
+ desc %{ expands if the item has a discount}
23
+ tag "shop:cart:item:unless_discounted" do |tag|
24
+ item = tag.locals.shop_line_item
25
+
26
+ tag.expand if item.price == item.value
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,55 @@
1
+ namespace :radiant do
2
+ namespace :extensions do
3
+ namespace :shop_discounts do
4
+
5
+ desc "Runs the migration of the Shop Discounts extension"
6
+ task :migrate => :environment do
7
+ require 'radiant/extension_migrator'
8
+ if ENV["VERSION"]
9
+ ShopDiscountsExtension.migrator.migrate(ENV["VERSION"].to_i)
10
+ Rake::Task['db:schema:dump'].invoke
11
+ else
12
+ ShopDiscountsExtension.migrator.migrate
13
+ Rake::Task['db:schema:dump'].invoke
14
+ end
15
+ end
16
+
17
+ desc "Copies public assets of the Shop Discounts to the instance public/ directory."
18
+ task :update => :environment do
19
+ is_svn_or_dir = proc {|path| path =~ /\.svn/ || File.directory?(path) }
20
+ puts "Copying assets from ShopDiscountsExtension"
21
+ Dir[ShopDiscountsExtension.root + "/public/**/*"].reject(&is_svn_or_dir).each do |file|
22
+ path = file.sub(ShopDiscountsExtension.root, '')
23
+ directory = File.dirname(path)
24
+ mkdir_p RAILS_ROOT + directory, :verbose => false
25
+ cp file, RAILS_ROOT + path, :verbose => false
26
+ end
27
+ unless ShopDiscountsExtension.root.starts_with? RAILS_ROOT # don't need to copy vendored tasks
28
+ puts "Copying rake tasks from ShopDiscountsExtension"
29
+ local_tasks_path = File.join(RAILS_ROOT, %w(lib tasks))
30
+ mkdir_p local_tasks_path, :verbose => false
31
+ Dir[File.join ShopDiscountsExtension.root, %w(lib tasks *.rake)].each do |file|
32
+ cp file, local_tasks_path, :verbose => false
33
+ end
34
+ end
35
+ end
36
+
37
+ desc "Syncs all available translations for this ext to the English ext master"
38
+ task :sync => :environment do
39
+ # The main translation root, basically where English is kept
40
+ language_root = ShopDiscountsExtension.root + "/config/locales"
41
+ words = TranslationSupport.get_translation_keys(language_root)
42
+
43
+ Dir["#{language_root}/*.yml"].each do |filename|
44
+ next if filename.match('_available_tags')
45
+ basename = File.basename(filename, '.yml')
46
+ puts "Syncing #{basename}"
47
+ (comments, other) = TranslationSupport.read_file(filename, basename)
48
+ words.each { |k,v| other[k] ||= words[k] } # Initializing hash variable as empty if it does not exist
49
+ other.delete_if { |k,v| !words[k] } # Remove if not defined in en.yml
50
+ TranslationSupport.write_file(filename, basename, comments, other)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end