solidus_product_assembly 1.0.0

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 (82) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +18 -0
  6. data/LICENSE.md +13 -0
  7. data/README.md +80 -0
  8. data/Rakefile +21 -0
  9. data/app/assets/images/spinner.gif +0 -0
  10. data/app/assets/javascripts/spree/backend/solidus_product_assembly.js +1 -0
  11. data/app/assets/javascripts/spree/frontend/solidus_product_assembly.js +1 -0
  12. data/app/assets/stylesheets/spree/backend/solidus_product_assembly.css +3 -0
  13. data/app/assets/stylesheets/spree/frontend/solidus_product_assembly.css +3 -0
  14. data/app/controllers/spree/admin/parts_controller.rb +49 -0
  15. data/app/controllers/spree/checkout_controller_decorator.rb +9 -0
  16. data/app/helpers/spree/admin/orders_helper_decorator.rb +9 -0
  17. data/app/models/spree/assemblies_part.rb +12 -0
  18. data/app/models/spree/inventory_unit_decorator.rb +13 -0
  19. data/app/models/spree/line_item_decorator.rb +44 -0
  20. data/app/models/spree/order_inventory_assembly.rb +39 -0
  21. data/app/models/spree/product_decorator.rb +56 -0
  22. data/app/models/spree/shipment_decorator.rb +50 -0
  23. data/app/models/spree/stock/availability_validator.rb +28 -0
  24. data/app/models/spree/stock/inventory_unit_builder_decorator.rb +30 -0
  25. data/app/models/spree/stock/inventory_validator_decorator.rb +12 -0
  26. data/app/models/spree/variant_decorator.rb +13 -0
  27. data/app/overrides/add_admin_product_form_fields.rb +5 -0
  28. data/app/overrides/add_admin_tabs.rb +5 -0
  29. data/app/overrides/add_line_item_description.rb +5 -0
  30. data/app/overrides/spree/admin/orders/_form/inject_product_assemblies.html.erb.deface +3 -0
  31. data/app/overrides/spree/admin/orders/_shipment/stock_contents.html.erb.deface +2 -0
  32. data/app/overrides/spree/checkout/_delivery/remove_unshippable_markup.html.erb.deface +1 -0
  33. data/app/overrides/spree/checkout/_delivery/render_line_item_manifest.html.erb.deface +3 -0
  34. data/app/overrides/spree/products/show/add_links_to_parts.html.erb.deface +21 -0
  35. data/app/overrides/spree/products/show/remove_add_to_cart_button_for_non_individual_sale_products.html.erb.deface +4 -0
  36. data/app/overrides/spree/shared/_order_details/part_description.html.erb.deface +8 -0
  37. data/app/views/spree/admin/orders/_assemblies.html.erb +56 -0
  38. data/app/views/spree/admin/orders/_stock_contents.html.erb +69 -0
  39. data/app/views/spree/admin/orders/_stock_item.html.erb +46 -0
  40. data/app/views/spree/admin/parts/_parts_table.html.erb +33 -0
  41. data/app/views/spree/admin/parts/available.html.erb +55 -0
  42. data/app/views/spree/admin/parts/available.js.erb +54 -0
  43. data/app/views/spree/admin/parts/index.html.erb +70 -0
  44. data/app/views/spree/admin/parts/update_parts_table.js.erb +2 -0
  45. data/app/views/spree/admin/products/_product_assembly_fields.html.erb +23 -0
  46. data/app/views/spree/admin/shared/_product_assembly_product_tabs.html.erb +3 -0
  47. data/app/views/spree/checkout/_line_item_manifest.html.erb +17 -0
  48. data/app/views/spree/orders/_cart_description.html.erb +8 -0
  49. data/bin/rails +7 -0
  50. data/config/locales/en.yml +14 -0
  51. data/config/locales/fr.yml +12 -0
  52. data/config/locales/ru.yml +12 -0
  53. data/config/locales/sv.yml +12 -0
  54. data/config/routes.rb +19 -0
  55. data/db/migrate/20091028152124_add_many_to_many_relation_to_products.rb +13 -0
  56. data/db/migrate/20091029165620_add_parts_fields_to_products.rb +27 -0
  57. data/db/migrate/20120316141830_namespace_product_assembly_for_spree_one.rb +9 -0
  58. data/db/migrate/20140620223938_add_id_to_spree_assemblies_parts.rb +9 -0
  59. data/lib/generators/solidus_product_assembly/install/install_generator.rb +24 -0
  60. data/lib/solidus_product_assembly.rb +3 -0
  61. data/lib/solidus_product_assembly/engine.rb +15 -0
  62. data/lib/solidus_product_assembly/version.rb +3 -0
  63. data/lib/tasks/spree2_upgrade.rake +29 -0
  64. data/solidus_product_assembly.gemspec +35 -0
  65. data/spec/features/admin/orders_spec.rb +29 -0
  66. data/spec/features/admin/parts_spec.rb +28 -0
  67. data/spec/features/checkout_spec.rb +92 -0
  68. data/spec/models/spree/assemblies_part_spec.rb +18 -0
  69. data/spec/models/spree/inventory_unit_spec.rb +32 -0
  70. data/spec/models/spree/line_item_spec.rb +72 -0
  71. data/spec/models/spree/order_contents_spec.rb +40 -0
  72. data/spec/models/spree/order_inventory_assembly_spec.rb +55 -0
  73. data/spec/models/spree/order_inventory_spec.rb +35 -0
  74. data/spec/models/spree/product_spec.rb +35 -0
  75. data/spec/models/spree/shipment_spec.rb +112 -0
  76. data/spec/models/spree/stock/availability_validator_spec.rb +71 -0
  77. data/spec/models/spree/stock/coordinator_spec.rb +52 -0
  78. data/spec/models/spree/stock/inventory_unit_builder_spec.rb +36 -0
  79. data/spec/models/spree/variant_spec.rb +28 -0
  80. data/spec/spec_helper.rb +57 -0
  81. data/spec/support/shared_contexts/order_with_bundle.rb +13 -0
  82. metadata +272 -0
