Permalink
Browse files

Initial commit

  • Loading branch information...
0 parents commit 7a6d85258735c0035d675364fc9000cdd7355e0e @romul committed Oct 30, 2009
@@ -0,0 +1,3 @@
+= Product Assembly
+
+Description goes here
@@ -0,0 +1,41 @@
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+
+desc 'Default: run unit tests.'
+task :default => :test
+
+desc 'Test the product_assembly extension.'
+Rake::TestTask.new(:test) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/**/*_test.rb'
+ t.verbose = true
+end
+
+namespace :test do
+ desc 'Functional test the product_assembly extension.'
+ Rake::TestTask.new(:functionals) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/functional/*_test.rb'
+ t.verbose = true
+ end
+
+ desc 'Unit test the product_assembly extension.'
+ Rake::TestTask.new(:units) do |t|
+ t.libs << 'lib'
+ t.pattern = 'test/unit/*_test.rb'
+ t.verbose = true
+ end
+end
+
+desc 'Generate documentation for the product_assembly extension.'
+Rake::RDocTask.new(:rdoc) do |rdoc|
+ rdoc.rdoc_dir = 'rdoc'
+ rdoc.title = 'ProductAssemblyExtension'
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.rdoc_files.include('README.markdown')
+ rdoc.rdoc_files.include('lib/**/*.rb')
+end
+
+# Load any custom rakefiles for extension
+Dir[File.dirname(__FILE__) + '/lib/tasks/*.rake'].sort.each { |f| require f }
@@ -0,0 +1,47 @@
+class Admin::PartsController < Admin::BaseController
+ helper :products
+ before_filter :find_product
+
+ def index
+ @parts = @product.parts
+ end
+
+ def remove
+ @part = Variant.find(params[:id])
+ @product.remove_part(@part)
+ render :update do |page|
+ page.replace_html :product_parts, :partial => "parts_table",
+ :locals => {:parts => @product.parts}
+ end
+ end
+
+ def available
+ if params[:q].blank?
+ @available_products = []
+ else
+ @available_products = Product.find(:all,
+ :conditions => ['lower(name) LIKE ? AND can_be_part = ?', "%#{params[:q].downcase}%", true])
+ end
+ respond_to do |format|
+ format.html
+ format.js {render :layout => false}
+ end
+ end
+
+ def create
+ @part = Variant.find(params[:part_id])
+ qty = params[:part_count].to_i
+ @product.add_part(@part, qty) if qty > 0
+ render :update do |page|
+ page.replace_html :product_parts, :partial => "parts_table",
+ :locals => {:parts => @product.parts}
+ page.hide :search_hits
+ end
+ end
+
+ private
+ def find_product
+ @product = Product.find_by_permalink(params[:product_id])
+ @product_admin_tabs << { :name => "Parts", :url => "admin_product_parts_url" }
+ end
+end
@@ -0,0 +1,2 @@
+module Admin::PartsHelper
+end
@@ -0,0 +1,5 @@
+class AssembliesPart < ActiveRecord::Base
+ set_primary_keys :assembly_id, :part_id
+ belongs_to :assembly, :class_name => "Product", :foreign_key => "assembly_id"
+ belongs_to :part, :class_name => "Variant", :foreign_key => "part_id"
+end
@@ -0,0 +1,32 @@
+<table class="index">
+ <thead>
+ <tr>
+ <th><%= t("sku") %></th>
+ <th><%= t("name") %></th>
+ <th><%= t("options") %></th>
+ <th><%= t("qty") %></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% parts.each do |part| %>
+ <tr id="<%= dom_id(part, :sel)%>">
+ <td><%= part.sku %></td>
+ <td><%= part.product.name %></td>
+ <td><%= variant_options part %></td>
+ <td><%= @product.count_of part %></td>
+ <td class="actions">
+ <%= image_tag "spinner.gif", :style => "display:none", :id => "#{dom_id(part, :rem_spinner)}" %>
+ <%= link_to_remote icon('delete') + ' ' + t('remove'),
+ {:url => remove_admin_product_part_url(@product, part),
+ :loading => "jQuery('##{dom_id(part, :rem_spinner)}').show()",
+ :complete => "jQuery('##{dom_id(part, :rem_spinner)}').hide();"},
+ :class => 'iconlink' %>
+ </td>
+ </tr>
+ <% end %>
+ <% if parts.empty? %>
+ <tr><td colspan="3"><%= t('none') %>.</td></tr>
+ <% end %>
+ </tbody>
+</table>
@@ -0,0 +1,51 @@
+<script type="text/javascript">
+ function displayRow(){
+ var row = document.getElementById("captionRow");
+ if (row.style.display == '') row.style.display = 'none';
+ else row.style.display = '';
+ }
+</script>
+<h4><%= t('available_parts') %></h4>
+<% # admin_product_parts_path(@product)
+%>
+<table class="index">
+ <thead>
+ <tr>
+ <th><%= t("name") %></th>
+ <th><%= t("options") %></th>
+ <th><%= t("qty") %></th>
+ <th></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @available_products.each do |product| %>
+ <tr id="<%= dom_id(product) %>">
+
+ <td><%= product.name %></td>
+ <td>
+ <% if product.has_variants? %>
+ <%= select_tag "part[id]",
+ options_for_select(product.variants.map { |v| [variant_options(v), v.id] }) %>
+ <% else %>
+ <%= hidden_field_tag "part[id]", product.master.id %>
+ <%= t :no_variants %>
+ <% end %>
+ </td>
+ <td><%= text_field_tag "part[count]", 1 %></td>
+ <td class="actions">
+ <%= image_tag "spinner.gif", :style => "display:none", :id => "#{dom_id(product, :spinner)}" %>
+ <%= link_to_remote icon('add') + ' ' + t('select'),
+ {:url => admin_product_parts_path(@product),
+ :loading => "jQuery('##{dom_id(product, :spinner)}').show()",
+ :complete => "jQuery('##{dom_id(product, :spinner)}').hide();",
+ :with => "'part_count=' + $('#part_count', $(this).parent().parent()).val() + '&part_id=' + ($('#part_id option:selected', $(this).parent().parent()).val() || $('#part_id', $(this).parent().parent()).val()) "
+ },
+ :class => 'iconlink' %>
+ </td>
+ </tr>
+ <% end %>
+ <% if @available_products.empty? %>
+ <tr><td colspan="3"><%= t('no_match_found') %>.</td></tr>
+ <% end %>
+ </tbody>
+</table>
@@ -0,0 +1,42 @@
+<%= render :partial => 'admin/shared/product_sub_menu' %>
+
+<%= render :partial => 'admin/shared/product_tabs', :locals => {:current => "Parts"} %>
+<div id="product_parts">
+ <%= render :partial => "parts_table", :locals => {:parts => @parts} %>
+</div>
+
+
+<% form_tag('#') do %>
+ <label><%= t('search') %>:</label>
+ <input id="searchtext" size="25">
+<% end %>
+
+<% javascript_tag do %>
+ function search_for_parts(){
+ jQuery.ajax({
+ data: {q: jQuery("#searchtext").val() },
+ success: function(request){
+ jQuery('#search_hits').html(request);
+ },
+ type: 'post',
+ url: '<%= available_admin_product_parts_url(@product) %>'
+ });
+ }
+
+ jQuery("#searchtext").keypress(function (e) {
+ if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
+ search_for_parts();
+
+ return false;
+ } else {
+ return true;
+ }
+ });
+
+ jQuery("#searchtext").delayedObserver(0.75, function(element, value) {
+ search_for_parts();
+ })
+<% end %>
+<br/>
+<div id="search_hits"></div>
+
@@ -0,0 +1,95 @@
+<div class="yui-gc">
+ <div class="yui-u first">
+
+ <% f.field_container :name do %>
+ <%= f.label :name, t("name") %> <span class="required">*</span><br />
+ <%= f.text_field :name, :class => 'fullwidth title' %>
+ <%= f.error_message_on :name %>
+ <% end %>
+
+ <% f.field_container :description do %>
+ <%= f.label :description, t("description")%><br />
+ <%= f.text_area :description, {:cols => 60, :rows => 4, :class => 'fullwidth'} %>
+ <%= f.error_message_on :description %>
+ <% end %>
+
+ </div>
+ <div class="yui-u">
+
+ <% f.field_container :price do %>
+ <%= f.label :price, t("master_price")%> <span class="required">*</span><br />
+ <%= f.text_field :price %>
+ <%= f.error_message_on :price %>
+ <% end %>
+
+ <p>
+ <%= f.label :available_on, t("available_on") %><br />
+ <%= f.error_message_on :available_on %>
+ <%= f.unobtrusive_date_picker :available_on %>
+ </p>
+
+ <p>
+ <%= f.label :sku, t("sku") %><br />
+ <%= f.text_field :sku, :size => 16 %>
+ </p>
+ <% unless @product.has_variants? %>
+ <p>
+ <%= f.label :on_hand, t("on_hand")%><br />
+ <%= f.text_field :on_hand, :size => 4 %>
+ </p>
+ <ul id="shipping-specs">
+ <li>
+ <%= f.label :weight, t("weight")%>
+ <%= f.text_field :weight, :size => 4 %>
+ </li>
+ <li>
+ <%= f.label :height, t("height")%>
+ <%= f.text_field :height, :size => 4 %>
+ </li>
+ <li>
+ <%= f.label :width, t("width")%>
+ <%= f.text_field :width, :size => 4 %>
+ </li>
+ <li>
+ <%= f.label :depth, t("depth")%>
+ <%= f.text_field :depth, :size => 4 %>
+ </li>
+ </ul>
+ <% end %>
+ <p>
+ <%= f.label :shipping_category_id, t("shipping_categories")%><br />
+ <%= f.collection_select(:shipping_category_id, @shipping_categories, :id, :name, {:include_blank => true}, {"style" => "width:200px"}) %>
+ <%= f.error_message_on :shipping_category %>
+ </p>
+
+ <p>
+ <%= f.label :tax_category_id, t("tax_category")%><br />
+ <%= f.collection_select(:tax_category_id, @tax_categories, :id, :name, {:include_blank => true}, {"style" => "width:200px"}) %>
+ <%= f.error_message_on :tax_category%>
+ </p>
+ <p>
+ <%= f.label :can_be_part, t("can_be_part")%><br />
+ <%= f.check_box(:can_be_part) %>
+ </p>
+ <p>
+ <%= f.label :individual_sale, t("individual_sale")%><br />
+ <%= f.check_box(:individual_sale) %>
+ </p>
+ </div>
+</div>
+
+<h2><%= t("metadata") %></h2>
+<p>
+ <%= f.label :meta_keywords, t("meta_keywords")%><br />
+ <%= f.text_field :meta_keywords, :class => 'fullwidth' %>
+</p>
+<p>
+ <%= f.label :meta_description, t("meta_description")%><br />
+ <%= f.text_field :meta_description, :class => 'fullwidth' %>
+</p>
+
+<%#= render 'properties_form', :f => f %>
+
+<% Variant.additional_fields.select{|af| af[:only].nil? || af[:only].include?(:product) }.each do |field| %>
+ <%= render :partial => "admin/shared/additional_field", :locals => {:field => field, :f => f} %>
+<% end %>
@@ -0,0 +1,10 @@
+# Put your extension routes here.
+
+map.namespace :admin do |admin|
+ admin.resources :products, :member => {:clone => :get}, :has_many => [:product_properties, :images] do |product|
+ product.resources :variants
+ product.resources :option_types, :member => { :select => :get, :remove => :get}, :collection => {:available => :get, :selected => :get}
+ product.resources :taxons, :member => {:select => :post, :remove => :post}, :collection => {:available => :post, :selected => :get}
+ product.resources :parts, :member => {:select => :post, :remove => :post}, :collection => {:available => :post, :selected => :get}
+ end
+end
@@ -0,0 +1,13 @@
+class AddManyToManyRelationToProducts < ActiveRecord::Migration
+ def self.up
+ create_table :assemblies_parts, :id => false do |t|
+ t.integer "assembly_id", :null => false
+ t.integer "part_id", :null => false
+ t.integer "count", :null => false, :default => 1
+ end
+ end
+
+ def self.down
+ drop_table :assemblies_parts
+ end
+end
@@ -0,0 +1,15 @@
+class AddPartsFieldsToProducts < ActiveRecord::Migration
+ def self.up
+ change_table(:products) do |t|
+ t.column :can_be_part, :boolean, :default => false, :null => false
+ t.column :individual_sale, :boolean, :default => true, :null => false
+ end
+ end
+
+ def self.down
+ change_table(:products) do |t|
+ t.remove :can_be_part
+ t.remove :individual_sale
+ end
+ end
+end
@@ -0,0 +1,2 @@
+# Use this file to load your own seed data from extensions.
+# See the db/seeds.rb file in the Spree core for some ideas on what you can do here.
Oops, something went wrong.

0 comments on commit 7a6d852

Please sign in to comment.