diff --git a/Gemfile b/Gemfile index e201ef2107..aa468612b3 100644 --- a/Gemfile +++ b/Gemfile @@ -19,9 +19,8 @@ gem 'activerecord-postgresql-adapter' gem 'pg', '~> 0.21.0' # OFN-maintained and patched version of Spree v2.0.4. See -# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Spree-2.0-upgrade +# https://github.com/openfoodfoundation/openfoodnetwork/wiki/Tech-Doc:-OFN's-Spree-fork%F0%9F%8D%B4 # for details. -gem 'spree_backend', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' gem 'spree_core', github: 'openfoodfoundation/spree', branch: '2-0-4-stable' gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable' @@ -120,6 +119,8 @@ gem 'foundation_rails_helper', github: 'willrjmarshall/foundation_rails_helper', gem 'jquery-migrate-rails' gem 'jquery-rails', '3.0.4' +gem 'jquery-ui-rails', '~> 4.0.0' +gem 'select2-rails', '~> 3.4.7' gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c' diff --git a/Gemfile.lock b/Gemfile.lock index b4d251d234..7a0d3c5f64 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -34,18 +34,6 @@ GIT revision: 8a8585a43cd04d1a50dc65227f337a91b18d66d5 branch: 2-0-4-stable specs: - spree_api (2.0.4) - rabl (= 0.8.4) - spree_core (= 2.0.4) - versioncake (= 1.0.0) - spree_backend (2.0.4) - deface (>= 0.9.0) - jquery-rails (~> 3.0.0) - jquery-ui-rails (~> 4.0.0) - rails (~> 3.2.8) - select2-rails (~> 3.4.7) - spree_api (= 2.0.4) - spree_core (= 2.0.4) spree_core (2.0.4) activemerchant (~> 1.34) acts_as_list (= 0.2.0) @@ -685,10 +673,6 @@ GEM rack unicorn uuidtools (2.1.5) - versioncake (1.0.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) warden (1.2.7) rack (>= 1.0) webdrivers (4.2.0) @@ -759,6 +743,7 @@ DEPENDENCIES immigrant jquery-migrate-rails jquery-rails (= 3.0.4) + jquery-ui-rails (~> 4.0.0) json_spec (~> 1.1.4) jwt (~> 2.2) kaminari (~> 0.14.1) @@ -792,12 +777,12 @@ DEPENDENCIES rubocop-rails sass (~> 3.3) sass-rails (~> 3.2.3) + select2-rails (~> 3.4.7) selenium-webdriver shoulda-matchers simple_form! simplecov spinjs-rails - spree_backend! spree_core! spree_i18n! spree_paypal_express! diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js index 76a286cc43..5525aa6828 100644 --- a/app/assets/javascripts/admin/all.js +++ b/app/assets/javascripts/admin/all.js @@ -16,6 +16,7 @@ //= require jquery.jstree/jquery.jstree //= require jquery.vAlign //= require jquery.horizontalNav +//= require jquery.adaptivemenu //= require angular //= require angular-resource //= require angular-animate @@ -28,11 +29,9 @@ // spree //= require spree -//= require admin/spree-select2 -//= require admin/spree_backend +//= require admin/spree/spree-select2 //= require modernizr //= require spin -//= require jquery.adaptivemenu //= require equalize //= require css_browser_selector_dev //= require responsive-tables diff --git a/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee b/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee index 76200d92ff..79d4ac4a4b 100644 --- a/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee +++ b/app/assets/javascripts/admin/orders/directives/customer_search_override.js.coffee @@ -3,6 +3,9 @@ angular.module("admin.orders").directive 'customerSearchOverride', -> scope: distributorId: '@' link: (scope, element, attr) -> + if $('#customer_autocomplete_template').length > 0 + customerTemplate = Handlebars.compile($('#customer_autocomplete_template').text()) + formatCustomerResult = (customer) -> customerTemplate customer: customer diff --git a/app/assets/javascripts/admin/spree/base.js.erb b/app/assets/javascripts/admin/spree/base.js.erb index b9ba57d9ff..1ddd4a8dd3 100644 --- a/app/assets/javascripts/admin/spree/base.js.erb +++ b/app/assets/javascripts/admin/spree/base.js.erb @@ -1,6 +1,6 @@ //= require_self //= require admin/handlebar_extensions -//= require admin/variant_autocomplete +//= require admin/spree/orders/variant_autocomplete /** This is a collection of javascript functions and whatnot @@ -21,12 +21,14 @@ jQuery(function($) { if (typeof $('.field.checkbox label').vAlign === 'function' ) $('.field.checkbox label').vAlign() - // if (typeof Spree !== 'undefined') { - // $('.main-menu-wrapper ul').AdaptiveMenu({ - // text: " " + Spree.translations.more + "", - // klass: "dropdown" - // }); - // } + // We activate AdaptiveMenu only if not on webdriver + // Re-adjusting the admin menu during tests causes tests to fail. + if (!navigator.webdriver && typeof Spree !== 'undefined') { + $('.main-menu-wrapper ul').AdaptiveMenu({ + text: " " + Spree.translations.more + "", + klass: "dropdown" + }); + } // Add some tips if (typeof $('.with-tip').powerTip === 'function' ) { @@ -174,6 +176,28 @@ $(document).ready(function() { $(target).prepend(new_table_row); }) + $('body').on('click', '.delete-resource', function() { + var el = $(this); + if (confirm(el.data("confirm"))) { + $.ajax({ + type: 'POST', + url: $(this).attr("href"), + data: { + _method: 'delete', + authenticity_token: AUTH_TOKEN + }, + dataType: 'html', + success: function(response) { + el.parents("tr").fadeOut('hide'); + }, + error: function(response, textStatus, errorThrown) { + show_flash_error(response.responseText); + } + }); + } + return false; + }); + // Fix sortable helper var fixHelper = function(e, ui) { ui.children().each(function() { diff --git a/app/assets/javascripts/admin/spree/calculator.js b/app/assets/javascripts/admin/spree/calculator.js new file mode 100644 index 0000000000..cb8ab4351d --- /dev/null +++ b/app/assets/javascripts/admin/spree/calculator.js @@ -0,0 +1,16 @@ +$(function() { + var calculator_select = $('select#calc_type') + var original_calc_type = calculator_select.attr('value'); + $('.calculator-settings-warning').hide(); + calculator_select.change(function() { + if (calculator_select.attr('value') == original_calc_type) { + $('div.calculator-settings').show(); + $('.calculator-settings-warning').hide(); + $('.calculator-settings').find('input,textarea').prop("disabled", false); + } else { + $('div.calculator-settings').hide(); + $('.calculator-settings-warning').show(); + $('.calculator-settings').find('input,texttarea').prop("disabled", true); + } + }); +}) diff --git a/app/assets/javascripts/admin/spree/image_settings.js.erb b/app/assets/javascripts/admin/spree/image_settings.js.erb new file mode 100644 index 0000000000..d8c0b2a635 --- /dev/null +++ b/app/assets/javascripts/admin/spree/image_settings.js.erb @@ -0,0 +1,59 @@ +$(document).ready(function() { + + if ($('input#preferences_use_s3[type="checkbox"]:checked').length > 0) { + $('#s3_settings, #s3_headers').show(); + } + + // Toggle display of S3 settings based on value of use_s3 checkbox + $('input#preferences_use_s3[type="checkbox"]').click(function() { + $('#s3_settings, #s3_headers').toggle(); + }); + + $(document).on('click', '.destroy_style', function(e) { + e.preventDefault(); + $(this).parent().remove(); + }); + + $(document).on('click', '.destroy_new_attachment_styles', function(e) { + e.preventDefault(); + $(this).closest('.new_attachment_styles').remove(); + }); + + $(document).on('click', '.destroy_new_s3_headers', function(e) { + e.preventDefault(); + $(this).closest('.new_s3_headers').remove(); + }); + + // Handle adding new styles + var styles_hash_index = 1; + $(document).on('click', '.add_new_style', function(e) { + e.preventDefault(); + $('#new-styles').append(generate_html_for_hash("new_attachment_styles", styles_hash_index)); + }); + + // Handle adding new headers + var headers_hash_index = 1; + $(document).on('click', '.add_header', function(e) { + e.preventDefault(); + $('#headers_list').append(generate_html_for_hash("new_s3_headers", headers_hash_index)); + }); + + // Generates html for new paperclip styles form fields + generate_html_for_hash = function(hash_name, index) { + var html = '
'; + html += '
'; + html += ''; + html += '
'; + html += '
' + html += ''; + html += ''; + html += '
' + html += '   ' + Spree.translations.destroy + ''; + html += '
'; + + index += 1; + return html; + }; +}); diff --git a/app/assets/javascripts/admin/spree/nested-attribute.js b/app/assets/javascripts/admin/spree/nested-attribute.js new file mode 100644 index 0000000000..0282992ac9 --- /dev/null +++ b/app/assets/javascripts/admin/spree/nested-attribute.js @@ -0,0 +1,23 @@ +//On page load +replace_ids = function(s){ + var new_id = new Date().getTime(); + return s.replace(/NEW_RECORD/g, new_id); +} + +$(function() { + $('a[id*=nested]').click(function() { + var template = $(this).attr('href').replace(/.*#/, ''); + html = replace_ids(eval(template)); + $('#ul-' + $(this).attr('id')).append(html); + update_remove_links(); + }); + update_remove_links(); +}) + +var update_remove_links = function() { + $('.remove').click(function() { + $(this).prevAll(':first').val(1); + $(this).parent().hide(); + return false; + }); +}; diff --git a/app/assets/javascripts/admin/spree/orders/shipments.js.erb b/app/assets/javascripts/admin/spree/orders/shipments.js.erb index e86dedead0..cf3d4d6803 100644 --- a/app/assets/javascripts/admin/spree/orders/shipments.js.erb +++ b/app/assets/javascripts/admin/spree/orders/shipments.js.erb @@ -15,11 +15,11 @@ $(document).ready(function() { console.log(msg); }); } - // $('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click); + $('[data-hook=admin_order_edit_form] a.ship').click(handle_ship_click); //handle shipping method edit click - // $('a.edit-method').click(toggleMethodEdit); - // $('a.cancel-method').click(toggleMethodEdit); + $('a.edit-method').click(toggleMethodEdit); + $('a.cancel-method').click(toggleMethodEdit); handle_shipping_method_save = function(){ var link = $(this); @@ -38,11 +38,11 @@ $(document).ready(function() { console.log(msg); }); } - // $('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save); + $('[data-hook=admin_order_edit_form] a.save-method').click(handle_shipping_method_save); //handle tracking edit click - // $('a.edit-tracking').click(toggleTrackingEdit); - // $('a.cancel-tracking').click(toggleTrackingEdit); + $('a.edit-tracking').click(toggleTrackingEdit); + $('a.cancel-tracking').click(toggleTrackingEdit); handle_tracking_save = function(){ var link = $(this); diff --git a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb index c30053facb..c7237e6553 100644 --- a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb +++ b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb @@ -29,10 +29,10 @@ $(document).ready(function() { }); //handle edit click - // $('a.edit-item').click(toggleItemEdit); + $('a.edit-item').click(toggleItemEdit); //handle cancel click - // $('a.cancel-item').click(toggleItemEdit); + $('a.cancel-item').click(toggleItemEdit); handle_save_click = function(){ var save = $(this); @@ -46,7 +46,7 @@ $(document).ready(function() { adjustItems(shipment_number, variant_id, quantity); return false; } - // $('a.save-item').click(handle_save_click); + $('a.save-item').click(handle_save_click); handle_delete_click = function(){ var del = $(this); @@ -57,7 +57,7 @@ $(document).ready(function() { adjustItems(shipment_number, variant_id, 0); } - // $('a.delete-item').click(handle_delete_click); + $('a.delete-item').click(handle_delete_click); } }); @@ -139,39 +139,3 @@ addVariantFromStockLocation = function() { } return 1 } - -formatVariantResult = function(variant) { - if (variant["images"][0] != undefined && variant["images"][0].urls != undefined) { - variant.image = variant.images[0].urls.mini - } - return variantTemplate({ variant: variant }) -} - -$.fn.variantAutocomplete = function() { - this.parent().children(".options_placeholder").attr('id', this.parent().data('index')) - this.select2({ - placeholder: Spree.translations.variant_placeholder, - minimumInputLength: 3, - ajax: { - url: Spree.url(Spree.routes.variants_search), - datatype: 'json', - data: function(term, page) { - return { - q: { - "product_name_or_sku_cont": term - } - } - }, - results: function (data, page) { - window.variants = data['variants']; - - return { results: data['variants'] } - } - }, - formatResult: formatVariantResult, - formatSelection: function (variant) { - $(this.element).parent().children('.options_placeholder').html(variant.options_text) - return variant.name; - } - }) -} diff --git a/app/assets/javascripts/admin/spree/states.js b/app/assets/javascripts/admin/spree/states.js new file mode 100755 index 0000000000..fccec35a9b --- /dev/null +++ b/app/assets/javascripts/admin/spree/states.js @@ -0,0 +1,8 @@ +$(document).ready(function() { + $("#country").change(function() { + var new_state_link_href = $('#new_state_link a').attr('href'); + var selected_country_id = $('#country option:selected').attr('value'); + var new_link = new_state_link_href.replace(/countries\/(\d+)/, 'countries/'+selected_country_id); + $('#new_state_link a').attr('href', new_link); + }); +}); diff --git a/app/assets/javascripts/admin/spree/zone.js.coffee b/app/assets/javascripts/admin/spree/zone.js.coffee new file mode 100644 index 0000000000..885521190d --- /dev/null +++ b/app/assets/javascripts/admin/spree/zone.js.coffee @@ -0,0 +1,43 @@ +$ -> + ($ '#country_based').click -> + show_country() + + ($ '#state_based').click -> + show_state() + + if ($ '#country_based').is(':checked') + show_country() + else if ($ '#state_based').is(':checked') + show_state() + else + show_state() + ($ '#state_based').click() + + +show_country = -> + ($ '#state_members :input').each -> + ($ this).prop 'disabled', true + + ($ '#state_members').hide() + ($ '#zone_members :input').each -> + ($ this).prop 'disabled', true + + ($ '#zone_members').hide() + ($ '#country_members :input').each -> + ($ this).prop 'disabled', false + + ($ '#country_members').show() + +show_state = -> + ($ '#country_members :input').each -> + ($ this).prop 'disabled', true + + ($ '#country_members').hide() + ($ '#zone_members :input').each -> + ($ this).prop 'disabled', true + + ($ '#zone_members').hide() + ($ '#state_members :input').each -> + ($ this).prop 'disabled', false + + ($ '#state_members').show() \ No newline at end of file diff --git a/app/assets/javascripts/admin/spree_backend.js b/app/assets/javascripts/admin/spree_backend.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/assets/javascripts/admin/utils/directives/variant_autocomplete.js.coffee b/app/assets/javascripts/admin/utils/directives/variant_autocomplete.js.coffee index dd8c9247eb..2b5fca20a6 100644 --- a/app/assets/javascripts/admin/utils/directives/variant_autocomplete.js.coffee +++ b/app/assets/javascripts/admin/utils/directives/variant_autocomplete.js.coffee @@ -1,10 +1,6 @@ angular.module("admin.utils").directive "variantAutocomplete", ($timeout) -> restrict: 'C' link: (scope, element, attrs) -> - # Make variantAutocomplete do nothing because it is called - # from core/app/assets/javascripts/admin/orders/edit.js - $.fn.variantAutocomplete = angular.noop - $timeout -> if $("#variant_autocomplete_template").length > 0 variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text()) diff --git a/app/assets/stylesheets/admin/all.scss b/app/assets/stylesheets/admin/all.scss index cd8063d43f..6d5992f8d4 100644 --- a/app/assets/stylesheets/admin/all.scss +++ b/app/assets/stylesheets/admin/all.scss @@ -4,15 +4,15 @@ * the top of the compiled file, but it's generally better to create a new file per style scope. * - *= require admin/spree_backend - *= require jquery.powertip - *= require responsive-tables *= require normalize *= require skeleton + *= require responsive-tables + *= require jquery.powertip *= require jquery.ui.datepicker *= require jquery-ui-timepicker-addon *= require shared/textAngular *= require shared/ng-tags-input.min + *= require select2 *= require_self */ @@ -33,6 +33,11 @@ @import 'plugins/powertip'; @import 'plugins/jstree'; @import 'plugins/font-awesome'; +@import 'plugins/select2'; + +@import 'sections/image_settings'; +@import 'sections/orders'; +@import 'sections/products'; @import 'hacks/mozilla'; @import 'hacks/opera'; diff --git a/app/assets/stylesheets/admin/sections/image_settings.scss b/app/assets/stylesheets/admin/sections/image_settings.scss new file mode 100644 index 0000000000..dc7a29b1b2 --- /dev/null +++ b/app/assets/stylesheets/admin/sections/image_settings.scss @@ -0,0 +1,3 @@ +.destroy_style, .destroy_header { + float: right; +} diff --git a/app/controllers/spree/admin/base_controller.rb b/app/controllers/spree/admin/base_controller.rb index 80c50a55f2..1f5fbcfc1e 100644 --- a/app/controllers/spree/admin/base_controller.rb +++ b/app/controllers/spree/admin/base_controller.rb @@ -86,10 +86,6 @@ module Spree raise(ActionController::InvalidAuthenticityToken) end - def config_locale - Spree::Backend::Config[:locale] - end - private def html_request? diff --git a/app/helpers/spree/admin/navigation_helper.rb b/app/helpers/spree/admin/navigation_helper.rb index 3a5495488a..7dc9619a08 100644 --- a/app/helpers/spree/admin/navigation_helper.rb +++ b/app/helpers/spree/admin/navigation_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: false + module Spree module Admin module NavigationHelper @@ -34,7 +36,9 @@ module Spree end selected = if options[:match_path] - request.fullpath.starts_with?("#{spree.root_path}admin#{options[:match_path]}") + request. + fullpath. + starts_with?("#{main_app.root_path}admin#{options[:match_path]}") else args.include?(controller.controller_name.to_sym) end diff --git a/app/services/permissions/order.rb b/app/services/permissions/order.rb index 4dcc1f6ffd..5e95ba92c8 100644 --- a/app/services/permissions/order.rb +++ b/app/services/permissions/order.rb @@ -1,3 +1,5 @@ +require 'open_food_network/permissions' + module Permissions class Order def initialize(user) diff --git a/app/views/spree/admin/images/new.html.haml b/app/views/spree/admin/images/new.html.haml index 22a1e01998..4026cef6fb 100644 --- a/app/views/spree/admin/images/new.html.haml +++ b/app/views/spree/admin/images/new.html.haml @@ -7,4 +7,4 @@ %span.or= t('spree.or') = link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button' -= javascript_include_tag 'admin/images/new.js' += javascript_include_tag 'admin/spree/images/new.js' diff --git a/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb b/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb new file mode 100644 index 0000000000..9484fa0dbb --- /dev/null +++ b/app/views/spree/admin/orders/customer_details/_autocomplete.js.erb @@ -0,0 +1,19 @@ + diff --git a/app/views/spree/admin/shared/_head.html.haml b/app/views/spree/admin/shared/_head.html.haml index 7c47905b0d..375830063b 100644 --- a/app/views/spree/admin/shared/_head.html.haml +++ b/app/views/spree/admin/shared/_head.html.haml @@ -18,7 +18,6 @@ = render "spree/admin/shared/routes" %script - = "jQuery.alerts.dialogClass = 'spree';" = raw "var AUTH_TOKEN = \"#{form_authenticity_token}\";" = render "layouts/bugherd_script" diff --git a/config/initializers/form_builder.rb b/config/initializers/form_builder.rb new file mode 100644 index 0000000000..71b6038dd7 --- /dev/null +++ b/config/initializers/form_builder.rb @@ -0,0 +1,15 @@ +# +# Allow some application_helper methods to be used in the scoped form_for manner +# +class ActionView::Helpers::FormBuilder + def field_container(method, options = {}, &block) + @template.field_container(@object_name,method,options,&block) + end + + def error_message_on(method, options = {}) + @template.error_message_on(@object_name, method, objectify_options(options)) + end +end + +ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}".html_safe } + diff --git a/config/routes/spree.rb b/config/routes/spree.rb index 4e9c6aca44..095350b699 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -83,6 +83,8 @@ Spree::Core::Engine.routes.draw do get '/variants/search', :to => "variants#search", :as => :search_variants + resources :properties + resources :orders do member do put :fire @@ -110,8 +112,16 @@ Spree::Core::Engine.routes.draw do end resource :customer, :controller => "orders/customer_details" + + resources :return_authorizations do + member do + put :fire + end + end end + resources :reports + resources :users do member do put :generate_api_key @@ -126,6 +136,7 @@ Spree::Core::Engine.routes.draw do end resource :image_settings + resources :trackers resources :zones resources :countries do @@ -152,6 +163,10 @@ Spree::Core::Engine.routes.draw do resources :tax_rates resource :tax_settings resources :tax_categories + + resources :shipping_methods + resources :shipping_categories + resources :payment_methods end resources :orders do diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb index 26c0af02ba..54c99ba8ea 100644 --- a/spec/features/admin/products_spec.rb +++ b/spec/features/admin/products_spec.rb @@ -203,6 +203,16 @@ feature ' expect(p.reload.property('fooprop')).to be_nil end + scenario "loading new image page", js: true do + product = create(:simple_product, supplier: @supplier2) + + visit spree.admin_product_images_path(product) + expect(page).to have_selector ".no-objects-found" + + page.find('a#new_image_link').click + expect(page).to have_selector "#image_attachment" + end + scenario "deleting product images", js: true do product = create(:simple_product, supplier: @supplier2) image = File.open(File.expand_path('../../../app/assets/images/logo-white.png', __dir__))