radiant-shop_packages-extension 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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'