radiant-shop_discounts-extension 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.DS_Store +0 -0
- data/.gitignore +1 -0
- data/README +3 -0
- data/Rakefile +138 -0
- data/VERSION +1 -0
- data/app/controllers/admin/shop/discounts/discountables_controller.rb +44 -0
- data/app/controllers/admin/shop/discounts_controller.rb +64 -0
- data/app/models/form_discount.rb +39 -0
- data/app/models/shop_discount.rb +37 -0
- data/app/models/shop_discountable.rb +64 -0
- data/app/views/admin/shop/discounts/edit.html.haml +11 -0
- data/app/views/admin/shop/discounts/edit/_foot.html.haml +16 -0
- data/app/views/admin/shop/discounts/edit/_form.html.haml +15 -0
- data/app/views/admin/shop/discounts/edit/_head.html.haml +4 -0
- data/app/views/admin/shop/discounts/edit/_inputs.html.haml +2 -0
- data/app/views/admin/shop/discounts/edit/_meta.html.haml +8 -0
- data/app/views/admin/shop/discounts/edit/_parts.html.haml +9 -0
- data/app/views/admin/shop/discounts/edit/_popups.html.haml +4 -0
- data/app/views/admin/shop/discounts/edit/buttons/_browse_categories.html.haml +1 -0
- data/app/views/admin/shop/discounts/edit/buttons/_browse_products.html.haml +1 -0
- data/app/views/admin/shop/discounts/edit/inputs/_amount.html.haml +3 -0
- data/app/views/admin/shop/discounts/edit/inputs/_code.html.haml +3 -0
- data/app/views/admin/shop/discounts/edit/inputs/_name.html.haml +3 -0
- data/app/views/admin/shop/discounts/edit/meta/_finish.html.haml +5 -0
- data/app/views/admin/shop/discounts/edit/meta/_start.html.haml +5 -0
- data/app/views/admin/shop/discounts/edit/parts/_categories.html.haml +3 -0
- data/app/views/admin/shop/discounts/edit/parts/_products.html.haml +3 -0
- data/app/views/admin/shop/discounts/edit/popups/_browse_categories.html.haml +6 -0
- data/app/views/admin/shop/discounts/edit/popups/_browse_products.html.haml +6 -0
- data/app/views/admin/shop/discounts/edit/shared/_category.html.haml +11 -0
- data/app/views/admin/shop/discounts/edit/shared/_product.html.haml +12 -0
- data/app/views/admin/shop/discounts/index.html.haml +13 -0
- data/app/views/admin/shop/discounts/index/_discount.html.haml +13 -0
- data/app/views/admin/shop/discounts/index/_foot.html.haml +5 -0
- data/app/views/admin/shop/discounts/index/_head.html.haml +2 -0
- data/app/views/admin/shop/discounts/index/buttons/_new_discount.html.haml +1 -0
- data/app/views/admin/shop/discounts/new.html.haml +11 -0
- data/app/views/admin/shop/discounts/remove.html.haml +12 -0
- data/config/locales/en.yml +17 -0
- data/config/routes.rb +17 -0
- data/cucumber.yml +1 -0
- data/db/migrate/20101015162137_setup_shop_discounts.rb +30 -0
- data/features/support/env.rb +16 -0
- data/features/support/paths.rb +14 -0
- data/lib/shop_discounts/models/discountable.rb +14 -0
- data/lib/shop_discounts/models/product.rb +20 -0
- data/lib/shop_discounts/models/purchaseable.rb +33 -0
- data/lib/shop_discounts/tags/cart.rb +18 -0
- data/lib/shop_discounts/tags/item.rb +30 -0
- data/lib/tasks/shop_discounts_extension_tasks.rake +55 -0
- data/public/javascripts/admin/extensions/shop/discounts/edit.js +76 -0
- data/public/stylesheets/sass/admin/extensions/shop/discounts/edit.sass +125 -0
- data/radiant-shop_discounts-extension.gemspec +124 -0
- data/shop_discounts_extension.rb +31 -0
- data/spec/controllers/admin/shop/discounts/discountables_controller_spec.rb +72 -0
- data/spec/controllers/admin/shop/discounts_controller_spec.rb +81 -0
- data/spec/datasets/forms_discount.rb +24 -0
- data/spec/datasets/shop_discountables.rb +22 -0
- data/spec/datasets/shop_discounts.rb +34 -0
- data/spec/lib/shop_discounts/models/discountable_spec.rb +114 -0
- data/spec/lib/shop_discounts/models/purchaseable_spec.rb +55 -0
- data/spec/lib/shop_discounts/tags/item_spec.rb +96 -0
- data/spec/models/form_discount_spec.rb +63 -0
- data/spec/models/shop_category_spec.rb +19 -0
- data/spec/models/shop_discount_spec.rb +130 -0
- data/spec/models/shop_line_item_spec.rb +15 -0
- data/spec/models/shop_product_spec.rb +40 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +23 -0
- metadata +161 -0
@@ -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 @@
|
|
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,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,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 @@
|
|
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
|
+
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
|