radiant-shop_packages-extension 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +2 -0
  2. data/README +3 -0
  3. data/Rakefile +138 -0
  4. data/VERSION +1 -0
  5. data/app/controllers/.DS_Store +0 -0
  6. data/app/controllers/admin/shop/packages/packings_controller.rb +90 -0
  7. data/app/controllers/admin/shop/packages_controller.rb +63 -0
  8. data/app/datasets/shop_packages.rb +25 -0
  9. data/app/models/shop_package.rb +79 -0
  10. data/app/models/shop_packing.rb +22 -0
  11. data/app/views/admin/shop/packages/edit.html.haml +11 -0
  12. data/app/views/admin/shop/packages/edit/_foot.html.haml +17 -0
  13. data/app/views/admin/shop/packages/edit/_form.html.haml +15 -0
  14. data/app/views/admin/shop/packages/edit/_head.html.haml +4 -0
  15. data/app/views/admin/shop/packages/edit/_inputs.html.haml +2 -0
  16. data/app/views/admin/shop/packages/edit/_meta.html.haml +8 -0
  17. data/app/views/admin/shop/packages/edit/_parts.html.haml +9 -0
  18. data/app/views/admin/shop/packages/edit/_popups.html.haml +4 -0
  19. data/app/views/admin/shop/packages/edit/buttons/_browse_products.html.haml +1 -0
  20. data/app/views/admin/shop/packages/edit/inputs/_name.html.haml +3 -0
  21. data/app/views/admin/shop/packages/edit/inputs/_price.html.haml +3 -0
  22. data/app/views/admin/shop/packages/edit/meta/_sku.html.haml +5 -0
  23. data/app/views/admin/shop/packages/edit/parts/_description.html.haml +1 -0
  24. data/app/views/admin/shop/packages/edit/parts/_products.html.haml +3 -0
  25. data/app/views/admin/shop/packages/edit/popups/_browse_products.html.haml +7 -0
  26. data/app/views/admin/shop/packages/edit/shared/_product.html.haml +8 -0
  27. data/app/views/admin/shop/packages/index.html.haml +13 -0
  28. data/app/views/admin/shop/packages/index/_foot.html.haml +8 -0
  29. data/app/views/admin/shop/packages/index/_head.html.haml +2 -0
  30. data/app/views/admin/shop/packages/index/_package.html.haml +9 -0
  31. data/app/views/admin/shop/packages/index/buttons/_new_package.html.haml +1 -0
  32. data/app/views/admin/shop/packages/new.html.haml +11 -0
  33. data/app/views/admin/shop/packages/remove.html.haml +12 -0
  34. data/config/locales/en.yml +11 -0
  35. data/config/routes.rb +13 -0
  36. data/cucumber.yml +1 -0
  37. data/db/migrate/20101015161749_setup_shop_packages.rb +27 -0
  38. data/lib/shop_packages/interface/packages.rb +34 -0
  39. data/lib/shop_packages/models/shop_packageable.rb +15 -0
  40. data/lib/shop_packages/tags/helpers.rb +41 -0
  41. data/lib/shop_packages/tags/package.rb +94 -0
  42. data/lib/tasks/shop_packages_extension_tasks.rake +55 -0
  43. data/public/javascripts/admin/extensions/shop/packages/edit.js +109 -0
  44. data/public/stylesheets/sass/admin/extensions/shop/packages/edit.sass +162 -0
  45. data/radiant-shop_packages-extension.gemspec +104 -0
  46. data/shop_packages_extension.rb +37 -0
  47. data/spec/controllers/admin/shop/packages/packings_controller_spec.rb +188 -0
  48. data/spec/controllers/admin/shop/packages_controller_spec.rb +32 -0
  49. data/spec/datasets/shop_packages.rb +23 -0
  50. data/spec/lib/shop_packages/tags/package_spec.rb +348 -0
  51. data/spec/models/shop_package_spec.rb +117 -0
  52. data/spec/models/shop_packing_spec.rb +67 -0
  53. data/spec/models/shop_product_spec.rb +25 -0
  54. data/spec/spec.opts +4 -0
  55. data/spec/spec_helper.rb +23 -0
  56. metadata +141 -0
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ pkg
2
+ .bundle
data/README ADDED
@@ -0,0 +1,3 @@
1
+ = Shop Packages
2
+
3
+ Description goes here
data/Rakefile ADDED
@@ -0,0 +1,138 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gem|
4
+ gem.name = "radiant-shop_packages-extension"
5
+ gem.summary = %Q{Shop Packages Extension for Radiant CMS}
6
+ gem.description = %Q{RadiantShop: Group up Products into packages, you can assign a price to a package}
7
+ gem.email = "dk@dirkkelly.com"
8
+ gem.homepage = "http://github.com/thefrontiergroup/radiant-shop_packages-extension"
9
+ gem.authors = ["Dirk Kelly"]
10
+ gem.add_dependency 'radiant-shop-extension'
11
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
12
+ end
13
+ Jeweler::GemcutterTasks.new
14
+ rescue LoadError
15
+ puts "Jeweler (or a dependency) not available. This is only required if you plan to package shop_packages as a gem."
16
+ end
17
+
18
+ # In rails 1.2, plugins aren't available in the path until they're loaded.
19
+ # Check to see if the rspec plugin is installed first and require
20
+ # it if it is. If not, use the gem version.
21
+
22
+ # Determine where the RSpec plugin is by loading the boot
23
+ unless defined? RADIANT_ROOT
24
+ ENV["RAILS_ENV"] = "test"
25
+ case
26
+ when ENV["RADIANT_ENV_FILE"]
27
+ require File.dirname(ENV["RADIANT_ENV_FILE"]) + "/boot"
28
+ when File.dirname(__FILE__) =~ %r{vendor/radiant/vendor/extensions}
29
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../../../")}/config/boot"
30
+ else
31
+ require "#{File.expand_path(File.dirname(__FILE__) + "/../../../")}/config/boot"
32
+ end
33
+ end
34
+
35
+ require 'rake'
36
+ require 'rake/rdoctask'
37
+ require 'rake/testtask'
38
+
39
+ rspec_base = File.expand_path(RADIANT_ROOT + '/vendor/plugins/rspec/lib')
40
+ $LOAD_PATH.unshift(rspec_base) if File.exist?(rspec_base)
41
+ require 'spec/rake/spectask'
42
+ require 'cucumber'
43
+ require 'cucumber/rake/task'
44
+
45
+ # Cleanup the RADIANT_ROOT constant so specs will load the environment
46
+ Object.send(:remove_const, :RADIANT_ROOT)
47
+
48
+ extension_root = File.expand_path(File.dirname(__FILE__))
49
+
50
+ task :default => :spec
51
+ task :stats => "spec:statsetup"
52
+
53
+ desc "Run all specs in spec directory"
54
+ Spec::Rake::SpecTask.new(:spec) do |t|
55
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
56
+ t.spec_files = FileList['spec/**/*_spec.rb']
57
+ end
58
+
59
+ task :features => 'spec:integration'
60
+
61
+ namespace :spec do
62
+ desc "Run all specs in spec directory with RCov"
63
+ Spec::Rake::SpecTask.new(:rcov) do |t|
64
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
65
+ t.spec_files = FileList['spec/**/*_spec.rb']
66
+ t.rcov = true
67
+ t.rcov_opts = ['--exclude', 'spec', '--rails']
68
+ end
69
+
70
+ desc "Print Specdoc for all specs"
71
+ Spec::Rake::SpecTask.new(:doc) do |t|
72
+ t.spec_opts = ["--format", "specdoc", "--dry-run"]
73
+ t.spec_files = FileList['spec/**/*_spec.rb']
74
+ end
75
+
76
+ [:models, :controllers, :views, :helpers].each do |sub|
77
+ desc "Run the specs under spec/#{sub}"
78
+ Spec::Rake::SpecTask.new(sub) do |t|
79
+ t.spec_opts = ['--options', "\"#{extension_root}/spec/spec.opts\""]
80
+ t.spec_files = FileList["spec/#{sub}/**/*_spec.rb"]
81
+ end
82
+ end
83
+
84
+ desc "Run the Cucumber features"
85
+ Cucumber::Rake::Task.new(:integration) do |t|
86
+ t.fork = true
87
+ t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'pretty')]
88
+ # t.feature_pattern = "#{extension_root}/features/**/*.feature"
89
+ t.profile = "default"
90
+ end
91
+
92
+ # Setup specs for stats
93
+ task :statsetup do
94
+ require 'code_statistics'
95
+ ::STATS_DIRECTORIES << %w(Model\ specs spec/models)
96
+ ::STATS_DIRECTORIES << %w(View\ specs spec/views)
97
+ ::STATS_DIRECTORIES << %w(Controller\ specs spec/controllers)
98
+ ::STATS_DIRECTORIES << %w(Helper\ specs spec/views)
99
+ ::CodeStatistics::TEST_TYPES << "Model specs"
100
+ ::CodeStatistics::TEST_TYPES << "View specs"
101
+ ::CodeStatistics::TEST_TYPES << "Controller specs"
102
+ ::CodeStatistics::TEST_TYPES << "Helper specs"
103
+ ::STATS_DIRECTORIES.delete_if {|a| a[0] =~ /test/}
104
+ end
105
+
106
+ namespace :db do
107
+ namespace :fixtures do
108
+ desc "Load fixtures (from spec/fixtures) into the current environment's database. Load specific fixtures using FIXTURES=x,y"
109
+ task :load => :environment do
110
+ require 'active_record/fixtures'
111
+ ActiveRecord::Base.establish_connection(RAILS_ENV.to_sym)
112
+ (ENV['FIXTURES'] ? ENV['FIXTURES'].split(/,/) : Dir.glob(File.join(RAILS_ROOT, 'spec', 'fixtures', '*.{yml,csv}'))).each do |fixture_file|
113
+ Fixtures.create_fixtures('spec/fixtures', File.basename(fixture_file, '.*'))
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ desc 'Generate documentation for the shop_packages extension.'
121
+ Rake::RDocTask.new(:rdoc) do |rdoc|
122
+ rdoc.rdoc_dir = 'rdoc'
123
+ rdoc.title = 'ShopPackagesExtension'
124
+ rdoc.options << '--line-numbers' << '--inline-source'
125
+ rdoc.rdoc_files.include('README')
126
+ rdoc.rdoc_files.include('lib/**/*.rb')
127
+ end
128
+
129
+ # For extensions that are in transition
130
+ desc 'Test the shop_packages extension.'
131
+ Rake::TestTask.new(:test) do |t|
132
+ t.libs << 'lib'
133
+ t.pattern = 'test/**/*_test.rb'
134
+ t.verbose = true
135
+ end
136
+
137
+ # Load any custom rakefiles for extension
138
+ Dir[File.dirname(__FILE__) + '/tasks/*.rake'].sort.each { |f| require f }
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
Binary file
@@ -0,0 +1,90 @@
1
+ class Admin::Shop::Packages::PackingsController < Admin::ResourceController
2
+ model_class ShopPacking
3
+
4
+ def sort
5
+ notice = 'Products successfully sorted.'
6
+ error = 'Could not sort products.'
7
+
8
+ begin
9
+ @shop_packings = CGI::parse(params[:packings])["package_products[]"]
10
+
11
+ @shop_packings.each_with_index do |id, index|
12
+ ShopPacking.find(id).update_attributes!({ :position, index+1 })
13
+ end
14
+
15
+ respond_to do |format|
16
+ format.html {
17
+ redirect_to admin_shop_packages_path
18
+ }
19
+ format.js { render :text => notice, :status => :ok }
20
+ format.json { render :json => { :notice => notice }, :status => :ok }
21
+ end
22
+ rescue
23
+ respond_to do |format|
24
+ format.html {
25
+ flash[:error] = error
26
+ redirect_to admin_shop_packages_path
27
+ }
28
+ format.js { render :text => error, :status => :unprocessable_entity }
29
+ format.json { render :json => { :error => error }, :status => :unprocessable_entity }
30
+ end
31
+ end
32
+ end
33
+
34
+ def create
35
+ notice = 'Product successfully attached.'
36
+ error = 'Could not attach product.'
37
+
38
+ begin
39
+ @shop_packing.package = ShopPackage.find(params[:package_id])
40
+ @shop_packing.product = ShopProduct.find(params[:product_id])
41
+ @shop_packing.save!
42
+
43
+ respond_to do |format|
44
+ format.js { render :partial => 'admin/shop/packages/edit/shared/product', :locals => { :product => @shop_packing.product, :packing => @shop_packing } }
45
+ end
46
+ rescue
47
+ respond_to do |format|
48
+ format.js { render :text => error, :status => :unprocessable_entity }
49
+ end
50
+ end
51
+ end
52
+
53
+ def update
54
+ notice = 'Product Quantity successfully updated.'
55
+ error = 'Could not update Product Quantity.'
56
+
57
+ begin
58
+ @shop_packing.update_attributes!({ :quantity => params[:quantity] })
59
+ respond_to do |format|
60
+ format.js { render :text => notice, :status => :ok }
61
+ end
62
+ rescue
63
+ respond_to do |format|
64
+ format.js { render :text => error, :status => :unprocessable_entity }
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ def destroy
71
+ notice = 'Product successfully removed.'
72
+ error = 'Could not remove product.'
73
+
74
+ begin
75
+ @shop_product = @shop_packing.product
76
+ @shop_package = @shop_packing.package
77
+
78
+ @shop_packing.destroy
79
+
80
+ respond_to do |format|
81
+ format.js { render :partial => 'admin/shop/packages/edit/shared/product', :locals => { :product => @shop_product } }
82
+ end
83
+ rescue
84
+ respond_to do |format|
85
+ format.js { render :text => error, :status => :unprocessable_entity }
86
+ end
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,63 @@
1
+ class Admin::Shop::PackagesController < Admin::ResourceController
2
+ model_class ShopPackage
3
+
4
+ helper :shop
5
+
6
+ before_filter :config_global
7
+ before_filter :config_index, :only => [ :index ]
8
+ before_filter :config_new, :only => [ :new, :create ]
9
+ before_filter :config_edit, :only => [ :edit, :update ]
10
+ before_filter :assets_global
11
+ before_filter :assets_index, :only => :index
12
+ before_filter :assets_edit, :only => [ :edit, :update ]
13
+
14
+ private
15
+
16
+ def config_global
17
+ @inputs ||= []
18
+ @meta ||= []
19
+ @buttons ||= []
20
+ @parts ||= []
21
+ @popups ||= []
22
+
23
+ @inputs << 'name'
24
+ @inputs << 'price'
25
+ end
26
+
27
+ def config_index
28
+ @buttons << 'new_package'
29
+ end
30
+
31
+ def config_new
32
+ @meta << 'sku'
33
+
34
+ @parts << 'description'
35
+ end
36
+
37
+ def config_edit
38
+ @meta << 'sku'
39
+
40
+ @parts << 'description'
41
+ @parts << 'products'
42
+
43
+ @buttons << 'browse_products'
44
+
45
+ @popups << 'browse_products'
46
+ end
47
+
48
+ def assets_global
49
+ end
50
+
51
+ def assets_index
52
+ include_stylesheet 'admin/extensions/shop/index'
53
+ end
54
+
55
+ def assets_edit
56
+ include_javascript 'admin/dragdrop'
57
+ include_javascript 'admin/extensions/shop/edit'
58
+ include_stylesheet 'admin/extensions/shop/edit'
59
+ include_stylesheet 'admin/extensions/shop/packages/edit'
60
+ include_javascript 'admin/extensions/shop/packages/edit'
61
+ end
62
+
63
+ end
@@ -0,0 +1,25 @@
1
+ class ShopPackagesDataset < Dataset::Base
2
+
3
+ uses :shop_products
4
+
5
+ def load
6
+ packages = {
7
+ :bread => [ :soft, :crusty, :warm ]
8
+ }
9
+
10
+ packages.each do |package, products|
11
+ create_record :shop_package, "all_#{package.to_s}".to_sym,
12
+ :name => "all #{package.to_s}",
13
+ :sku => "all_#{package.to_s}",
14
+ :price => 1 * 10
15
+ products.each_with_index do |product, i|
16
+ create_record :shop_packing, "#{product.to_s}_bread".to_s.to_sym,
17
+ :quantity => 1,
18
+ :position => 1,
19
+ :package => shop_packages("all_#{package.to_s}".to_sym),
20
+ :product => shop_products("#{product.to_s}_bread".to_sym)
21
+ end
22
+ end
23
+ end
24
+
25
+ end
@@ -0,0 +1,79 @@
1
+ class ShopPackage < ActiveRecord::Base
2
+
3
+ belongs_to :created_by, :class_name => 'User'
4
+ belongs_to :updated_by, :class_name => 'User'
5
+
6
+ has_many :packings, :class_name => 'ShopPacking', :foreign_key => :package_id, :dependent => :destroy
7
+ has_many :products, :class_name => 'ShopProduct', :foreign_key => :product_id, :through => :packings
8
+ has_many :line_items, :class_name => 'ShopLineItem', :as => :item
9
+ has_many :orders, :class_name => 'ShopOrder', :through => :line_items
10
+
11
+ before_validation :assign_sku
12
+
13
+ validates_presence_of :name, :sku
14
+
15
+ validates_uniqueness_of :name, :sku
16
+
17
+ validates_numericality_of :price, :greater_than => 0.00, :allow_nil => true, :precisions => 2
18
+
19
+ # Returns the products not attached to the category
20
+ def available_products; ShopProduct.all - self.products; end
21
+
22
+ # Returns the slug of the first product
23
+ def slug; packings.first.product.slug; end
24
+
25
+ # Returns the url of the first product
26
+ def url; packings.first.product.url; end
27
+
28
+ # Not a valid option, but useful incase a tag is called
29
+ def category; nil; end
30
+
31
+ # Overloads the base to_json to return what we want
32
+ def to_json(*attrs); super self.class.params; end
33
+
34
+ # Returns the aggregate value of the products in the package
35
+ def value
36
+ value = 0
37
+ self.packings.map { |pkg| value += (pkg.product.price.to_f * pkg.quantity) }
38
+ value
39
+ end
40
+
41
+ # Returns the aggregate weight of the products in the package
42
+ def weight
43
+ weight = 0
44
+ self.packings.map { |pkg| weight += (pkg.product.weight.to_f * pkg.quantity) }
45
+ weight
46
+ end
47
+
48
+ class << self
49
+
50
+ # Returns attributes attached to the product
51
+ def attrs
52
+ [ :id, :name, :price, :sku, :description, :created_at, :updated_at ]
53
+ end
54
+
55
+ # Returns methods with usefuly information
56
+ def methds
57
+ []
58
+ end
59
+
60
+ # Returns the objects to include
61
+ def inclde
62
+ [ :category, :products ]
63
+ end
64
+
65
+ # Returns a custom hash of attributes on the product
66
+ def params
67
+ { :only => self.attrs, :methods => self.methds, :include => self.inclde }
68
+ end
69
+
70
+ end
71
+
72
+ private
73
+
74
+ # Assigns an sku based off the name
75
+ def assign_sku
76
+ self.sku = ShopProduct.to_sku(sku.present? ? sku : name)
77
+ end
78
+
79
+ end
@@ -0,0 +1,22 @@
1
+ class ShopPacking < ActiveRecord::Base
2
+
3
+ default_scope :order => 'shop_packings.position ASC'
4
+
5
+ belongs_to :package, :class_name => 'ShopPackage', :foreign_key => :package_id
6
+ belongs_to :product, :class_name => 'ShopProduct', :foreign_key => :product_id
7
+
8
+ before_validation :set_quantity
9
+
10
+ validates_uniqueness_of :product_id, :scope => :package_id
11
+
12
+ def value
13
+ self.product.price.to_f * self.quantity
14
+ end
15
+
16
+ private
17
+
18
+ def set_quantity
19
+ self.quantity = [1,self.quantity].max
20
+ end
21
+
22
+ end
@@ -0,0 +1,11 @@
1
+ - @page_title = @shop_package.name
2
+
3
+ - render_region :main do |main|
4
+ - main.head do
5
+ = render 'admin/shop/packages/edit/head'
6
+
7
+ - main.popups do
8
+ = render 'admin/shop/packages/edit/popups'
9
+
10
+ - main.form do
11
+ = render 'admin/shop/packages/edit/form'