Skip to content
Browse files

first commit

  • Loading branch information...
1 parent fa0dec3 commit 54ef9d60449ace50dc6d7bed62bcfec884e912fc @jsqu99 committed Feb 28, 2011
View
10 .gitignore
@@ -0,0 +1,10 @@
+\#*
+*~
+.#*
+.DS_Store
+.idea
+.project
+tmp
+nbproject
+*.swp
+doc/notes.txt
View
23 LICENSE
@@ -0,0 +1,23 @@
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+ * Neither the name of the Rails Dog LLC nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
View
13 README.md
@@ -0,0 +1,13 @@
+SpreeOnDemandVariants
+=====================
+
+Introduction goes here.
+
+
+Example
+=======
+
+Example goes here.
+
+
+Copyright (c) 2011 [name of extension creator], released under the New BSD License
View
31 Rakefile
@@ -0,0 +1,31 @@
+require File.expand_path('../../config/application', __FILE__)
+
+require 'rubygems'
+require 'rake'
+require 'rake/testtask'
+require 'rake/packagetask'
+require 'rake/gempackagetask'
+
+spec = eval(File.read('spree_on_demand_variants.gemspec'))
+
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+end
+
+desc "Release to gemcutter"
+task :release => :package do
+ require 'rake/gemcutter'
+ Rake::Gemcutter::Tasks.new(spec).define
+ Rake::Task['gem:push'].invoke
+end
+
+desc "Default Task"
+task :default => [ :spec ]
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new
+
+# require 'cucumber/rake/task'
+# Cucumber::Rake::Task.new do |t|
+# t.cucumber_opts = %w{--format pretty}
+# end
View
4 app/controllers/admin/option_values_controller.rb
@@ -0,0 +1,4 @@
+class Admin::OptionValuesController < Admin::BaseController
+ resource_controller
+ belongs_to :option_types # what does this do?
+end
View
43 app/controllers/products_controller_decorator.rb
@@ -0,0 +1,43 @@
+ProductsController.class_eval do
+# before_filter :load_option_types_for_on_demand_variants, :only => :show
+#
+# def load_option_types_for_on_demand_variants
+# if @product.has_on_demand_variants?
+# @option_types= @product.option_types
+# end
+# end
+
+
+ # Adds a new item to the order (creating a new order if none already exists)
+ #
+ # Parameters can be passed using the following possible parameter configurations:
+ #
+ # * Single variant/quantity pairing
+ # +:variants => {variant_id => quantity}+
+ #
+ # * Multiple products at once
+ # +:products => {product_id => variant_id, product_id => variant_id}, :quantity => quantity +
+ # +:products => {product_id => variant_id, product_id => variant_id}}, :quantity => {variant_id => quantity, variant_id => quantity}+
+ def populate
+ @order = current_order(true)
+
+ params[:products].each do |product_id,variant_id|
+ quantity = params[:quantity].to_i if !params[:quantity].is_a?(Hash)
+ quantity = params[:quantity][variant_id].to_i if params[:quantity].is_a?(Hash)
+ @order.add_variant(Variant.find(variant_id), quantity) if quantity > 0
+ end if params[:products]
+
+ params[:variants].each do |variant_id, quantity|
+ quantity = quantity.to_i
+ @order.add_variant(Variant.find(variant_id), quantity) if quantity > 0
+ end if params[:variants]
+
+# need to see what the parms look like before going any further
+# params[:option_values].each do |option_value_id, quantity|
+# quantity = quantity.to_i
+# @order.add_variant(Variant.find(variant_id), quantity) if quantity > 0
+# end if params[:variants]
+
+ redirect_to cart_path
+ end
+end
View
5 app/models/product_decorator.rb
@@ -0,0 +1,5 @@
+Product.class_eval do
+ def has_on_demand_variants?
+ has_on_demand_variants
+ end
+end
View
41 app/views/admin/option_values/_form.html.erb
@@ -0,0 +1,41 @@
+<div class="yui-gb">
+ <div class="yui-u first">
+
+ <!-- each option type -->
+ <% @product.options.each do |option| %>
+
+ <h2><%= option.presentation %></h2>
+
+ <h3>What price modifier strategy does this <%= option.presentation %> use?</h3>
+
+ <%= f.fields_for(option) do |option_fields| %>
+ <p><%= option_fields.label :price_modifier_type, t("price_modifier_type") %>:<br />
+ <%= option_fields.select(:price_modifier_type, options_for_select([["none",t("none")],["single",t("single")],["multiple", t("multiple")]]) %>
+ <!-- TODO?: options_from_collection_for_select(@price_modifier_types, 'id', 'name') -->
+ </p>
+ <% end %> <!-- fields for -->
+
+ <table class="index">
+ <tr>
+ <th><%= t("option_values") %></th>
+ <th><%= t("price") %></th>
+ </tr>
+
+ <!-- each option value -->
+ <% option.option_type.option_values.each do |ov| %>
+
+ <% option_fields.fields_for(ov) do |ov_fields| %>
+ <tr id="<%= dom_id(ov) %>" %>
+ <td><%= ov.presentation %></td>
+ <td><%= ov_fields.label :price_modifier, t("price_modifier") %>:<br />
+ <%= ov_fields.text_field :price_modifier %>
+ </td>
+ </tr>
+ <% end %> <!-- ov fields_for -->
+ <% end %> <!-- each -->
+ <% end %> <!-- option fields_for -->
+ <% end %> <!-- each -->
+
+ </table>
+ </div>
+</div>
View
13 app/views/admin/option_values/edit.html.erb
@@ -0,0 +1,13 @@
+<%= render :partial => 'admin/shared/product_sub_menu' %>
+
+<%= render :partial => 'admin/shared/product_tabs', :locals => {:current => "Variants"} %>
+
+<%= render "shared/error_messages", :target => @variant %>
+
+<%= form_for(@variant, :url => object_url, :html => { :method => :put }) do |f| %>
+ <%= hook :admin_variant_edit_form, {:f => f} do %>
+ <%= render :partial => "form", :locals => { :f => f } %>
+ <% end %>
+
+ <%= render :partial => 'admin/shared/edit_resource_links' %>
+<% end %>
View
57 app/views/admin/option_values/index.html.erb
@@ -0,0 +1,57 @@
+<%= render :partial => 'admin/shared/product_sub_menu' %>
+
+<%= render :partial => 'admin/shared/product_tabs', :locals => {:current => "Variants"} %>
+
+
+ <!-- TODO: here we _should_ show each option value that has been set up as an on-demand option value -->
+ <!-- <table class="index">
+<tr>
+ <th><%= t("options") %></th>
+ <th><%= t("price") %></th>
+ <th><%= t("sku") %></th>
+ <% Variant.additional_fields.select{|f| f[:only].nil? || f[:only].include?(:variant) }.each do |field| %>
+ <th><%= t("activerecord.attributes.variant." + field[:name].downcase, :default => field[:name].titleize) %></th>
+ <% end %>
+ <th><%= t("on_hand") %></th>
+ <th><%= t("action") %></th>
+ </tr>
+
+ <% @variants.each do |variant| %>
+
+-->
+ <!-- you can skip variant with no options: that's just the default variant that all products have -->
+<!--
+ <% next if variant.option_values.empty? %>
+ <tr id="<%= dom_id(variant) %>" <%= 'style="color:red;"' if variant.deleted? %>>
+ <td><%= variant_options variant %></td>
+ <td><%= variant.price %></td>
+ <td><%= variant.sku %></td>
+ <% Variant.additional_fields.select{|f| f[:only].nil? || f[:only].include?(:variant) }.each do |field| %>
+ <td><%= variant[field[:name].gsub(" ", "_").downcase] %></td>
+ <% end %>
+ <td><%= variant.on_hand %></td>
+ <td valign="top">
+ <%= link_to_edit(variant) unless variant.deleted? %>
+ &nbsp;
+ <%= link_to_delete(variant) unless variant.deleted? %>
+ </td>
+ </tr>
+ <% end %>
+ <% unless @product.has_variants? %>
+ <tr><td colspan="9"><%= t("none") %></td></tr>
+ <% end %>
+</table>
+-->
+<% if @product.options.empty? %>
+ <p>
+ <%= t("to_add_variants_you_must_first_define") %> <%= link_to t("option_types"), selected_admin_product_option_types_url(@product) %>
+ </p>
+<% else %>
+ <div id="new_variant"></div>
+ <br/>
+ <p id="new_var_link">
+ <%= link_to icon('add') + ' ' + t("new_variant"), new_admin_product_variant_url(@product), :remote => :true, 'data-update' => 'new_variant', :class => 'iconlink' %>
+ &nbsp;|&nbsp;<%= link_to @deleted.blank? ? t("show_deleted") : t("show_active"), admin_product_variants_url(@product, :deleted => @deleted.blank? ? "on" : "off") %>
+ </p>
+ <%= image_tag "spinner.gif", :plugin=>"spree", :style => "display:none", :id => 'busy_indicator' %>
+<% end %>
View
9 app/views/admin/option_values/new.html.erb
@@ -0,0 +1,9 @@
+<%= render "shared/error_messages", :target => @variant %>
+
+<%= form_for(@product, :url => collection_url) do |f| %>
+<fieldset>
+ <%= render :partial => "form", :locals => { :f => f } %>
+
+ <%= render :partial => 'admin/shared/new_resource_links' %>
+</fieldset>
+<% end %>
View
5 app/views/admin/products/_has_on_demand_variants.html.erb
@@ -0,0 +1,5 @@
+<p>
+ <%= f.label :has_on_demand_variants, t("has_on_demand_variants")%><br />
+ <%= f.check_box :has_on_demand_variants %>
+</p>
+
View
1 app/views/admin/products/_option_values_tab.html.erb
@@ -0,0 +1 @@
+<%= tab(:option_types, :match_path => '/option_values') %>
View
61 app/views/products/_cart_form.html.erb
@@ -0,0 +1,61 @@
+<%= form_for :order, :url => populate_orders_url do |f| %>
+<%= hook :inside_product_cart_form do %>
+
+ <% if product_price(@product) %>
+ <%= hook :product_price do %>
+ <p class="prices">
+ <%= t("price") %>
+ <br />
+ <span class="price selling"><%= product_price(@product) %></span>
+ </p>
+ <% end %>
+ <% end %>
+
+ <% if @product.has_on_demand_variants?
+ @product.option_types.each do |ot|
+ %>
+ <%= f.label ot.name, ot.name %>
+ <% option_values=OptionValue.where(:option_type_id => ot.id) %>
+ <%= select_tag ot.name, options_from_collection_for_select(option_values, "id", "presentation"), :class => 'on-demand-option-select' %>
+ <% end %>
+ <% elsif @product.has_variants? %>
+ <div id="product-variants">
+ <h2><%= t('variants') %></h2>
+ <ul>
+ <% has_checked = false
+ @product.variants.active.each_with_index do |v,index|
+ next if v.option_values.empty? || (!v.in_stock && !Spree::Config[:show_zero_stock_products])
+ checked = !has_checked && (v.in_stock || Spree::Config[:allow_backorders])
+ has_checked = true if checked %>
+ <li>
+ <label>
+ <%= radio_button_tag "products[#{@product.id}]", v.id, checked, :disabled => !v.in_stock && !Spree::Config[:allow_backorders] %>
+ <span class="variant-description">
+ <%= variant_options v %>
+ </span>
+ <% if variant_price_diff v %>
+ <span class="price diff"><%= variant_price_diff v %></span>
+ <% end %>
+ </label>
+ </li>
+ <% end%>
+ </ul>
+ </div>
+ <% end%>
+ <% if @product.has_stock? || Spree::Config[:allow_backorders] %>
+ <%= text_field_tag @product.has_variants? ? :quantity : "variants[#{@product.master.id}]"),
+ 1, :class => "title", :size => 3 %>
+ &nbsp;
+ <button type='submit' class='large primary'>
+ <%= image_tag('/images/add-to-cart.png') + t('add_to_cart') %>
+ </button>
+ <% else %>
+ <%= content_tag('strong', t('out_of_stock')) %>
+ <% end %>
+
+<% end %>
+<% end %>
+
+<% content_for :head do %>
+ <%= javascript_include_tag 'product' %>
+<% end %>
View
3 config/locales/en.yml
@@ -0,0 +1,3 @@
+---
+en:
+ has_on_demand_variants: "Has on-demand variants?"
View
7 config/routes.rb
@@ -0,0 +1,7 @@
+Rails.application.routes.draw do
+ namespace :admin do
+ resources :products do
+ resources :option_values
+ end
+ end
+end
View
9 db/migrate/20110222203247_add_dynamic_variants_flag_to_products.rb
@@ -0,0 +1,9 @@
+class AddDynamicVariantsFlagToProducts < ActiveRecord::Migration
+ def self.up
+ add_column :products, :has_on_demand_variants, :boolean, :default => false
+ end
+
+ def self.down
+ remove_column :products, :has_on_demand_variants
+ end
+end
View
11 db/migrate/20110225135642_add_price_modifiers_to_option_values.rb
@@ -0,0 +1,11 @@
+class AddPriceModifiersToOptionValues < ActiveRecord::Migration
+ def self.up
+ add_column :product_option_types, :price_modifier_type, :string, :null => true, :default => nil
+ add_column :option_values, :price_modifier, :decimal, :null => true, :default => nil, :precision => 8, :scale => 2
+ end
+
+ def self.down
+ remove_column :product_option_types, :price_modifier_type
+ remove_column :option_values, :price_modifier
+ end
+end
View
17 lib/spree_on_demand_variants.rb
@@ -0,0 +1,17 @@
+require 'spree_core'
+require 'spree_on_demand_variants_hooks'
+
+module SpreeOnDemandVariants
+ class Engine < Rails::Engine
+
+ config.autoload_paths += %W(#{config.root}/lib)
+
+ def self.activate
+ Dir.glob(File.join(File.dirname(__FILE__), "../app/**/*_decorator*.rb")) do |c|
+ Rails.env.production? ? require(c) : load(c)
+ end
+ end
+
+ config.to_prepare &method(:activate).to_proc
+ end
+end
View
4 lib/spree_on_demand_variants_hooks.rb
@@ -0,0 +1,4 @@
+class SpreeOnDemandVariantsHooks < Spree::ThemeSupport::HookListener
+ insert_after :admin_product_form_additional_fields, 'admin/products/has_on_demand_variants'
+ insert_after :admin_product_sub_tabs, 'admin/products/option_values_tab'
+end
View
25 lib/tasks/install.rake
@@ -0,0 +1,25 @@
+namespace :spree_on_demand_variants do
+ desc "Copies all migrations and assets (NOTE: This will be obsolete with Rails 3.1)"
+ task :install do
+ Rake::Task['spree_on_demand_variants:install:migrations'].invoke
+ Rake::Task['spree_on_demand_variants:install:assets'].invoke
+ end
+
+ namespace :install do
+ desc "Copies all migrations (NOTE: This will be obsolete with Rails 3.1)"
+ task :migrations do
+ source = File.join(File.dirname(__FILE__), '..', '..', 'db')
+ destination = File.join(Rails.root, 'db')
+ Spree::FileUtilz.mirror_files(source, destination)
+ end
+
+ desc "Copies all assets (NOTE: This will be obsolete with Rails 3.1)"
+ task :assets do
+ source = File.join(File.dirname(__FILE__), '..', '..', 'public')
+ destination = File.join(Rails.root, 'public')
+ puts "INFO: Mirroring assets from #{source} to #{destination}"
+ Spree::FileUtilz.mirror_files(source, destination)
+ end
+ end
+
+end
View
1 lib/tasks/spree_on_demand_variants.rake
@@ -0,0 +1 @@
+# add custom rake tasks here
View
30 spec/spec_helper.rb
@@ -0,0 +1,30 @@
+# This file is copied to ~/spec when you run 'ruby script/generate rspec'
+# from the project root directory.
+ENV["RAILS_ENV"] ||= 'test'
+require File.expand_path("../../../config/environment", __FILE__)
+require 'rspec/rails'
+
+# Requires supporting files with custom matchers and macros, etc,
+# in ./support/ and its subdirectories.
+Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
+
+RSpec.configure do |config|
+ # == Mock Framework
+ #
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
+ #
+ # config.mock_with :mocha
+ # config.mock_with :flexmock
+ # config.mock_with :rr
+ config.mock_with :rspec
+
+ config.fixture_path = "#{::Rails.root}/spec/fixtures"
+
+ #config.include Devise::TestHelpers, :type => :controller
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
+ # examples within a transaction, comment the following line or assign false
+ # instead of true.
+ config.use_transactional_fixtures = true
+end
+
+@configuration ||= AppConfiguration.find_or_create_by_name("Default configuration")
View
21 spree_on_demand_variants.gemspec
@@ -0,0 +1,21 @@
+Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = 'spree_on_demand_variants'
+ s.version = '1.0.0'
+ s.summary = 'Add gem summary here'
+ #s.description = 'Add (optional) gem description here'
+ s.required_ruby_version = '>= 1.8.7'
+
+ # s.author = 'David Heinemeier Hansson'
+ # s.email = 'david@loudthinking.com'
+ # s.homepage = 'http://www.rubyonrails.org'
+ # s.rubyforge_project = 'actionmailer'
+
+ s.files = Dir['CHANGELOG', 'README.md', 'LICENSE', 'lib/**/*', 'app/**/*']
+ s.require_path = 'lib'
+ s.requirements << 'none'
+
+ s.has_rdoc = true
+
+ s.add_dependency('spree_core', '>= 0.40.2')
+end

0 comments on commit 54ef9d6

Please sign in to comment.
Something went wrong with that request. Please try again.