@@ -0,0 +1,28 @@
1
+ module Spree
2
+ module Stock
3
+ # Overridden from spree core to make it also check for assembly parts stock
4
+ class AvailabilityValidator < ActiveModel::Validator
5
+ def validate(line_item)
6
+ line_item.quantity_by_variant.each do |variant, variant_quantity|
7
+ inventory_units = line_item.inventory_units.where(variant: variant).count
8
+ quantity = variant_quantity - inventory_units
9
+
10
+ next if quantity <= 0
11
+ next unless variant
12
+
13
+ quantifier = Stock::Quantifier.new(variant)
14
+
15
+ unless quantifier.can_supply? quantity
16
+ display_name = %Q{#{variant.name}}
17
+ display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank?
18
+
19
+ line_item.errors[:quantity] << Spree.t(
20
+ :selected_quantity_not_available,
21
+ item: display_name.inspect
22
+ )
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ module Spree
2
+ module Stock
3
+ InventoryUnitBuilder.class_eval do
4
+ def units
5
+ @order.line_items.flat_map do |line_item|
6
+ line_item.quantity_by_variant.flat_map do |variant, quantity|
7
+ quantity.times.map { build_inventory_unit(variant, line_item) }
8
+ end
9
+ end
10
+ end
11
+
12
+ def build_inventory_unit(variant, line_item)
13
+ @order.inventory_units.includes(
14
+ variant: {
15
+ product: {
16
+ shipping_category: {
17
+ shipping_methods: [:calculator, { zones: :zone_members }]
18
+ }
19
+ }
20
+ }
21
+ ).build(
22
+ pending: true,
23
+ variant: variant,
24
+ line_item: line_item,
25
+ order: @order
26
+ )
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ Spree::Stock::InventoryValidator.class_eval do
2
+ def validate(line_item)
3
+ total_quantity = line_item.quantity_by_variant.values.sum
4
+
5
+ if line_item.inventory_units.count != total_quantity
6
+ line_item.errors[:inventory] << Spree.t(
7
+ :inventory_not_available,
8
+ item: line_item.variant.name
9
+ )
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ Spree::Variant.class_eval do
2
+ has_and_belongs_to_many :assemblies, :class_name => "Spree::Product",
3
+ :join_table => "spree_assemblies_parts",
4
+ :foreign_key => "part_id", :association_foreign_key => "assembly_id"
5
+
6
+ def assemblies_for(products)
7
+ assemblies.where(id: products)
8
+ end
9
+
10
+ def part?
11
+ assemblies.exists?
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => "spree/admin/products/_form",
2
+ :name => "product_assembly_admin_product_form_right",
3
+ :insert_after => "[data-hook='admin_product_form_right'], #admin_product_form_right[data-hook]",
4
+ :partial => "spree/admin/products/product_assembly_fields",
5
+ :disabled => false)
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => "spree/admin/shared/_product_tabs",
2
+ :name => "product_assembly_admin_product_tabs",
3
+ :insert_bottom => "[data-hook='admin_product_tabs']",
4
+ :partial => "spree/admin/shared/product_assembly_product_tabs",
5
+ :disabled => false)
@@ -0,0 +1,5 @@
1
+ Deface::Override.new(:virtual_path => "spree/orders/_line_item",
2
+ :name => "product_assembly_cart_item_description",
3
+ :insert_bottom => "[data-hook='cart_item_description']",
4
+ :partial => "spree/orders/cart_description",
5
+ :disabled => false)
@@ -0,0 +1,3 @@
1
+ <!-- insert_top 'div[data-hook=admin_order_form_fields]' -->
2
+
3
+ <%= render partial: 'spree/admin/orders/assemblies', locals: { order: order } %>
@@ -0,0 +1,2 @@
1
+ <!-- replace_contents '.stock-contents tbody' -->
2
+ <%= render 'stock_contents', shipment: shipment %>
@@ -0,0 +1,3 @@
1
+ <!-- replace_contents 'table[data-hook=stock-contents] tbody' -->
2
+
3
+ <%= render 'line_item_manifest', ship_form: ship_form %>
@@ -0,0 +1,21 @@
1
+ <!-- insert_after '#cart-form' -->
2
+ <% if @product.parts.any?(&:in_stock?) %>
3
+
4
+ <h6><%= Spree.t(:parts_included) %></h6>
5
+
6
+ <ul id="products" class="inline product-listing" data-hook>
7
+ <% @product.parts.each do |variant| %>
8
+ <% if variant.in_stock? %>
9
+ <li id="product_<%= variant.product.id %>" class="columns three <%= cycle("alpha", "secondary", "", "omega secondary") %>" data-hook="products_list_item" itemscope itemtype="http://schema.org/Product">
10
+ <div class="product-image">
11
+ <%= link_to small_image(variant.product, :itemprop => "name"), variant.product %>
12
+ </div>
13
+ <%= link_to truncate(variant.product.name, :length => 50), variant.product, :class => 'info', :itemprop => "name", :title => variant.product.name %>
14
+ <% if variant.product.individual_sale? %>
15
+ <span class="price selling" itemprop="price"><%= number_to_currency variant.price %></span>
16
+ <% end %>
17
+ </li>
18
+ <% end %>
19
+ <% end %>
20
+ </ul>
21
+ <% end %>
@@ -0,0 +1,4 @@
1
+ <!-- surround '[data-hook="cart_form"]' -->
2
+ <% if @product.individual_sale? %>
3
+ <%= render_original %>
4
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <!-- insert_bottom 'td[data-hook=order_item_description]' -->
2
+ <% if item.product.assembly? %>
3
+ <ul class='assembly_parts'>
4
+ <% item.parts.each do |v| %>
5
+ <li>(<%= item.count_of(v) %>) <%= link_to v.name, product_path(v.product) %> (<%= v.sku %>)</li>
6
+ <% end %>
7
+ </ul>
8
+ <% end %>
@@ -0,0 +1,56 @@
1
+ <% if order.line_items.assemblies.any? %>
2
+ <fieldset class="no-border-bottom">
3
+ <legend align="center" class="" data-hook="">
4
+ <%= Spree.t(:product_bundles) %>
5
+ </legend>
6
+ </fieldset>
7
+
8
+ <table class="product-bundles index" data-hook="line-items">
9
+ <colgroup>
10
+ <col style="width: 10%;" />
11
+ <col style="width: 20%;" />
12
+ <col style="width: 20%;" />
13
+ <col style="width: 15%;" />
14
+ </colgroup>
15
+
16
+ <thead>
17
+ <tr>
18
+ <th colspan="2"><%= Spree::Product.human_attribute_name(:name) %></th>
19
+ <th><%= Spree::LineItem.human_attribute_name(:price) %></th>
20
+ <th><%= Spree::LineItem.human_attribute_name(:quantity) %></th>
21
+ <th><%= Spree::LineItem.human_attribute_name(:total) %></th>
22
+ <th class="orders-actions actions" data-hook="admin_order_form_line_items_header_actions">&nbsp;</th>
23
+ </tr>
24
+ </thead>
25
+
26
+ <tbody>
27
+ <% order.line_items.assemblies.each do |item| %>
28
+ <%= content_tag :tr, class: 'line-item', id: "line-item-#{item.id}", data: { line_item_id: item.id } do %>
29
+ <td class="line-item-image"><%= image_tag item.variant.display_image.attachment(:mini) %></td>
30
+ <td class="line-item-name">
31
+ <%= item.variant.product.name %><br><%= "(" + variant_options(item.variant) + ")" unless item.variant.option_values.empty? %>
32
+ <% if item.variant.sku.present? %>
33
+ <strong><%= Spree::Variant.human_attribute_name(:sku) %>:</strong> <%= item.variant.sku %>
34
+ <% end %>
35
+ </td>
36
+ <td class="line-item-price align-center"><%= item.single_money.to_html %></td>
37
+ <td class="line-item-qty-show align-center">
38
+ <%= item.quantity %>
39
+ </td>
40
+ <td class="line-item-qty-edit">
41
+ <%= number_field_tag :quantity, item.quantity, :min => 0, :class => "line_item_quantity", :size => 5 %>
42
+ </td>
43
+ <td class="line-item-total align-center"><%= line_item_shipment_price(item, item.quantity) %></td>
44
+ <td class="cart-line-item-delete actions" data-hook="cart_line_item_delete">
45
+ <% if can? :update, item %>
46
+ <%= link_to '', '#', :class => 'save-line-item fa fa-ok no-text with-tip', :title => Spree.t('actions.save') %>
47
+ <%= link_to '', '#', :class => 'cancel-line-item fa fa-cancel no-text with-tip', :title => Spree.t('actions.cancel') %>
48
+ <%= link_to '', '#', :class => 'edit-line-item fa fa-edit no-text with-tip', :title => Spree.t('actions.edit') %>
49
+ <%= link_to '', '#', :class => 'delete-line-item fa fa-trash no-text with-tip', :title => Spree.t('actions.delete') %>
50
+ <% end %>
51
+ </td>
52
+ <% end %>
53
+ <% end %>
54
+ </tbody>
55
+ </table>
56
+ <% end %>
@@ -0,0 +1,69 @@
1
+ <%= render 'stock_item', shipment: shipment %>
2
+
3
+ <% unless shipment.shipped? %>
4
+ <tr class="edit-method hidden total">
5
+ <td colspan="5">
6
+ <div class="field alpha five columns">
7
+ <%= label_tag 'selected_shipping_rate_id', Spree.t(:shipping_method) %>
8
+ <%= select_tag :selected_shipping_rate_id,
9
+ options_for_select(shipment.shipping_rates.map {|sr| ["#{sr.name} #{sr.display_price}", sr.id] }, shipment.selected_shipping_rate_id),
10
+ {:class => 'select2 fullwidth', :data => {'shipment-number' => shipment.number } } %>
11
+ </div>
12
+ </td>
13
+ <td class="actions">
14
+ <% if can? :update, shipment %>
15
+ <%= link_to '', '#', :class => 'save-method fa fa-ok no-text with-tip',
16
+ :data => {'shipment-number' => shipment.number, :action => 'save'}, title: Spree.t('actions.save') %>
17
+ <%= link_to '', '#', :class => 'cancel-method fa fa-cancel no-text with-tip',
18
+ :data => {:action => 'cancel'}, :title => Spree.t('actions.cancel') %>
19
+ <% end %>
20
+ </td>
21
+ </tr>
22
+ <% end %>
23
+
24
+ <tr class="show-method total">
25
+ <% if shipment.shipping_method %>
26
+ <td colspan="4">
27
+ <strong><%= shipment.shipping_method.name %></strong>
28
+ </td>
29
+ <td class="total" align="center">
30
+ <span><%= shipment.display_cost %></span>
31
+ </td>
32
+ <% else %>
33
+ <td colspan='5'><%= Spree.t(:no_shipping_method_selected) %></td>
34
+ <% end %>
35
+
36
+ <td class="actions">
37
+ <% if can? :update, shipment %>
38
+ <%= link_to '', '#', :class => 'edit-method fa fa-edit no-text with-tip', :data => {:action => 'edit'}, :title => Spree.t('edit') %>
39
+ <% end %>
40
+ </td>
41
+ </tr>
42
+
43
+ <tr class="edit-tracking hidden total">
44
+ <td colspan="5">
45
+ <label><%= Spree.t(:tracking_number) %>:</label>
46
+ <%= text_field_tag :tracking, shipment.tracking %>
47
+ </td>
48
+ <td class="actions">
49
+ <% if can? :update, shipment %>
50
+ <%= link_to '', '#', :class => 'save-tracking fa fa-ok no-text with-tip', :data => {'shipment-number' => shipment.number, :action => 'save'}, :title => Spree.t('actions.save') %>
51
+ <%= link_to '', '#', :class => 'cancel-tracking fa fa-cancel no-text with-tip', :data => {:action => 'cancel'}, :title => Spree.t('actions.cancel') %>
52
+ <% end %>
53
+ </td>
54
+ </tr>
55
+
56
+ <tr class="show-tracking total">
57
+ <td colspan="5">
58
+ <% if shipment.tracking.present? %>
59
+ <strong><%= Spree.t(:tracking) %>:</strong> <%= shipment.tracking %>
60
+ <% else %>
61
+ <%= Spree.t(:no_tracking_present) %>
62
+ <% end %>
63
+ </td>
64
+ <td class="actions">
65
+ <% if can? :update, shipment %>
66
+ <%= link_to '', '#', :class => 'edit-tracking fa fa-edit no-text with-tip', :data => {:action => 'edit'}, :title => Spree.t('edit') %>
67
+ <% end %>
68
+ </td>
69
+ </tr>
@@ -0,0 +1,46 @@
1
+ <% shipment.manifest.each do |item| %>
2
+ <tr class="stock-item" data-item-quantity="<%= item.quantity %>">
3
+ <td class="item-image"><%= mini_image(item.variant) %></td>
4
+ <td class="item-name">
5
+ <%= item.variant.product.name %><br><%= "(" + variant_options(item.variant) + ")" unless item.variant.option_values.empty? %>
6
+ <% if item.part && item.line_item %>
7
+ <i><%= Spree.t(:part_of_bundle, sku: item.product.sku) %></i>
8
+ <% end %>
9
+ </td>
10
+ <td class="item-price align-center">
11
+ <% if item.part %>
12
+ ---
13
+ <% else %>
14
+ <%= item.line_item.single_money.to_html if item.line_item %>
15
+ <% end %>
16
+ </td>
17
+ <td class="item-qty-show align-center">
18
+ <% item.states.each do |state,count| %>
19
+ <%= count %> x <%= state.humanize.downcase %>
20
+ <% end %>
21
+ </td>
22
+ <% unless shipment.shipped? %>
23
+ <td class="item-qty-edit hidden">
24
+ <%= number_field_tag :quantity, item.quantity, :min => 0, :class => "line_item_quantity", :size => 5 %>
25
+ </td>
26
+ <% end %>
27
+ <td class="item-total align-center">
28
+ <% if item.part %>
29
+ ---
30
+ <% else %>
31
+ <%= line_item_shipment_price(item.line_item, item.quantity) if item.line_item %>
32
+ <% end %>
33
+ </td>
34
+ <td class="cart-item-delete actions" data-hook="cart_item_delete">
35
+ <% if !shipment.shipped? && !item.part %>
36
+ <% if can? :update, item %>
37
+ <%= link_to '', '#', :class => 'save-item fa fa-ok no-text with-tip', :data => {'shipment-number' => shipment.number, 'variant-id' => item.variant.id, :action => 'save'}, :title => Spree.t('actions.save'), :style => 'display: none' %>
38
+ <%= link_to '', '#', :class => 'cancel-item fa fa-cancel no-text with-tip', :data => {:action => 'cancel'}, :title => Spree.t('actions.cancel'), :style => 'display: none' %>
39
+ <%= link_to '', '#', :class => 'edit-item fa fa-edit no-text with-tip', :data => {:action => 'edit'}, :title => Spree.t('edit') %>
40
+ <%= link_to '', '#', :class => 'split-item fa fa-arrows-h no-text with-tip', :data => {:action => 'split', 'variant-id' => item.variant.id}, :title => Spree.t('split') %>
41
+ <%= link_to '', '#', :class => 'delete-item fa fa-trash no-text with-tip', :data => {'shipment-number' => shipment.number, 'variant-id' => item.variant.id, :action => 'remove'}, :title => Spree.t('actions.delete') %>
42
+ <% end %>
43
+ <% end %>
44
+ </td>
45
+ </tr>
46
+ <% end %>
@@ -0,0 +1,33 @@
1
+ <table class="index">
2
+ <thead>
3
+ <tr>
4
+ <th><%= Spree.t(:sku) %></th>
5
+ <th><%= Spree.t(:name) %></th>
6
+ <th><%= Spree.t(:options) %></th>
7
+ <th><%= Spree.t(:qty) %></th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ <% parts.each do |part| %>
12
+ <tr id="<%= dom_id(part, :sel)%>">
13
+ <td><%= part.sku %></td>
14
+ <td><%= part.product.name %></td>
15
+ <td><%= variant_options part %></td>
16
+ <td><%= text_field_tag :count, @product.count_of(part) %></td>
17
+ <td class="actions">
18
+ <%= link_to(icon('edit'),
19
+ set_count_admin_product_part_url(@product, part),
20
+ :class => "set_count_admin_product_part_link save-line-item fa fa-ok no-text") %>
21
+
22
+ <%= link_to(icon('delete'),
23
+ remove_admin_product_part_url(@product, part),
24
+ :class => "remove_admin_product_part_link delete-line-item fa fa-trash no-text") %>
25
+ </td>
26
+ </tr>
27
+ <% end %>
28
+ <% if parts.empty? %>
29
+ <tr><td colspan="5"><%= Spree.t(:none) %>.</td></tr>
30
+ <% end %>
31
+ </tbody>
32
+ </table>
33
+ <%= javascript_tag("subscribe_product_part_links();") if request.xhr? %>
@@ -0,0 +1,55 @@
1
+ <script type="text/javascript">
2
+ function displayRow(){
3
+ var row = document.getElementById("captionRow");
4
+ if (row.style.display == '') row.style.display = 'none';
5
+ else row.style.display = '';
6
+ }
7
+ </script>
8
+
9
+ <h4><%= Spree.t(:available_parts) %></h4>
10
+ <table class="index">
11
+ <thead>
12
+ <tr>
13
+ <th><%= Spree.t(:name) %></th>
14
+ <th><%= Spree.t(:options) %></th>
15
+ <th><%= Spree.t(:qty) %></th>
16
+ <th></th>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <% @available_products.each do |product| %>
21
+ <tr id="<%= dom_id(product) %>">
22
+
23
+ <td><%= product.name %></td>
24
+ <td>
25
+ <% if product.has_variants? %>
26
+ <%= select_tag "part[id]",
27
+ options_for_select(product.variants.map { |v| [variant_options(v), v.id] }) %>
28
+ <% else %>
29
+ <%= hidden_field_tag "part[id]", product.master.id %>
30
+ <%= Spree.t(:no_variants) %>
31
+ <% end %>
32
+ </td>
33
+ <td><%= text_field_tag "part[count]", 1 %></td>
34
+ <td class="actions">
35
+ <%= link_to(icon('add') + ' ' + Spree.t(:select),
36
+ admin_product_parts_path(@product),
37
+ :class => "add_product_part_link") %>
38
+ </td>
39
+ </tr>
40
+ <% end %>
41
+ <% if @available_products.empty? %>
42
+ <tr><td colspan="3"><%= Spree.t(:no_match_found) %>.</td></tr>
43
+ <% end %>
44
+ </tbody>
45
+ </table>
46
+
47
+ <%= javascript_tag do %>
48
+ $("a.add_product_part_link").click(function(){
49
+ part_id_val = $('select option:selected', $(this).parent().parent()).val() ||
50
+ $('input:first', $(this).parent().parent()).val();
51
+ params = { part_count : $('input:last', $(this).parent().parent()).val(),
52
+ part_id : part_id_val};
53
+ return make_post_request($(this), params);
54
+ });
55
+ <% end %>
@@ -0,0 +1,54 @@
1
+ <script type="text/javascript">
2
+ function displayRow(){
3
+ var row = document.getElementById("captionRow");
4
+ if (row.style.display == '') row.style.display = 'none';
5
+ else row.style.display = '';
6
+ }
7
+ </script>
8
+ <h4><%= Spree.t(:available_parts) %></h4>
9
+ <table class="index">
10
+ <thead>
11
+ <tr>
12
+ <th><%= Spree.t(:name) %></th>
13
+ <th><%= Spree.t(:options) %></th>
14
+ <th><%= Spree.t(:qty) %></th>
15
+ <th></th>
16
+ </tr>
17
+ </thead>
18
+ <tbody>
19
+ <% @available_products.each do |product| %>
20
+ <tr id="<%= dom_id(product) %>">
21
+
22
+ <td><%= product.name %></td>
23
+ <td>
24
+ <% if product.has_variants? %>
25
+ <%= select_tag "part[id]",
26
+ options_for_select(product.variants.map { |v| [variant_options(v), v.id] }) %>
27
+ <% else %>
28
+ <%= hidden_field_tag "part[id]", product.master.id %>
29
+ <%= Spree.t(:no_variants) %>
30
+ <% end %>
31
+ </td>
32
+ <td><%= text_field_tag "part[count]", 1 %></td>
33
+ <td class="actions">
34
+ <%= link_to(icon('add') + ' ' + Spree.t(:select),
35
+ admin_product_parts_path(@product),
36
+ :class => "add_product_part_link") %>
37
+ </td>
38
+ </tr>
39
+ <% end %>
40
+ <% if @available_products.empty? %>
41
+ <tr><td colspan="3"><%= Spree.t(:no_match_found) %>.</td></tr>
42
+ <% end %>
43
+ </tbody>
44
+ </table>
45
+
46
+ <%= javascript_tag do %>
47
+ $("a.add_product_part_link").click(function(){
48
+ part_id_val = $('select option:selected', $(this).parent().parent()).val() ||
49
+ $('input:first', $(this).parent().parent()).val();
50
+ params = { part_count : $('input:last', $(this).parent().parent()).val(),
51
+ part_id : part_id_val};
52
+ return make_post_request($(this), params);
53
+ });
54
+ <% end %>