From 4fa09639cb7337d2bc16f6ae263fc06c41a44625 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 6 Jun 2018 16:27:23 +1000 Subject: [PATCH 001/125] Rewrite user stat query for improved performance of homepage --- app/controllers/home_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 55b6b827e1..94dcd7d49c 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -7,7 +7,7 @@ class HomeController < BaseController if ContentConfig.home_show_stats @num_distributors = Enterprise.is_distributor.activated.visible.count @num_producers = Enterprise.is_primary_producer.activated.visible.count - @num_users = Spree::User.joins(:orders).merge(Spree::Order.complete).count('DISTINCT spree_users.*') + @num_users = Spree::Order.complete.count('DISTINCT user_id') @num_orders = Spree::Order.complete.count end end From f2e1caabff4e30fbb08c77684f9b54f0184be78e Mon Sep 17 00:00:00 2001 From: Frank West Date: Fri, 15 Jun 2018 08:27:26 -0700 Subject: [PATCH 002/125] Fix NoMethodError in order cycles index When a user's session has timed out and they try to load new data on the order cycles page by changing filters, the application throws a `NoMethodError` because we are prepending the load data method before checking the user's session. We can fix this by removing the prepend on this action. --- app/controllers/admin/order_cycles_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/admin/order_cycles_controller.rb b/app/controllers/admin/order_cycles_controller.rb index 445e268085..bb2e2da2a7 100644 --- a/app/controllers/admin/order_cycles_controller.rb +++ b/app/controllers/admin/order_cycles_controller.rb @@ -6,7 +6,7 @@ module Admin class OrderCyclesController < ResourceController include OrderCyclesHelper - prepend_before_filter :load_data_for_index, :only => :index + before_filter :load_data_for_index, only: :index before_filter :require_coordinator, only: :new before_filter :remove_protected_attrs, only: [:update] before_filter :check_editable_schedule_ids, only: [:create, :update] From b8f1571282c0aefab0ba3bd12ac9138538c921e1 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Fri, 15 Jun 2018 17:34:44 +0100 Subject: [PATCH 003/125] added directive to make links open in new tab by default in textangular text areas in enterprise description, enterprise group description and in shopfront open and closed messages --- .../directives/textangular_links_target_blank.js.coffee | 6 ++++++ app/views/admin/enterprise_groups/_form_about.html.haml | 2 +- app/views/admin/enterprises/form/_about_us.html.haml | 2 +- .../admin/enterprises/form/_shop_preferences.html.haml | 4 ++-- 4 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/admin/utils/directives/textangular_links_target_blank.js.coffee diff --git a/app/assets/javascripts/admin/utils/directives/textangular_links_target_blank.js.coffee b/app/assets/javascripts/admin/utils/directives/textangular_links_target_blank.js.coffee new file mode 100644 index 0000000000..0c8237ef5c --- /dev/null +++ b/app/assets/javascripts/admin/utils/directives/textangular_links_target_blank.js.coffee @@ -0,0 +1,6 @@ +angular.module("admin.utils").directive "textangularLinksTargetBlank", () -> + restrict: 'CA' + link: (scope, element, attrs) -> + setTimeout -> + element.find(".ta-editor").scope().defaultTagAttributes.a.target = '_blank' + , 500 diff --git a/app/views/admin/enterprise_groups/_form_about.html.haml b/app/views/admin/enterprise_groups/_form_about.html.haml index e7932bc272..55edc977c1 100644 --- a/app/views/admin/enterprise_groups/_form_about.html.haml +++ b/app/views/admin/enterprise_groups/_form_about.html.haml @@ -1,6 +1,6 @@ %fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='about'" } } %legend {{menu.selected.label}} = f.field_container :long_description do - %text-angular{'id' => 'enterprise_group_long_description', 'name' => 'enterprise_group[long_description]', 'class' => 'text-angular', + %text-angular{'id' => 'enterprise_group_long_description', 'name' => 'enterprise_group[long_description]', 'class' => 'text-angular', "textangular-links-target-blank" => true, 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]"} != @enterprise_group[:long_description] diff --git a/app/views/admin/enterprises/form/_about_us.html.haml b/app/views/admin/enterprises/form/_about_us.html.haml index fdc9827e4f..77f2822511 100644 --- a/app/views/admin/enterprises/form/_about_us.html.haml +++ b/app/views/admin/enterprises/form/_about_us.html.haml @@ -12,6 +12,6 @@ -# ['bold', 'italics', 'underline', 'strikeThrough', 'ul', 'ol', 'redo', 'undo', 'clear'], -# ['justifyLeft','justifyCenter','justifyRight','indent','outdent'], -# ['html', 'insertImage', 'insertLink', 'insertVideo'] - %text-angular{'ng-model' => 'Enterprise.long_description', 'id' => 'enterprise_long_description', 'name' => 'enterprise[long_description]', 'class' => 'text-angular', + %text-angular{'ng-model' => 'Enterprise.long_description', 'id' => 'enterprise_long_description', 'name' => 'enterprise[long_description]', 'class' => 'text-angular', "textangular-links-target-blank" => true, 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", 'placeholder' => t('.desc_long_placeholder')} diff --git a/app/views/admin/enterprises/form/_shop_preferences.html.haml b/app/views/admin/enterprises/form/_shop_preferences.html.haml index fceac454aa..2d52bcb169 100644 --- a/app/views/admin/enterprises/form/_shop_preferences.html.haml +++ b/app/views/admin/enterprises/form/_shop_preferences.html.haml @@ -3,7 +3,7 @@ .three.columns.alpha = f.label "enterprise_preferred_shopfront_message", t('.shopfront_message') .eight.columns.omega - %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular', + %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular', "textangular-links-target-blank" => true, 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", 'placeholder' => t('.shopfront_message_placeholder')} .row @@ -11,7 +11,7 @@ .three.columns.alpha = f.label "enterprise_preferred_shopfront_closed_message", t('.shopfront_closed_message') .eight.columns.omega - %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular', + %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular', "textangular-links-target-blank" => true, 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", 'placeholder' => t('.shopfront_closed_message_placeholder')} .row From e73b37820166901e1bd9ebc2641696a5b6ef61a9 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Fri, 15 Jun 2018 21:50:44 +0100 Subject: [PATCH 004/125] Adjust embedded response headers --- app/controllers/application_controller.rb | 6 ++++-- spec/requests/embedded_shopfronts_headers_spec.rb | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d22e8a6ba4..e3ea8b375f 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -60,7 +60,7 @@ class ApplicationController < ActionController::Base return if embedding_without_https? response.headers.delete 'X-Frame-Options' - response.headers['Content-Security-Policy'] = "frame-ancestors #{URI(request.referer).host.downcase}" + response.headers['Content-Security-Policy'] = "frame-ancestors 'self' #{URI(request.referer).host.downcase}" check_embedded_request set_embedded_layout @@ -73,8 +73,10 @@ class ApplicationController < ActionController::Base end def embeddable? - whitelist = Spree::Config[:embedded_shopfronts_whitelist] domain = embedded_shopfront_referer + return true if domain == request.host + + whitelist = Spree::Config[:embedded_shopfronts_whitelist] Spree::Config[:enable_embedded_shopfronts] && whitelist.present? && domain.present? && whitelist.include?(domain) end diff --git a/spec/requests/embedded_shopfronts_headers_spec.rb b/spec/requests/embedded_shopfronts_headers_spec.rb index 9d2c1c523e..6d6ea4b9f6 100644 --- a/spec/requests/embedded_shopfronts_headers_spec.rb +++ b/spec/requests/embedded_shopfronts_headers_spec.rb @@ -52,7 +52,7 @@ describe "setting response headers for embedded shopfronts", type: :request do expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to be_nil - expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors external-site.com" + expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors 'self' external-site.com" get spree.admin_path @@ -73,7 +73,7 @@ describe "setting response headers for embedded shopfronts", type: :request do expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to be_nil - expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors www.external-site.com" + expect(response.headers['Content-Security-Policy']).to eq "frame-ancestors 'self' www.external-site.com" end end end From ff0e0d9f3d6461caf8f749942f1e6de607779619 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Sat, 16 Jun 2018 02:49:22 +0100 Subject: [PATCH 005/125] Move logic from ApplicationController to service and improve clarity --- app/controllers/application_controller.rb | 47 +--------- app/services/embedded_page_service.rb | 90 +++++++++++++++++++ .../embedded_shopfronts_headers_spec.rb | 4 +- 3 files changed, 95 insertions(+), 46 deletions(-) create mode 100644 app/services/embedded_page_service.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e3ea8b375f..08a552cb6b 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -56,50 +56,9 @@ class ApplicationController < ActionController::Base end def enable_embedded_shopfront - return unless embeddable? - return if embedding_without_https? - - response.headers.delete 'X-Frame-Options' - response.headers['Content-Security-Policy'] = "frame-ancestors 'self' #{URI(request.referer).host.downcase}" - - check_embedded_request - set_embedded_layout - end - - def embedded_shopfront_referer - return if request.referer.blank? - domain = URI(request.referer).host.downcase - domain.start_with?('www.') ? domain[4..-1] : domain - end - - def embeddable? - domain = embedded_shopfront_referer - return true if domain == request.host - - whitelist = Spree::Config[:embedded_shopfronts_whitelist] - Spree::Config[:enable_embedded_shopfronts] && whitelist.present? && domain.present? && whitelist.include?(domain) - end - - def embedding_without_https? - request.referer && URI(request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development? - end - - def check_embedded_request - return unless params[:embedded_shopfront] - - # Show embedded shopfront CSS - session[:embedded_shopfront] = true - - # Get shopfront slug and set redirect path - if params[:controller] == 'enterprises' && params[:action] == 'shop' && params[:id] - slug = params[:id] - session[:shopfront_redirect] = '/' + slug + '/shop?embedded_shopfront=true' - end - end - - def set_embedded_layout - return unless session[:embedded_shopfront] - @shopfront_layout = 'embedded' + embed_service = EmbeddedPageService.new(params, session, request, response) + embed_service.embed! + @shopfront_layout = 'embedded' if embed_service.use_embedded_layout end def action diff --git a/app/services/embedded_page_service.rb b/app/services/embedded_page_service.rb new file mode 100644 index 0000000000..b4ab2372cc --- /dev/null +++ b/app/services/embedded_page_service.rb @@ -0,0 +1,90 @@ +# Processes requests for pages embedded in iframes + +class EmbeddedPageService + attr_reader :use_embedded_layout + + def initialize(params, session, request, response) + @params = params + @session = session + @request = request + @response = response + + @embedding_domain = @session[:embedding_domain] + @use_embedded_layout = false + end + + def embed! + return unless embeddable? + return if embedding_without_https? + + process_embedded_request + set_response_headers + set_embedded_layout + end + + private + + def embeddable? + return true if current_referer == @request.host + + domain = current_referer_without_www + whitelist = Spree::Config[:embedded_shopfronts_whitelist] + + embedding_enabled? && whitelist.present? && domain.present? && whitelist.include?(domain) + end + + def embedding_without_https? + @request.referer && URI(@request.referer).scheme != 'https' && !Rails.env.test? && !Rails.env.development? + end + + def process_embedded_request + return unless @params[:embedded_shopfront] + + set_embedding_domain + + @session[:embedded_shopfront] = true + set_logout_redirect + end + + def set_response_headers + @response.headers.delete 'X-Frame-Options' + @response.headers['Content-Security-Policy'] = "frame-ancestors 'self' #{@embedding_domain}" + end + + def set_embedding_domain + return unless @params[:embedded_shopfront] + return if current_referer == @request.host + + @embedding_domain = current_referer + @session[:embedding_domain] = current_referer + end + + def set_logout_redirect + return unless enterprise_slug + @session[:shopfront_redirect] = '/' + enterprise_slug + '/shop?embedded_shopfront=true' + end + + def enterprise_slug + return false unless @params[:controller] == 'enterprises' && @params[:action] == 'shop' && @params[:id] + @params[:id] + end + + def current_referer + return if @request.referer.blank? + URI(@request.referer).host.downcase + end + + def current_referer_without_www + return unless current_referer + current_referer.start_with?('www.') ? current_referer[4..-1] : current_referer + end + + def set_embedded_layout + return unless @session[:embedded_shopfront] + @use_embedded_layout = true + end + + def embedding_enabled? + Spree::Config[:enable_embedded_shopfronts] + end +end diff --git a/spec/requests/embedded_shopfronts_headers_spec.rb b/spec/requests/embedded_shopfronts_headers_spec.rb index 6d6ea4b9f6..6428b009be 100644 --- a/spec/requests/embedded_shopfronts_headers_spec.rb +++ b/spec/requests/embedded_shopfronts_headers_spec.rb @@ -48,7 +48,7 @@ describe "setting response headers for embedded shopfronts", type: :request do end it "allows iframes on certain pages when enabled in configuration" do - get shops_path + get enterprise_shop_path(enterprise) + '?embedded_shopfront=true' expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to be_nil @@ -69,7 +69,7 @@ describe "setting response headers for embedded shopfronts", type: :request do end it "matches the URL structure in the header" do - get shops_path + get enterprise_shop_path(enterprise) + '?embedded_shopfront=true' expect(response.status).to be 200 expect(response.headers['X-Frame-Options']).to be_nil From 6e8187145995cdd88725ad74c57dea9585c91018 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Wed, 20 Jun 2018 15:14:56 +0100 Subject: [PATCH 006/125] Specs for new EmbeddedPageService --- spec/services/embedded_page_service_spec.rb | 59 +++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 spec/services/embedded_page_service_spec.rb diff --git a/spec/services/embedded_page_service_spec.rb b/spec/services/embedded_page_service_spec.rb new file mode 100644 index 0000000000..f1ea8a971e --- /dev/null +++ b/spec/services/embedded_page_service_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe EmbeddedPageService do + let(:enterprise_slug) { 'test-enterprise' } + let(:params) { { controller: 'enterprises', action: 'shop', id: enterprise_slug, embedded_shopfront: true } } + let(:session) { {} } + let(:request) { ActionController::TestRequest.new('HTTP_HOST' => 'ofn-instance.com', 'HTTP_REFERER' => 'https://embedding-enterprise.com') } + let(:response) { ActionController::TestResponse.new(200, 'X-Frame-Options' => 'DENY', 'Content-Security-Policy' => "frame-ancestors 'none'") } + let(:service) { EmbeddedPageService.new(params, session, request, response) } + + before do + Spree::Config.set( + enable_embedded_shopfronts: true, + embedded_shopfronts_whitelist: 'embedding-enterprise.com example.com' + ) + end + + describe "#embed!" do + context "when the request's referer is in the whitelist" do + before { service.embed! } + + it "sets the response headers to enables embedding requests from the embedding site" do + expect(response.headers).to_not include 'X-Frame-Options' => 'DENY' + expect(response.headers).to include 'Content-Security-Policy' => "frame-ancestors 'self' embedding-enterprise.com" + end + + it "sets session variables" do + expect(session[:embedded_shopfront]).to eq true + expect(session[:embedding_domain]).to eq 'embedding-enterprise.com' + expect(session[:shopfront_redirect]).to eq '/' + enterprise_slug + '/shop?embedded_shopfront=true' + end + end + + context "when embedding is enabled for a different site in the current session" do + before do + session[:embedding_domain] = 'another-enterprise.com' + session[:shopfront_redirect] = '/another-enterprise/shop?embedded_shopfront=true' + service.embed! + end + + it "resets the session variables for the new request" do + expect(session[:embedded_shopfront]).to eq true + expect(session[:embedding_domain]).to eq 'embedding-enterprise.com' + expect(session[:shopfront_redirect]).to eq '/' + enterprise_slug + '/shop?embedded_shopfront=true' + end + end + + context "when the request's referer is not in the whitelist" do + before do + Spree::Config.set(embedded_shopfronts_whitelist: 'example.com') + service.embed! + end + + it "does not enable embedding" do + expect(response.headers['X-Frame-Options']).to eq 'DENY' + end + end + end +end From aaba6da1629a4f0782a10341c6c85e3aa13dc5b3 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Sat, 16 Jun 2018 14:30:17 +0100 Subject: [PATCH 007/125] Add available_on notes to PI guide --- app/views/admin/product_import/guide/_columns.html.haml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/views/admin/product_import/guide/_columns.html.haml b/app/views/admin/product_import/guide/_columns.html.haml index d5aa454670..c79a881162 100644 --- a/app/views/admin/product_import/guide/_columns.html.haml +++ b/app/views/admin/product_import/guide/_columns.html.haml @@ -91,3 +91,10 @@ %td (Various, see notes) %td Sets the product shipping category %td See below for a list of available categories + %tr + %td + %strong available_on + %td No + %td 2018-05-21 + %td Sets the date from which the product will be available + %td Date format is: YYYY-MM-DD From 172fa168ead0a01be6e623045b46f401c3cf4377 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Thu, 21 Jun 2018 14:18:32 +0100 Subject: [PATCH 008/125] Change layout attribute to method with question mark --- app/controllers/application_controller.rb | 2 +- app/services/embedded_page_service.rb | 6 ++++-- spec/services/embedded_page_service_spec.rb | 6 +++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 08a552cb6b..65d1fb1f33 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -58,7 +58,7 @@ class ApplicationController < ActionController::Base def enable_embedded_shopfront embed_service = EmbeddedPageService.new(params, session, request, response) embed_service.embed! - @shopfront_layout = 'embedded' if embed_service.use_embedded_layout + @shopfront_layout = 'embedded' if embed_service.use_embedded_layout? end def action diff --git a/app/services/embedded_page_service.rb b/app/services/embedded_page_service.rb index b4ab2372cc..8d6e27df26 100644 --- a/app/services/embedded_page_service.rb +++ b/app/services/embedded_page_service.rb @@ -1,8 +1,6 @@ # Processes requests for pages embedded in iframes class EmbeddedPageService - attr_reader :use_embedded_layout - def initialize(params, session, request, response) @params = params @session = session @@ -22,6 +20,10 @@ class EmbeddedPageService set_embedded_layout end + def use_embedded_layout? + @use_embedded_layout + end + private def embeddable? diff --git a/spec/services/embedded_page_service_spec.rb b/spec/services/embedded_page_service_spec.rb index f1ea8a971e..eb44b014ab 100644 --- a/spec/services/embedded_page_service_spec.rb +++ b/spec/services/embedded_page_service_spec.rb @@ -15,7 +15,7 @@ describe EmbeddedPageService do ) end - describe "#embed!" do + describe "processing embedded page requests" do context "when the request's referer is in the whitelist" do before { service.embed! } @@ -29,6 +29,10 @@ describe EmbeddedPageService do expect(session[:embedding_domain]).to eq 'embedding-enterprise.com' expect(session[:shopfront_redirect]).to eq '/' + enterprise_slug + '/shop?embedded_shopfront=true' end + + it "publicly reports that embedded layout should be used" do + expect(service.use_embedded_layout?).to be true + end end context "when embedding is enabled for a different site in the current session" do From e25574790b32de7ec9d47c3c3abe068444bf6e10 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 6 Apr 2018 14:55:21 +1000 Subject: [PATCH 009/125] Split out float: right css from .help-btn.tiny selector --- app/assets/stylesheets/darkswarm/ui.css.scss | 3 +++ app/views/shared/components/_show_profiles.html.haml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/ui.css.scss b/app/assets/stylesheets/darkswarm/ui.css.scss index 1d1b9e166a..529fb6e48b 100644 --- a/app/assets/stylesheets/darkswarm/ui.css.scss +++ b/app/assets/stylesheets/darkswarm/ui.css.scss @@ -87,6 +87,9 @@ button.success, .button.success { &.tiny { padding: 0rem; margin: 0; + } + + &.right { float: right; } diff --git a/app/views/shared/components/_show_profiles.html.haml b/app/views/shared/components/_show_profiles.html.haml index 84a55ae405..5a1b5ec1db 100644 --- a/app/views/shared/components/_show_profiles.html.haml +++ b/app/views/shared/components/_show_profiles.html.haml @@ -1,6 +1,6 @@ .small-12.medium-6.columns.text-right .profile-checkbox - %button.button.secondary.tiny.help-btn.ng-scope{:popover => t(:components_profiles_popover, sitename: Spree::Config[:site_name]), "popover-placement" => "left"}>< + %button.button.secondary.tiny.right.help-btn.ng-scope{:popover => t(:components_profiles_popover, sitename: Spree::Config[:site_name]), "popover-placement" => "left"}>< %i.ofn-i_013-help %label %input{"ng-model" => "show_profiles", type: "checkbox", name: "profile"} From 6e76fd816474a85add770d10509c08e639634309 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 20 Apr 2018 11:27:33 +1000 Subject: [PATCH 010/125] Add Api::CustomersController with update action --- app/controllers/api/customers_controller.rb | 16 ++++++ app/models/spree/ability_decorator.rb | 4 ++ config/routes.rb | 2 + .../api/customers_controller_spec.rb | 49 +++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 app/controllers/api/customers_controller.rb create mode 100644 spec/controllers/api/customers_controller_spec.rb diff --git a/app/controllers/api/customers_controller.rb b/app/controllers/api/customers_controller.rb new file mode 100644 index 0000000000..9df7534259 --- /dev/null +++ b/app/controllers/api/customers_controller.rb @@ -0,0 +1,16 @@ +module Api + class CustomersController < Spree::Api::BaseController + respond_to :json + + def update + @customer = Customer.find(params[:id]) + authorize! :update, @customer + + if @customer.update_attributes(params[:customer]) + render text: @customer.id, :status => 200 + else + invalid_resource!(@customer) + end + end + end +end diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 385b9be032..daf8161142 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -64,6 +64,10 @@ class AbilityDecorator can [:update, :destroy], Spree::CreditCard do |credit_card| credit_card.user == user end + + can [:update], Customer do |customer| + customer.user == user + end end # New users can create an enterprise, and gain other permissions from doing this. diff --git a/config/routes.rb b/config/routes.rb index 53356e2f52..f0f6bd4488 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -217,6 +217,8 @@ Openfoodnetwork::Application.routes.draw do get :job_queue end + resources :customers, only: [:update] + post '/product_images/:product_id', to: 'product_images#update_product_image' end diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb new file mode 100644 index 0000000000..764f767549 --- /dev/null +++ b/spec/controllers/api/customers_controller_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +module Api + describe CustomersController, type: :controller do + include AuthenticationWorkflow + render_views + + let(:user) { create(:user) } + let(:customer) { create(:customer, user: user) } + let(:params) { { format: :json, id: customer.id, customer: { code: '123' } } } + + describe "#update" do + context "as a user who is not associated with the customer" do + before do + allow(controller).to receive(:spree_current_user) { create(:user) } + end + + it "returns unauthorized" do + spree_post :update, params + assert_unauthorized! + end + end + + context "as the user associated with the customer" do + before do + allow(controller).to receive(:spree_current_user) { user } + end + + context "when the update request is successful" do + it "returns the id of the updated customer" do + spree_post :update, params + expect(response.status).to eq 200 + expect(response.body).to eq customer.id.to_s + end + end + + context "when the update request fails" do + before { params[:customer][:email] = '' } + + it "returns a 422, with an error message" do + spree_post :update, params + expect(response.status).to be 422 + expect(JSON.parse(response.body)['error']).to be + end + end + end + end + end +end From 29922d4be992854318c8bfe62434d8275e3575de Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 11 Apr 2018 09:54:43 +1000 Subject: [PATCH 011/125] Add allow_charges field to Customer model --- .../20180406045821_add_charges_allowed_to_customers.rb | 5 +++++ db/schema.rb | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20180406045821_add_charges_allowed_to_customers.rb diff --git a/db/migrate/20180406045821_add_charges_allowed_to_customers.rb b/db/migrate/20180406045821_add_charges_allowed_to_customers.rb new file mode 100644 index 0000000000..4503dc87b6 --- /dev/null +++ b/db/migrate/20180406045821_add_charges_allowed_to_customers.rb @@ -0,0 +1,5 @@ +class AddChargesAllowedToCustomers < ActiveRecord::Migration + def change + add_column :customers, :allow_charges, :boolean, default: false, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 787c37c227..caad9f27a5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -79,15 +79,16 @@ ActiveRecord::Schema.define(:version => 20180418025217) do add_index "coordinator_fees", ["order_cycle_id"], :name => "index_coordinator_fees_on_order_cycle_id" create_table "customers", :force => true do |t| - t.string "email", :null => false - t.integer "enterprise_id", :null => false + t.string "email", :null => false + t.integer "enterprise_id", :null => false t.string "code" t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.integer "bill_address_id" t.integer "ship_address_id" t.string "name" + t.boolean "allow_charges", :default => false, :null => false end add_index "customers", ["bill_address_id"], :name => "index_customers_on_bill_address_id" From ffa8a8c7d685e04e39b445d1abc840ae8628123f Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 27 Apr 2018 16:04:58 +1000 Subject: [PATCH 012/125] Create Api::BaseController to allow use of ActiveModelSerializers Also add index action to Api::CustomersController --- app/controllers/api/base_controller.rb | 13 +++++++++ app/controllers/api/customers_controller.rb | 9 ++++--- app/controllers/api/statuses_controller.rb | 2 +- app/serializers/api/customer_serializer.rb | 5 ++++ config/routes.rb | 2 +- .../api/customers_controller_spec.rb | 27 ++++++++++++++++--- spec/support/api_helper.rb | 15 +++++++++++ 7 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 app/controllers/api/base_controller.rb create mode 100644 app/serializers/api/customer_serializer.rb create mode 100644 spec/support/api_helper.rb diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb new file mode 100644 index 0000000000..f25c47417d --- /dev/null +++ b/app/controllers/api/base_controller.rb @@ -0,0 +1,13 @@ +# Base controller for OFN's API +# Includes the minimum machinery required by ActiveModelSerializers +module Api + class BaseController < Spree::Api::BaseController + # Need to include these because Spree::Api::BaseContoller inherits + # from ActionController::Metal rather than ActionController::Base + # and they are required by ActiveModelSerializers + include ActionController::Serialization + include ActionController::UrlFor + include Rails.application.routes.url_helpers + use_renderers :json + end +end diff --git a/app/controllers/api/customers_controller.rb b/app/controllers/api/customers_controller.rb index 9df7534259..cbbe4ce35f 100644 --- a/app/controllers/api/customers_controller.rb +++ b/app/controllers/api/customers_controller.rb @@ -1,13 +1,16 @@ module Api - class CustomersController < Spree::Api::BaseController - respond_to :json + class CustomersController < BaseController + def index + @customers = current_api_user.customers + render json: @customers, each_serializer: CustomerSerializer + end def update @customer = Customer.find(params[:id]) authorize! :update, @customer if @customer.update_attributes(params[:customer]) - render text: @customer.id, :status => 200 + render json: @customer, serializer: CustomerSerializer, status: 200 else invalid_resource!(@customer) end diff --git a/app/controllers/api/statuses_controller.rb b/app/controllers/api/statuses_controller.rb index c8844b868b..49a6f991ff 100644 --- a/app/controllers/api/statuses_controller.rb +++ b/app/controllers/api/statuses_controller.rb @@ -1,5 +1,5 @@ module Api - class StatusesController < BaseController + class StatusesController < ::BaseController respond_to :json def job_queue diff --git a/app/serializers/api/customer_serializer.rb b/app/serializers/api/customer_serializer.rb new file mode 100644 index 0000000000..44914e0a49 --- /dev/null +++ b/app/serializers/api/customer_serializer.rb @@ -0,0 +1,5 @@ +module Api + class CustomerSerializer < ActiveModel::Serializer + attributes :id, :enterprise_id, :name, :code, :email, :allow_charges + end +end diff --git a/config/routes.rb b/config/routes.rb index f0f6bd4488..ba4da8ae2e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -217,7 +217,7 @@ Openfoodnetwork::Application.routes.draw do get :job_queue end - resources :customers, only: [:update] + resources :customers, only: [:index, :update] post '/product_images/:product_id', to: 'product_images#update_product_image' end diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb index 764f767549..f6c8f4e0a5 100644 --- a/spec/controllers/api/customers_controller_spec.rb +++ b/spec/controllers/api/customers_controller_spec.rb @@ -3,13 +3,32 @@ require 'spec_helper' module Api describe CustomersController, type: :controller do include AuthenticationWorkflow + include OpenFoodNetwork::ApiHelper render_views let(:user) { create(:user) } - let(:customer) { create(:customer, user: user) } - let(:params) { { format: :json, id: customer.id, customer: { code: '123' } } } + + describe "index" do + let!(:customer1) { create(:customer) } + let!(:customer2) { create(:customer) } + + before do + user.customers << customer1 + allow(controller).to receive(:spree_current_user) { user } + end + + it "lists customers associated with the current user" do + spree_get :index + expect(response.status).to eq 200 + expect(json_response.length).to eq 1 + expect(json_response.first[:id]).to eq customer1.id + end + end describe "#update" do + let(:customer) { create(:customer, user: user) } + let(:params) { { format: :json, id: customer.id, customer: { code: '123' } } } + context "as a user who is not associated with the customer" do before do allow(controller).to receive(:spree_current_user) { create(:user) } @@ -30,7 +49,7 @@ module Api it "returns the id of the updated customer" do spree_post :update, params expect(response.status).to eq 200 - expect(response.body).to eq customer.id.to_s + expect(json_response[:id]).to eq customer.id end end @@ -40,7 +59,7 @@ module Api it "returns a 422, with an error message" do spree_post :update, params expect(response.status).to be 422 - expect(JSON.parse(response.body)['error']).to be + expect(json_response[:error]).to be end end end diff --git a/spec/support/api_helper.rb b/spec/support/api_helper.rb new file mode 100644 index 0000000000..08918fb761 --- /dev/null +++ b/spec/support/api_helper.rb @@ -0,0 +1,15 @@ +module OpenFoodNetwork + module ApiHelper + def json_response + json_response = JSON.parse(response.body) + case json_response + when Hash + json_response.with_indifferent_access + when Array + json_response.map(&:with_indifferent_access) + else + json_response + end + end + end +end From 6457a17fde359f00ddae254e67a0dc4a9d2799d0 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 27 Apr 2018 17:42:34 +1000 Subject: [PATCH 013/125] Add basic view allowing customers to authorise shop use of their credit cards --- .../authorised_shops_controller.js.coffee | 3 ++ .../darkswarm/services/customer.js.coffee | 20 ++++++++++ .../darkswarm/services/customers.js.coffee | 13 +++++++ .../darkswarm/services/shops.js.coffee | 13 +++++++ .../stylesheets/darkswarm/account.css.scss | 6 +++ .../spree/users/_authorised_shops.html.haml | 13 +++++++ app/views/spree/users/_cards.html.haml | 13 +++++-- config/locales/en.yml | 3 ++ spec/features/consumer/account/cards_spec.rb | 11 +++++- .../services/customer_spec.js.coffee | 39 +++++++++++++++++++ .../services/customers_spec.js.coffee | 24 ++++++++++++ .../darkswarm/services/shops_spec.js.coffee | 27 +++++++++++++ 12 files changed, 181 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/controllers/authorised_shops_controller.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/customer.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/customers.js.coffee create mode 100644 app/assets/javascripts/darkswarm/services/shops.js.coffee create mode 100644 app/views/spree/users/_authorised_shops.html.haml create mode 100644 spec/javascripts/unit/darkswarm/services/customer_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/services/customers_spec.js.coffee create mode 100644 spec/javascripts/unit/darkswarm/services/shops_spec.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/authorised_shops_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/authorised_shops_controller.js.coffee new file mode 100644 index 0000000000..f100a0a7c3 --- /dev/null +++ b/app/assets/javascripts/darkswarm/controllers/authorised_shops_controller.js.coffee @@ -0,0 +1,3 @@ +angular.module("Darkswarm").controller "AuthorisedShopsCtrl", ($scope, Customers, Shops) -> + $scope.customers = Customers.index() + $scope.shopsByID = Shops.byID diff --git a/app/assets/javascripts/darkswarm/services/customer.js.coffee b/app/assets/javascripts/darkswarm/services/customer.js.coffee new file mode 100644 index 0000000000..ac27945c54 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/customer.js.coffee @@ -0,0 +1,20 @@ +angular.module("Darkswarm").factory 'Customer', ($resource, RailsFlashLoader) -> + Customer = $resource('/api/customers/:id/:action.json', {}, { + 'index': + method: 'GET' + isArray: true + 'update': + method: 'PUT' + params: + id: '@id' + transformRequest: (data, headersGetter) -> + angular.toJson(customer: data) + }) + + Customer.prototype.update = -> + @$update().then (response) => + RailsFlashLoader.loadFlash({success: t('js.changes_saved')}) + , (response) => + RailsFlashLoader.loadFlash({error: response.data.error}) + + Customer diff --git a/app/assets/javascripts/darkswarm/services/customers.js.coffee b/app/assets/javascripts/darkswarm/services/customers.js.coffee new file mode 100644 index 0000000000..cf5c56563a --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/customers.js.coffee @@ -0,0 +1,13 @@ +angular.module("Darkswarm").factory 'Customers', (Customer) -> + new class Customers + all: [] + byID: {} + + index: (params={}) -> + Customer.index params, (data) => @load(data) + @all + + load: (customers) -> + for customer in customers + @all.push customer + @byID[customer.id] = customer diff --git a/app/assets/javascripts/darkswarm/services/shops.js.coffee b/app/assets/javascripts/darkswarm/services/shops.js.coffee new file mode 100644 index 0000000000..0af4152508 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/shops.js.coffee @@ -0,0 +1,13 @@ +angular.module("Darkswarm").factory 'Shops', ($injector) -> + new class Shops + all: [] + byID: {} + + constructor: -> + if $injector.has('shops') + @load($injector.get('shops')) + + load: (shops) -> + for shop in shops + @all.push shop + @byID[shop.id] = shop diff --git a/app/assets/stylesheets/darkswarm/account.css.scss b/app/assets/stylesheets/darkswarm/account.css.scss index c41cd2ef98..44d93b4cd1 100644 --- a/app/assets/stylesheets/darkswarm/account.css.scss +++ b/app/assets/stylesheets/darkswarm/account.css.scss @@ -28,6 +28,12 @@ margin-bottom: 0px; } } + + .authorised_shops{ + table { + width: 100%; + } + } } .orders { diff --git a/app/views/spree/users/_authorised_shops.html.haml b/app/views/spree/users/_authorised_shops.html.haml new file mode 100644 index 0000000000..692c953f12 --- /dev/null +++ b/app/views/spree/users/_authorised_shops.html.haml @@ -0,0 +1,13 @@ +%table + %tr + %th= t(:shop_title) + %th= t(:allow_charges?) + %tr.customer{ id: "customer{{ customer.id }}", ng: { repeat: "customer in customers" } } + %td.shop{ ng: { bind: 'shopsByID[customer.enterprise_id].name' } } + %td.allow_charges + %input{ type: 'checkbox', + name: 'allow_charges', + ng: { model: 'customer.allow_charges', + change: 'customer.update()', + "true-value" => "true", + "false-value" => "false" } } diff --git a/app/views/spree/users/_cards.html.haml b/app/views/spree/users/_cards.html.haml index 80069c282f..8929aac791 100644 --- a/app/views/spree/users/_cards.html.haml +++ b/app/views/spree/users/_cards.html.haml @@ -10,6 +10,13 @@ %button.button.primary{ ng: { click: 'showForm()', hide: 'CreditCard.visible' } } = t(:add_a_card) - .small-12.medium-6.columns.new_card{ ng: { show: 'CreditCard.visible', class: '{visible: CreditCard.visible}' } } - %h3= t(:add_a_new_card) - = render 'new_card_form' + .small-12.medium-6.columns + .new_card{ ng: { show: 'CreditCard.visible', class: '{visible: CreditCard.visible}' } } + %h3= t(:add_a_new_card) + = render 'new_card_form' + .authorised_shops{ ng: { controller: 'AuthorisedShopsCtrl', hide: 'CreditCard.visible' } } + %h3 + = t('.authorised_shops') + %button.button.secondary.tiny.help-btn.ng-scope{ :popover => t('.authorised_shops_popover'), "popover-placement" => 'right' } + %i.ofn-i_013-help + = render 'authorised_shops' diff --git a/config/locales/en.yml b/config/locales/en.yml index 35754e0bc2..597dd60c36 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2740,5 +2740,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using saved_cards: default?: Default? delete?: Delete? + cards: + authorised_shops: Authorised Shops + authorised_shops_popover: This is a list of shops which are permitted to charge your default credit card for OFN services (eg. subscriptions). Your card details will be kept secure and will not be shared with shop owners. localized_number: invalid_format: has an invalid format. Please enter a number. diff --git a/spec/features/consumer/account/cards_spec.rb b/spec/features/consumer/account/cards_spec.rb index 2f78511135..25c6410ade 100644 --- a/spec/features/consumer/account/cards_spec.rb +++ b/spec/features/consumer/account/cards_spec.rb @@ -4,6 +4,7 @@ feature "Credit Cards", js: true do include AuthenticationWorkflow describe "as a logged in user" do let(:user) { create(:user) } + let!(:customer) { create(:customer, user: user) } let!(:default_card) { create(:credit_card, user_id: user.id, gateway_customer_profile_id: 'cus_AZNMJ', is_default: true) } let!(:non_default_card) { create(:credit_card, user_id: user.id, gateway_customer_profile_id: 'cus_FDTG') } @@ -49,10 +50,10 @@ feature "Credit Cards", js: true do expect(page).to have_content I18n.t('js.default_card_updated') + expect(default_card.reload.is_default).to be false within(".card#card#{default_card.id}") do expect(find_field('default_card')).to_not be_checked end - expect(default_card.reload.is_default).to be false expect(non_default_card.reload.is_default).to be true # Shows the interface for adding a card @@ -67,6 +68,14 @@ feature "Credit Cards", js: true do expect(page).to have_content I18n.t(:card_has_been_removed, number: "x-#{default_card.last_digits}") expect(page).to_not have_selector ".card#card#{default_card.id}" + + # Allows authorisation of card use by shops + within "tr#customer#{customer.id}" do + expect(find_field('allow_charges')).to_not be_checked + find_field('allow_charges').click + end + expect(page).to have_content I18n.t('js.changes_saved') + expect(customer.reload.allow_charges).to be true end end end diff --git a/spec/javascripts/unit/darkswarm/services/customer_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/customer_spec.js.coffee new file mode 100644 index 0000000000..33a1d72cdc --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/customer_spec.js.coffee @@ -0,0 +1,39 @@ +describe 'Customer', -> + describe "update", -> + $httpBackend = null + customer = null + response = { id: 3, code: '1234' } + RailsFlashLoaderMock = jasmine.createSpyObj('RailsFlashLoader', ['loadFlash']) + + beforeEach -> + module 'Darkswarm' + module ($provide) -> + $provide.value 'RailsFlashLoader', RailsFlashLoaderMock + null + + inject (_$httpBackend_, Customer)-> + customer = new Customer(id: 3) + $httpBackend = _$httpBackend_ + + it "nests the params inside 'customer'", -> + $httpBackend + .expectPUT('/api/customers/3.json', { customer: { id: 3 } }) + .respond 200, response + customer.update() + $httpBackend.flush() + + describe "when the request succeeds", -> + it "shows a success flash", -> + $httpBackend.expectPUT('/api/customers/3.json').respond 200, response + customer.update() + $httpBackend.flush() + expect(RailsFlashLoaderMock.loadFlash) + .toHaveBeenCalledWith({success: jasmine.any(String)}) + + describe "when the request fails", -> + it "shows a error flash", -> + $httpBackend.expectPUT('/api/customers/3.json').respond 400, { error: 'Some error' } + customer.update() + $httpBackend.flush() + expect(RailsFlashLoaderMock.loadFlash) + .toHaveBeenCalledWith({error: 'Some error'}) diff --git a/spec/javascripts/unit/darkswarm/services/customers_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/customers_spec.js.coffee new file mode 100644 index 0000000000..9680b89341 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/customers_spec.js.coffee @@ -0,0 +1,24 @@ +describe 'Customers', -> + describe "index", -> + $httpBackend = null + Customers = null + customerList = ['somecustomer'] + + beforeEach -> + module 'Darkswarm' + module ($provide) -> + $provide.value 'RailsFlashLoader', null + null + + inject (_$httpBackend_, _Customers_)-> + Customers = _Customers_ + $httpBackend = _$httpBackend_ + + it "asks for customers and returns @all, promises to populate via @load", -> + spyOn(Customers,'load').and.callThrough() + $httpBackend.expectGET('/api/customers.json').respond 200, customerList + result = Customers.index() + $httpBackend.flush() + expect(Customers.load).toHaveBeenCalled() + expect(result).toEqual customerList + expect(Customers.all).toEqual customerList diff --git a/spec/javascripts/unit/darkswarm/services/shops_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/shops_spec.js.coffee new file mode 100644 index 0000000000..ddc9e14af5 --- /dev/null +++ b/spec/javascripts/unit/darkswarm/services/shops_spec.js.coffee @@ -0,0 +1,27 @@ +describe 'Shops', -> + describe "initialisation", -> + Shops = null + shops = ['some shop'] + + beforeEach -> + module 'Darkswarm' + + describe "when the injector does not have a value for 'shops'", -> + beforeEach -> + inject (_Shops_) -> + Shops = _Shops_ + + it "does nothing, leaves @all empty", -> + expect(Shops.all).toEqual [] + + describe "when the injector has a value for 'shops'", -> + beforeEach -> + module ($provide) -> + $provide.value 'shops', shops + null + + inject (_Shops_) -> + Shops = _Shops_ + + it "loads injected shops array into @all", -> + expect(Shops.all).toEqual shops From 32622c77bceae8cca405e6224ad0edffba9d88df Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 13:57:21 +1000 Subject: [PATCH 014/125] Add basic help modal directive Useful for showing help text that is too long for a tool tip --- .../darkswarm/directives/help_modal.js.coffee | 10 ++++++++++ app/assets/javascripts/templates/help-modal.html.haml | 9 +++++++++ app/assets/stylesheets/darkswarm/help-modal.css.scss | 9 +++++++++ 3 files changed, 28 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/directives/help_modal.js.coffee create mode 100644 app/assets/javascripts/templates/help-modal.html.haml create mode 100644 app/assets/stylesheets/darkswarm/help-modal.css.scss diff --git a/app/assets/javascripts/darkswarm/directives/help_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/help_modal.js.coffee new file mode 100644 index 0000000000..6aef4f481b --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/help_modal.js.coffee @@ -0,0 +1,10 @@ +Darkswarm.directive "helpModal", ($modal, $compile, $templateCache)-> + restrict: 'A' + scope: + helpText: "@helpModal" + + link: (scope, elem, attrs, ctrl)-> + compiled = $compile($templateCache.get('help-modal.html'))(scope) + + elem.on "click", => + $modal.open(controller: ctrl, template: compiled, scope: scope, windowClass: 'help-modal small') diff --git a/app/assets/javascripts/templates/help-modal.html.haml b/app/assets/javascripts/templates/help-modal.html.haml new file mode 100644 index 0000000000..f87abd8fd4 --- /dev/null +++ b/app/assets/javascripts/templates/help-modal.html.haml @@ -0,0 +1,9 @@ +.row.help-icon + .small-12.text-center + %i.ofn-i_013-help +.row.help-text + .small-12.columns.text-center + {{ helpText }} +.row.text-center + %button.primary.small{ ng: { click: '$close()' } } + = t(:ok) diff --git a/app/assets/stylesheets/darkswarm/help-modal.css.scss b/app/assets/stylesheets/darkswarm/help-modal.css.scss new file mode 100644 index 0000000000..c26b17edc2 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/help-modal.css.scss @@ -0,0 +1,9 @@ +.help-modal { + .help-text { + font-size: 1rem; + margin: 20px 0px; + } + .help-icon { + font-size: 4rem; + } +} From 7db7084008106dd3aa80c4c786d0495107b992d2 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 14:05:05 +1000 Subject: [PATCH 015/125] Use help-modal to display help text for authorised shops Also updated the text slightly to make it more clear when the purpose of authorised shops are --- app/views/spree/users/_cards.html.haml | 2 +- config/locales/en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/users/_cards.html.haml b/app/views/spree/users/_cards.html.haml index 8929aac791..180dc7d478 100644 --- a/app/views/spree/users/_cards.html.haml +++ b/app/views/spree/users/_cards.html.haml @@ -17,6 +17,6 @@ .authorised_shops{ ng: { controller: 'AuthorisedShopsCtrl', hide: 'CreditCard.visible' } } %h3 = t('.authorised_shops') - %button.button.secondary.tiny.help-btn.ng-scope{ :popover => t('.authorised_shops_popover'), "popover-placement" => 'right' } + %button.button.secondary.tiny.help-btn.ng-scope{ "help-modal" => t('.authorised_shops_popover') } %i.ofn-i_013-help = render 'authorised_shops' diff --git a/config/locales/en.yml b/config/locales/en.yml index 597dd60c36..aaec61c99a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2742,6 +2742,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using delete?: Delete? cards: authorised_shops: Authorised Shops - authorised_shops_popover: This is a list of shops which are permitted to charge your default credit card for OFN services (eg. subscriptions). Your card details will be kept secure and will not be shared with shop owners. + authorised_shops_popover: This is the list of shops which are permitted to charge your default credit card for any subscriptions (ie. repeating orders) you may have. Your card details will be kept secure and will not be shared with shop owners. You will always be notified when you are charged. localized_number: invalid_format: has an invalid format. Please enter a number. From d1d9c5a092d91b84e2f64dc7e6c1b5a237993f17 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 14:12:41 +1000 Subject: [PATCH 016/125] Add help button to saved cards list on account page Describes the purpose of the default card --- app/views/spree/users/_cards.html.haml | 6 +++++- config/locales/en.yml | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/app/views/spree/users/_cards.html.haml b/app/views/spree/users/_cards.html.haml index 180dc7d478..6f7d13a06a 100644 --- a/app/views/spree/users/_cards.html.haml +++ b/app/views/spree/users/_cards.html.haml @@ -2,7 +2,11 @@ .credit_cards{"ng-controller" => "CreditCardsCtrl"} .row .small-12.medium-6.columns - %h3= t(:saved_cards) + %h3 + = t(:saved_cards) + %button.button.secondary.tiny.help-btn.ng-scope{ "help-modal" => t('.saved_cards_popover') } + %i.ofn-i_013-help + .saved_cards{ ng: { show: 'savedCreditCards.length > 0' } } = render 'saved_cards' .no_cards{ ng: { hide: 'savedCreditCards.length > 0' } } diff --git a/config/locales/en.yml b/config/locales/en.yml index aaec61c99a..8a34f8b9ff 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2743,5 +2743,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using cards: authorised_shops: Authorised Shops authorised_shops_popover: This is the list of shops which are permitted to charge your default credit card for any subscriptions (ie. repeating orders) you may have. Your card details will be kept secure and will not be shared with shop owners. You will always be notified when you are charged. + saved_cards_popover: This is the list of cards you have opted to save for later use. Your 'default' will be selected automatically when you checkout an order, and can be charged by any shops you have allowed to do so (see right). localized_number: invalid_format: has an invalid format. Please enter a number. From 5e6291bce36de8315a8fb6ee60e3e9dadf796944 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 15:31:32 +1000 Subject: [PATCH 017/125] Don't request customers if list is already populated --- app/assets/javascripts/darkswarm/services/customers.js.coffee | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/darkswarm/services/customers.js.coffee b/app/assets/javascripts/darkswarm/services/customers.js.coffee index cf5c56563a..fe2c862c37 100644 --- a/app/assets/javascripts/darkswarm/services/customers.js.coffee +++ b/app/assets/javascripts/darkswarm/services/customers.js.coffee @@ -4,6 +4,7 @@ angular.module("Darkswarm").factory 'Customers', (Customer) -> byID: {} index: (params={}) -> + return @all if @all.length Customer.index params, (data) => @load(data) @all From 0d9b03b0660ad32dcdd3dda217be483e56468bd1 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Fri, 22 Jun 2018 11:42:50 +0100 Subject: [PATCH 018/125] Hide postcode - not necessary as passed from billing address and wrecks mobile UX --- .../javascripts/darkswarm/directives/stripe_elements.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/directives/stripe_elements.js.coffee b/app/assets/javascripts/darkswarm/directives/stripe_elements.js.coffee index d325b6f962..d88e0868a6 100644 --- a/app/assets/javascripts/darkswarm/directives/stripe_elements.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/stripe_elements.js.coffee @@ -10,7 +10,7 @@ Darkswarm.directive "stripeElements", ($injector, StripeElements) -> stripe = $injector.get('stripeObject') card = stripe.elements().create 'card', - hidePostalCode: false + hidePostalCode: true style: base: fontFamily: "Roboto, Arial, sans-serif" From ddb9ae1140a9df5d4e4f2a204595c81ff9d77060 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 15:34:17 +1000 Subject: [PATCH 019/125] Load all shops that a user is associated with as a customer Regardless of the presence of an order --- app/controllers/api/customers_controller.rb | 2 +- app/helpers/injection_helper.rb | 3 ++- app/models/customer.rb | 5 +++++ spec/controllers/api/customers_controller_spec.rb | 12 ++++++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/customers_controller.rb b/app/controllers/api/customers_controller.rb index cbbe4ce35f..e983b372c9 100644 --- a/app/controllers/api/customers_controller.rb +++ b/app/controllers/api/customers_controller.rb @@ -1,7 +1,7 @@ module Api class CustomersController < BaseController def index - @customers = current_api_user.customers + @customers = current_api_user.customers.of_regular_shops render json: @customers, each_serializer: CustomerSerializer end diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index ea5589abe6..f4e857607e 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -69,7 +69,8 @@ module InjectionHelper end def inject_shops - shops = Enterprise.where(id: @orders.pluck(:distributor_id).uniq) + customers = spree_current_user.customers.of_regular_shops + shops = Enterprise.where(id: @orders.pluck(:distributor_id).uniq | customers.pluck(:enterprise_id)) inject_json_ams "shops", shops.all, Api::ShopForOrdersSerializer end diff --git a/app/models/customer.rb b/app/models/customer.rb index dfddd90c80..0ec6f52262 100644 --- a/app/models/customer.rb +++ b/app/models/customer.rb @@ -23,6 +23,11 @@ class Customer < ActiveRecord::Base scope :of, ->(enterprise) { where(enterprise_id: enterprise) } + scope :of_regular_shops, lambda { + next scoped unless Spree::Config.accounts_distributor_id + where('enterprise_id <> ?', Spree::Config.accounts_distributor_id) + } + before_create :associate_user private diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb index f6c8f4e0a5..360037cc90 100644 --- a/spec/controllers/api/customers_controller_spec.rb +++ b/spec/controllers/api/customers_controller_spec.rb @@ -23,6 +23,18 @@ module Api expect(json_response.length).to eq 1 expect(json_response.first[:id]).to eq customer1.id end + + context "when the accounts distributor id has been set" do + before do + Spree::Config.set(accounts_distributor_id: customer1.enterprise.id) + end + + it "ignores the customer for that enterprise (if it exists)" do + spree_get :index + expect(response.status).to eq 200 + expect(json_response.length).to eq 0 + end + end end describe "#update" do From 792701297b2be66bdfc74dde3ca59f0dd8f8a493 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 27 Jun 2018 11:12:54 +1000 Subject: [PATCH 020/125] Remove unused scope Enterprise.active_distributors Working on the Spree upgrade, we found that this scope is using the soon obsolete column `spree_products.count_on_hand`. Trying to measure the impact of changing this scope, I couldn't find any use of it. There is a variable called `active_distributors` used when serialising enterprises, but that variable is initialised with `Enterprise.distributors_with_active_order_cycles.ready_for_checkout`, not using the `active_distributors` scope. See also: https://github.com/openfoodfoundation/openfoodnetwork/issues/2013 --- app/models/enterprise.rb | 6 ----- spec/models/enterprise_spec.rb | 42 ---------------------------------- 2 files changed, 48 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 97855812ef..2a7a69df0a 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -129,12 +129,6 @@ class Enterprise < ActiveRecord::Base joins('LEFT OUTER JOIN exchange_variants ON (exchange_variants.exchange_id = exchanges.id)'). joins('LEFT OUTER JOIN spree_variants ON (spree_variants.id = exchange_variants.variant_id)') - scope :active_distributors, lambda { - with_distributed_products_outer.with_order_cycles_as_distributor_outer. - where('(product_distributions.product_id IS NOT NULL AND spree_products.deleted_at IS NULL AND spree_products.available_on <= ? AND spree_products.count_on_hand > 0) OR (order_cycles.id IS NOT NULL AND order_cycles.orders_open_at <= ? AND order_cycles.orders_close_at >= ?)', Time.zone.now, Time.zone.now, Time.zone.now). - select('DISTINCT enterprises.*') - } - scope :distributors_with_active_order_cycles, lambda { with_order_cycles_as_distributor_outer. merge(OrderCycle.active). diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 8fc1b57a0b..54ec420b36 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -321,48 +321,6 @@ describe Enterprise do end end - describe "active_distributors" do - it "finds active distributors by product distributions" do - d = create(:distributor_enterprise) - create(:product, :distributors => [d]) - Enterprise.active_distributors.should == [d] - end - - it "doesn't show distributors of deleted products" do - d = create(:distributor_enterprise) - create(:product, :distributors => [d], :deleted_at => Time.zone.now) - Enterprise.active_distributors.should be_empty - end - - it "doesn't show distributors of unavailable products" do - d = create(:distributor_enterprise) - create(:product, :distributors => [d], :available_on => 1.week.from_now) - Enterprise.active_distributors.should be_empty - end - - it "doesn't show distributors of out of stock products" do - d = create(:distributor_enterprise) - create(:product, :distributors => [d], :on_hand => 0) - Enterprise.active_distributors.should be_empty - end - - it "finds active distributors by order cycles" do - s = create(:supplier_enterprise) - d = create(:distributor_enterprise) - p = create(:product) - create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [p.master]) - Enterprise.active_distributors.should == [d] - end - - it "doesn't show distributors from inactive order cycles" do - s = create(:supplier_enterprise) - d = create(:distributor_enterprise) - p = create(:product) - create(:simple_order_cycle, suppliers: [s], distributors: [d], variants: [p.master], orders_open_at: 1.week.from_now, orders_close_at: 2.weeks.from_now) - Enterprise.active_distributors.should be_empty - end - end - describe "supplying_variant_in" do it "finds producers by supply of master variant" do s = create(:supplier_enterprise) From 306bfa1944c6c94821f6aef2477c8a41cb162a9c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 27 Jun 2018 11:25:44 +1000 Subject: [PATCH 021/125] Remove unused method enterprise method `Enterprise.has_supplied_products_on_hand?` is not used anywhere. --- app/models/enterprise.rb | 4 ---- spec/models/enterprise_spec.rb | 20 -------------------- 2 files changed, 24 deletions(-) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 2a7a69df0a..ea1724f20a 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -193,10 +193,6 @@ class Enterprise < ActiveRecord::Base end end - def has_supplied_products_on_hand? - self.supplied_products.where('count_on_hand > 0').present? - end - def to_param permalink end diff --git a/spec/models/enterprise_spec.rb b/spec/models/enterprise_spec.rb index 54ec420b36..73cd3e1c5b 100644 --- a/spec/models/enterprise_spec.rb +++ b/spec/models/enterprise_spec.rb @@ -489,26 +489,6 @@ describe Enterprise do end end - describe "has_supplied_products_on_hand?" do - before :each do - @supplier = create(:supplier_enterprise) - end - - it "returns false when no products" do - @supplier.should_not have_supplied_products_on_hand - end - - it "returns false when the product is out of stock" do - create(:product, :supplier => @supplier, :on_hand => 0) - @supplier.should_not have_supplied_products_on_hand - end - - it "returns true when the product is in stock" do - create(:product, :supplier => @supplier, :on_hand => 1) - @supplier.should have_supplied_products_on_hand - end - end - describe "finding variants distributed by the enterprise" do it "finds master and other variants" do d = create(:distributor_enterprise) From b7de80dd7f5a0d85bc8d6033af6c19d083e4e901 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 27 Jun 2018 11:41:55 +1000 Subject: [PATCH 022/125] Remove unused count_on_hand setting from spec This spec doesn't need to set the product's `count_on_hand`. The product comes with a count of 3, but what matters is the count of variants. --- spec/controllers/cart_controller_spec.rb | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/spec/controllers/cart_controller_spec.rb b/spec/controllers/cart_controller_spec.rb index f7f48c3a06..5d939b6254 100644 --- a/spec/controllers/cart_controller_spec.rb +++ b/spec/controllers/cart_controller_spec.rb @@ -6,11 +6,7 @@ module OpenFoodNetwork render_views let(:user) { FactoryBot.create(:user) } - let(:product1) do - p1 = FactoryBot.create(:product) - p1.update_column(:count_on_hand, 10) - p1 - end + let(:product1) { FactoryBot.create(:product) } let(:cart) { Cart.create(user: user) } let(:distributor) { FactoryBot.create(:distributor_enterprise) } From 108c4a7abb01da1e336a6765c8e9715c21e4e8f3 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 22 Jun 2018 21:31:47 +1000 Subject: [PATCH 023/125] Add GETTING_STARTED.md and update README.md --- CONTRIBUTING.md | 20 +++------- GETTING_STARTED.md | 96 ++++++++++++++++++++++++++++++++++++++++++++++ README.md | 88 ++++++++---------------------------------- 3 files changed, 116 insertions(+), 88 deletions(-) create mode 100644 GETTING_STARTED.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60bc662403..f24bf3935a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,28 +1,17 @@ # Contributing We love pull requests from everyone. Any contribution is valuable, but there are two issue streams that we especially love people to work on: -1) Our delivery backlog, is managed via a ZenHub board (ZenHub extensions are available for most major browsers). We use a Kanban-style approach, whereby devs pick issues from the top of the backlog which has been organised according to current priorities. If you have some time and are interested in working on some issues from the backlog, please make yourself known on the [#dev](https://openfoodnetwork.slack.com/messages/C2GQ45KNU) channel on Slack and we can direct you to the most appropriate issue to pick up. +1) Our delivery backlog, is managed via a ZenHub board (ZenHub extensions are available for most major browsers). We use a Kanban-style approach, whereby devs pick issues from the top of the backlog which has been organised according to current priorities. If you have some time and are interested in working on some issues from the backlog, please make yourself known on the [#dev][slack-dev] channel on Slack and we can direct you to the most appropriate issue to pick up. 2) Our list of bugs and other self-contained issues that we consider to be a good starting point for new contributors, or devs who aren’t able to commit to seeing a whole feature through. These issues are marked with the `# good first issue` label. ## Set up -Set up your local development environment by following the appropriate guide from the `Development environment setup` section in the [developer wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki). +Please follow the [GETTING_STARTED](GETTING_STARTED.md) guide to set up your local dev environment. -Add an `upstream` remote that points to the main repo: +This guide assumes that the git remote name of the main repo is `upstream` and that your fork is named `origin`. - cd ~/location-of-your-local-ofn-repo - git remote add upstream https://github.com/openfoodfoundation/openfoodnetwork - -If you haven't already done so, fork this repo using the `Fork` button in the top-right corner of this screen. Then ensure that your fork is listed as the `origin` remote on your local machine. - - git remote set-url origin https://github.com/your-username/openfoodnetwork - -Fetch the latest version of `master` from `upstream` (ie. the main repo): - - git fetch upstream master - -Create a new branch on your local machine for (based on `upstream/master`): +Create a new branch on your local machine to make your changes against (based on `upstream/master`): git checkout -b branch-name-here --no-track upstream/master @@ -66,3 +55,4 @@ From here, your pull request will progress through the [Review, Test, Merge & De [rebase]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing/workflow-walkthrough [travis]: https://travis-ci.org/ [semaphore]: https://semaphoreci.com/ +[slack-dev]: https://openfoodnetwork.slack.com/messages/C2GQ45KNU diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md new file mode 100644 index 0000000000..384d8c6043 --- /dev/null +++ b/GETTING_STARTED.md @@ -0,0 +1,96 @@ +### Getting Started + +This is a general guide to setting up an Open Food Network development environment on your local machine. + +The following guides are located in the wiki and provide more OS-specific step-by-step instructions: + +- [Ubuntu Setup Guide][ubuntu] +- [macOS Sierra Setup Guide][sierra] +- [OSX El Capitan Setup Guide][el-capitan] + +### Dependencies + +* Rails 3.2.x +* Ruby 2.1.5 +* PostgreSQL database +* PhantomJS (for testing) +* See Gemfile for a list of gems required + +If you are likely to need to manage multiple version of ruby on your local machine, we recommend version managers such as [rbenv](https://github.com/rbenv/rbenv) or [RVM](https://rvm.io/). + +For those new to Rails, the following tutorial will help get you up to speed with configuring a [Rails environment](http://guides.rubyonrails.org/getting_started.html). + +### Get it + +If you're planning on contributing code to the project (which we [LOVE](CONTRIBUTING.md)), it is a good idea to begin by forking this repo using the `Fork` button in the top-right corner of this screen. You should then be able to use `git clone` to copy your fork onto your local machine. + + git clone https://github.com/YOUR_GITHUB_USERNAME_HERE/openfoodnetwork + +Jump into your new local copy of the Open Food Network: + + cd openfoodnetwork + +And then add an `upstream` remote that points to the main repo: + + git remote add upstream https://github.com/openfoodfoundation/openfoodnetwork + +Fetch the latest version of `master` from `upstream` (ie. the main repo): + + git fetch upstream master + +### Get it running + +When ready, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot. + +If you run into any other issues getting your local environment up and running please consult [the wiki](wiki). + +If still you get stuck do not hesitate to open an issue reporting the full output of the script. + +Now, your dreams of spinning up a development server can be realised: + + bundle exec rails server + +To login as Spree default user, use: + + email: spree@example.com + password: spree123 + +### Testing + +Tests, both unit and integration, are based on RSpec. To run the test suite, first prepare the test database: + + bundle exec rake db:test:prepare + +Then the tests can be run with: + + bundle exec rspec spec + +The project is configured to use [Zeus](zeus) to reduce the pre-test startup time while Rails loads. See the [Zeus GitHub page](zeus) for usage instructions. + +Once [npm dependencies are installed](karma), AngularJS tests can be run with: + + ./script/karma run + +If you want karma to automatically rerun the tests on file modification, use: + + ./script/karma start + +### Multilingual +Do not forget to run `rake tmp:cache:clear` after locales are updated to reload I18n js translations. + +### Rubocop +The project is configured to use [rubocop](rubocop) to automatically check for style and syntax errors. + +You can run rubocop against your changes using: + + rubocop + + +[developer-wiki]: https://github.com/openfoodfoundation/openfoodnetwork/wiki +[sierra]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup:-macOS-(Sierra) +[el-capitan]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup:-OS-X-(El-Capitan) +[ubuntu]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Development-Environment-Setup:-Ubuntu +[wiki]: https://github.com/openfoodfoundation/openfoodnetwork/wiki +[zeus]: https://github.com/burke/zeus +[rubocop]: https://rubocop.readthedocs.io/en/latest/ +[karma]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Karma diff --git a/README.md b/README.md index 018e605ad7..0c75996004 100644 --- a/README.md +++ b/README.md @@ -10,85 +10,22 @@ Supported by the Open Food Foundation, we are proudly open source and not-for-pr We're part of global movement - get involved! -* Fill in this short survey to tell us who you are and what you want to do with OFN: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit# -* Find out more and join in the conversation - http://openfoodnetwork.org +* Join the conversation [on Slack](slack). Make sure you introduce yourself in the #general channel +* Head to [https://openfoodnetwork.org](https://openfoodnetwork.org) for more information about the global OFN project +* Check out the [User Guide](https://guide.openfoodnetwork.org/) for a list of features and tutorials +## Contributing -## Getting started +If you are interested in contributing to the OFN in any capacity, please introducing yourself [on Slack](slack), and have a look through our [Contributor Guide](contributor-guide) -Below are instructions for setting up a development environment for Open Food Network. More information is in the [developer wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki). +Our [GETTING_STARTED](GETTING_STARTED.md) and [CONTRIBUTING](CONTRIBUTING.md) guides are the best place to start for developers looking to set up a development environment and make contributions to the codebase. -If you're interested in provisioning a server, see [the project's Ansible playbooks](https://github.com/openfoodfoundation/ofn_deployment). +## Provisioning +If you're interested in provisioning a server, see [ofn-install](ofn-install) for the project's Ansible playbooks. -### Dependencies +We also have a [Super Admin Guide](super-admin-guide) to help with configuration of new servers. -* Rails 3.2.x -* Ruby 2.1.5 -* PostgreSQL database -* PhantomJS (for testing) -* See Gemfile for a list of gems required - - -### Get it - -The source code is managed with Git (a version control system) and -hosted at GitHub. - -You can view the code at: - - https://github.com/openfoodfoundation/openfoodnetwork - -You can download the source with the command: - - git clone https://github.com/openfoodfoundation/openfoodnetwork.git - - -### Get it running - -For those new to Rails, the following tutorial will help get you up to speed with configuring a [Rails environment](http://guides.rubyonrails.org/getting_started.html). - -When ready, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot. - -If you run into any other issues getting your local environment up and running please consult [the wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki). - -If still you get stuck do not hesitate to open an issue reporting the full output of the script. - -Now, your dreams of spinning up a development server can be realised: -``` -bundle exec rails server -``` -To login as Spree default user, use: -``` -email: spree@example.com -password: spree123 -``` -### Testing - -Tests, both unit and integration, are based on RSpec. To run the test suite, first prepare the test database: - - bundle exec rake db:test:prepare - -Then the tests can be run with: - - bundle exec rspec spec - -The site is configured to use -[Zeus](https://github.com/burke/zeus) to reduce the pre-test -startup time while Rails loads. See the Zeus github page for -usage instructions. - -Once [npm dependencies are -installed](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Karma), AngularJS tests can be run with: - - ./script/karma run - -If you want karma to automatically rerun the tests on file modification, use: - - ./script/karma start - -### Multilingual -Do not forget to run `rake tmp:cache:clear` after locales are updated to reload I18n js translations. ## Credits @@ -110,4 +47,9 @@ Do not forget to run `rake tmp:cache:clear` after locales are updated to reload ## Licence -Copyright (c) 2012 - 2015 Open Food Foundation, released under the AGPL licence. +Copyright (c) 2012 - 2018 Open Food Foundation, released under the AGPL licence. + +[slack]: https://join.slack.com/t/openfoodnetwork/shared_invite/enQtMzU2Mjk5MDc2MjA5LTM4ZTAzZjIwNzIxMmU5ODFiNWY1MTU2ZWUyNzQwNjdjNTY0N2VhY2UwOGU4ZmVjNzYyZDU2NjY3NzZkZmQwYjk +[contributor-guide]: https://ofn-user-guide.gitbook.io/ofn-contributor-guide/who-are-we +[ofn-install]: https://github.com/openfoodfoundation/ofn-install +[super-admin-guide]: https://ofn-user-guide.gitbook.io/ofn-super-admin-guide From c496d0f14d77a769aa37e70c2b4963b891a7d3d4 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 10 May 2018 17:49:13 +1000 Subject: [PATCH 024/125] Allow credit owed on payments made via stripe to be refunded via the admin section --- app/assets/stylesheets/admin/icons.css.scss | 1 + app/models/spree/gateway/stripe_connect.rb | 5 ++ .../spree/admin/payments_controller_spec.rb | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/app/assets/stylesheets/admin/icons.css.scss b/app/assets/stylesheets/admin/icons.css.scss index e7737ce8e9..9bd900d083 100644 --- a/app/assets/stylesheets/admin/icons.css.scss +++ b/app/assets/stylesheets/admin/icons.css.scss @@ -1,3 +1,4 @@ @import 'plugins/font-awesome'; .icon-refund:before { @extend .icon-ok:before } +.icon-credit:before { @extend .icon-ok:before } diff --git a/app/models/spree/gateway/stripe_connect.rb b/app/models/spree/gateway/stripe_connect.rb index 6efd2f79ef..e9e70671b2 100644 --- a/app/models/spree/gateway/stripe_connect.rb +++ b/app/models/spree/gateway/stripe_connect.rb @@ -43,6 +43,11 @@ module Spree provider.void(response_code, gateway_options) end + def credit(money, _creditcard, response_code, gateway_options) + gateway_options[:stripe_account] = stripe_account_id + provider.refund(money, response_code, gateway_options) + end + def create_profile(payment) return unless payment.source.gateway_customer_profile_id.nil? diff --git a/spec/controllers/spree/admin/payments_controller_spec.rb b/spec/controllers/spree/admin/payments_controller_spec.rb index 50edfc468a..7bf9e6e522 100644 --- a/spec/controllers/spree/admin/payments_controller_spec.rb +++ b/spec/controllers/spree/admin/payments_controller_spec.rb @@ -66,5 +66,59 @@ describe Spree::Admin::PaymentsController, type: :controller do end end end + + context "requesting a partial credit on a payment" do + let(:params) { { id: payment.id, order_id: order.number, e: :credit } } + + # Required for the respond override in the controller decorator to work + before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } + + context "that was processed by stripe" do + let!(:payment_method) { create(:stripe_payment_method, distributors: [shop], preferred_enterprise_id: shop.id) } + let!(:payment) { create(:payment, order: order, state: 'completed', payment_method: payment_method, response_code: 'ch_1a2b3c', amount: order.total + 5) } + + + before do + allow(Stripe).to receive(:api_key) { "sk_test_12345" } + end + + context "where the request succeeds" do + before do + stub_request(:post, "https://sk_test_12345:@api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + to_return(:status => 200, :body => JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "partially refunds the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + expect(order.outstanding_balance).to eq 0 + end + end + + context "where the request fails" do + before do + stub_request(:post, "https://sk_test_12345:@api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + to_return(:status => 200, :body => JSON.generate(error: { message: "Bup-bow!"}) ) + end + + it "does not void the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq -5 + expect(flash[:error]).to eq "Bup-bow!" + end + end + end + end end end From 2da623436258b66e6cd0b6375fb5a1d181413653 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 7 Jun 2018 15:50:28 +1000 Subject: [PATCH 025/125] Add spec for StripeGateway#refund --- .../spree/gateway/stripe_connect_spec.rb | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/spec/models/spree/gateway/stripe_connect_spec.rb b/spec/models/spree/gateway/stripe_connect_spec.rb index 4e39a7812e..eb9bacdd2c 100644 --- a/spec/models/spree/gateway/stripe_connect_spec.rb +++ b/spec/models/spree/gateway/stripe_connect_spec.rb @@ -2,10 +2,11 @@ require 'spec_helper' describe Spree::Gateway::StripeConnect, type: :model do let(:provider) do - double('provider').tap do |p| - p.stub(:purchase) - p.stub(:authorize) - p.stub(:capture) + instance_double(ActiveMerchant::Billing::StripeGateway).tap do |p| + allow(p).to receive(:purchase) + allow(p).to receive(:authorize) + allow(p).to receive(:capture) + allow(p).to receive(:refund) end end @@ -14,8 +15,8 @@ describe Spree::Gateway::StripeConnect, type: :model do before do allow(Stripe).to receive(:api_key) { "sk_test_123456" } allow(subject).to receive(:stripe_account_id) { stripe_account_id } - subject.stub(:options_for_purchase_or_auth).and_return(['money', 'cc', 'opts']) - subject.stub(:provider).and_return provider + allow(subject).to receive(:options_for_purchase_or_auth).and_return(['money', 'cc', 'opts']) + allow(subject).to receive(:provider).and_return provider end describe "#token_from_card_profile_ids" do @@ -70,4 +71,22 @@ describe Spree::Gateway::StripeConnect, type: :model do expect(subject.send(:tokenize_instance_customer_card, customer_id, card_id)).to eq token_mock[:id] end end + + describe "#credit" do + let(:gateway_options) { { some: 'option' } } + let(:money) { double(:money) } + let(:response_code) { double(:response_code) } + + before do + subject.credit(money, double(:creditcard), response_code, gateway_options) + end + + it "delegates to ActiveMerchant::Billing::StripeGateway#refund" do + expect(provider).to have_received(:refund) + end + + it "adds the stripe_account to the gateway options hash" do + expect(provider).to have_received(:refund).with(money, response_code, hash_including(stripe_account: stripe_account_id)) + end + end end From 82e3016a2682c3885afbfd708270bb0c8e49c8ec Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 7 Jun 2018 15:56:38 +1000 Subject: [PATCH 026/125] Add comment to StripeGateway wrapper methods indicating that they are named by Spree --- app/models/spree/gateway/stripe_connect.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/spree/gateway/stripe_connect.rb b/app/models/spree/gateway/stripe_connect.rb index e9e70671b2..2f192eb655 100644 --- a/app/models/spree/gateway/stripe_connect.rb +++ b/app/models/spree/gateway/stripe_connect.rb @@ -31,6 +31,7 @@ module Spree StripeAccount.find_by_enterprise_id(preferred_enterprise_id).andand.stripe_user_id end + # NOTE: the name of this method is determined by Spree::Payment::Processing def purchase(money, creditcard, gateway_options) provider.purchase(*options_for_purchase_or_auth(money, creditcard, gateway_options)) rescue Stripe::StripeError => e @@ -38,11 +39,13 @@ module Spree failed_activemerchant_billing_response(e.message) end + # NOTE: the name of this method is determined by Spree::Payment::Processing def void(response_code, _creditcard, gateway_options) gateway_options[:stripe_account] = stripe_account_id provider.void(response_code, gateway_options) end + # NOTE: the name of this method is determined by Spree::Payment::Processing def credit(money, _creditcard, response_code, gateway_options) gateway_options[:stripe_account] = stripe_account_id provider.refund(money, response_code, gateway_options) From 09534b41e9a806daf91c5633d0b03e009e297b30 Mon Sep 17 00:00:00 2001 From: Frank West Date: Fri, 15 Jun 2018 11:07:39 -0700 Subject: [PATCH 027/125] Remove taxon when primary taxon is changed We are adding taxons to the product as you change the primary taxon. However we never remove the previous primary taxon so it forces the user to update the taxons manually. This can be a big problem if you are bulk updating products. We now remove the taxon that matches the previously set primary taxon. --- app/models/spree/product_decorator.rb | 6 ++++++ spec/models/spree/product_spec.rb | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index b9d45c4039..18220aaafd 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -38,6 +38,7 @@ Spree::Product.class_eval do before_validation :sanitize_permalink before_save :add_primary_taxon_to_taxons after_touch :touch_distributors + after_save :remove_previous_primary_taxon_from_taxons after_save :ensure_standard_variant after_save :update_units after_save :refresh_products_cache @@ -245,6 +246,11 @@ Spree::Product.class_eval do taxons << primary_taxon unless taxons.include? primary_taxon end + def remove_previous_primary_taxon_from_taxons + return unless primary_taxon_id_changed? && primary_taxon_id_was + taxons.destroy(primary_taxon_id_was) + end + def self.all_variant_unit_option_types Spree::OptionType.where('name LIKE ?', 'unit_%%') end diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb index bf443bf2b9..f90de704e2 100644 --- a/spec/models/spree/product_spec.rb +++ b/spec/models/spree/product_spec.rb @@ -193,6 +193,22 @@ module Spree expect { product.delete }.to change { distributor.reload.updated_at } end end + + it "adds the primary taxon to the product's taxon list" do + taxon = create(:taxon) + product = create(:product, primary_taxon: taxon) + + expect(product.taxons).to include(taxon) + end + + it "removes the previous primary taxon from the taxon list" do + original_taxon = create(:taxon) + product = create(:product, primary_taxon: original_taxon) + product.primary_taxon = create(:taxon) + product.save! + + expect(product.taxons).not_to include(original_taxon) + end end describe "scopes" do From fc2844a3d5e1fcf97e389c2ef4d76382f8e2b556 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 4 May 2018 11:38:35 +1000 Subject: [PATCH 028/125] Add default_card method to user model --- app/models/spree/user_decorator.rb | 4 ++++ spec/models/spree/user_spec.rb | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/app/models/spree/user_decorator.rb b/app/models/spree/user_decorator.rb index 3877428c86..8ae76a11b4 100644 --- a/app/models/spree/user_decorator.rb +++ b/app/models/spree/user_decorator.rb @@ -73,6 +73,10 @@ Spree.user_class.class_eval do owned_enterprises(:reload).size < enterprise_limit end + def default_card + credit_cards.where(is_default: true).first + end + private def limit_owned_enterprises diff --git a/spec/models/spree/user_spec.rb b/spec/models/spree/user_spec.rb index 39a1ce530e..3cd4da93af 100644 --- a/spec/models/spree/user_spec.rb +++ b/spec/models/spree/user_spec.rb @@ -126,4 +126,32 @@ describe Spree.user_class do end end end + + describe "default_card" do + let(:user) { create(:user) } + + context "when the user has no credit cards" do + it "returns nil" do + expect(user.default_card).to be nil + end + end + + context "when the user has one credit card" do + let!(:card) { create(:credit_card, user: user) } + + it "should be assigned as the default and be returned" do + expect(card.reload.is_default).to be true + expect(user.default_card.id).to be card.id + end + end + + context "when the user has more than one card" do + let!(:non_default_card) { create(:credit_card, user: user) } + let!(:default_card) { create(:credit_card, user: user, is_default: true) } + + it "returns the card which is specified as the default" do + expect(user.default_card.id).to be default_card.id + end + end + end end From 45895e9924f8344658047c3decb71dd47d3020c9 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 4 May 2018 11:39:26 +1000 Subject: [PATCH 029/125] Use the user's default card to pay for subcriptions --- lib/open_food_network/subscription_payment_updater.rb | 2 +- .../open_food_network/subscription_payment_updater_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/open_food_network/subscription_payment_updater.rb b/lib/open_food_network/subscription_payment_updater.rb index 2a166def68..eb33aaf2f2 100644 --- a/lib/open_food_network/subscription_payment_updater.rb +++ b/lib/open_food_network/subscription_payment_updater.rb @@ -47,7 +47,7 @@ module OpenFoodNetwork end def saved_credit_card - order.subscription.credit_card + order.user.default_card end def errors_present? diff --git a/spec/lib/open_food_network/subscription_payment_updater_spec.rb b/spec/lib/open_food_network/subscription_payment_updater_spec.rb index 5fb76a0c86..8d590f59b7 100644 --- a/spec/lib/open_food_network/subscription_payment_updater_spec.rb +++ b/spec/lib/open_food_network/subscription_payment_updater_spec.rb @@ -151,7 +151,7 @@ module OpenFoodNetwork let!(:payment) { create(:payment, source: nil) } before { allow(updater).to receive(:payment) { payment } } - context "when no credit card is specified by the subscription" do + context "when no saved credit card is found" do before { allow(updater).to receive(:saved_credit_card) { nil } } it "returns false and down not update the payment source" do @@ -161,7 +161,7 @@ module OpenFoodNetwork end end - context "when a credit card is specified by the subscription" do + context "when a saved credit card is found" do let(:credit_card) { create(:credit_card) } before { allow(updater).to receive(:saved_credit_card) { credit_card } } From cf8ca1f8c10e3a0dbb81daf71e7cba31a8b7843b Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 4 May 2018 12:06:03 +1000 Subject: [PATCH 030/125] Add show action to Admin::CustomersController --- app/controllers/admin/customers_controller.rb | 4 +++ app/models/spree/ability_decorator.rb | 2 +- config/routes.rb | 2 +- .../admin/customers_controller_spec.rb | 33 +++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/customers_controller.rb b/app/controllers/admin/customers_controller.rb index 6ff6278b10..d57340b653 100644 --- a/app/controllers/admin/customers_controller.rb +++ b/app/controllers/admin/customers_controller.rb @@ -23,6 +23,10 @@ module Admin end end + def show + render_as_json @customer + end + def create @customer = Customer.new(params[:customer]) if user_can_create_customer? diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index daf8161142..f5d05c9a3d 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -257,7 +257,7 @@ class AbilityDecorator can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :xero_invoices], :report can [:create], Customer - can [:admin, :index, :update, :destroy, :addresses, :cards], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id) + can [:admin, :index, :update, :destroy, :addresses, :cards, :show], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id) can [:admin, :new, :index], Subscription can [:create, :edit, :update, :cancel, :pause, :unpause], Subscription do |subscription| user.enterprises.include?(subscription.shop) diff --git a/config/routes.rb b/config/routes.rb index ba4da8ae2e..0ab7fe1a3c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -147,7 +147,7 @@ Openfoodnetwork::Application.routes.draw do resources :inventory_items, only: [:create, :update] - resources :customers, only: [:index, :create, :update, :destroy] do + resources :customers, only: [:index, :create, :update, :destroy, :show] do get :addresses, on: :member get :cards, on: :member end diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index 41a639c4b3..bd9ff1f0f7 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -235,4 +235,37 @@ describe Admin::CustomersController, type: :controller do end end end + + describe "show" do + let(:enterprise) { create(:distributor_enterprise) } + let(:another_enterprise) { create(:distributor_enterprise) } + + context "json" do + let!(:customer) { create(:customer, enterprise: enterprise) } + + context "where I manage the customer's enterprise" do + render_views + + before do + controller.stub spree_current_user: enterprise.owner + end + + it "renders the customer as json" do + spree_get :show, format: :json, id: customer.id + expect(JSON.parse(response.body)["id"]).to eq customer.id + end + end + + context "where I don't manage the customer's enterprise" do + before do + controller.stub spree_current_user: another_enterprise.owner + end + + it "prevents me from updating the customer" do + spree_get :show, format: :json, id: customer.id + expect(response).to redirect_to spree.unauthorized_path + end + end + end + end end From 21c24eb69b9237facbff1053b2f05ce718a8eb02 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 9 May 2018 11:35:13 +1000 Subject: [PATCH 031/125] Validate presence and auth of default card for customer --- app/services/subscription_validator.rb | 9 ++++---- spec/services/subscription_validator_spec.rb | 23 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/app/services/subscription_validator.rb b/app/services/subscription_validator.rb index d7dcbd39f3..14cae211a6 100644 --- a/app/services/subscription_validator.rb +++ b/app/services/subscription_validator.rb @@ -76,10 +76,11 @@ class SubscriptionValidator end def credit_card_ok? - return unless payment_method.andand.type == "Spree::Gateway::StripeConnect" - return errors.add(:credit_card, :blank) unless credit_card_id - return if customer.andand.user.andand.credit_card_ids.andand.include? credit_card_id - errors.add(:credit_card, :not_available) + return unless customer && payment_method + return unless payment_method.type == "Spree::Gateway::StripeConnect" + return errors.add(:credit_card, :charges_not_allowed) unless customer.allow_charges + return if customer.user.andand.default_card.present? + errors.add(:credit_card, :no_default_card) end def subscription_line_items_present? diff --git a/spec/services/subscription_validator_spec.rb b/spec/services/subscription_validator_spec.rb index 59db5415b8..43ab894aa6 100644 --- a/spec/services/subscription_validator_spec.rb +++ b/spec/services/subscription_validator_spec.rb @@ -332,10 +332,10 @@ describe SubscriptionValidator do context "when using the StripeConnect payment gateway" do let(:payment_method) { instance_double(Spree::PaymentMethod, type: "Spree::Gateway::StripeConnect") } - before { expect(subscription).to receive(:credit_card_id).at_least(:once) { credit_card_id } } + before { expect(subscription).to receive(:customer).at_least(:once) { customer } } - context "when a credit card is not present" do - let(:credit_card_id) { nil } + context "when the customer does not allow charges" do + let(:customer) { instance_double(Customer, allow_charges: false) } it "adds an error and returns false" do expect(validator.valid?).to be false @@ -343,12 +343,11 @@ describe SubscriptionValidator do end end - context "when a credit card is present" do - let(:credit_card_id) { 12 } - before { expect(subscription).to receive(:customer).at_least(:once) { customer } } + context "when the customer allows charges" do + let(:customer) { instance_double(Customer, allow_charges: true) } context "and the customer is not associated with a user" do - let(:customer) { instance_double(Customer, user: nil) } + before { allow(customer).to receive(:user) { nil } } it "adds an error and returns false" do expect(validator.valid?).to be false @@ -357,10 +356,10 @@ describe SubscriptionValidator do end context "and the customer is associated with a user" do - let(:customer) { instance_double(Customer, user: user) } + before { expect(customer).to receive(:user).once { user } } - context "and the user has no credit cards which match that specified" do - let(:user) { instance_double(Spree::User, credit_card_ids: [1, 2, 3, 4]) } + context "and the user has no default card set" do + let(:user) { instance_double(Spree::User, default_card: nil) } it "adds an error and returns false" do expect(validator.valid?).to be false @@ -368,8 +367,8 @@ describe SubscriptionValidator do end end - context "and the user has a credit card which matches that specified" do - let(:user) { instance_double(Spree::User, credit_card_ids: [1, 2, 3, 12]) } + context "and the user has a default card set" do + let(:user) { instance_double(Spree::User, default_card: 'some card') } it "returns true" do expect(validator.valid?).to be true From a03dd1e10c16f8df313b4c3649c2d1ff892b6d19 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 9 May 2018 11:37:23 +1000 Subject: [PATCH 032/125] Serialize default card auth and presence for Customers --- app/serializers/api/admin/customer_serializer.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/serializers/api/admin/customer_serializer.rb b/app/serializers/api/admin/customer_serializer.rb index 327ac97189..ea666f308f 100644 --- a/app/serializers/api/admin/customer_serializer.rb +++ b/app/serializers/api/admin/customer_serializer.rb @@ -1,5 +1,6 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name + attributes :allow_charges, :default_card_present? has_one :ship_address, serializer: Api::AddressSerializer has_one :bill_address, serializer: Api::AddressSerializer @@ -18,4 +19,9 @@ class Api::Admin::CustomerSerializer < ActiveModel::Serializer tag_rule_map || { text: tag, rules: nil } end end + + def default_card_present? + return unless object.user + object.user.default_card.present? + end end From c71a5ec0df7a766b7de80c046c778c75408d50ee Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 9 May 2018 11:39:56 +1000 Subject: [PATCH 033/125] Update subscription form to use new card validations for Stripe payment method --- .../controllers/details_controller.js.coffee | 52 ++++++++++--------- .../services/credit_card_resource.js.coffee | 5 -- .../services/customer_resource.js.coffee | 2 + .../admin/subscriptions/_details.html.haml | 11 ++-- config/locales/en.yml | 8 +-- spec/features/admin/subscriptions_spec.rb | 24 ++++----- 6 files changed, 50 insertions(+), 52 deletions(-) delete mode 100644 app/assets/javascripts/admin/subscriptions/services/credit_card_resource.js.coffee create mode 100644 app/assets/javascripts/admin/subscriptions/services/customer_resource.js.coffee diff --git a/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee b/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee index b3afc1c5d6..b4ace027dc 100644 --- a/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee +++ b/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee @@ -1,38 +1,42 @@ -angular.module("admin.subscriptions").controller "DetailsController", ($scope, $http, CreditCardResource, StatusMessage) -> +angular.module("admin.subscriptions").controller "DetailsController", ($scope, $http, CustomerResource, StatusMessage) -> $scope.cardRequired = false $scope.registerNextCallback 'details', -> $scope.subscription_form.$submitted = true - if $scope.subscription_details_form.$valid - $scope.subscription_form.$setPristine() - StatusMessage.clear() - $scope.setView('address') - else - StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error') + return unless $scope.validate() + $scope.subscription_form.$setPristine() + StatusMessage.clear() + $scope.setView('address') $scope.$watch "subscription.customer_id", (newValue, oldValue) -> return if !newValue? - $scope.loadAddresses(newValue) unless $scope.subscription.id? - $scope.loadCreditCards(newValue) + $scope.loadCustomer(newValue) unless $scope.subscription.id? $scope.$watch "subscription.payment_method_id", (newValue, oldValue) -> return if !newValue? paymentMethod = ($scope.paymentMethods.filter (pm) -> pm.id == newValue)[0] return unless paymentMethod? - if paymentMethod.type == "Spree::Gateway::StripeConnect" - $scope.cardRequired = true - else - $scope.cardRequired = false - $scope.subscription.credit_card_id = null + $scope.cardRequired = (paymentMethod.type == "Spree::Gateway::StripeConnect") + $scope.loadCustomer() if $scope.cardRequired && !$scope.customer - $scope.loadAddresses = (customer_id) -> - $http.get("/admin/customers/#{customer_id}/addresses") - .success (response) => - delete response.bill_address.id - delete response.ship_address.id - angular.extend($scope.subscription.bill_address, response.bill_address) - angular.extend($scope.subscription.ship_address, response.ship_address) - $scope.shipAddressFromBilling() unless response.ship_address.address1? + $scope.loadCustomer = -> + params = { id: $scope.subscription.customer_id } + $scope.customer = CustomerResource.get params, (response) -> + for address in ['bill_address','ship_address'] + return unless response[address] + delete response[address].id + return if $scope.subscription[address].address1? + angular.extend($scope.subscription[address], response[address]) + $scope.shipAddressFromBilling() unless response.ship_address?.address1? - $scope.loadCreditCards = (customer_id) -> - $scope.creditCards = CreditCardResource.index(customer_id: customer_id) + $scope.validate = -> + return true if $scope.subscription_details_form.$valid && $scope.creditCardOk() + StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error') + false + + $scope.creditCardOk = -> + return true unless $scope.cardRequired + return false unless $scope.customer + return false unless $scope.customer.allow_charges + return false unless $scope.customer.default_card_present + true diff --git a/app/assets/javascripts/admin/subscriptions/services/credit_card_resource.js.coffee b/app/assets/javascripts/admin/subscriptions/services/credit_card_resource.js.coffee deleted file mode 100644 index 0bb31cf3b0..0000000000 --- a/app/assets/javascripts/admin/subscriptions/services/credit_card_resource.js.coffee +++ /dev/null @@ -1,5 +0,0 @@ -angular.module("admin.subscriptions").factory 'CreditCardResource', ($resource) -> - resource = $resource '/admin/customers/:customer_id/cards.json', {}, - 'index': - method: 'GET' - isArray: true diff --git a/app/assets/javascripts/admin/subscriptions/services/customer_resource.js.coffee b/app/assets/javascripts/admin/subscriptions/services/customer_resource.js.coffee new file mode 100644 index 0000000000..56c999278e --- /dev/null +++ b/app/assets/javascripts/admin/subscriptions/services/customer_resource.js.coffee @@ -0,0 +1,2 @@ +angular.module("admin.subscriptions").factory 'CustomerResource', ($resource) -> + $resource '/admin/customers/:id.json' diff --git a/app/views/admin/subscriptions/_details.html.haml b/app/views/admin/subscriptions/_details.html.haml index 6fa57f41f4..7dedbf26f4 100644 --- a/app/views/admin/subscriptions/_details.html.haml +++ b/app/views/admin/subscriptions/_details.html.haml @@ -14,19 +14,16 @@ .error{ ng: { repeat: 'error in errors.schedule', show: 'subscription_details_form.schedule_id.$pristine'} } {{ error }} .row - .columns.alpha.field{ ng: { class: '{four: cardRequired, seven: !cardRequired}' } } + .seven.columns.alpha.field %label{ for: 'payment_method_id'} = t('admin.payment_method') %span.with-tip.icon-question-sign{ data: { powertip: "#{t('.allowed_payment_method_types_tip')}" } } %input.ofn-select2.fullwidth#payment_method_id{ name: 'payment_method_id', type: 'number', data: 'paymentMethods', required: true, placeholder: t('admin.choose'), ng: { model: 'subscription.payment_method_id' } } .error{ ng: { show: 'subscription_form.$submitted && subscription_details_form.payment_method_id.$error.required' } }= t(:error_required) .error{ ng: { repeat: 'error in errors.payment_method', show: 'subscription_details_form.payment_method_id.$pristine' } } {{ error }} - .three.columns.field{ ng: { show: 'cardRequired' } } - %label{ for: 'credit_card_id'}= t('.credit_card') - %input.ofn-select2.fullwidth#credit_card_id{ name: 'credit_card_id', type: 'number', data: 'creditCards', text: 'formatted', placeholder: t('admin.choose'), ng: { model: 'subscription.credit_card_id', required: "cardRequired" } } - .error{ ng: { show: 'creditCards.$promise && creditCards.$resolved && creditCards.length == 0' } }= t('.no_cards_available') - .error{ ng: { show: 'subscription_form.$submitted && subscription_details_form.credit_card_id.$error.required' } }= t(:error_required) - .error{ ng: { repeat: 'error in errors.credit_card', show: 'subscription_details_form.credit_card_id.$pristine' } } {{ error }} + .error{ ng: { show: 'cardRequired && customer.$promise && customer.$resolved && !customer.allow_charges' } }= t('.charges_not_allowed') + .error{ ng: { show: 'cardRequired && customer.$promise && customer.$resolved && customer.allow_charges && !customer.default_card_present' } }= t('.no_default_card') + .error{ ng: { repeat: 'error in errors.credit_card', show: 'subscription_details_form.payment_method_id.$pristine' } } {{ error }} .two.columns   .seven.columns.omega.field %label{ for: 'shipping_method_id'}= t('admin.shipping_method') diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a34f8b9ff..87a6799143 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -100,8 +100,8 @@ en: shipping_method: not_available_to_shop: "is not available to %{shop}" credit_card: - not_available: "is not available" - blank: "is required" + charges_not_allowed: "charges are not allowed by this customer" + no_default_card: "not available for this customer" devise: confirmations: send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." @@ -1025,7 +1025,9 @@ en: invalid_error: Oops! Please fill in all of the required fields... allowed_payment_method_types_tip: Only Cash and Stripe payment methods may be used at the moment credit_card: Credit Card - no_cards_available: No cards available + charges_not_allowed: Charges are not allowed by this customer + no_default_card: Customer has no cards available to charge + card_ok: Customer has a card available to charge loading_flash: loading: LOADING SUBSCRIPTIONS review: diff --git a/spec/features/admin/subscriptions_spec.rb b/spec/features/admin/subscriptions_spec.rb index ad115cbb5a..556164386a 100644 --- a/spec/features/admin/subscriptions_spec.rb +++ b/spec/features/admin/subscriptions_spec.rb @@ -124,9 +124,7 @@ feature 'Subscriptions' do let(:address) { create(:address) } let!(:customer_user) { create(:user) } let!(:credit_card1) { create(:credit_card, user: customer_user, cc_type: 'visa', last_digits: 1111, month: 10, year: 2030) } - let!(:credit_card2) { create(:credit_card, user: customer_user, cc_type: 'master', last_digits: 9999, month: 2, year: 2044) } - let!(:credit_card3) { create(:credit_card, cc_type: 'visa', last_digits: 5555, month: 6, year: 2066) } - let!(:customer) { create(:customer, enterprise: shop, bill_address: address, user: customer_user) } + let!(:customer) { create(:customer, enterprise: shop, bill_address: address, user: customer_user, allow_charges: true) } let!(:product1) { create(:product, supplier: shop) } let!(:product2) { create(:product, supplier: shop) } let!(:variant1) { create(:variant, product: product1, unit_value: '100', price: 12.00, option_values: []) } @@ -149,21 +147,14 @@ feature 'Subscriptions' do select2_select payment_method.name, from: 'payment_method_id' select2_select shipping_method.name, from: 'shipping_method_id' - # Credit card - card1_option = "Visa x-1111 #{I18n.t(:card_expiry_abbreviation)}:10/2030" - card2_option = "Master x-9999 #{I18n.t(:card_expiry_abbreviation)}:02/2044" - card3_option = "Visa x-5555 #{I18n.t(:card_expiry_abbreviation)}:06/2066" - expect(page).to have_select2 'credit_card_id', with_options: [card1_option, card2_option], without_options: [card3_option] - - # No date or credit card filled out, so error returned + # No date, so error returned click_button('Next') - expect(page).to have_content 'can\'t be blank', count: 2 + expect(page).to have_content 'can\'t be blank', count: 1 expect(page).to have_content 'Oops! Please fill in all of the required fields...' find_field('begins_at').click within(".ui-datepicker-calendar") do find('.ui-datepicker-today').click end - select2_select card2_option, from: 'credit_card_id' click_button('Next') expect(page).to have_content 'BILLING ADDRESS' @@ -263,7 +254,6 @@ feature 'Subscriptions' do expect(subscription.shipping_method).to eq shipping_method expect(subscription.bill_address.firstname).to eq 'Freda' expect(subscription.ship_address.firstname).to eq 'Freda' - expect(subscription.credit_card_id).to eq credit_card2.id # Standing Line Items are created expect(subscription.subscription_line_items.count).to eq 1 @@ -287,6 +277,7 @@ feature 'Subscriptions' do let!(:variant3_oc) { create(:simple_order_cycle, coordinator: shop, orders_open_at: 2.days.from_now, orders_close_at: 7.days.from_now) } let!(:variant3_ex) { variant3_oc.exchanges.create(sender: shop, receiver: shop, variants: [variant3]) } let!(:payment_method) { create(:payment_method, distributors: [shop]) } + let!(:stripe_payment_method) { create(:stripe_payment_method, name: 'Credit Card', distributors: [shop], preferred_enterprise_id: shop.id) } let!(:shipping_method) { create(:shipping_method, distributors: [shop]) } let!(:subscription) { create(:subscription, @@ -306,6 +297,13 @@ feature 'Subscriptions' do click_button 'edit-details' expect(page).to have_selector '#s2id_customer_id.select2-container-disabled' expect(page).to have_selector '#s2id_schedule_id.select2-container-disabled' + + # Can't use a Stripe payment method because customer does not allow it + select2_select stripe_payment_method.name, from: 'payment_method_id' + expect(page).to have_content I18n.t('admin.subscriptions.details.charges_not_allowed') + click_button 'Save Changes' + expect(page).to have_content 'Credit card charges are not allowed by this customer' + select2_select payment_method.name, from: 'payment_method_id' click_button 'Review' # Existing products should be visible From e0d46aa10549b0ae18c8a0745e374291b9fcaf07 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 10 May 2018 13:08:03 +1000 Subject: [PATCH 034/125] Add new serializer to allow search for customer addresses --- .../controllers/details_controller.js.coffee | 1 + app/controllers/admin/customers_controller.rb | 6 +++++- .../admin/subscription_customer_serializer.rb | 20 +++++++++++++++++++ .../subscription_customer_serializer_spec.rb | 18 +++++++++++++++++ 4 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 app/serializers/api/admin/subscription_customer_serializer.rb create mode 100644 spec/serializers/admin/subscription_customer_serializer_spec.rb diff --git a/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee b/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee index b4ace027dc..55d2a46b42 100644 --- a/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee +++ b/app/assets/javascripts/admin/subscriptions/controllers/details_controller.js.coffee @@ -21,6 +21,7 @@ angular.module("admin.subscriptions").controller "DetailsController", ($scope, $ $scope.loadCustomer = -> params = { id: $scope.subscription.customer_id } + params.ams_prefix = 'subscription' unless $scope.subscription.id $scope.customer = CustomerResource.get params, (response) -> for address in ['bill_address','ship_address'] return unless response[address] diff --git a/app/controllers/admin/customers_controller.rb b/app/controllers/admin/customers_controller.rb index d57340b653..0e7eec1e90 100644 --- a/app/controllers/admin/customers_controller.rb +++ b/app/controllers/admin/customers_controller.rb @@ -24,7 +24,7 @@ module Admin end def show - render_as_json @customer + render_as_json @customer, ams_prefix: params[:ams_prefix] end def create @@ -91,5 +91,9 @@ module Admin spree_current_user.admin? || spree_current_user.enterprises.include?(@customer.enterprise) end + + def ams_prefix_whitelist + [:subscription] + end end end diff --git a/app/serializers/api/admin/subscription_customer_serializer.rb b/app/serializers/api/admin/subscription_customer_serializer.rb new file mode 100644 index 0000000000..7533fbc93a --- /dev/null +++ b/app/serializers/api/admin/subscription_customer_serializer.rb @@ -0,0 +1,20 @@ +module Api + module Admin + # Used by admin subscription form + # Searches for a ship and bill addresses for the customer + # where they are not already explicitly set + class SubscriptionCustomerSerializer < CustomerSerializer + def bill_address + finder.bill_address + end + + def ship_address + finder.ship_address + end + + def finder + @finder ||= OpenFoodNetwork::AddressFinder.new(object, object.email) + end + end + end +end diff --git a/spec/serializers/admin/subscription_customer_serializer_spec.rb b/spec/serializers/admin/subscription_customer_serializer_spec.rb new file mode 100644 index 0000000000..af5d769804 --- /dev/null +++ b/spec/serializers/admin/subscription_customer_serializer_spec.rb @@ -0,0 +1,18 @@ +describe Api::Admin::SubscriptionCustomerSerializer do + let(:address) { build(:address) } + let(:customer) { build(:customer) } + let(:serializer) { Api::Admin::SubscriptionCustomerSerializer.new(customer) } + let(:finder_mock) { instance_double(OpenFoodNetwork::AddressFinder, bill_address: address, ship_address: address) } + + before do + allow(serializer).to receive(:finder) { finder_mock } + end + + it "serializes a customer " do + result = JSON.parse(serializer.to_json) + expect(result['email']).to eq customer.email + expect(result['ship_address']['id']).to be nil + expect(result['ship_address']['address1']).to eq address.address1 + expect(result['ship_address']['firstname']).to eq address.firstname + end +end From 21c3f7d21cacc7886e4e9a8f464c4a545e8a2469 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 10 May 2018 18:35:41 +1000 Subject: [PATCH 035/125] Remove unrequired #cards and #addresses actions from Admin::CustomerController --- app/controllers/admin/customers_controller.rb | 16 --- app/models/spree/ability_decorator.rb | 2 +- config/routes.rb | 5 +- .../admin/customers_controller_spec.rb | 97 ------------------- 4 files changed, 2 insertions(+), 118 deletions(-) diff --git a/app/controllers/admin/customers_controller.rb b/app/controllers/admin/customers_controller.rb index 0e7eec1e90..e5368077d7 100644 --- a/app/controllers/admin/customers_controller.rb +++ b/app/controllers/admin/customers_controller.rb @@ -59,22 +59,6 @@ module Admin end end - # GET /admin/customers/:id/addresses - # Used by subscriptions form to load details for selected customer - def addresses - finder = OpenFoodNetwork::AddressFinder.new(@customer, @customer.email) - bill_address = Api::AddressSerializer.new(finder.bill_address).serializable_hash - ship_address = Api::AddressSerializer.new(finder.ship_address).serializable_hash - render json: { bill_address: bill_address, ship_address: ship_address } - end - - # GET /admin/customers/:id/cards - # Used by subscriptions form to load details for selected customer - def cards - cards = Spree::CreditCard.where(user_id: @customer.user_id) - render json: ActiveModel::ArraySerializer.new(cards, each_serializer: Api::CreditCardSerializer) - end - private def collection diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index f5d05c9a3d..53198251b9 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -257,7 +257,7 @@ class AbilityDecorator can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :xero_invoices], :report can [:create], Customer - can [:admin, :index, :update, :destroy, :addresses, :cards, :show], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id) + can [:admin, :index, :update, :destroy, :show], Customer, enterprise_id: Enterprise.managed_by(user).pluck(:id) can [:admin, :new, :index], Subscription can [:create, :edit, :update, :cancel, :pause, :unpause], Subscription do |subscription| user.enterprises.include?(subscription.shop) diff --git a/config/routes.rb b/config/routes.rb index 0ab7fe1a3c..913b09da67 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -147,10 +147,7 @@ Openfoodnetwork::Application.routes.draw do resources :inventory_items, only: [:create, :update] - resources :customers, only: [:index, :create, :update, :destroy, :show] do - get :addresses, on: :member - get :cards, on: :member - end + resources :customers, only: [:index, :create, :update, :destroy, :show] resources :tag_rules, only: [], format: :json do get :map_by_tag, on: :collection diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index bd9ff1f0f7..63aad6ed60 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -139,103 +139,6 @@ describe Admin::CustomersController, type: :controller do end end - describe "#addresses" do - let!(:enterprise) { create(:enterprise) } - let(:bill_address) { create(:address, firstname: "Dominic", address1: "123 Lala Street" ) } - let(:ship_address) { create(:address, firstname: "Dom", address1: "123 Sesame Street") } - let(:managed_customer) { create(:customer, enterprise: enterprise, bill_address: bill_address, ship_address: ship_address) } - let(:unmanaged_customer) { create(:customer) } - let(:params) { { format: :json } } - - before { login_as_enterprise_user [enterprise] } - - context "when I manage the customer" do - before { params.merge!(id: managed_customer.id) } - - it "returns with serialized addresses for the customer" do - spree_get :addresses, params - json_response = JSON.parse(response.body) - expect(json_response.keys).to include "bill_address", "ship_address" - expect(json_response["bill_address"]["firstname"]).to eq "Dominic" - expect(json_response["bill_address"]["address1"]).to eq "123 Lala Street" - expect(json_response["ship_address"]["firstname"]).to eq "Dom" - expect(json_response["ship_address"]["address1"]).to eq "123 Sesame Street" - end - end - - context "when I don't manage the customer" do - before { params.merge!(customer_id: unmanaged_customer.id) } - - it "redirects to unauthorised" do - spree_get :addresses, params - expect(response).to redirect_to spree.unauthorized_path - end - end - - context "when no customer with a matching id exists" do - before { params.merge!(customer_id: 1) } - - it "redirects to unauthorised" do - spree_get :addresses, params - expect(response).to redirect_to spree.unauthorized_path - end - end - end - - describe "#cards" do - let(:user) { create(:user) } - let!(:enterprise) { create(:enterprise) } - let!(:credit_card1) { create(:credit_card, user: user) } - let!(:credit_card2) { create(:credit_card) } - let(:managed_customer) { create(:customer, enterprise: enterprise) } - let(:unmanaged_customer) { create(:customer) } - let(:params) { { format: :json } } - - before { login_as_enterprise_user [enterprise] } - - context "when I manage the customer" do - before { params.merge!(id: managed_customer.id) } - - context "when the customer is not associated with a user" do - it "returns with an empty array" do - spree_get :cards, params - json_response = JSON.parse(response.body) - expect(json_response).to eq [] - end - end - - context "when the customer is associated with a user" do - before { managed_customer.update_attributes(user_id: user.id) } - - it "returns with serialized cards for the customer" do - spree_get :cards, params - json_response = JSON.parse(response.body) - expect(json_response).to be_an Array - expect(json_response.length).to be 1 - expect(json_response.first["id"]).to eq credit_card1.id - end - end - end - - context "when I don't manage the customer" do - before { params.merge!(customer_id: unmanaged_customer.id) } - - it "redirects to unauthorised" do - spree_get :cards, params - expect(response).to redirect_to spree.unauthorized_path - end - end - - context "when no customer with a matching id exists" do - before { params.merge!(customer_id: 1) } - - it "redirects to unauthorised" do - spree_get :cards, params - expect(response).to redirect_to spree.unauthorized_path - end - end - end - describe "show" do let(:enterprise) { create(:distributor_enterprise) } let(:another_enterprise) { create(:distributor_enterprise) } From 4863f2b5b42e7c25bb8c1fbaf2fe3c1703d5eb33 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 10 May 2018 18:45:07 +1000 Subject: [PATCH 036/125] Remove unrequired credit_card_id field from subscriptions table --- app/models/subscription.rb | 1 - ...0083800_remove_credit_card_from_subscriptions.rb | 13 +++++++++++++ db/schema.rb | 5 +---- spec/models/subscription_spec.rb | 1 - 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 db/migrate/20180510083800_remove_credit_card_from_subscriptions.rb diff --git a/app/models/subscription.rb b/app/models/subscription.rb index c5a3d8bd55..165b063ae0 100644 --- a/app/models/subscription.rb +++ b/app/models/subscription.rb @@ -8,7 +8,6 @@ class Subscription < ActiveRecord::Base belongs_to :payment_method, class_name: 'Spree::PaymentMethod' belongs_to :bill_address, foreign_key: :bill_address_id, class_name: Spree::Address belongs_to :ship_address, foreign_key: :ship_address_id, class_name: Spree::Address - belongs_to :credit_card, foreign_key: :credit_card_id, class_name: 'Spree::CreditCard' has_many :subscription_line_items, inverse_of: :subscription has_many :order_cycles, through: :schedule has_many :proxy_orders diff --git a/db/migrate/20180510083800_remove_credit_card_from_subscriptions.rb b/db/migrate/20180510083800_remove_credit_card_from_subscriptions.rb new file mode 100644 index 0000000000..0821fbef61 --- /dev/null +++ b/db/migrate/20180510083800_remove_credit_card_from_subscriptions.rb @@ -0,0 +1,13 @@ +class RemoveCreditCardFromSubscriptions < ActiveRecord::Migration + def up + remove_foreign_key :subscriptions, name: :subscriptions_credit_card_id_fk + remove_index :subscriptions, :credit_card_id + remove_column :subscriptions, :credit_card_id + end + + def down + add_column :subscriptions, :credit_card_id, :integer + add_index :subscriptions, :credit_card_id + add_foreign_key :subscriptions, :spree_credit_cards, name: :subscriptions_credit_card_id_fk, column: :credit_card_id + end +end diff --git a/db/schema.rb b/db/schema.rb index caad9f27a5..d3121a1f40 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20180418025217) do +ActiveRecord::Schema.define(:version => 20180510083800) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -1118,13 +1118,11 @@ ActiveRecord::Schema.define(:version => 20180418025217) do t.integer "ship_address_id", :null => false t.datetime "canceled_at" t.datetime "paused_at" - t.integer "credit_card_id" t.decimal "shipping_fee_estimate", :precision => 8, :scale => 2 t.decimal "payment_fee_estimate", :precision => 8, :scale => 2 end add_index "subscriptions", ["bill_address_id"], :name => "index_subscriptions_on_bill_address_id" - add_index "subscriptions", ["credit_card_id"], :name => "index_subscriptions_on_credit_card_id" add_index "subscriptions", ["customer_id"], :name => "index_subscriptions_on_customer_id" add_index "subscriptions", ["payment_method_id"], :name => "index_subscriptions_on_payment_method_id" add_index "subscriptions", ["schedule_id"], :name => "index_subscriptions_on_schedule_id" @@ -1363,7 +1361,6 @@ ActiveRecord::Schema.define(:version => 20180418025217) do add_foreign_key "subscriptions", "schedules", name: "subscriptions_schedule_id_fk" add_foreign_key "subscriptions", "spree_addresses", name: "subscriptions_bill_address_id_fk", column: "bill_address_id" add_foreign_key "subscriptions", "spree_addresses", name: "subscriptions_ship_address_id_fk", column: "ship_address_id" - add_foreign_key "subscriptions", "spree_credit_cards", name: "subscriptions_credit_card_id_fk", column: "credit_card_id" add_foreign_key "subscriptions", "spree_payment_methods", name: "subscriptions_payment_method_id_fk", column: "payment_method_id" add_foreign_key "subscriptions", "spree_shipping_methods", name: "subscriptions_shipping_method_id_fk", column: "shipping_method_id" diff --git a/spec/models/subscription_spec.rb b/spec/models/subscription_spec.rb index f0cb9f39e6..c8ae2b5f24 100644 --- a/spec/models/subscription_spec.rb +++ b/spec/models/subscription_spec.rb @@ -9,7 +9,6 @@ describe Subscription, type: :model do it { expect(subject).to belong_to(:payment_method) } it { expect(subject).to belong_to(:ship_address) } it { expect(subject).to belong_to(:bill_address) } - it { expect(subject).to belong_to(:credit_card) } it { expect(subject).to have_many(:subscription_line_items) } it { expect(subject).to have_many(:order_cycles) } it { expect(subject).to have_many(:proxy_orders) } From edde929ced344e02928928220a6b13b86e570c0f Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 11 May 2018 14:42:01 +1000 Subject: [PATCH 037/125] Replace uses of #stub with #allow in Admin::CustomersController --- .../admin/customers_controller_spec.rb | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index 63aad6ed60..b1503d89f7 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -9,7 +9,7 @@ describe Admin::CustomersController, type: :controller do context "html" do before do - controller.stub spree_current_user: enterprise.owner + allow(controller).to receive(:spree_current_user) { enterprise.owner } end it "returns an empty @collection" do @@ -23,7 +23,7 @@ describe Admin::CustomersController, type: :controller do context "where I manage the enterprise" do before do - controller.stub spree_current_user: enterprise.owner + allow(controller).to receive(:spree_current_user) { enterprise.owner } end context "and enterprise_id is given in params" do @@ -50,7 +50,7 @@ describe Admin::CustomersController, type: :controller do context "and I do not manage the enterprise" do before do - controller.stub spree_current_user: another_enterprise.owner + allow(controller).to receive(:spree_current_user) { another_enterprise.owner } end it "returns an empty collection" do @@ -72,7 +72,7 @@ describe Admin::CustomersController, type: :controller do render_views before do - controller.stub spree_current_user: enterprise.owner + allow(controller).to receive(:spree_current_user) { enterprise.owner } end it "allows me to update the customer" do @@ -85,7 +85,7 @@ describe Admin::CustomersController, type: :controller do context "where I don't manage the customer's enterprise" do before do - controller.stub spree_current_user: another_enterprise.owner + allow(controller).to receive(:spree_current_user) { another_enterprise.owner } end it "prevents me from updating the customer" do @@ -109,7 +109,7 @@ describe Admin::CustomersController, type: :controller do context "json" do context "where I manage the customer's enterprise" do before do - controller.stub spree_current_user: enterprise.owner + allow(controller).to receive(:spree_current_user) { enterprise.owner } end it "allows me to create the customer" do @@ -119,7 +119,7 @@ describe Admin::CustomersController, type: :controller do context "where I don't manage the customer's enterprise" do before do - controller.stub spree_current_user: another_enterprise.owner + allow(controller).to receive(:spree_current_user) { another_enterprise.owner } end it "prevents me from creating the customer" do @@ -129,7 +129,7 @@ describe Admin::CustomersController, type: :controller do context "where I am the admin user" do before do - controller.stub spree_current_user: create(:admin_user) + allow(controller).to receive(:spree_current_user) { create(:admin_user) } end it "allows admins to create the customer" do @@ -150,7 +150,7 @@ describe Admin::CustomersController, type: :controller do render_views before do - controller.stub spree_current_user: enterprise.owner + allow(controller).to receive(:spree_current_user) { enterprise.owner } end it "renders the customer as json" do @@ -161,7 +161,7 @@ describe Admin::CustomersController, type: :controller do context "where I don't manage the customer's enterprise" do before do - controller.stub spree_current_user: another_enterprise.owner + allow(controller).to receive(:spree_current_user) { another_enterprise.owner } end it "prevents me from updating the customer" do From a902af42a33766423f9a451a9b87e61ab4215dc7 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Mon, 25 Jun 2018 15:30:20 +1000 Subject: [PATCH 038/125] Update attribute that errors are added to from credit_card to payment_method --- app/services/subscription_validator.rb | 5 ++--- config/locales/en.yml | 6 +++--- spec/services/subscription_validator_spec.rb | 9 ++++----- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/services/subscription_validator.rb b/app/services/subscription_validator.rb index 14cae211a6..33fc2baf77 100644 --- a/app/services/subscription_validator.rb +++ b/app/services/subscription_validator.rb @@ -23,7 +23,6 @@ class SubscriptionValidator delegate :shop, :customer, :schedule, :shipping_method, :payment_method, to: :subscription delegate :bill_address, :ship_address, :begins_at, :ends_at, to: :subscription - delegate :credit_card, :credit_card_id, to: :subscription delegate :subscription_line_items, to: :subscription def initialize(subscription) @@ -78,9 +77,9 @@ class SubscriptionValidator def credit_card_ok? return unless customer && payment_method return unless payment_method.type == "Spree::Gateway::StripeConnect" - return errors.add(:credit_card, :charges_not_allowed) unless customer.allow_charges + return errors.add(:payment_method, :charges_not_allowed) unless customer.allow_charges return if customer.user.andand.default_card.present? - errors.add(:credit_card, :no_default_card) + errors.add(:payment_method, :no_default_card) end def subscription_line_items_present? diff --git a/config/locales/en.yml b/config/locales/en.yml index 87a6799143..76da2ba08e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -97,11 +97,11 @@ en: payment_method: not_available_to_shop: "is not available to %{shop}" invalid_type: "must be a Cash or Stripe method" + charges_not_allowed: "^Credit card charges are not allowed by this customer" + no_default_card: "^No default card available for this customer" shipping_method: not_available_to_shop: "is not available to %{shop}" - credit_card: - charges_not_allowed: "charges are not allowed by this customer" - no_default_card: "not available for this customer" + devise: confirmations: send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." diff --git a/spec/services/subscription_validator_spec.rb b/spec/services/subscription_validator_spec.rb index 43ab894aa6..6670d14fa4 100644 --- a/spec/services/subscription_validator_spec.rb +++ b/spec/services/subscription_validator_spec.rb @@ -30,7 +30,6 @@ describe SubscriptionValidator do ship_address: true, begins_at: true, ends_at: true, - credit_card: true } end @@ -339,7 +338,7 @@ describe SubscriptionValidator do it "adds an error and returns false" do expect(validator.valid?).to be false - expect(validator.errors[:credit_card]).to_not be_empty + expect(validator.errors[:payment_method]).to_not be_empty end end @@ -351,7 +350,7 @@ describe SubscriptionValidator do it "adds an error and returns false" do expect(validator.valid?).to be false - expect(validator.errors[:credit_card]).to_not be_empty + expect(validator.errors[:payment_method]).to_not be_empty end end @@ -363,7 +362,7 @@ describe SubscriptionValidator do it "adds an error and returns false" do expect(validator.valid?).to be false - expect(validator.errors[:credit_card]).to_not be_empty + expect(validator.errors[:payment_method]).to_not be_empty end end @@ -372,7 +371,7 @@ describe SubscriptionValidator do it "returns true" do expect(validator.valid?).to be true - expect(validator.errors[:credit_card]).to be_empty + expect(validator.errors[:payment_method]).to be_empty end end end From 4fd333bbaf8d929ea38fa431fa249b5dd2440a92 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Mon, 25 Jun 2018 15:31:59 +1000 Subject: [PATCH 039/125] Remove obsolete reference to credit_card from subscription serializer --- app/serializers/api/admin/subscription_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/api/admin/subscription_serializer.rb b/app/serializers/api/admin/subscription_serializer.rb index cbba4cc483..91b30e4e8c 100644 --- a/app/serializers/api/admin/subscription_serializer.rb +++ b/app/serializers/api/admin/subscription_serializer.rb @@ -2,7 +2,7 @@ module Api module Admin class SubscriptionSerializer < ActiveModel::Serializer attributes :id, :shop_id, :customer_id, :schedule_id, :payment_method_id, :shipping_method_id, :begins_at, :ends_at - attributes :customer_email, :schedule_name, :edit_path, :canceled_at, :paused_at, :state, :credit_card_id + attributes :customer_email, :schedule_name, :edit_path, :canceled_at, :paused_at, :state attributes :shipping_fee_estimate, :payment_fee_estimate has_many :subscription_line_items, serializer: Api::Admin::SubscriptionLineItemSerializer From 0afa9fae8ea464a6580017c04901a0c8fc4b723e Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 28 Jun 2018 17:56:58 +1000 Subject: [PATCH 040/125] Check authorisation before attempting to charge credit cards on order cycle close --- config/locales/en.yml | 2 +- .../subscription_payment_updater.rb | 6 +- .../subscription_payment_updater_spec.rb | 63 +++++++++++++++---- 3 files changed, 57 insertions(+), 14 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 76da2ba08e..4b30116d7e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -75,7 +75,7 @@ en: email: taken: "There's already an account for this email. Please login or reset your password." spree/order: - no_card: There are no valid credit cards available + no_card: There are no authorised credit cards available to charge order_cycle: attributes: orders_close_at: diff --git a/lib/open_food_network/subscription_payment_updater.rb b/lib/open_food_network/subscription_payment_updater.rb index eb33aaf2f2..bdf437c963 100644 --- a/lib/open_food_network/subscription_payment_updater.rb +++ b/lib/open_food_network/subscription_payment_updater.rb @@ -42,10 +42,14 @@ module OpenFoodNetwork end def ensure_credit_card - return false if saved_credit_card.blank? + return false if saved_credit_card.blank? || !allow_charges? payment.update_attributes(source: saved_credit_card) end + def allow_charges? + order.customer.allow_charges? + end + def saved_credit_card order.user.default_card end diff --git a/spec/lib/open_food_network/subscription_payment_updater_spec.rb b/spec/lib/open_food_network/subscription_payment_updater_spec.rb index 8d590f59b7..4e238476d5 100644 --- a/spec/lib/open_food_network/subscription_payment_updater_spec.rb +++ b/spec/lib/open_food_network/subscription_payment_updater_spec.rb @@ -96,8 +96,10 @@ module OpenFoodNetwork context "and the payment source is not a credit card" do before { expect(updater).to receive(:card_set?) { false } } - context "and no credit card is available on the subscription" do - before { expect(updater).to receive(:ensure_credit_card) { false } } + context "and no default credit card has been set by the customer" do + before do + allow(order).to receive(:user) { instance_double(Spree::User, default_card: nil) } + end it "adds an error to the order and does not update the payment" do expect(payment).to_not receive(:update_attributes) @@ -105,8 +107,23 @@ module OpenFoodNetwork end end - context "but a credit card is available on the subscription" do - before { expect(updater).to receive(:ensure_credit_card) { true } } + context "and the customer has not authorised the shop to charge to credit cards" do + before do + allow(order).to receive(:user) { instance_double(Spree::User, default_card: create(:credit_card)) } + allow(order).to receive(:customer) { instance_double(Customer, allow_charges?: false) } + end + + it "adds an error to the order and does not update the payment" do + expect(payment).to_not receive(:update_attributes) + expect{ updater.update! }.to change(order.errors[:base], :count).from(0).to(1) + end + end + + context "and an authorised default credit card is available to charge" do + before do + allow(order).to receive(:user) { instance_double(Spree::User, default_card: create(:credit_card)) } + allow(order).to receive(:customer) { instance_double(Customer, allow_charges?: true) } + end context "when the payment total doesn't match the outstanding balance on the order" do before { allow(order).to receive(:outstanding_balance) { 5 } } @@ -151,8 +168,10 @@ module OpenFoodNetwork let!(:payment) { create(:payment, source: nil) } before { allow(updater).to receive(:payment) { payment } } - context "when no saved credit card is found" do - before { allow(updater).to receive(:saved_credit_card) { nil } } + context "when no default credit card is found" do + before do + allow(order).to receive(:user) { instance_double(Spree::User, default_card: nil) } + end it "returns false and down not update the payment source" do expect do @@ -161,14 +180,34 @@ module OpenFoodNetwork end end - context "when a saved credit card is found" do + context "when a default credit card is found" do let(:credit_card) { create(:credit_card) } - before { allow(updater).to receive(:saved_credit_card) { credit_card } } + before do + allow(order).to receive(:user) { instance_double(Spree::User, default_card: credit_card) } + end - it "returns true and stores the credit card as the payment source" do - expect do - expect(updater.send(:ensure_credit_card)).to be true - end.to change(payment, :source_id).from(nil).to(credit_card.id) + context "and charge have not been authorised by the customer" do + before do + allow(order).to receive(:customer) { instance_double(Customer, allow_charges?: false) } + end + + it "returns false and does not update the payment source" do + expect do + expect(updater.send(:ensure_credit_card)).to be false + end.to_not change(payment, :source).from(nil) + end + end + + context "and charges have been authorised by the customer" do + before do + allow(order).to receive(:customer) { instance_double(Customer, allow_charges?: true) } + end + + it "returns true and stores the credit card as the payment source" do + expect do + expect(updater.send(:ensure_credit_card)).to be true + end.to change(payment, :source_id).from(nil).to(credit_card.id) + end end end end From 3dacd06b6b77e3b3d469c026cfb6e1b2372ce35a Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 28 Jun 2018 18:56:13 +1000 Subject: [PATCH 041/125] Reload order before sending emails to ensure state is up to date --- app/jobs/subscription_confirm_job.rb | 2 ++ spec/jobs/subscription_confirm_job_spec.rb | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/jobs/subscription_confirm_job.rb b/app/jobs/subscription_confirm_job.rb index d9c284d7f8..f0c8e8d07f 100644 --- a/app/jobs/subscription_confirm_job.rb +++ b/app/jobs/subscription_confirm_job.rb @@ -46,11 +46,13 @@ class SubscriptionConfirmJob end def send_confirm_email + @order.update! record_success(@order) SubscriptionMailer.confirmation_email(@order).deliver end def send_failed_payment_email + @order.update! record_and_log_error(:failed_payment, @order) SubscriptionMailer.failed_payment_email(@order).deliver end diff --git a/spec/jobs/subscription_confirm_job_spec.rb b/spec/jobs/subscription_confirm_job_spec.rb index f1b64b1343..7556a30478 100644 --- a/spec/jobs/subscription_confirm_job_spec.rb +++ b/spec/jobs/subscription_confirm_job_spec.rb @@ -174,7 +174,7 @@ describe SubscriptionConfirmJob do end describe "#send_confirm_email" do - let(:order) { double(:order) } + let(:order) { instance_double(Spree::Order) } let(:mail_mock) { double(:mailer_mock, deliver: true) } before do @@ -183,6 +183,7 @@ describe SubscriptionConfirmJob do end it "records a success and sends the email" do + expect(order).to receive(:update!) expect(job).to receive(:record_success).with(order).once job.send(:send_confirm_email) expect(SubscriptionMailer).to have_received(:confirmation_email).with(order) @@ -191,7 +192,7 @@ describe SubscriptionConfirmJob do end describe "#send_failed_payment_email" do - let(:order) { double(:order) } + let(:order) { instance_double(Spree::Order) } let(:mail_mock) { double(:mailer_mock, deliver: true) } before do @@ -200,6 +201,7 @@ describe SubscriptionConfirmJob do end it "records and logs an error and sends the email" do + expect(order).to receive(:update!) expect(job).to receive(:record_and_log_error).with(:failed_payment, order).once job.send(:send_failed_payment_email) expect(SubscriptionMailer).to have_received(:failed_payment_email).with(order) From 15db5e1d5002ac3880d6a4d87266ad3d99c3cdd7 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Mon, 9 Jul 2018 20:23:01 +1000 Subject: [PATCH 042/125] Updating translations for config/locales/en_GB.yml --- config/locales/en_GB.yml | 319 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 305 insertions(+), 14 deletions(-) diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index eec1f844f6..d50003b209 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -1,4 +1,5 @@ en_GB: + language_name: "English" activerecord: attributes: spree/order: @@ -7,25 +8,108 @@ en_GB: completed_at: Completed At number: Number email: Customer E-Mail + spree/payment: + amount: Amount + order_cycle: + orders_close_at: Close date errors: models: spree/user: attributes: email: taken: "There's already an account for this email. Please login or reset your password." + spree/order: + no_card: There are no valid credit cards available + order_cycle: + attributes: + orders_close_at: + after_orders_open_at: must be after open date + activemodel: + errors: + models: + subscription_validator: + attributes: + subscription_line_items: + at_least_one_product: "^Please add at least one product" + not_available: "^%{name} is not available from the selected schedule" + ends_at: + after_begins_at: "must be after begins at" + customer: + does_not_belong_to_shop: "does not belong to %{shop}" + schedule: + not_coordinated_by_shop: "is not coordinated by %{shop}" + payment_method: + not_available_to_shop: "is not available to %{shop}" + invalid_type: "must be a Cash or Stripe method" + shipping_method: + not_available_to_shop: "is not available to %{shop}" + credit_card: + not_available: "is not available" + blank: "is required" devise: + confirmations: + send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." + failed_to_send: "An error occurred whilst sending your confirmation email." + resend_confirmation_email: "Resend confirmation email." + confirmed: "Thanks for confirming your email! You can now log in." + not_confirmed: "Your email address could not be confirmed. Perhaps you have already completed this step?" + user_registrations: + spree_user: + signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account." failure: invalid: | Invalid email or password. Were you a guest last time? Perhaps you need to create an account or reset your password. + unconfirmed: "You have to confirm your account before continuing." + already_registered: "This email address is already registered. Please log in to continue, or go back and use another email address." + user_passwords: + spree_user: + updated_not_active: "Your password has been reset, but your email has not been confirmed yet." enterprise_mailer: confirmation_instructions: subject: "Please confirm the email address for %{enterprise}" welcome: subject: "%{enterprise} is now on %{sitename}" + invite_manager: + subject: "%{enterprise} has invited you to be a manager" producer_mailer: order_cycle: subject: "Order cycle report for %{producer}" + subscription_mailer: + placement_summary_email: + subject: A summary of recently placed subscription orders + greeting: "Hi %{name}," + intro: "Below is a summary of the subscription orders that have just been placed for %{shop}." + confirmation_summary_email: + subject: A summary of recently confirmed subscription orders + greeting: "Hi %{name}," + intro: "Below is a summary of the subscription orders that have just been finalised for %{shop}." + summary_overview: + total: A total of %{count} subscriptions were marked for automatic processing. + success_zero: Of these, none were processed successfully. + success_some: Of these, %{count} were processed successfully. + success_all: All were processed successfully. + issues: Details of the issues encountered are provided below. + summary_detail: + no_message_provided: No error message provided + changes: + title: Insufficient Stock (%{count} orders) + explainer: These orders were processed but insufficient stock was available for some requested items + empty: + title: No Stock (%{count} orders) + explainer: These orders were unable to be processed because no stock was available for any requested items + complete: + title: Already Processed (%{count} orders) + explainer: These orders were already marked as complete, and were therefore left untouched + processing: + title: Error Encountered (%{count} orders) + explainer: Automatic processing of these orders failed due to an error. The error has been listed where possible. + failed_payment: + title: Failed Payment (%{count} orders) + explainer: Automatic processing of payment for these orders failed due to an error. The error has been listed where possible. + other: + title: Other Failure (%{count} orders) + explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this. home: "OFN" title: Open Food Network welcome_to: 'Welcome to ' @@ -56,6 +140,9 @@ en_GB: say_no: "No" say_yes: "Yes" then: then + ongoing: Ongoing + bill_address: Billing Address + ship_address: Shipping Address sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By" required_fields: Required fields are denoted with an asterisk select_continue: Select and Continue @@ -106,23 +193,36 @@ en_GB: filter_results: Filter Results quantity: Quantity pick_up: Pick up + copy: Copy actions: create_and_add_another: "Create and Add Another" admin: + begins_at: Begins At + begins_on: Begins On + customer: Customer date: Date email: Email + ends_at: Ends At + ends_on: Ends On name: Name on_hand: In Stock on_demand: Unlimited on_demand?: Unlimited? order_cycle: Order Cycle + payment: Payment + payment_method: Payment Method phone: Phone price: Price producer: Producer + image: Image product: Product quantity: Quantity + schedule: Schedule + shipping: Shipping + shipping_method: Shipping Method shop: Shop sku: SKU + status_state: County tags: Tags variant: Variant weight: Weight @@ -140,6 +240,10 @@ en_GB: save: Save cancel: Cancel back: Back + show_more: Show more + show_n_more: Show %{num} more + choose: "Choose..." + please_select: Please select... columns: Columns actions: Actions viewing: "Viewing: %{current_view_name}" @@ -276,12 +380,20 @@ en_GB: available_on: Available On av_on: "Av. On" import_date: Imported + upload_an_image: Upload an image + product_search_keywords: Product Search Keywords + product_search_tip: Type words to help search your products in the shops. Use space to separate each keyword. + SEO_keywords: SEO Keywords + seo_tip: Type words to help search your products in the web. Use space to separate each keyword. Search: Search properties: property_name: Property Name inherited_property: Inherited Property variants: to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order." + product_distributions: "Product Distributions" + group_buy_options: "Group Buy Options" + back_to_products_list: "Back to products list" product_import: title: Product Import file_not_found: File not found or could not be opened @@ -290,6 +402,8 @@ en_GB: model: no_file: "error: no file uploaded" could_not_process: "could not process file: invalid filetype" + incorrect_value: incorrect value + conditional_blank: can't be blank if unit_type is blank no_product: did not match any products in the database not_found: not found in database blank: can't be blank @@ -304,7 +418,13 @@ en_GB: product_list: Product list inventories: Inventories import: Import + upload: Upload import: + review: Review + proceed: Proceed + save: Save + results: Results + save_imported: Save imported products no_valid_entries: No valid entries found none_to_save: There are no entries that can be saved some_invalid_entries: Imported file contains some invalid entries @@ -319,10 +439,10 @@ en_GB: reset_absent?: Reset absent products? overwrite_all: Overwrite all overwrite_empty: Overwrite if empty - default_stock: Set default stock level - default_tax_cat: Set default tax category - default_shipping_cat: Set default shipping category - default_available_date: Set default available date + default_stock: Set stock level + default_tax_cat: Set tax category + default_shipping_cat: Set shipping category + default_available_date: Set available date validation_overview: Import validation overview entries_found: Entries found in imported file entries_with_errors: Items contain errors and will not be imported @@ -342,8 +462,8 @@ en_GB: inventory_updated: Inventory items updated products_reset: Products had stock level reset to zero inventory_reset: Inventory items had stock level reset to zero - all_saved: "All %{num} items saved successfully" - total_saved: "%{num} items saved successfully" + all_saved: "All items saved successfully" + some_saved: "items saved successfully" save_errors: Save errors view_products: View Products view_inventory: View Inventory @@ -398,6 +518,7 @@ en_GB: max_fulfilled_units: "Max Fulfilled Units" order_error: "Some errors must be resolved before you can update orders.\nAny fields with red borders contain errors." variants_without_unit_value: "WARNING: Some variants do not have a unit value" + select_variant: "Select a variant" enterprise: select_outgoing_oc_products_from: Select outgoing OC products from enterprises: @@ -424,6 +545,9 @@ en_GB: contact: name: Name name_placeholder: eg. Amanda Plum + email_address: Public Email Address + email_address_placeholder: eg. hello@food.co.uk + email_address_tip: "This email address will be displayed in your public profile" phone: Phone phone_placeholder: eg. 98 7654 3210 website: Website @@ -500,6 +624,10 @@ en_GB: allow_order_changes_tip: "Allow customers to change their order as long the order cycle is open." allow_order_changes_false: "Placed orders cannot be changed / cancelled" allow_order_changes_true: "Customers can change / cancel orders while order cycle is open" + enable_subscriptions: "Subscriptions" + enable_subscriptions_tip: "Enable subscriptions functionality?" + enable_subscriptions_false: "Disabled" + enable_subscriptions_true: "Enabled" shopfront_message: Shopfront Message shopfront_message_placeholder: > An optional explanation for customers detailing how your shopfront works, @@ -542,6 +670,7 @@ en_GB: resend: Resend owner: 'Owner' contact: "Contact" + contact_tip: "The manager who will receive enterprise emails for orders and notifications. Must have a confirmed email adress." owner_tip: The primary user responsible for this enterprise. notifications: Notifications notifications_tip: Notifications about orders will be send to this email address. @@ -549,6 +678,11 @@ en_GB: notifications_note: 'Note: A new email address may need to be confirmed prior to use' managers: Managers managers_tip: The other users with permission to manage this enterprise. + invite_manager: "Invite Manager" + invite_manager_tip: "Invite an unregistered user to sign up and become a manager of this enterprise." + add_unregistered_user: "Add an unregistered user" + email_confirmed: "Email confirmed" + email_not_confirmed: "Email not confirmed" actions: edit_profile: Edit Profile properties: Properties @@ -605,7 +739,10 @@ en_GB: welcome_title: Welcome to the Open Food Network! welcome_text: You have successfully created a next_step: Next step - choose_starting_point: 'Choose your starting point:' + choose_starting_point: 'Choose your package:' + invite_manager: + user_already_exists: "User already exists" + error: "Something went wrong" order_cycles: edit: advanced_settings: Advanced Settings @@ -642,11 +779,27 @@ en_GB: add_a_tag: Add a tag delivery_details: Pickup / Delivery details debug_info: Debug information + index: + involving: Involving + schedule: Schedule + schedules: Schedules + adding_a_new_schedule: Adding A New Schedule + updating_a_schedule: Updating A Schedule + new_schedule: New Schedule + create_schedule: Create Schedule + update_schedule: Update Schedule + delete_schedule: Delete Schedule + created_schedule: Created schedule + updated_schedule: Updated schedule + deleted_schedule: Deleted schedule + schedule_name_placeholder: Schedule Name + name_required_error: Please enter a name for this schedule + no_order_cycles_error: Please select at least one order cycle (drag and drop) name_and_timing_form: name: Name orders_open: Orders open at coordinator: Coordinator - order_closes: Orders close + orders_close: Orders close row: suppliers: suppliers distributors: distributors @@ -658,9 +811,22 @@ en_GB: customer_instructions_placeholder: Pick-up or delivery notes products: Products fees: Fees + destroy_errors: + schedule_present: That order cycle is linked to a schedule and cannot be deleted. Please unlink or delete the schedule first. + bulk_update: + no_data: Hm, something went wrong. No order cycle data found. + date_warning: + msg: This order cycle is linked to %{n} open subscription orders. Changing this date now will not affect any orders which have already been placed, but should be avoided if possible. Are you sure you want to proceed? + cancel: Cancel + proceed: Proceed producer_properties: index: title: Producer Properties + proxy_orders: + cancel: + could_not_cancel_the_order: Could not cancel the order + resume: + could_not_resume_the_order: Could not resume the order shared: user_guide_link: user_guide: User Guide @@ -734,10 +900,67 @@ en_GB: packing: name: Packing Reports subscriptions: + subscriptions: Subscriptions + new: New Subscription + create: Create Subscription + index: + please_select_a_shop: Please select a shop + edit_subscription: Edit Subscription + pause_subscription: Pause Subscription + cancel_subscription: Cancel Subscription + setup_explanation: + just_a_few_more_steps: 'Just a few more steps before you can begin:' + enable_subscriptions: "Enable subscriptions for at least one of your shops" + enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage" + enable_subscriptions_step_2: 2. Under "Shop Preferences", enable the Subscriptions option + set_up_shipping_and_payment_methods_html: Set up %{shipping_link} and %{payment_link} methods + set_up_shipping_and_payment_methods_note_html: Note that only Cash and Stripe payment methods may
be used with subscriptions + ensure_at_least_one_customer_html: Ensure that at least one %{customer_link} exists + create_at_least_one_schedule: Create at least one Schedule + create_at_least_one_schedule_step_1_html: 1. Go to the on the %{order_cycles_link} page + create_at_least_one_schedule_step_2: 2. Create an order cycle if you have not already done so + create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form + once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link} + reload_this_page: reload this page + steps: + details: 1. Basic Details + products: 3. Add Products + review: 4. Review & Save + details: + details: Details + invalid_error: Oops! Please fill in all of the required fields... + allowed_payment_method_types_tip: Only Cash and Stripe payment methods may be used at the moment + credit_card: Credit Card + no_cards_available: No cards available + loading_flash: + loading: LOADING SUBSCRIPTIONS review: details: Details address: Address products: Products + product_already_in_order: This product has already been added to the order. Please edit the quantity directly. + orders: + number: Number + confirm_edit: Are you sure you want to edit this order? Doing so may make it more difficult to automatically sync changes to the subscription in the future. + confirm_cancel_msg: Are you sure you want to cancel this subscription? This action cannot be undone. + cancel_failure_msg: 'Sorry, cancellation failed!' + confirm_pause_msg: Are you sure you want to pause this subscription? + pause_failure_msg: 'Sorry, pausing failed!' + confirm_unpause_msg: Are you sure you want to unpause this subscription? + unpause_failure_msg: 'Sorry, unpausing failed!' + confirm_cancel_open_orders_msg: "Some orders for this subscription are currently open. The customer has already been notified that the order will be placed. Would you like to cancel these order(s) or keep them?" + resume_canceled_orders_msg: "Some orders for this subscription can be resumed right now. You can resume them from the orders dropdown." + yes_cancel_them: Cancel them + no_keep_them: Keep them + yes_i_am_sure: Yes, I'm sure + order_update_issues_msg: Some orders could not be automatically updated, this is most likely because they have been manually edited. Please review the issues listed below and make any adjustments to individual orders if required. + no_results: + no_subscriptions: No subscriptions yet... + why_dont_you_add_one: Why don't you add one? :) + no_matching_subscriptions: No matching subscriptions found + schedules: + destroy: + associated_subscriptions_error: This schedule cannot be deleted because it has associated subscriptions stripe_connect_settings: edit: title: "Stripe Connect" @@ -786,6 +1009,7 @@ en_GB: require_customer_login: "This shop is for customers only." require_login_html: "Please %{login} if you have an account already. Otherwise, %{register} to become a customer." require_customer_html: "Please %{contact} %{enterprise} to become a customer." + card_could_not_be_updated: Card could not be updated card_could_not_be_saved: card could not be saved spree_gateway_error_flash_for_checkout: "There was a problem with your payment information: %{error}" invoice_billing_address: "Billing address:" @@ -852,8 +1076,11 @@ en_GB: no_payment: no payment methods no_shipping_or_payment: no shipping or payment methods unconfirmed: unconfirmed + days: days + label_shop: "Shop" label_shops: "Shops" label_map: "Map" + label_producer: "Producer" label_producers: "Producers" label_groups: "Groups" label_about: "About" @@ -919,6 +1146,7 @@ en_GB: footer_legal_tos: "Terms and conditions" footer_legal_visit: "Find us on" footer_legal_text_html: "Open Food Network is a free and open source software platform. Our content is licensed with %{content_license} and our code with %{code_license}." + footer_skylight_dashboard_html: Performance data is available on %{dashboard}. home_shop: Shop Now brandstory_headline: "Re-imagining Local Food" brandstory_intro: "Online tools for buying, selling & distributing local food" @@ -1002,6 +1230,7 @@ en_GB: email_admin_html: "You can manage your account by logging into the %{link} or by clicking on the cog in the top right hand side of the homepage, and selecting Administration." email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of running a food enterprise. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}" join_community: "Join the community" + email_confirmation_activate_account: "Before we can activate your new account, we need to confirm your email address." email_confirmation_greeting: "Hi, %{contact}!" email_confirmation_profile_created: "A profile for %{name} has been successfully created! To activate your Profile we need to confirm this email address." email_confirmation_click_link: "Please click the link below to confirm your email and to continue setting up your profile." @@ -1029,6 +1258,23 @@ en_GB: email_payment_not_paid: NOT PAID email_payment_summary: Payment summary email_payment_method: "Paying via:" + email_so_placement_intro_html: "You have a new order with %{distributor}" + email_so_placement_details_html: "Here are the details of your order for %{distributor}:" + email_so_placement_changes: "Unfortunately, not all products that you requested were available. The original quantities that you requested appear crossed-out below." + email_so_payment_success_intro_html: "An automatic payment has been processed for your order from %{distributor}." + email_so_placement_explainer_html: "This order was automatically created for you." + email_so_edit_true_html: "You can make changes until orders close on %{orders_close_at}." + email_so_edit_false_html: "You can view details of this order at any time." + email_so_contact_distributor_html: "If you have any questions you can contact %{distributor} via %{email}." + email_so_confirmation_intro_html: "Your order with %{distributor} is now confirmed" + email_so_confirmation_explainer_html: "This order was automatically placed for you, and it has now been finalised." + email_so_confirmation_details_html: "Here's everything you need to know about your order from %{distributor}:" + email_so_empty_intro_html: "We tried to place a new order with %{distributor}, but had some problems..." + email_so_empty_explainer_html: "Unfortunately, none of products that you ordered were available, so no order has been placed. The original quantities that you requested appear crossed-out below." + email_so_empty_details_html: "Here are the details of the unplaced order for %{distributor}:" + email_so_failed_payment_intro_html: "We tried to process a payment, but had some problems..." + email_so_failed_payment_explainer_html: "The payment for your subscription with %{distributor} failed because of a problem with your credit card. %{distributor} has been notified of this failed payment." + email_so_failed_payment_details_html: "Here are the details of the failure provided by the payment gateway:" email_shipping_delivery_details: Delivery details email_shipping_delivery_time: "Delivery on:" email_shipping_delivery_address: "Delivery address:" @@ -1038,8 +1284,16 @@ en_GB: email_special_instructions: "Your notes:" email_signup_greeting: Hello! email_signup_welcome: "Welcome to %{sitename}!" + email_signup_confirmed_email: "Thanks for confirming your email." + email_signup_shop_html: "You can now log in at %{link}." email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic farmers, wonderful food hubs and delicious food! If you are a producer or food enterprise, we are excited to have you as a part of the network." email_signup_help_html: "We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at %{email}" + invite_email: + greeting: "Hello!" + invited_to_manage: "You have been invited to manage %{enterprise} on %{instance}." + confirm_your_email: "You should have received or will soon receive an email with a confirmation link. You won’t be able to access %{enterprise}'s profile until you have confirmed your email." + set_a_password: "You will then be prompted to set a password before you are able to administer the enterprise." + mistakenly_sent: "Not sure why you have received this email? Please contact %{owner_email} for more information." producer_mail_greeting: "Dear" producer_mail_text_before: "We now have all the consumer orders for the next food delivery." producer_mail_order_text: "Here is a summary of the orders for your products:" @@ -1202,6 +1456,7 @@ en_GB: shops_signup_help: We're ready to help. shops_signup_help_text: You need a better return. You need new buyers and logistics partners. You need your story told across wholesale, retail, and the kitchen table. shops_signup_detail: Here's the detail. + orders: Orders orders_fees: Fees... orders_edit_title: Shopping cart orders_edit_headline: Your shopping cart @@ -1287,6 +1542,7 @@ en_GB: november: "November" december: "December" email_not_found: "Email address not found" + email_unconfirmed: "You must confirm your email address before you can reset your password." email_required: "You must provide an email address" logging_in: "Hold on a moment, we're logging you in" signup_email: "Your email" @@ -1301,6 +1557,7 @@ en_GB: password_reset_sent: "An email with instructions on resetting your password has been sent!" reset_password: "Reset password" who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?" + update_and_recalculate_fees: "Update And Recalculate Fees" enterprise: registration: modal: @@ -1537,6 +1794,10 @@ en_GB: calculator: "Calculator" calculator_values: "Calculator values" flat_percent_per_item: "Flat Percent (per item)" + flat_rate_per_item: "Flat Rate (per item)" + flat_rate_per_order: "Flat Rate (per order)" + flexible_rate: "Flexible Rate" + price_sack: "Price Sack" new_order_cycles: "New Order Cycles" new_order_cycle: "New Order Cycle" select_a_coordinator_for_your_order_cycle: "Select a coordinator for your order cycle" @@ -1571,12 +1832,7 @@ en_GB: spree_admin_enterprises_fees: "Enterprise Fees" spree_admin_enterprises_none_create_a_new_enterprise: "CREATE A NEW ENTERPRISE" spree_admin_enterprises_none_text: "You don't have any enterprises yet" - spree_admin_enterprises_producers_name: "Name" - spree_admin_enterprises_producers_total_products: "Total Products" - spree_admin_enterprises_producers_active_products: "Active Products" - spree_admin_enterprises_producers_order_cycles: "Products in OCs" spree_admin_enterprises_tabs_hubs: "HUBS" - spree_admin_enterprises_tabs_producers: "PRODUCERS" spree_admin_enterprises_producers_manage_products: "MANAGE PRODUCTS" spree_admin_enterprises_any_active_products_text: "You don't have any active products." spree_admin_enterprises_create_new_product: "CREATE A NEW PRODUCT" @@ -1812,6 +2068,8 @@ en_GB: products_unsaved: "Changes to %{n} products remain unsaved." is_already_manager: "is already a manager!" no_change_to_save: "No change to save" + user_invited: "%{email} has been invited to manage this enterprise" + add_manager: "Add an existing user" users: "Users" about: "About" images: "Images" @@ -1822,6 +2080,7 @@ en_GB: social: "Social" business_details: "Business Details" properties: "Properties" + shipping: "Shipping" shipping_methods: "Shipping Methods" payment_methods: "Payment Methods" payment_method_fee: "Transaction fee" @@ -1838,7 +2097,7 @@ en_GB: content_configuration_pricing_table: "(TODO: Pricing table)" content_configuration_case_studies: "(TODO: Case studies)" content_configuration_detail: "(TODO: Detail)" - enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, please contact the current manager of this profile at %{email}." + enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}." enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})." enterprise_role_uniqueness_error: "^That role is already present." inventory_item_visibility_error: must be true or false @@ -1872,6 +2131,15 @@ en_GB: order_cycles_email_to_producers_notice: 'Emails to be sent to producers have been queued for sending.' order_cycles_no_permission_to_coordinate_error: "None of your enterprises have permission to coordinate an order cycle" order_cycles_no_permission_to_create_error: "You don't have permission to create an order cycle coordinated by that enterprise" + back_to_orders_list: "Back to order list" + no_orders_found: "No Orders Found" + order_information: "Order Information" + date_completed: "Date Completed" + amount: "Amount" + state_names: + ready: Ready + pending: Pending + shipped: Shipped js: saving: 'Saving...' changes_saved: 'Changes saved.' @@ -1889,9 +2157,14 @@ en_GB: choose: Choose resolve_errors: Please resolve the following errors more_items: "+ %{count} More" + default_card_updated: Default Card Updated admin: + enterprise_limit_reached: "You have reached the standard limit of enterprises per account. Write to %{contact_email} if you need to increase it." modals: got_it: Got it + close: "Close" + invite: "Invite" + invite_title: "Invite an unregistered user" tag_rule_help: title: Tag Rules overview: Overview @@ -2055,6 +2328,10 @@ en_GB: customers: select_shop: 'Please select a shop first' could_not_create: Sorry! Could not create + subscriptions: + closes: closes + closed: closed + close_date_not_set: Close date not set producers: signup: start_free_profile: "Start with a free profile, and expand when you're ready!" @@ -2062,6 +2339,8 @@ en_GB: email: Email account_updated: "Account updated!" my_account: "My account" + date: "Date" + time: "Time" admin: orders: invoice: @@ -2122,6 +2401,7 @@ en_GB: inherits_properties?: Inherits Properties? available_on: Available On av_on: "Av. On" + import_date: "Import Date" products_variant: variant_has_n_overrides: "This variant has %{n} override(s)" new_variant: "New variant" @@ -2134,6 +2414,8 @@ en_GB: display_as: display_as: Display As reports: + table: + select_and_search: "Select filters and click on SEARCH to access your data." bulk_coop: bulk_coop_supplier_report: 'Bulk Co-op - Totals by Supplier' bulk_coop_allocation: 'Bulk Co-op - Allocation' @@ -2168,14 +2450,23 @@ en_GB: address: address adjustments: adjustments awaiting_return: awaiting return + canceled: cancelled cart: cart complete: complete confirm: confirm delivery: delivery + paused: paused payment: payment + pending: pending resumed: resumed returned: returned skrill: skrill + subscription_state: + active: active + pending: pending + ended: ended + paused: paused + canceled: cancelled payment_states: balance_due: balance due completed: completed From b478ef9fd049301edb872e7bfd550faedbd07866 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 10 Jul 2018 09:59:00 +1000 Subject: [PATCH 043/125] Make admin serialiser specs runnable on their own --- app/serializers/api/admin/subscription_customer_serializer.rb | 2 ++ spec/serializers/admin/customer_serializer_spec.rb | 2 ++ spec/serializers/admin/enterprise_serializer_spec.rb | 2 ++ spec/serializers/admin/exchange_serializer_spec.rb | 1 + spec/serializers/admin/index_enterprise_serializer_spec.rb | 2 ++ spec/serializers/admin/subscription_customer_serializer_spec.rb | 2 ++ 6 files changed, 11 insertions(+) diff --git a/app/serializers/api/admin/subscription_customer_serializer.rb b/app/serializers/api/admin/subscription_customer_serializer.rb index 7533fbc93a..6f8490abec 100644 --- a/app/serializers/api/admin/subscription_customer_serializer.rb +++ b/app/serializers/api/admin/subscription_customer_serializer.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + module Api module Admin # Used by admin subscription form diff --git a/spec/serializers/admin/customer_serializer_spec.rb b/spec/serializers/admin/customer_serializer_spec.rb index 697b03f41a..7d46f8aa83 100644 --- a/spec/serializers/admin/customer_serializer_spec.rb +++ b/spec/serializers/admin/customer_serializer_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + describe Api::Admin::CustomerSerializer do let(:customer) { create(:customer, tag_list: "one, two, three") } let!(:tag_rule) { create(:tag_rule, enterprise: customer.enterprise, preferred_customer_tags: "two") } diff --git a/spec/serializers/admin/enterprise_serializer_spec.rb b/spec/serializers/admin/enterprise_serializer_spec.rb index b8226a73e5..0898b7d4a0 100644 --- a/spec/serializers/admin/enterprise_serializer_spec.rb +++ b/spec/serializers/admin/enterprise_serializer_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + describe Api::Admin::EnterpriseSerializer do let(:enterprise) { create(:distributor_enterprise) } it "serializes an enterprise" do diff --git a/spec/serializers/admin/exchange_serializer_spec.rb b/spec/serializers/admin/exchange_serializer_spec.rb index 649a0b427e..31ab38fb86 100644 --- a/spec/serializers/admin/exchange_serializer_spec.rb +++ b/spec/serializers/admin/exchange_serializer_spec.rb @@ -1,3 +1,4 @@ +require 'spec_helper' require 'open_food_network/order_cycle_permissions' describe Api::Admin::ExchangeSerializer do diff --git a/spec/serializers/admin/index_enterprise_serializer_spec.rb b/spec/serializers/admin/index_enterprise_serializer_spec.rb index 3651f53f8d..a6ad4d8d02 100644 --- a/spec/serializers/admin/index_enterprise_serializer_spec.rb +++ b/spec/serializers/admin/index_enterprise_serializer_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + describe Api::Admin::IndexEnterpriseSerializer do include AuthenticationWorkflow diff --git a/spec/serializers/admin/subscription_customer_serializer_spec.rb b/spec/serializers/admin/subscription_customer_serializer_spec.rb index af5d769804..8ca1bc4805 100644 --- a/spec/serializers/admin/subscription_customer_serializer_spec.rb +++ b/spec/serializers/admin/subscription_customer_serializer_spec.rb @@ -1,3 +1,5 @@ +require 'spec_helper' + describe Api::Admin::SubscriptionCustomerSerializer do let(:address) { build(:address) } let(:customer) { build(:customer) } From f9a333875576d948032b457154d2ab8e113fbbab Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 10 Jul 2018 10:01:18 +1000 Subject: [PATCH 044/125] Simplify serialiser with `delegate` --- .../api/admin/subscription_customer_serializer.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/serializers/api/admin/subscription_customer_serializer.rb b/app/serializers/api/admin/subscription_customer_serializer.rb index 6f8490abec..2cb10bf80a 100644 --- a/app/serializers/api/admin/subscription_customer_serializer.rb +++ b/app/serializers/api/admin/subscription_customer_serializer.rb @@ -6,13 +6,8 @@ module Api # Searches for a ship and bill addresses for the customer # where they are not already explicitly set class SubscriptionCustomerSerializer < CustomerSerializer - def bill_address - finder.bill_address - end - - def ship_address - finder.ship_address - end + delegate :bill_address, to: :finder + delegate :ship_address, to: :finder def finder @finder ||= OpenFoodNetwork::AddressFinder.new(object, object.email) From 459057a7dbc779f57d68f22b75fcb69d6fe3efe3 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 10 Jul 2018 10:31:51 +1000 Subject: [PATCH 045/125] Revert accidental copy and paste --- app/serializers/api/admin/subscription_customer_serializer.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/serializers/api/admin/subscription_customer_serializer.rb b/app/serializers/api/admin/subscription_customer_serializer.rb index 2cb10bf80a..c018aaf8b6 100644 --- a/app/serializers/api/admin/subscription_customer_serializer.rb +++ b/app/serializers/api/admin/subscription_customer_serializer.rb @@ -1,5 +1,3 @@ -require 'spec_helper' - module Api module Admin # Used by admin subscription form From 24f77184cf07a2507b3b8dd76e747cc5daf3282f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 11 Jul 2018 11:31:27 +1000 Subject: [PATCH 046/125] Move i18n locale doc to wiki and reference that --- config/locales/en.yml | 47 +++++++------------------------------------ 1 file changed, 7 insertions(+), 40 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 4b30116d7e..b466c99a3e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,58 +1,25 @@ # English language file # --------------------- # -# This is the source language file maintained by the Australian OFN team. +# This is the source language file maintained by the global OFN team and used +# by the Australian OFN instance. +# # Visit Transifex to translate this file into other languages: # # https://www.transifex.com/open-food-foundation/open-food-network/ # -# If you translate this file in a text editor, please share your results with us by +# Read more about it at: # -# - uploading the file to Transifex or -# - opening a pull request at GitHub. -# -# -# See http://community.openfoodnetwork.org/t/localisation-ofn-in-your-language/397 +# https://github.com/openfoodfoundation/openfoodnetwork/wiki/i18n # # Changing this file # ================== # # You are welcome to fix typos, add missing translations and remove unused ones. -# Here are some guidelines to make sure that this file is becoming more beautiful -# with every change we do. +# But read our guidelines first: # -# * Change text: No problem. Fix the typo. And please enclose the text in quotes -# to avoid any accidents. +# https://github.com/openfoodfoundation/openfoodnetwork/wiki/i18n#development # -# Example 1: "When you're using double quotes, they look like \"this\"" -# Example 2: "When you’re using double quotes, they look like “this”" -# -# The second example uses unicode to make it look prettier and avoid backslashes. -# -# * Add translations: Cool, every bit of text in the application should be here. -# If you add a translation for a view or mailer, please make use of the nested -# structure. Use the "lazy" lookup. See: http://guides.rubyonrails.org/i18n.html#looking-up-translations -# -# Avoid global keys. There are a lot already. And some are okay, for example -# "enterprises" should be the same everywhere on the page. But in doubt, -# create a new translation and give it a meaningful scope. -# -# Don't worry about duplication. We may use the same word in different contexts, -# but another language could use different words. So don't try to re-use -# translations between files. -# -# Don't move big parts around or rename scopes with a lot of entries without -# a really good reason. In some cases that causes a lot of translations in -# other languages to be lost. That causes more work for translators. -# -# * Remove translations: If you are sure that they are not used anywhere, -# please remove them. Be aware that some translations are looked up with -# variables. For example app/views/admin/contents/_fieldset.html.haml looks -# up labels for preferences. Unfortunately, they don't have a scope. -# -# * Participate in the community discussions: -# - https://community.openfoodnetwork.org/t/workflow-to-structure-translations/932 - en: # Overridden here due to a bug in spree i18n (Issue #870, and issue #1800) language_name: "English" # Localised name of this language From 5508c6741f7c64e66ffd8028c89de229fe779f8c Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Wed, 11 Jul 2018 14:10:05 +0800 Subject: [PATCH 047/125] Fix broken "great-pr" link in CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 60bc662403..5ea968c65c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -47,7 +47,7 @@ Push your changes to a branch on your fork: ## Submitting a Pull Request -Use the GitHub UI to submit a [new pull request][pr] against upstream/master. To increase the chances that your pull request is swiftly accepted please have a look at our guide to [[making a great pull request]]. +Use the GitHub UI to submit a [new pull request][pr] against upstream/master. To increase the chances that your pull request is swiftly accepted please have a look at our guide to [making a great pull request][great-pr]. TL;DR: * Write tests From 056df623590c132850774d171b42ce6e83af000f Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 11 Jul 2018 18:02:29 +0100 Subject: [PATCH 048/125] Add changelog category to PR template --- .github/PULL_REQUEST_TEMPLATE.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7468fd5248..a0c8f5638b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -16,6 +16,11 @@ context for others to understand it] [In case this should be present in the release notes, please write them or remove this section otherwise] +[To streamline the release process, please designate your PR with ONE of the following +categories, based on the specification from keepachangelog.com (and delete the others):] + +Changelog Category: Added | Changed | Deprecated | Removed | Fixed | Security + #### How is this related to the Spree upgrade? [Any known conflicts with the Spree Upgrade? explain them or remove this section From b302a1d03d05a6affdfba25c81d0597fb61e4c3d Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Thu, 14 Jun 2018 16:43:53 +0100 Subject: [PATCH 049/125] added Enterprise registration exit message and moved step TYPE translations to a new structure on en.yml (test if transifex picks up the existing translations) --- app/views/registration/steps/_about.html.haml | 1 + app/views/registration/steps/_type.html.haml | 16 +++++++------- config/locales/en.yml | 22 +++++++++++-------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/app/views/registration/steps/_about.html.haml b/app/views/registration/steps/_about.html.haml index d65b989ee3..529fdebea3 100644 --- a/app/views/registration/steps/_about.html.haml +++ b/app/views/registration/steps/_about.html.haml @@ -15,6 +15,7 @@ .small-12.columns .alert-box.info{ "ofn-inline-alert" => true, ng: { show: "visible" } } %h6{ "ng-bind" => "'enterprise_success' | t:{enterprise: enterprise.name}" } + %span {{'enterprise_registration_exit_message' | t}} %a.close{ ng: { click: "close()" } } × .small-12.large-8.columns diff --git a/app/views/registration/steps/_type.html.haml b/app/views/registration/steps/_type.html.haml index 9276a5731a..ad5e075d16 100644 --- a/app/views/registration/steps/_type.html.haml +++ b/app/views/registration/steps/_type.html.haml @@ -6,9 +6,9 @@ .row .small-12.columns %header - %h2{ "ng-bind" => "'enterprise.registration.modal.steps.type.headline' | t:{enterprise: enterprise.name}" } + %h2= t(".headline", enterprise: "{{enterprise.name}}") %h4 - {{'enterprise.registration.modal.steps.type.question' | t}} + = t(".question") %form{ name: 'type', novalidate: true, ng: { controller: "RegistrationFormCtrl", submit: "create(type)" } } .row#enterprise-types{ 'data-equalizer' => true, ng: { if: "::enterprise.type != 'own'" } } @@ -17,32 +17,32 @@ .small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true } %a.btnpanel#producer-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = true", class: "{selected: enterprise.is_primary_producer}" } } %i.ofn-i_059-producer - %h4 {{'enterprise.registration.modal.steps.type.yes_producer' | t}} + %h4= t(".yes_producer") .small-12.medium-6.large-6.columns{ 'data-equalizer-watch' => true } %a.btnpanel#hub-panel{ href: "#", ng: { click: "enterprise.is_primary_producer = false", class: "{selected: enterprise.is_primary_producer == false}" } } %i.ofn-i_063-hub - %h4 {{'enterprise.registration.modal.steps.type.no_producer' | t}} + %h4= t(".no_producer") .row .small-12.columns %input.chunky{ id: 'enterprise_is_primary_producer', name: 'is_primary_producer', hidden: true, required: true, ng: { model: 'enterprise.is_primary_producer' } } %span.error{ ng: { show: "type.is_primary_producer.$error.required && submitted" } } - {{'enterprise.registration.modal.steps.type.producer_field_error' | t}} + = t(".producer_field_error") .row .small-12.columns .panel.callout .left %i.ofn-i_013-help   - %p {{'enterprise.registration.modal.steps.type.yes_producer_help' | t}} + %p= t(".yes_producer_help") .panel.callout .left %i.ofn-i_013-help   - %p {{'enterprise.registration.modal.steps.type.no_producer_help' | t}} + %p= t(".no_producer_help") .row.buttons .small-12.columns %input.button.secondary{ type: "button", value: "{{'back' | t}}", ng: { click: "select('contact')" } } - %input.button.primary.right{ ng: { disabled: 'isDisabled' }, type: "submit", value: "{{'create_profile' | t}}" } + %input.button.primary.right{ ng: { disabled: 'isDisabled' }, type: "submit", value: t(".create_profile") } diff --git a/config/locales/en.yml b/config/locales/en.yml index 4b30116d7e..da0ff0cba6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1737,6 +1737,17 @@ See the %{link} to find out more about %{sitename}'s features and to start using registration_greeting: "Greetings!" who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?" update_and_recalculate_fees: "Update And Recalculate Fees" + registration: + steps: + type: + headline: "Last step to add %{enterprise}!" + question: "Are you a producer?" + yes_producer: "Yes, I'm a producer" + no_producer: "No, I'm not a producer" + producer_field_error: "Please choose one. Are you are producer?" + yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it." + no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other." + create_profile: "Create Profile" enterprise: registration: modal: @@ -1775,14 +1786,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using phone_field_placeholder: 'eg. (03) 1234 5678' type: title: 'Type' - headline: "Last step to add %{enterprise}!" - question: "Are you a producer?" - yes_producer: "Yes, I'm a producer" - no_producer: "No, I'm not a producer" - producer_field_error: "Please choose one. Are you are producer?" - yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it." - no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other." - about: title: 'About' images: @@ -1823,6 +1826,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using enterprise_about_headline: "Nice one!" enterprise_about_message: "Now let's flesh out the details about" enterprise_success: "Success! %{enterprise} added to the Open Food Network " + enterprise_registration_exit_message: "If you exit this wizard at any stage, you can continue to create your profile by going to the admin interface." enterprise_description: "Short Description" enterprise_description_placeholder: "A short sentence describing your enterprise" enterprise_long_desc: "Long Description" @@ -1875,7 +1879,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using registration_type_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it." registration_type_no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other." # END - create_profile: "Create Profile" + registration_images_headline: "Thanks!" registration_images_description: "Let's upload some pretty pictures so your profile looks great! :)" From 86f2d7a34460560d51f2e7efd5975e2aa2e475f9 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 26 Jun 2018 07:31:21 +1000 Subject: [PATCH 050/125] Remove impossible route Hash fragments are not part of the http request and not sent to the server. So the routes will never see a hash fragment which means that this route is never used. --- config/routes.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/config/routes.rb b/config/routes.rb index 913b09da67..7e2bc47a32 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,7 +8,6 @@ Openfoodnetwork::Application.routes.draw do get "/t/products/:id", to: redirect("/") get "/about_us", to: redirect(ContentConfig.footer_about_url) - get "/#/login", to: "home#index", as: :spree_login get "/login", to: redirect("/#/login") get "/discourse/login", to: "discourse_sso#login" From 97d1b5d7fe14e1b0a4ab6af241d1d311da167c74 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 15 Jun 2018 16:43:22 +1000 Subject: [PATCH 051/125] Add spec for creating users --- spec/features/admin/users_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 spec/features/admin/users_spec.rb diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb new file mode 100644 index 0000000000..de62c84aa6 --- /dev/null +++ b/spec/features/admin/users_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" + +feature "Managing users" do + include AuthenticationWorkflow + + context "as super-admin" do + before { quick_login_as_admin } + + describe "creating a user" do + it "works" do + visit spree.new_admin_user_path + fill_in "Email", with: "user1@example.org" + fill_in "Password", with: "user1Secret" + fill_in "Confirm Password", with: "user1Secret" + expect do + click_button "Create" + end.to change { Spree::User.count }.by 1 + expect(page).to have_text "Created Successfully" + end + end + end +end From 652cc6e677e88cd7419a60871ed67d2b19d2eb13 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:08:15 +1000 Subject: [PATCH 052/125] Import admin user edit view from spree_auth_devise We would like to do some customisations and importing the whole file is simpler and less error prone than using Spree's overrides. --- app/views/spree/admin/users/edit.html.erb | 28 +++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 app/views/spree/admin/users/edit.html.erb diff --git a/app/views/spree/admin/users/edit.html.erb b/app/views/spree/admin/users/edit.html.erb new file mode 100644 index 0000000000..1dccf3bb38 --- /dev/null +++ b/app/views/spree/admin/users/edit.html.erb @@ -0,0 +1,28 @@ + <% content_for :page_title do %> + <%= Spree.t(:editing_user) %> + <% end %> + + <% content_for :page_actions do %> +
  • + <%= button_link_to Spree.t(:back_to_users_list), spree.admin_users_path, :icon => 'icon-arrow-left' %> +
  • + <% end %> + +
    + <%= Spree.t(:general_settings) %> + +
    + <%= render :partial => 'spree/shared/error_messages', :locals => { :target => @user } %> +
    + +
    + <%= form_for [:admin, @user] do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + +
    + <%= render :partial => 'spree/admin/shared/edit_resource_links' %> +
    + <% end %> +
    + +
    \ No newline at end of file From 23dd09a8fa9403616d29605358694001afefd4da Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:17:53 +1000 Subject: [PATCH 053/125] Convert Spree view from erb to haml --- app/views/spree/admin/users/edit.html.erb | 28 ---------------------- app/views/spree/admin/users/edit.html.haml | 14 +++++++++++ 2 files changed, 14 insertions(+), 28 deletions(-) delete mode 100644 app/views/spree/admin/users/edit.html.erb create mode 100644 app/views/spree/admin/users/edit.html.haml diff --git a/app/views/spree/admin/users/edit.html.erb b/app/views/spree/admin/users/edit.html.erb deleted file mode 100644 index 1dccf3bb38..0000000000 --- a/app/views/spree/admin/users/edit.html.erb +++ /dev/null @@ -1,28 +0,0 @@ - <% content_for :page_title do %> - <%= Spree.t(:editing_user) %> - <% end %> - - <% content_for :page_actions do %> -
  • - <%= button_link_to Spree.t(:back_to_users_list), spree.admin_users_path, :icon => 'icon-arrow-left' %> -
  • - <% end %> - -
    - <%= Spree.t(:general_settings) %> - -
    - <%= render :partial => 'spree/shared/error_messages', :locals => { :target => @user } %> -
    - -
    - <%= form_for [:admin, @user] do |f| %> - <%= render :partial => 'form', :locals => { :f => f } %> - -
    - <%= render :partial => 'spree/admin/shared/edit_resource_links' %> -
    - <% end %> -
    - -
    \ No newline at end of file diff --git a/app/views/spree/admin/users/edit.html.haml b/app/views/spree/admin/users/edit.html.haml new file mode 100644 index 0000000000..93ef949000 --- /dev/null +++ b/app/views/spree/admin/users/edit.html.haml @@ -0,0 +1,14 @@ +- content_for :page_title do + = Spree.t(:editing_user) +- content_for :page_actions do + %li + = button_link_to Spree.t(:back_to_users_list), spree.admin_users_path, icon: "icon-arrow-left" +%fieldset.alpha.ten.columns{"data-hook" => "admin_user_edit_general_settings"} + %legend= Spree.t(:general_settings) + %div{"data-hook" => "admin_user_edit_form_header"} + = render partial: "spree/shared/error_messages", locals: { target: @user } + %div{"data-hook" => "admin_user_edit_form"} + = form_for [:admin, @user] do |f| + = render partial: "form", locals: { f: f } + %div{"data-hook" => "admin_user_edit_form_button"} + = render partial: "spree/admin/shared/edit_resource_links" From cb1dc6e657e56cb01de4004525a4cdc8fc44ea69 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:25:46 +1000 Subject: [PATCH 054/125] Import admin user edit form from spree_auth_devise --- app/views/spree/admin/users/_form.html.erb | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 app/views/spree/admin/users/_form.html.erb diff --git a/app/views/spree/admin/users/_form.html.erb b/app/views/spree/admin/users/_form.html.erb new file mode 100644 index 0000000000..fb48bd1742 --- /dev/null +++ b/app/views/spree/admin/users/_form.html.erb @@ -0,0 +1,37 @@ +
    +
    + <%= f.field_container :email do %> + <%= f.label :email, Spree.t(:email) %> + <%= f.email_field :email, :class => 'fullwidth' %> + <%= error_message_on :user, :email %> + <% end %> + +
    + <%= label_tag nil, Spree.t(:roles) %> +
      + <% @roles.each do |role| %> +
    • + <%= check_box_tag 'user[spree_role_ids][]', role.id, @user.spree_roles.include?(role), :id => "user_spree_role_#{role.name}" %> + <%= label_tag role.name %> +
    • + <% end %> +
    + <%= hidden_field_tag 'user[spree_role_ids][]', '' %> +
    + +
    + +
    + <%= f.field_container :password do %> + <%= f.label :password, Spree.t(:password) %> + <%= f.password_field :password, :class => 'fullwidth' %> + <%= f.error_message_on :password %> + <% end %> + + <%= f.field_container :password do %> + <%= f.label :password_confirmation, Spree.t(:confirm_password) %> + <%= f.password_field :password_confirmation, :class => 'fullwidth' %> + <%= f.error_message_on :password_confirmation %> + <% end %> +
    +
    \ No newline at end of file From 2032ed63283dfb77257206c2d812c3d72c391332 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:29:26 +1000 Subject: [PATCH 055/125] Convert admin user edit form to haml --- app/views/spree/admin/users/_form.html.erb | 37 --------------------- app/views/spree/admin/users/_form.html.haml | 23 +++++++++++++ 2 files changed, 23 insertions(+), 37 deletions(-) delete mode 100644 app/views/spree/admin/users/_form.html.erb create mode 100644 app/views/spree/admin/users/_form.html.haml diff --git a/app/views/spree/admin/users/_form.html.erb b/app/views/spree/admin/users/_form.html.erb deleted file mode 100644 index fb48bd1742..0000000000 --- a/app/views/spree/admin/users/_form.html.erb +++ /dev/null @@ -1,37 +0,0 @@ -
    -
    - <%= f.field_container :email do %> - <%= f.label :email, Spree.t(:email) %> - <%= f.email_field :email, :class => 'fullwidth' %> - <%= error_message_on :user, :email %> - <% end %> - -
    - <%= label_tag nil, Spree.t(:roles) %> -
      - <% @roles.each do |role| %> -
    • - <%= check_box_tag 'user[spree_role_ids][]', role.id, @user.spree_roles.include?(role), :id => "user_spree_role_#{role.name}" %> - <%= label_tag role.name %> -
    • - <% end %> -
    - <%= hidden_field_tag 'user[spree_role_ids][]', '' %> -
    - -
    - -
    - <%= f.field_container :password do %> - <%= f.label :password, Spree.t(:password) %> - <%= f.password_field :password, :class => 'fullwidth' %> - <%= f.error_message_on :password %> - <% end %> - - <%= f.field_container :password do %> - <%= f.label :password_confirmation, Spree.t(:confirm_password) %> - <%= f.password_field :password_confirmation, :class => 'fullwidth' %> - <%= f.error_message_on :password_confirmation %> - <% end %> -
    -
    \ No newline at end of file diff --git a/app/views/spree/admin/users/_form.html.haml b/app/views/spree/admin/users/_form.html.haml new file mode 100644 index 0000000000..97e4a5d848 --- /dev/null +++ b/app/views/spree/admin/users/_form.html.haml @@ -0,0 +1,23 @@ +.row{"data-hook" => "admin_user_form_fields"} + .alpha.five.columns + = f.field_container :email do + = f.label :email, Spree.t(:email) + = f.email_field :email, class: "fullwidth" + = error_message_on :user, :email + .field{"data-hook" => "admin_user_form_roles"} + = label_tag nil, Spree.t(:roles) + %ul + - @roles.each do |role| + %li + = check_box_tag "user[spree_role_ids][]", role.id, @user.spree_roles.include?(role), id: "user_spree_role_#{role.name}" + = label_tag role.name + = hidden_field_tag "user[spree_role_ids][]", "" + .omega.five.columns + = f.field_container :password do + = f.label :password, Spree.t(:password) + = f.password_field :password, class: "fullwidth" + = f.error_message_on :password + = f.field_container :password do + = f.label :password_confirmation, Spree.t(:confirm_password) + = f.password_field :password_confirmation, class: "fullwidth" + = f.error_message_on :password_confirmation \ No newline at end of file From 9050a52cc2dfad03431e28e1e769fb406c43ceea Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:35:12 +1000 Subject: [PATCH 056/125] Move admin user form override into view --- .../_form/add_enterprise_limit_form_element.html.haml.deface | 5 ----- app/views/spree/admin/users/_form.html.haml | 3 +++ 2 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 app/overrides/spree/admin/users/_form/add_enterprise_limit_form_element.html.haml.deface diff --git a/app/overrides/spree/admin/users/_form/add_enterprise_limit_form_element.html.haml.deface b/app/overrides/spree/admin/users/_form/add_enterprise_limit_form_element.html.haml.deface deleted file mode 100644 index 0b00900b5c..0000000000 --- a/app/overrides/spree/admin/users/_form/add_enterprise_limit_form_element.html.haml.deface +++ /dev/null @@ -1,5 +0,0 @@ -/ insert_bottom "div[data-hook='admin_user_form_fields'] div.alpha" - -= f.field_container :enterprise_limit do - = f.label :enterprise_limit, t(:enterprise_limit) - = f.text_field :enterprise_limit, :class => 'fullwidth' \ No newline at end of file diff --git a/app/views/spree/admin/users/_form.html.haml b/app/views/spree/admin/users/_form.html.haml index 97e4a5d848..a11624cfa2 100644 --- a/app/views/spree/admin/users/_form.html.haml +++ b/app/views/spree/admin/users/_form.html.haml @@ -12,6 +12,9 @@ = check_box_tag "user[spree_role_ids][]", role.id, @user.spree_roles.include?(role), id: "user_spree_role_#{role.name}" = label_tag role.name = hidden_field_tag "user[spree_role_ids][]", "" + = f.field_container :enterprise_limit do + = f.label :enterprise_limit, t(:enterprise_limit) + = f.text_field :enterprise_limit, class: "fullwidth" .omega.five.columns = f.field_container :password do = f.label :password, Spree.t(:password) From 8157897f766697fe4f232c1cc326b54ecc2a8226 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 14:36:31 +1000 Subject: [PATCH 057/125] Remove unused data hooks --- app/views/spree/admin/users/_form.html.haml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/spree/admin/users/_form.html.haml b/app/views/spree/admin/users/_form.html.haml index a11624cfa2..e495f29632 100644 --- a/app/views/spree/admin/users/_form.html.haml +++ b/app/views/spree/admin/users/_form.html.haml @@ -1,10 +1,10 @@ -.row{"data-hook" => "admin_user_form_fields"} +.row .alpha.five.columns = f.field_container :email do = f.label :email, Spree.t(:email) = f.email_field :email, class: "fullwidth" = error_message_on :user, :email - .field{"data-hook" => "admin_user_form_roles"} + .field = label_tag nil, Spree.t(:roles) %ul - @roles.each do |role| From 6a58deb436b853e5b731c67c76e71877556f5fad Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 15:01:41 +1000 Subject: [PATCH 058/125] Add message about unconfirmed email to user form --- app/views/spree/admin/users/_email_confirmation.html.haml | 2 ++ app/views/spree/admin/users/edit.html.haml | 1 + config/locales/en.yml | 3 +++ spec/features/admin/users_spec.rb | 6 ++++++ 4 files changed, 12 insertions(+) create mode 100644 app/views/spree/admin/users/_email_confirmation.html.haml diff --git a/app/views/spree/admin/users/_email_confirmation.html.haml b/app/views/spree/admin/users/_email_confirmation.html.haml new file mode 100644 index 0000000000..65be495337 --- /dev/null +++ b/app/views/spree/admin/users/_email_confirmation.html.haml @@ -0,0 +1,2 @@ +%p.alert-box + = t(".confirmation_pending", address: @user.email) diff --git a/app/views/spree/admin/users/edit.html.haml b/app/views/spree/admin/users/edit.html.haml index 93ef949000..1457f1065a 100644 --- a/app/views/spree/admin/users/edit.html.haml +++ b/app/views/spree/admin/users/edit.html.haml @@ -9,6 +9,7 @@ = render partial: "spree/shared/error_messages", locals: { target: @user } %div{"data-hook" => "admin_user_edit_form"} = form_for [:admin, @user] do |f| + = render "email_confirmation" unless @user.confirmed? = render partial: "form", locals: { f: f } %div{"data-hook" => "admin_user_edit_form_button"} = render partial: "spree/admin/shared/edit_resource_links" diff --git a/config/locales/en.yml b/config/locales/en.yml index 0ebf5200c8..8b06972e95 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2585,6 +2585,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using shared: configuration_menu: stripe_connect: Stripe Connect + users: + email_confirmation: + confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}." variants: autocomplete: producer_name: Producer diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb index de62c84aa6..2e78a19500 100644 --- a/spec/features/admin/users_spec.rb +++ b/spec/features/admin/users_spec.rb @@ -7,6 +7,11 @@ feature "Managing users" do before { quick_login_as_admin } describe "creating a user" do + it "shows no confirmation message to start with" do + visit spree.new_admin_user_path + expect(page).to have_no_text "Email confirmation is pending" + end + it "works" do visit spree.new_admin_user_path fill_in "Email", with: "user1@example.org" @@ -16,6 +21,7 @@ feature "Managing users" do click_button "Create" end.to change { Spree::User.count }.by 1 expect(page).to have_text "Created Successfully" + expect(page).to have_text "Email confirmation is pending" end end end From 60b66540df241e2e0025b4c054a05029208eb15d Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 18:09:35 +1000 Subject: [PATCH 059/125] Add resend email button to admin user form Fixes https://github.com/openfoodfoundation/openfoodnetwork/issues/1589 --- .../resend_user_email_confirmation.js.coffee | 19 +++++++++++++++++++ .../admin/openfoodnetwork.css.scss | 8 ++++++++ .../admin/users/_email_confirmation.html.haml | 4 +++- config/locales/en.yml | 5 +++++ 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee diff --git a/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee b/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee new file mode 100644 index 0000000000..b6361ec7ae --- /dev/null +++ b/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee @@ -0,0 +1,19 @@ +angular.module("admin.users").directive "resendUserEmailConfirmation", ($http) -> + scope: + email: "@resendUserEmailConfirmation" + link: (scope, element, attrs) -> + sent = false + text = element.text() + sending = " " + t "js.admin.resend_user_email_confirmation.sending" + done = " " + t "js.admin.resend_user_email_confirmation.done" + failed = " " + t "js.admin.resend_user_email_confirmation.failed" + + element.bind "click", -> + return if sent + element.text(text + sending) + $http.post("/user/spree_user/confirmation", {spree_user: {email: scope.email}}).success (data) -> + sent = true + element.addClass "action--disabled" + element.text text + done + .error (data) -> + element.text text + failed diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index d10ca748d0..348b85820a 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -71,6 +71,14 @@ a { cursor:pointer; } +a.action--disabled { + cursor: default; + + &:hover { + color: #5498da; + } +} + form.order_cycle { h2 { margin-top: 2em; diff --git a/app/views/spree/admin/users/_email_confirmation.html.haml b/app/views/spree/admin/users/_email_confirmation.html.haml index 65be495337..fb2fd75232 100644 --- a/app/views/spree/admin/users/_email_confirmation.html.haml +++ b/app/views/spree/admin/users/_email_confirmation.html.haml @@ -1,2 +1,4 @@ -%p.alert-box +%p.alert-box{"ng-app" => "admin.users"} = t(".confirmation_pending", address: @user.email) + %a{"resend-user-email-confirmation" => @user.email} + = t(".resend") \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 8b06972e95..675ea554a5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2435,6 +2435,10 @@ See the %{link} to find out more about %{sitename}'s features and to start using resolve: Resolve new_tag_rule_dialog: select_rule_type: "Select a rule type:" + resend_user_email_confirmation: + sending: "..." + done: "done ✓" + failed: "failed ✗" out_of_stock: reduced_stock_available: Reduced stock available out_of_stock_text: > @@ -2588,6 +2592,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using users: email_confirmation: confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}." + resend: "Resend" variants: autocomplete: producer_name: Producer From 9020e7ddd99f67a2668a09785a54cdf55d965591 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 7 Jun 2018 18:11:52 +1000 Subject: [PATCH 060/125] Import admin user list from Spree --- app/views/spree/admin/users/index.html.erb | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 app/views/spree/admin/users/index.html.erb diff --git a/app/views/spree/admin/users/index.html.erb b/app/views/spree/admin/users/index.html.erb new file mode 100644 index 0000000000..a5373244e1 --- /dev/null +++ b/app/views/spree/admin/users/index.html.erb @@ -0,0 +1,53 @@ +<% content_for :page_title do %> + <%= Spree.t(:listing_users) %> +<% end %> + +<% content_for :page_actions do %> +
  • + <%= button_link_to Spree.t(:new_user), new_object_url, :icon => 'icon-plus', :id => 'admin_new_user_link' %> +
  • +<% end %> + + + + + + + + + + + + + + <% @users.each do |user|%> + + + + + <% end %> + +
    <%= sort_link @search,:email, Spree.t(:user), {}, {:title => 'users_email_title'} %>
    <%=link_to user.email, object_url(user) %> + <%= link_to_edit user, :no_text => true %> + <%= link_to_delete user, :no_text => true %> +
    + +<%= paginate @users %> + +<% content_for :sidebar_title do %> + <%= Spree.t(:search) %> +<% end %> + +<% content_for :sidebar do %> +
    + <%= search_form_for [:admin, @search] do |f| %> +
    + <%= f.label Spree.t(:email) %>
    + <%= f.text_field :email_cont, :class => 'fullwidth' %> +
    +
    + <%= button Spree.t(:search), 'icon-search' %> +
    + <% end %> +
    +<% end %> From 339b04a0445c75be65031ea0d6254fa0ff3554e8 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:00:55 +1000 Subject: [PATCH 061/125] Convert spree admin user list to haml --- app/views/spree/admin/users/index.html.erb | 53 --------------------- app/views/spree/admin/users/index.html.haml | 35 ++++++++++++++ 2 files changed, 35 insertions(+), 53 deletions(-) delete mode 100644 app/views/spree/admin/users/index.html.erb create mode 100644 app/views/spree/admin/users/index.html.haml diff --git a/app/views/spree/admin/users/index.html.erb b/app/views/spree/admin/users/index.html.erb deleted file mode 100644 index a5373244e1..0000000000 --- a/app/views/spree/admin/users/index.html.erb +++ /dev/null @@ -1,53 +0,0 @@ -<% content_for :page_title do %> - <%= Spree.t(:listing_users) %> -<% end %> - -<% content_for :page_actions do %> -
  • - <%= button_link_to Spree.t(:new_user), new_object_url, :icon => 'icon-plus', :id => 'admin_new_user_link' %> -
  • -<% end %> - - - - - - - - - - - - - - <% @users.each do |user|%> - - - - - <% end %> - -
    <%= sort_link @search,:email, Spree.t(:user), {}, {:title => 'users_email_title'} %>
    <%=link_to user.email, object_url(user) %> - <%= link_to_edit user, :no_text => true %> - <%= link_to_delete user, :no_text => true %> -
    - -<%= paginate @users %> - -<% content_for :sidebar_title do %> - <%= Spree.t(:search) %> -<% end %> - -<% content_for :sidebar do %> -
    - <%= search_form_for [:admin, @search] do |f| %> -
    - <%= f.label Spree.t(:email) %>
    - <%= f.text_field :email_cont, :class => 'fullwidth' %> -
    -
    - <%= button Spree.t(:search), 'icon-search' %> -
    - <% end %> -
    -<% end %> diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml new file mode 100644 index 0000000000..023cb11ec6 --- /dev/null +++ b/app/views/spree/admin/users/index.html.haml @@ -0,0 +1,35 @@ +- content_for :page_title do + = Spree.t(:listing_users) +- content_for :page_actions do + %li + = button_link_to Spree.t(:new_user), new_object_url, icon: "icon-plus", id: "admin_new_user_link" +%table#listing_users.index{"data-hook" => ""} + %colgroup + %col{style: "width: 85%"} + %col{style: "width: 15%"} + %thead + %tr{"data-hook" => "admin_users_index_headers"} + %th= sort_link @search,:email, Spree.t(:user), {}, {title: "users_email_title"} + %th.actions{"data-hook" => "admin_users_index_header_actions"} + %tbody + - @users.each do |user| + - # HAML seems to have a bug that it can't parse `class cycle('odd', 'even')` on the element. + - # So we assign it first: + - row_class = cycle("odd", "even") + %tr{id: spree_dom_id(user), "data-hook" => "admin_users_index_rows", class: row_class} + %td.user_email= link_to user.email, object_url(user) + %td.actions{"data-hook" => "admin_users_index_row_actions"} + = link_to_edit user, no_text: true + = link_to_delete user, no_text: true += paginate @users +- content_for :sidebar_title do + = Spree.t(:search) +- content_for :sidebar do + .box.align-center{"data-hook" => "admin_users_index_search"} + = search_form_for [:admin, @search] do |f| + .field + = f.label Spree.t(:email) + %br + = f.text_field :email_cont, class: "fullwidth" + %div{"data-hook" => "admin_users_index_search_buttons"} + = button Spree.t(:search), "icon-search" From ab9975cb6cdd994eb1cf1c92daa15eedb63dad27 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:04:33 +1000 Subject: [PATCH 062/125] Move override into view --- .../index/add_enterprise_limit_column.html.haml.deface | 3 --- .../add_enterprise_limit_column_header.html.haml.deface | 3 --- .../index/reconfigure_column_spacing.html.haml.deface | 6 ------ app/views/spree/admin/users/index.html.haml | 7 +++++-- 4 files changed, 5 insertions(+), 14 deletions(-) delete mode 100644 app/overrides/spree/admin/users/index/add_enterprise_limit_column.html.haml.deface delete mode 100644 app/overrides/spree/admin/users/index/add_enterprise_limit_column_header.html.haml.deface delete mode 100644 app/overrides/spree/admin/users/index/reconfigure_column_spacing.html.haml.deface diff --git a/app/overrides/spree/admin/users/index/add_enterprise_limit_column.html.haml.deface b/app/overrides/spree/admin/users/index/add_enterprise_limit_column.html.haml.deface deleted file mode 100644 index d16e186be8..0000000000 --- a/app/overrides/spree/admin/users/index/add_enterprise_limit_column.html.haml.deface +++ /dev/null @@ -1,3 +0,0 @@ -/ insert_before "td[data-hook='admin_users_index_row_actions']" - -%td.user_enterprise_limit= user.enterprise_limit \ No newline at end of file diff --git a/app/overrides/spree/admin/users/index/add_enterprise_limit_column_header.html.haml.deface b/app/overrides/spree/admin/users/index/add_enterprise_limit_column_header.html.haml.deface deleted file mode 100644 index f2222ef012..0000000000 --- a/app/overrides/spree/admin/users/index/add_enterprise_limit_column_header.html.haml.deface +++ /dev/null @@ -1,3 +0,0 @@ -/ insert_before "th[data-hook='admin_users_index_header_actions']" - -%th= sort_link @search,:enterprise_limit, t(:enterprise_limit) \ No newline at end of file diff --git a/app/overrides/spree/admin/users/index/reconfigure_column_spacing.html.haml.deface b/app/overrides/spree/admin/users/index/reconfigure_column_spacing.html.haml.deface deleted file mode 100644 index d666e1b7c5..0000000000 --- a/app/overrides/spree/admin/users/index/reconfigure_column_spacing.html.haml.deface +++ /dev/null @@ -1,6 +0,0 @@ -/ replace "table#listing_users colgroup" - -%colgroup - %col{ style: "width: 65%" } - %col{ style: "width: 20%" } - %col{ style: "width: 15%" } \ No newline at end of file diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml index 023cb11ec6..854e6f1a08 100644 --- a/app/views/spree/admin/users/index.html.haml +++ b/app/views/spree/admin/users/index.html.haml @@ -5,11 +5,13 @@ = button_link_to Spree.t(:new_user), new_object_url, icon: "icon-plus", id: "admin_new_user_link" %table#listing_users.index{"data-hook" => ""} %colgroup - %col{style: "width: 85%"} - %col{style: "width: 15%"} + %col{ style: "width: 65%" } + %col{ style: "width: 20%" } + %col{ style: "width: 15%" } %thead %tr{"data-hook" => "admin_users_index_headers"} %th= sort_link @search,:email, Spree.t(:user), {}, {title: "users_email_title"} + %th= sort_link @search,:enterprise_limit, t(:enterprise_limit) %th.actions{"data-hook" => "admin_users_index_header_actions"} %tbody - @users.each do |user| @@ -18,6 +20,7 @@ - row_class = cycle("odd", "even") %tr{id: spree_dom_id(user), "data-hook" => "admin_users_index_rows", class: row_class} %td.user_email= link_to user.email, object_url(user) + %td.user_enterprise_limit= user.enterprise_limit %td.actions{"data-hook" => "admin_users_index_row_actions"} = link_to_edit user, no_text: true = link_to_delete user, no_text: true From a347837044227dcdb62c4d4d3d2b4f4664d56fc0 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:08:32 +1000 Subject: [PATCH 063/125] Move override into view --- .../spree/admin/users/index/add_roles_link.html.haml.deface | 3 --- app/views/spree/admin/users/index.html.haml | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 app/overrides/spree/admin/users/index/add_roles_link.html.haml.deface diff --git a/app/overrides/spree/admin/users/index/add_roles_link.html.haml.deface b/app/overrides/spree/admin/users/index/add_roles_link.html.haml.deface deleted file mode 100644 index f99a1ebff4..0000000000 --- a/app/overrides/spree/admin/users/index/add_roles_link.html.haml.deface +++ /dev/null @@ -1,3 +0,0 @@ -/ insert_before "table#listing_users" - -= render 'admin/shared/users_sub_menu' \ No newline at end of file diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml index 854e6f1a08..1628126d97 100644 --- a/app/views/spree/admin/users/index.html.haml +++ b/app/views/spree/admin/users/index.html.haml @@ -3,6 +3,9 @@ - content_for :page_actions do %li = button_link_to Spree.t(:new_user), new_object_url, icon: "icon-plus", id: "admin_new_user_link" + += render "admin/shared/users_sub_menu" + %table#listing_users.index{"data-hook" => ""} %colgroup %col{ style: "width: 65%" } From 28c2ad71604084a32ac3b3075b465794eb147818 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:13:01 +1000 Subject: [PATCH 064/125] Move override into view --- .../index/replace_show_link_with_edit_link.html.haml.deface | 3 --- app/views/spree/admin/users/index.html.haml | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 app/overrides/spree/admin/users/index/replace_show_link_with_edit_link.html.haml.deface diff --git a/app/overrides/spree/admin/users/index/replace_show_link_with_edit_link.html.haml.deface b/app/overrides/spree/admin/users/index/replace_show_link_with_edit_link.html.haml.deface deleted file mode 100644 index 330e06ea9d..0000000000 --- a/app/overrides/spree/admin/users/index/replace_show_link_with_edit_link.html.haml.deface +++ /dev/null @@ -1,3 +0,0 @@ -/ replace "code[erb-loud]:contains('link_to user.email, object_url(user)')" - -= link_to user.email, edit_object_url(user) \ No newline at end of file diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml index 1628126d97..91bffa6c96 100644 --- a/app/views/spree/admin/users/index.html.haml +++ b/app/views/spree/admin/users/index.html.haml @@ -22,7 +22,7 @@ - # So we assign it first: - row_class = cycle("odd", "even") %tr{id: spree_dom_id(user), "data-hook" => "admin_users_index_rows", class: row_class} - %td.user_email= link_to user.email, object_url(user) + %td.user_email= link_to user.email, edit_object_url(user) %td.user_enterprise_limit= user.enterprise_limit %td.actions{"data-hook" => "admin_users_index_row_actions"} = link_to_edit user, no_text: true From e37213f6a5c6088f5d14810f54922fc3cb05be48 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:14:26 +1000 Subject: [PATCH 065/125] Remove redundant edit action --- app/views/spree/admin/users/index.html.haml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml index 91bffa6c96..8b3633887e 100644 --- a/app/views/spree/admin/users/index.html.haml +++ b/app/views/spree/admin/users/index.html.haml @@ -25,7 +25,6 @@ %td.user_email= link_to user.email, edit_object_url(user) %td.user_enterprise_limit= user.enterprise_limit %td.actions{"data-hook" => "admin_users_index_row_actions"} - = link_to_edit user, no_text: true = link_to_delete user, no_text: true = paginate @users - content_for :sidebar_title do From a531135804f0a5e66f93cd4d3e6b9e33e0e34e9c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 15:17:15 +1000 Subject: [PATCH 066/125] Remove unused data-hooks --- app/views/spree/admin/users/index.html.haml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/views/spree/admin/users/index.html.haml b/app/views/spree/admin/users/index.html.haml index 8b3633887e..e7ef05d711 100644 --- a/app/views/spree/admin/users/index.html.haml +++ b/app/views/spree/admin/users/index.html.haml @@ -6,35 +6,35 @@ = render "admin/shared/users_sub_menu" -%table#listing_users.index{"data-hook" => ""} +%table#listing_users.index %colgroup %col{ style: "width: 65%" } %col{ style: "width: 20%" } %col{ style: "width: 15%" } %thead - %tr{"data-hook" => "admin_users_index_headers"} + %tr %th= sort_link @search,:email, Spree.t(:user), {}, {title: "users_email_title"} %th= sort_link @search,:enterprise_limit, t(:enterprise_limit) - %th.actions{"data-hook" => "admin_users_index_header_actions"} + %th.actions %tbody - @users.each do |user| - # HAML seems to have a bug that it can't parse `class cycle('odd', 'even')` on the element. - # So we assign it first: - row_class = cycle("odd", "even") - %tr{id: spree_dom_id(user), "data-hook" => "admin_users_index_rows", class: row_class} + %tr{id: spree_dom_id(user), class: row_class} %td.user_email= link_to user.email, edit_object_url(user) %td.user_enterprise_limit= user.enterprise_limit - %td.actions{"data-hook" => "admin_users_index_row_actions"} + %td.actions = link_to_delete user, no_text: true = paginate @users - content_for :sidebar_title do = Spree.t(:search) - content_for :sidebar do - .box.align-center{"data-hook" => "admin_users_index_search"} + .box.align-center = search_form_for [:admin, @search] do |f| .field = f.label Spree.t(:email) %br = f.text_field :email_cont, class: "fullwidth" - %div{"data-hook" => "admin_users_index_search_buttons"} + %div = button Spree.t(:search), "icon-search" From fbe2f7ab4c586d4fd99f93a7b746a35585672b97 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 8 Jun 2018 17:52:59 +1000 Subject: [PATCH 067/125] Remove unused variable from mailer The second variable passed by Devise is actually a hash, not a token. --- app/mailers/spree/user_mailer_decorator.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/mailers/spree/user_mailer_decorator.rb b/app/mailers/spree/user_mailer_decorator.rb index 991db0074c..778f4d421a 100644 --- a/app/mailers/spree/user_mailer_decorator.rb +++ b/app/mailers/spree/user_mailer_decorator.rb @@ -5,9 +5,10 @@ Spree::UserMailer.class_eval do :subject => t(:welcome_to) + Spree::Config[:site_name]) end - def confirmation_instructions(user, token) + # Overriding `Spree::UserMailer.confirmation_instructions` which is + # overriding `Devise::Mailer.confirmation_instructions`. + def confirmation_instructions(user, _opts) @user = user - @token = token subject = t('spree.user_mailer.confirmation_instructions.subject') mail(to: user.email, from: from_address, From 43883d1ab46c606d260e83061658fe41250ff920 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 20 Jun 2018 14:40:48 +1000 Subject: [PATCH 068/125] Simplify email confirmation directive Making better use of Angular features. Adding a spec for this functionality. --- .../resend_user_email_confirmation.js.coffee | 12 +++++------- .../admin/users/_email_confirmation.html.haml | 3 +-- config/locales/en.yml | 8 ++++---- spec/features/admin/users_spec.rb | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee b/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee index b6361ec7ae..a9ec8af2ec 100644 --- a/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee +++ b/app/assets/javascripts/admin/users/directives/resend_user_email_confirmation.js.coffee @@ -1,19 +1,17 @@ angular.module("admin.users").directive "resendUserEmailConfirmation", ($http) -> + template: "{{ 'js.admin.resend_user_email_confirmation.' + status | t }}" scope: email: "@resendUserEmailConfirmation" link: (scope, element, attrs) -> sent = false - text = element.text() - sending = " " + t "js.admin.resend_user_email_confirmation.sending" - done = " " + t "js.admin.resend_user_email_confirmation.done" - failed = " " + t "js.admin.resend_user_email_confirmation.failed" + scope.status = "resend" element.bind "click", -> return if sent - element.text(text + sending) + scope.status = "sending" $http.post("/user/spree_user/confirmation", {spree_user: {email: scope.email}}).success (data) -> sent = true element.addClass "action--disabled" - element.text text + done + scope.status = "done" .error (data) -> - element.text text + failed + scope.status = "failed" diff --git a/app/views/spree/admin/users/_email_confirmation.html.haml b/app/views/spree/admin/users/_email_confirmation.html.haml index fb2fd75232..f851ea339e 100644 --- a/app/views/spree/admin/users/_email_confirmation.html.haml +++ b/app/views/spree/admin/users/_email_confirmation.html.haml @@ -1,4 +1,3 @@ %p.alert-box{"ng-app" => "admin.users"} = t(".confirmation_pending", address: @user.email) - %a{"resend-user-email-confirmation" => @user.email} - = t(".resend") \ No newline at end of file + %a{"resend-user-email-confirmation" => @user.email} \ No newline at end of file diff --git a/config/locales/en.yml b/config/locales/en.yml index 675ea554a5..67c8d17fd3 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2436,9 +2436,10 @@ See the %{link} to find out more about %{sitename}'s features and to start using new_tag_rule_dialog: select_rule_type: "Select a rule type:" resend_user_email_confirmation: - sending: "..." - done: "done ✓" - failed: "failed ✗" + resend: "Resend" + sending: "Resend..." + done: "Resend done ✓" + failed: "Resend failed ✗" out_of_stock: reduced_stock_available: Reduced stock available out_of_stock_text: > @@ -2592,7 +2593,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using users: email_confirmation: confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}." - resend: "Resend" variants: autocomplete: producer_name: Producer diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb index 2e78a19500..5a3666e2a8 100644 --- a/spec/features/admin/users_spec.rb +++ b/spec/features/admin/users_spec.rb @@ -24,5 +24,20 @@ feature "Managing users" do expect(page).to have_text "Email confirmation is pending" end end + + describe "resending confirmation email", js: true do + let(:user) { create :user, confirmed_at: nil } + + it "displays success" do + visit spree.edit_admin_user_path user + + # The `a` element doesn't have an href, so we can't use click_link. + find("a", text: "Resend").click + expect(page).to have_text "Resend done" + + # And it's successful. (testing it here for reduced test time) + expect(Delayed::Job.last.payload_object.method_name).to eq :send_confirmation_instructions_without_delay + end + end end end From d5d1eae715286a8121440dfaad1f2f3ce935d609 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 29 Jun 2018 09:37:44 +1000 Subject: [PATCH 069/125] Improve spec description --- spec/features/admin/users_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/users_spec.rb b/spec/features/admin/users_spec.rb index 5a3666e2a8..9af920577a 100644 --- a/spec/features/admin/users_spec.rb +++ b/spec/features/admin/users_spec.rb @@ -12,7 +12,7 @@ feature "Managing users" do expect(page).to have_no_text "Email confirmation is pending" end - it "works" do + it "confirms successful creation" do visit spree.new_admin_user_path fill_in "Email", with: "user1@example.org" fill_in "Password", with: "user1Secret" From dfb510debe60f61cebde8ec8ddf18d3de3127801 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Thu, 28 Jun 2018 23:17:42 +0100 Subject: [PATCH 070/125] admin page fetcher is now receiving a onLastPageComplete function that is used to show "no results" messages only after the last page is fetched --- .../javascripts/admin/bulk_product_update.js.coffee | 6 +++++- .../admin/index_utils/services/paged_fetcher.js.coffee | 8 ++++++-- .../javascripts/admin/services/bulk_products.js.coffee | 3 ++- .../spree/admin/products/index/_indicators.html.haml | 4 ++-- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index a9f2f20d14..2a3497898b 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -1,5 +1,6 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, $window, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) -> $scope.loading = true + $scope.loadingAllPages = true $scope.StatusMessage = StatusMessage @@ -49,7 +50,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout $scope.fetchProducts = -> $scope.loading = true - BulkProducts.fetch($scope.currentFilters).then -> + $scope.loadingAllPages = true + BulkProducts.fetch($scope.currentFilters, -> + $scope.loadingAllPages = false + ).then -> $scope.resetProducts() $scope.loading = false diff --git a/app/assets/javascripts/admin/index_utils/services/paged_fetcher.js.coffee b/app/assets/javascripts/admin/index_utils/services/paged_fetcher.js.coffee index d65887bb2c..82487996ae 100644 --- a/app/assets/javascripts/admin/index_utils/services/paged_fetcher.js.coffee +++ b/app/assets/javascripts/admin/index_utils/services/paged_fetcher.js.coffee @@ -3,14 +3,18 @@ angular.module("admin.indexUtils").factory "PagedFetcher", (dataFetcher) -> # Given a URL like http://example.com/foo?page=::page::&per_page=20 # And the response includes an attribute pages with the number of pages to fetch # Fetch each page async, and call the processData callback with the resulting data - fetch: (url, processData) -> + fetch: (url, processData, onLastPageComplete) -> dataFetcher(@urlForPage(url, 1)).then (data) => processData data if data.pages > 1 for page in [2..data.pages] - dataFetcher(@urlForPage(url, page)).then (data) -> + lastPromise = dataFetcher(@urlForPage(url, page)).then (data) -> processData data + onLastPageComplete && lastPromise.then onLastPageComplete + return + else + onLastPageComplete && onLastPageComplete() urlForPage: (url, page) -> url.replace("::page::", page) diff --git a/app/assets/javascripts/admin/services/bulk_products.js.coffee b/app/assets/javascripts/admin/services/bulk_products.js.coffee index 022345e9d8..a528c522ca 100644 --- a/app/assets/javascripts/admin/services/bulk_products.js.coffee +++ b/app/assets/javascripts/admin/services/bulk_products.js.coffee @@ -8,7 +8,8 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher, , "" url = "/api/products/bulk_products?page=::page::;per_page=20;#{queryString}" - PagedFetcher.fetch url, (data) => @addProducts data.products + processData = (data) => @addProducts data.products + PagedFetcher.fetch url, processData, onComplete cloneProduct: (product) -> $http.post("/api/products/" + product.id + "/clone").success (data) => diff --git a/app/views/spree/admin/products/index/_indicators.html.haml b/app/views/spree/admin/products/index/_indicators.html.haml index bfdd104690..5cf28af7de 100644 --- a/app/views/spree/admin/products/index/_indicators.html.haml +++ b/app/views/spree/admin/products/index/_indicators.html.haml @@ -5,10 +5,10 @@ %img.spinner{ src: "/assets/spinning-circles.svg" } %h1= t('.title') -%div.sixteen.columns.alpha{ 'ng-show' => '!loading && filteredProducts.length == 0 && query.length==0' } +%div.sixteen.columns.alpha{ 'ng-show' => '!loadingAllPages && filteredProducts.length == 0 && query.length==0' } %h1#no_results= t('.no_products') -%div.sixteen.columns.alpha{ 'ng-show' => '!loading && filteredProducts.length == 0 && query.length!=0' } +%div.sixteen.columns.alpha{ 'ng-show' => '!loadingAllPages && filteredProducts.length == 0 && query.length!=0' } %h1#no_results = t('.no_results') ' From 185cf9a312102455df5ac5f4bc43df78103dc15f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 12 Jul 2018 15:42:47 +1000 Subject: [PATCH 071/125] Remove code duplication --- .../consumer/shopping/embedded_groups_spec.rb | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/spec/features/consumer/shopping/embedded_groups_spec.rb b/spec/features/consumer/shopping/embedded_groups_spec.rb index 4122fb30ce..19fe83685a 100644 --- a/spec/features/consumer/shopping/embedded_groups_spec.rb +++ b/spec/features/consumer/shopping/embedded_groups_spec.rb @@ -17,9 +17,7 @@ feature "Using embedded shopfront functionality", js: true do end it "displays in an iframe" do - expect(page).to have_selector 'iframe#group_test_iframe' - - within_frame 'group_test_iframe' do + on_embedded_page do within 'div#group-page' do expect(page).to have_content 'About Us' end @@ -27,9 +25,7 @@ feature "Using embedded shopfront functionality", js: true do end it "displays powered by OFN text at bottom of page" do - expect(page).to have_selector 'iframe#group_test_iframe' - - within_frame 'group_test_iframe' do + on_embedded_page do within 'div#group-page' do expect(page).to have_selector 'div.powered-by-embedded' expect(page).to have_css "img[src*='favicon.ico']" @@ -40,9 +36,7 @@ feature "Using embedded shopfront functionality", js: true do end it "doesn't display contact details when embedded" do - expect(page).to have_selector 'iframe#group_test_iframe' - - within_frame 'group_test_iframe' do + on_embedded_page do within 'div#group-page' do expect(page).to have_no_selector 'div.contact-container' @@ -52,9 +46,7 @@ feature "Using embedded shopfront functionality", js: true do end it "does not display the header when embedded" do - expect(page).to have_selector 'iframe#group_test_iframe' - - within_frame 'group_test_iframe' do + on_embedded_page do within 'div#group-page' do expect(page).to have_no_selector 'header' expect(page).to have_no_selector 'img.group-logo' @@ -64,9 +56,7 @@ feature "Using embedded shopfront functionality", js: true do end it 'opens links to shops in a new window' do - expect(page).to have_selector 'iframe#group_test_iframe' - - within_frame 'group_test_iframe' do + on_embedded_page do within 'div#group-page' do enterprise_links = page.all(:xpath, "//*[contains(@href, 'enterprise-5/shop')]", :visible => :false).count enterprise_links_with_target_blank = page.all(:xpath, "//*[contains(@href, 'enterprise-5/shop') and @target = '_blank']", :visible => :false).count @@ -75,4 +65,14 @@ feature "Using embedded shopfront functionality", js: true do end end end + + private + + def on_embedded_page + expect(page).to have_selector 'iframe#group_test_iframe' + + within_frame 'group_test_iframe' do + yield + end + end end From ed747ec6124d8b645fea20a02f20eed9f74c5ee6 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 12 Jul 2018 15:54:29 +1000 Subject: [PATCH 072/125] Use embedded groups example for tests --- spec/features/consumer/shopping/embedded_groups_spec.rb | 8 +++----- spec/support/views/group_iframe_test.html | 8 -------- 2 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 spec/support/views/group_iframe_test.html diff --git a/spec/features/consumer/shopping/embedded_groups_spec.rb b/spec/features/consumer/shopping/embedded_groups_spec.rb index 19fe83685a..dd301ec273 100644 --- a/spec/features/consumer/shopping/embedded_groups_spec.rb +++ b/spec/features/consumer/shopping/embedded_groups_spec.rb @@ -2,8 +2,6 @@ require 'spec_helper' feature "Using embedded shopfront functionality", js: true do - Capybara.server_port = 9999 - describe 'embedded groups' do let(:enterprise) { create(:distributor_enterprise) } let!(:group) { create(:enterprise_group, enterprises: [enterprise], permalink: 'group1', on_front_page: true) } @@ -13,7 +11,7 @@ feature "Using embedded shopfront functionality", js: true do Spree::Config[:embedded_shopfronts_whitelist] = 'test.com' page.driver.browser.js_errors = false allow_any_instance_of(ActionDispatch::Request).to receive(:referer).and_return('https://www.test.com') - Capybara.current_session.driver.visit('spec/support/views/group_iframe_test.html') + visit "/embedded-group-preview.html?group1" end it "displays in an iframe" do @@ -69,9 +67,9 @@ feature "Using embedded shopfront functionality", js: true do private def on_embedded_page - expect(page).to have_selector 'iframe#group_test_iframe' + expect(page).to have_selector "iframe" - within_frame 'group_test_iframe' do + within_frame :frame do yield end end diff --git a/spec/support/views/group_iframe_test.html b/spec/support/views/group_iframe_test.html deleted file mode 100644 index dcb4abbceb..0000000000 --- a/spec/support/views/group_iframe_test.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From 6f737d8d1e1d856ee306022f19c51eb2bc21f00a Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 12 Jul 2018 16:01:19 +1000 Subject: [PATCH 073/125] Unclutter spec setup --- spec/features/consumer/shopping/embedded_groups_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/consumer/shopping/embedded_groups_spec.rb b/spec/features/consumer/shopping/embedded_groups_spec.rb index dd301ec273..21ee73c00d 100644 --- a/spec/features/consumer/shopping/embedded_groups_spec.rb +++ b/spec/features/consumer/shopping/embedded_groups_spec.rb @@ -4,14 +4,14 @@ feature "Using embedded shopfront functionality", js: true do describe 'embedded groups' do let(:enterprise) { create(:distributor_enterprise) } - let!(:group) { create(:enterprise_group, enterprises: [enterprise], permalink: 'group1', on_front_page: true) } + let(:group) { create(:enterprise_group, enterprises: [enterprise]) } before do Spree::Config[:enable_embedded_shopfronts] = true Spree::Config[:embedded_shopfronts_whitelist] = 'test.com' page.driver.browser.js_errors = false allow_any_instance_of(ActionDispatch::Request).to receive(:referer).and_return('https://www.test.com') - visit "/embedded-group-preview.html?group1" + visit "/embedded-group-preview.html?#{group.permalink}" end it "displays in an iframe" do From 66980b247a466afa320513a8677f8f0875844558 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 12 Jul 2018 16:35:27 +1000 Subject: [PATCH 074/125] Fix test of opening shops in new windows The test case had some hard-coded enterprise name that didn't match anything. It then confirmed that all found links (none) would open a new window. So it wasn't confirming anything. --- .../consumer/shopping/embedded_groups_spec.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spec/features/consumer/shopping/embedded_groups_spec.rb b/spec/features/consumer/shopping/embedded_groups_spec.rb index 21ee73c00d..6df7734d6d 100644 --- a/spec/features/consumer/shopping/embedded_groups_spec.rb +++ b/spec/features/consumer/shopping/embedded_groups_spec.rb @@ -53,12 +53,17 @@ feature "Using embedded shopfront functionality", js: true do end end - it 'opens links to shops in a new window' do + it "opens links to shops in a new window" do on_embedded_page do within 'div#group-page' do - enterprise_links = page.all(:xpath, "//*[contains(@href, 'enterprise-5/shop')]", :visible => :false).count - enterprise_links_with_target_blank = page.all(:xpath, "//*[contains(@href, 'enterprise-5/shop') and @target = '_blank']", :visible => :false).count - expect(enterprise_links).to equal(enterprise_links_with_target_blank) + shop_links_xpath = "//*[contains(@href, '#{enterprise.permalink}/shop')]" + + expect(page).to have_xpath shop_links_xpath, visible: false + + shop_links = page.all(:xpath, shop_links_xpath, visible: false) + shop_links.each do |link| + expect(link[:target]).to eq "_blank" + end end end end From 4ebcf4e3c3419863a1d774737e49456ffee41080 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 13 Jul 2018 13:58:32 +0800 Subject: [PATCH 075/125] Add internationalisation info to CONTRIBUTING.md --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5ea968c65c..bb45f49082 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -30,6 +30,10 @@ If you want to run the whole test suite, we recommend using a free CI service to bundle exec rspec spec +## Internationalisation (i18n) + +The locale `en` is maintained in the source code, but other locales are managed at [Transifex][ofn-transifex]. Read more about [internationalisation][i18n] in the developer wiki. + ## Making a change Make your changes to the codebase. We recommend using TDD. Add a test, make changes and get the test suite back to green. @@ -66,3 +70,5 @@ From here, your pull request will progress through the [Review, Test, Merge & De [rebase]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing/workflow-walkthrough [travis]: https://travis-ci.org/ [semaphore]: https://semaphoreci.com/ +[ofn-transifex]: https://www.transifex.com/open-food-foundation/open-food-network/ +[i18n]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/i18n From 599f1a966ba82dc6fa5e2cddc2fb71591694c7ec Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 12 Jul 2018 17:11:21 +1000 Subject: [PATCH 076/125] Use embedded shops example for tests --- public/embedded-shop-preview.html | 20 ++++++++++++++++ .../shopping/embedded_shopfronts_spec.rb | 23 +++++++++++-------- spec/support/views/iframe_test.html | 8 ------- 3 files changed, 34 insertions(+), 17 deletions(-) create mode 100644 public/embedded-shop-preview.html delete mode 100644 spec/support/views/iframe_test.html diff --git a/public/embedded-shop-preview.html b/public/embedded-shop-preview.html new file mode 100644 index 0000000000..a3c53f6440 --- /dev/null +++ b/public/embedded-shop-preview.html @@ -0,0 +1,20 @@ + + Embedded Shop + + +

    + This is a preview page for embedded shops. + Choose a shop to display by copying its permalink id into the URL after the question mark. + Example: embedded-shop-preview.html?bawbawfoodhub +

    + + + + + + diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 87b6a7e5ca..da99492945 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -7,8 +7,6 @@ feature "Using embedded shopfront functionality", js: true do include CheckoutWorkflow include UIComponentHelper - Capybara.server_port = 9999 - describe "using iframes" do let(:distributor) { create(:distributor_enterprise, name: 'My Embedded Hub', permalink: 'test_enterprise', with_payment_and_shipping: true) } let(:supplier) { create(:supplier_enterprise) } @@ -24,9 +22,8 @@ feature "Using embedded shopfront functionality", js: true do Spree::Config[:enable_embedded_shopfronts] = true Spree::Config[:embedded_shopfronts_whitelist] = 'test.com' - page.driver.browser.js_errors = false allow_any_instance_of(ActionDispatch::Request).to receive(:referer).and_return('https://www.test.com') - Capybara.current_session.driver.visit('spec/support/views/iframe_test.html') + visit "/embedded-shop-preview.html?#{distributor.permalink}" end after do @@ -34,9 +31,7 @@ feature "Using embedded shopfront functionality", js: true do end it "displays modified shopfront layout" do - expect(page).to have_selector 'iframe#test_iframe' - - within_frame 'test_iframe' do + on_embedded_page do within 'nav.top-bar' do expect(page).to have_selector 'ul.left', visible: false expect(page).to have_selector 'ul.center', visible: false @@ -48,7 +43,7 @@ feature "Using embedded shopfront functionality", js: true do end xit "allows shopping and checkout" do - within_frame 'test_iframe' do + on_embedded_page do fill_in "variants[#{variant.id}]", with: 1 wait_until_enabled 'input.add_to_cart' @@ -97,7 +92,7 @@ feature "Using embedded shopfront functionality", js: true do end it "redirects to embedded hub on logout when embedded" do - within_frame 'test_iframe' do + on_embedded_page do find('ul.right li#login-link a').click login_with_modal @@ -110,6 +105,16 @@ feature "Using embedded shopfront functionality", js: true do end end + private + + def on_embedded_page + expect(page).to have_selector "iframe" + + within_frame :frame do + yield + end + end + def login_with_modal expect(page).to have_selector 'div.login-modal', visible: true diff --git a/spec/support/views/iframe_test.html b/spec/support/views/iframe_test.html deleted file mode 100644 index fe71aa66e3..0000000000 --- a/spec/support/views/iframe_test.html +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - From 8e90488117d9c9b5ce912918e69b09d1d92ca868 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 13 Jul 2018 16:21:28 +1000 Subject: [PATCH 077/125] Use progress formatter on Travis to avoid timeout We had a few Travis builds lately that timed out, because no output was received. Even though our standard formatter Fuubar should detect Travis and print the right output, nothing was visible in our builds. https://github.com/travis-ci/travis-ci/issues/1337 In this patch, I tell Travis to use Rspec's default formatter to print dots for every passed test. --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7039fe0c1a..952e999999 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,7 +42,7 @@ before_script: script: - 'if [ "$KARMA" = "true" ]; then bundle exec rake karma:run; else echo "Skipping karma run"; fi' - - "bundle exec rake 'knapsack:rspec[--tag ~performance]'" + - "bundle exec rake 'knapsack:rspec[--format progress --tag ~performance]'" after_success: - > From e3b7e050a0c2a8fb39d9b057b802b7001d9333ba Mon Sep 17 00:00:00 2001 From: Frank West Date: Fri, 29 Jun 2018 06:46:30 -0700 Subject: [PATCH 078/125] Remove spree product navigation override This was here to override the original spree products navigation link, but since moving back to the index action this had the side effect of adding an additional navigation item instead. We can simply remove this override to get rid of the additional menu item. --- .../_product_sub_menu/add_products_tab.html.haml.deface | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 app/overrides/spree/admin/shared/_product_sub_menu/add_products_tab.html.haml.deface diff --git a/app/overrides/spree/admin/shared/_product_sub_menu/add_products_tab.html.haml.deface b/app/overrides/spree/admin/shared/_product_sub_menu/add_products_tab.html.haml.deface deleted file mode 100644 index 074a76f3ed..0000000000 --- a/app/overrides/spree/admin/shared/_product_sub_menu/add_products_tab.html.haml.deface +++ /dev/null @@ -1,4 +0,0 @@ -/ insert_bottom "[data-hook='admin_product_sub_tabs']" - -- if spree_current_user.admin? - = tab :spree_products, url: admin_products_path, :match_path => '/products' \ No newline at end of file From 622517501c63445cc45f33677d0eb3667c26821b Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 13 Jul 2018 19:06:09 +1000 Subject: [PATCH 079/125] Make spec robust on slow computers This spec just failed in an unrelated pull request. https://travis-ci.org/openfoodfoundation/openfoodnetwork/jobs/403435522 This change should fix it even on very slow computers. --- spec/models/proxy_order_spec.rb | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/spec/models/proxy_order_spec.rb b/spec/models/proxy_order_spec.rb index 67d4af87f2..b84089c015 100644 --- a/spec/models/proxy_order_spec.rb +++ b/spec/models/proxy_order_spec.rb @@ -5,6 +5,11 @@ describe ProxyOrder, type: :model do let(:order_cycle) { create(:simple_order_cycle) } let(:subscription) { create(:subscription) } + around do |example| + # We are testing if database columns have been set to "now". + Timecop.freeze(Time.zone.now) { example.run } + end + context "when the order cycle is not yet closed" do let(:proxy_order) { create(:proxy_order, subscription: subscription, order: order, order_cycle: order_cycle) } before { order_cycle.update_attributes(orders_open_at: 1.day.ago, orders_close_at: 3.days.from_now) } @@ -14,7 +19,7 @@ describe ProxyOrder, type: :model do it "returns true and sets canceled_at to the current time" do expect(proxy_order.cancel).to be true - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(proxy_order.state).to eq 'canceled' end end @@ -25,7 +30,7 @@ describe ProxyOrder, type: :model do it "returns true and sets canceled_at to the current time, and cancels the order" do expect(Spree::OrderMailer).to receive(:cancel_email) { double(:email, deliver: true) } expect(proxy_order.cancel).to be true - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(order.reload.state).to eq 'canceled' expect(proxy_order.state).to eq 'canceled' end @@ -36,7 +41,7 @@ describe ProxyOrder, type: :model do it "returns true and sets canceled_at to the current time" do expect(proxy_order.cancel).to be true - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(order.reload.state).to eq 'cart' expect(proxy_order.state).to eq 'canceled' end @@ -124,7 +129,7 @@ describe ProxyOrder, type: :model do it "returns false and does nothing" do expect(proxy_order.resume).to eq false - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(proxy_order.state).to eq 'canceled' end end @@ -138,7 +143,7 @@ describe ProxyOrder, type: :model do it "returns false and does nothing" do expect(proxy_order.resume).to eq false - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(order.reload.state).to eq 'canceled' expect(proxy_order.state).to eq 'canceled' end @@ -149,7 +154,7 @@ describe ProxyOrder, type: :model do it "returns false and does nothing" do expect(proxy_order.resume).to eq false - expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.zone.now + expect_cancelled_now proxy_order expect(order.reload.state).to eq 'complete' expect(proxy_order.state).to eq 'canceled' end @@ -184,4 +189,13 @@ describe ProxyOrder, type: :model do end end end + + private + + def expect_cancelled_now(subject) + # We still need to use be_within, because the Database timestamp is not as + # accurate as the Rails timestamp. If we use `eq`, we have differing nano + # seconds. + expect(subject.reload.canceled_at).to be_within(1.second).of Time.zone.now + end end From a4210a1cabcd0d1740f76b9d5e8f06a3d96aa34b Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 00:14:29 +0100 Subject: [PATCH 080/125] PI post-save UI changes --- app/views/admin/product_import/_save_results.html.haml | 4 ++-- config/locales/en.yml | 5 +++-- spec/features/admin/product_import_spec.rb | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/views/admin/product_import/_save_results.html.haml b/app/views/admin/product_import/_save_results.html.haml index 9ab9652ac1..901bb466e1 100644 --- a/app/views/admin/product_import/_save_results.html.haml +++ b/app/views/admin/product_import/_save_results.html.haml @@ -56,8 +56,8 @@ %a.button.view{href: main_app.admin_inventory_path, ng: {show: 'updates.inventory_created > 0 || updates.inventory_updated > 0'}} = t('admin.product_import.save.view_inventory') - %a.button.view{href: admin_products_path + '?latest_import=true', ng: {show: 'updates.products_created > 0 || updates.products_updated > 0'}} + %a.button.view{href: admin_products_path, ng: {show: 'updates.products_created > 0 || updates.products_updated > 0'}} = t('admin.product_import.save.view_products') %a.button{href: main_app.admin_product_import_path} - = t('admin.back') + = t('admin.product_import.save.import_again') diff --git a/config/locales/en.yml b/config/locales/en.yml index 67c8d17fd3..ebe1c524bb 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -516,8 +516,9 @@ en: all_saved: "All items saved successfully" some_saved: "items saved successfully" save_errors: Save errors - view_products: View Products - view_inventory: View Inventory + import_again: Upload Another File + view_products: Go To Products Page + view_inventory: Go To Inventory Page variant_overrides: loading_flash: diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index 35ebee5b1a..faedb012b7 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -72,7 +72,7 @@ feature "Product Import", js: true do wait_until { page.find("a.button.view").present? } - click_link 'View Products' + click_link I18n.t('admin.product_import.save.view_products') expect(page).to have_content 'Bulk Edit Products' wait_until { page.find("#p_#{potatoes.id}").present? } @@ -174,7 +174,7 @@ feature "Product Import", js: true do potatoes = Spree::Product.find_by_name('Potatoes') expect(potatoes.variants.first.import_date).to be_within(1.minute).of Time.zone.now - click_link 'View Products' + click_link I18n.t('admin.product_import.save.view_products') wait_until { page.find("#p_#{carrots.id}").present? } @@ -251,7 +251,7 @@ feature "Product Import", js: true do expect(Float(cabbage_override.price)).to eq 1.50 expect(cabbage_override.count_on_hand).to eq 2001 - click_link 'View Inventory' + click_link I18n.t('admin.product_import.save.view_inventory') expect(page).to have_content 'Inventory' select enterprise2.name, from: "hub_id", visible: false From 8aed78b0e63f7d529759eb05d23cef44802ab83a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 10:21:36 +0100 Subject: [PATCH 081/125] Don't allow save if invalid entries are present --- .../admin/product_import/import.html.haml | 4 ++-- config/locales/en.yml | 3 ++- spec/features/admin/product_import_spec.rb | 23 ++++--------------- 3 files changed, 8 insertions(+), 22 deletions(-) diff --git a/app/views/admin/product_import/import.html.haml b/app/views/admin/product_import/import.html.haml index bb8c85b8e4..7f96c7f907 100644 --- a/app/views/admin/product_import/import.html.haml +++ b/app/views/admin/product_import/import.html.haml @@ -41,7 +41,7 @@ %div{ng: {if: 'count((entries | entriesFilterValid:"invalid")) > 0'}} %br %h5= t('admin.product_import.import.some_invalid_entries') - %p= t('admin.product_import.import.save_valid?') + %p= t('admin.product_import.import.fix_before_import') %div{ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0'}} %br %h5= t('admin.product_import.import.no_errors') @@ -50,7 +50,7 @@ = hidden_field_tag :filepath, @filepath = hidden_field_tag "settings[import_into]", @import_into - %a.button.proceed{href: '', ng: {click: 'acceptResults()'}}= t('admin.product_import.import.proceed') + %a.button.proceed{href: '', ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0', click: 'acceptResults()'}}= t('admin.product_import.import.proceed') %a.button{href: main_app.admin_product_import_path}= t('admin.cancel') diff --git a/config/locales/en.yml b/config/locales/en.yml index 67c8d17fd3..8ed4aef6c4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -478,7 +478,8 @@ en: save_imported: Save imported products no_valid_entries: No valid entries found none_to_save: There are no entries that can be saved - some_invalid_entries: Imported file contains some invalid entries + some_invalid_entries: Imported file contains invalid entries + fix_before_import: Please fix these errors and try importing the file again save_valid?: Save valid entries for now and discard the others? no_errors: No errors detected! save_all_imported?: Save all imported products? diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index 35ebee5b1a..c4a504fba4 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -107,12 +107,10 @@ feature "Product Import", js: true do expect(page).to_not have_selector 'input[type=submit][value="Save"]' end - it "handles validation and saving of named tax and shipping categories" do + it "handles saving of named tax and shipping categories" do csv_data = CSV.generate do |csv| csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type", "tax_category", "shipping_category"] csv << ["Carrots", "User Enterprise", "Vegetables", "5", "3.20", "500", "g", tax_category.name, shipping_category.name] - csv << ["Potatoes", "User Enterprise", "Vegetables", "6", "6.50", "1", "kg", "Unknown Tax Category", shipping_category.name] - csv << ["Peas", "User Enterprise", "Vegetables", "7", "2.50", "1", "kg", tax_category2.name, "Unknown Shipping Category"] end File.write('/tmp/test.csv', csv_data) @@ -127,8 +125,7 @@ feature "Product Import", js: true do import_data - expect(page).to have_selector '.item-count', text: "3" - expect(page).to have_selector '.invalid-count', text: "2" + expect(page).to have_selector '.item-count', text: "1" expect(page).to have_selector '.create-count', text: "1" expect(page).to_not have_selector '.update-count' @@ -267,8 +264,6 @@ feature "Product Import", js: true do csv_data = CSV.generate do |csv| csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type", "tax_category", "shipping_category"] csv << ["Carrots", "User Enterprise", "Vegetables", "5", "3.20", "500", "g", tax_category.name, shipping_category.name] - csv << ["Potatoes", "User Enterprise", "Vegetables", "6", "6.50", "1", "kg", "Unknown Tax Category", shipping_category.name] - csv << ["Peas", "User Enterprise", "Vegetables", "7", "2.50", "1", "kg", tax_category2.name, "Unknown Shipping Category"] csv << ["Pumpkin", "User Enterprise", "Vegetables", "3", "3.50", "1", "kg", tax_category.name, ""] csv << ["Spinach", "User Enterprise", "Vegetables", "7", "3.60", "1", "kg", "", shipping_category.name] end @@ -307,8 +302,7 @@ feature "Product Import", js: true do import_data - expect(page).to have_selector '.item-count', text: "5" - expect(page).to have_selector '.invalid-count', text: "2" + expect(page).to have_selector '.item-count', text: "3" expect(page).to have_selector '.create-count', text: "3" expect(page).to_not have_selector '.update-count' @@ -403,16 +397,7 @@ feature "Product Import", js: true do expect(page).to have_selector '.create-count', text: "1" expect(page.body).to have_content 'you do not have permission' - - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - - save_data - - expect(page).to have_selector '.created-count', text: '1' - - expect(Spree::Product.find_by_name('My Carrots')).to be_a Spree::Product - expect(Spree::Product.find_by_name('Your Potatoes')).to be_nil + expect(page).to_not have_selector 'a.button.proceed', visible: true end end From f344b7893de991921df288bac361e4c39939fa56 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 20:48:12 +0100 Subject: [PATCH 082/125] Remove Product Import guide page --- .../admin/product_import_controller.rb | 6 -- .../admin/product_import/guide.html.haml | 69 ------------ .../product_import/guide/_columns.html.haml | 100 ------------------ .../product_import/guide/_units.html.haml | 54 ---------- .../product_import/guide/_variants.html.haml | 54 ---------- .../admin/product_import/index.html.haml | 6 -- config/routes.rb | 1 - 7 files changed, 290 deletions(-) delete mode 100644 app/views/admin/product_import/guide.html.haml delete mode 100644 app/views/admin/product_import/guide/_columns.html.haml delete mode 100644 app/views/admin/product_import/guide/_units.html.haml delete mode 100644 app/views/admin/product_import/guide/_variants.html.haml diff --git a/app/controllers/admin/product_import_controller.rb b/app/controllers/admin/product_import_controller.rb index 4037bcd85b..f2b1972a9c 100644 --- a/app/controllers/admin/product_import_controller.rb +++ b/app/controllers/admin/product_import_controller.rb @@ -4,12 +4,6 @@ module Admin class ProductImportController < Spree::Admin::BaseController before_filter :validate_upload_presence, except: %i[index guide validate_data] - def guide - @product_categories = Spree::Taxon.order('name ASC').pluck(:name).uniq - @tax_categories = Spree::TaxCategory.order('name ASC').pluck(:name) - @shipping_categories = Spree::ShippingCategory.order('name ASC').pluck(:name) - end - def import # Save uploaded file to tmp directory @filepath = save_uploaded_file(params[:file]) diff --git a/app/views/admin/product_import/guide.html.haml b/app/views/admin/product_import/guide.html.haml deleted file mode 100644 index aab0350606..0000000000 --- a/app/views/admin/product_import/guide.html.haml +++ /dev/null @@ -1,69 +0,0 @@ -- content_for :page_title do - Product Import Guide - -- content_for :page_actions do - %div.toolbar{ 'data-hook' => "toolbar" } - %ul.actions.header-action-links.inline-menu - %li - = button_link_to 'Back to Import', main_app.admin_product_import_path - -= render partial: 'spree/admin/shared/product_sub_menu' - -.product-import-introduction - - %h5 Spreadsheet Columns - - = render 'admin/product_import/guide/columns' - - %h5 Weight, volume, or single items - - %p - When creating a product you can specify a number of options. If the product is measured - by weight, unit_value should be set to a number and unit_type should be set to either - g for grams, Kg for kilograms, or T for tonnes. - - %p - For items such as liquids, the unit_type can be ml for millilitres, L for litres or - Kl for kilolitres. - - %p - For other items that are sold in different units such as "a bunch of carrots", you can - enter 1 for units, leave unit_type blank, and enter a name in the variant_unit_name - column such as "loaf" or "bunch". - - %h6 Example spreadsheet data: - - = render 'admin/product_import/guide/units' - - - %h5 Product Variants - - %p - Variants are distinguished by the units and display_name fields and grouped by product name. - The example below shows a salad that comes in 500g and 750g variants, and a cake that comes in - multiple flavours. - - %h6 Example spreadsheet data: - - = render 'admin/product_import/guide/variants' - - - %h5 Category Values - - %p - Listed below are the available Product categories, as well as Tax and Shipping categories. - - %h6 Product Categories - - - @product_categories.each do |pc| - %span.category= pc - - %h6 Tax Categories - - - @tax_categories.each do |tc| - %span.category= tc - - %h6 Shipping Categories - - - @shipping_categories.each do |sc| - %span.category= sc diff --git a/app/views/admin/product_import/guide/_columns.html.haml b/app/views/admin/product_import/guide/_columns.html.haml deleted file mode 100644 index c79a881162..0000000000 --- a/app/views/admin/product_import/guide/_columns.html.haml +++ /dev/null @@ -1,100 +0,0 @@ -%table.product-import-columns - %thead - %tr - %th Column Title - %th Required - %th Examples - %th Description - %th Notes - %tbody - %tr - %td - %strong name - %td Yes - %td Potatoes - %td The name of the product - %td - %tr - %td - %strong supplier - %td Yes - %td Pennylane Farm - %td The name of the product's supplier - %td - %tr - %td - %strong category - %td Yes - %td Vegetables - %td The product category - %td See below for a list of available categories - %tr - %td - %strong on_hand - %td Yes - %td 15 - %td The amount currently in stock - %td - %tr - %td - %strong price - %td Yes - %td 2.50 - %td The price of the product - %td - %tr - %td - %strong units - %td Yes - %td 750 - %td The weight or volume value. - %td - %tr - %td - %strong unit_type - %td Yes - %td g - %td The unit type, i.e. g for grams, Kg for Kilograms, ml for millilitres. Can be blank (see notes). - %td If unit_type is left blank, a variant_unit_name must be given. - %tr - %td - %strong variant_unit_name - %td Maybe - %td bunch - %td If the product is sold as an item such as "bunch", "loaf" or "case", that goes here. - %td Used for products that don't use a unit_type for weight or volume. - %tr - %td - %strong display_name - %td No - %td Orange - %td Used to name product variants, if they have a distinct name. - %td - %tr - %td - %strong on_demand - %td No - %td 1 - %td Flag the product as "made on demand". The product will not use stock levels. - %td 1 for active, 0 for disabled, or leave blank to ignore. - %tr - %td - %strong tax_category - %td No - %td (Various, see notes) - %td Sets the product tax category - %td See below for a list of available categories - %tr - %td - %strong shipping_category - %td No - %td (Various, see notes) - %td Sets the product shipping category - %td See below for a list of available categories - %tr - %td - %strong available_on - %td No - %td 2018-05-21 - %td Sets the date from which the product will be available - %td Date format is: YYYY-MM-DD diff --git a/app/views/admin/product_import/guide/_units.html.haml b/app/views/admin/product_import/guide/_units.html.haml deleted file mode 100644 index 07161bdb1c..0000000000 --- a/app/views/admin/product_import/guide/_units.html.haml +++ /dev/null @@ -1,54 +0,0 @@ -%table - %thead - %tr - %th - %th name - %th category - %th supplier - %th on_hand - %th price - %th units - %th unit_type - %th variant_unit_name - %tbody - %tr - %td 1 - %td Salad Bag - %td Salads - %td Sue's Salads - %td 26 - %td 3.50 - %td 500 - %td g - %td - %tr - %td 2 - %td Fruit Juice - %td Drinks - %td Country Juices - %td 12 - %td 3.50 - %td 300 - %td ml - %td - %tr - %td 3 - %td Potatoes - %td Vegetables - %td Fernwell Farm - %td 67 - %td 4.20 - %td 1 - %td kg - %td - - %tr - %td 3 - %td Wholemeal Bread - %td Baked goods - %td Tim's Bakery - %td 66 - %td 3.00 - %td 1 - %td - %td loaf diff --git a/app/views/admin/product_import/guide/_variants.html.haml b/app/views/admin/product_import/guide/_variants.html.haml deleted file mode 100644 index dfd95879c1..0000000000 --- a/app/views/admin/product_import/guide/_variants.html.haml +++ /dev/null @@ -1,54 +0,0 @@ -%table - %thead - %tr - %th - %th name - %th category - %th supplier - %th on_hand - %th price - %th units - %th unit_type - %th display_name - %tbody - %tr - %td 1 - %td Salad Bag - %td Salads - %td Sue's Salads - %td 26 - %td 3.50 - %td 500 - %td g - %td - %tr - %td 2 - %td Salad Bag - %td Salads - %td Sue's Salads - %td 44 - %td 5.50 - %td 750 - %td g - %td - %tr - %td 3 - %td Cake - %td Baked goods - %td Tim's Cakes - %td 10 - %td 4 - %td 500 - %td g - %td Banana and Walnut - %tr - %td 4 - %td Cake - %td Baked goods - %td Tim's Cakes - %td 18 - %td 4 - %td 500 - %td g - %td Carrot - diff --git a/app/views/admin/product_import/index.html.haml b/app/views/admin/product_import/index.html.haml index f2e8e5208b..fd17684ef0 100644 --- a/app/views/admin/product_import/index.html.haml +++ b/app/views/admin/product_import/index.html.haml @@ -1,12 +1,6 @@ - content_for :page_title do #{t('admin.product_import.title')} -- content_for :page_actions do - %div.toolbar{ 'data-hook' => "toolbar" } - %ul.actions.header-action-links.inline-menu - %li - = button_link_to 'View Guide', main_app.admin_product_import_guide_path - = render partial: 'spree/admin/shared/product_sub_menu' = render 'upload_form' diff --git a/config/routes.rb b/config/routes.rb index 7e2bc47a32..229b26e331 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -133,7 +133,6 @@ Openfoodnetwork::Application.routes.draw do get '/inventory', to: 'variant_overrides#index' get '/product_import', to: 'product_import#index' - get '/product_import/guide', to: 'product_import#guide', as: 'product_import_guide' post '/product_import', to: 'product_import#import' post '/product_import/validate_data', to: 'product_import#validate_data', as: 'product_import_process_async' post '/product_import/save_data', to: 'product_import#save_data', as: 'product_import_save_async' From 632b991952c14b810eb3d594bdefa71315682a9f Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 21:25:42 +0100 Subject: [PATCH 083/125] Add downloadable templates --- public/inventory_template.csv | 1 + public/product_list_template.csv | 1 + 2 files changed, 2 insertions(+) create mode 100644 public/inventory_template.csv create mode 100644 public/product_list_template.csv diff --git a/public/inventory_template.csv b/public/inventory_template.csv new file mode 100644 index 0000000000..68e0fce918 --- /dev/null +++ b/public/inventory_template.csv @@ -0,0 +1 @@ +producer,supplier,name,display_name,units,price,on_hand diff --git a/public/product_list_template.csv b/public/product_list_template.csv new file mode 100644 index 0000000000..f97e4f80d7 --- /dev/null +++ b/public/product_list_template.csv @@ -0,0 +1 @@ +supplier,sku,name,display_name,category,units,unit_type,variant_unit_name,price,on_hand,available_on,on_demand,shipping_category,tax_category From c4af50e95c12262aca65b78b84a0876ed4213d67 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 21:26:17 +0100 Subject: [PATCH 084/125] Add sidebar to Import index page --- .../stylesheets/admin/product_import.css.scss | 65 +++++++++---------- .../admin/product_import_controller.rb | 6 ++ .../product_import/_upload_sidebar.html.haml | 30 +++++++++ .../admin/product_import/index.html.haml | 2 + config/locales/en.yml | 7 ++ 5 files changed, 75 insertions(+), 35 deletions(-) create mode 100644 app/views/admin/product_import/_upload_sidebar.html.haml diff --git a/app/assets/stylesheets/admin/product_import.css.scss b/app/assets/stylesheets/admin/product_import.css.scss index 4210439b78..79265c9231 100644 --- a/app/assets/stylesheets/admin/product_import.css.scss +++ b/app/assets/stylesheets/admin/product_import.css.scss @@ -1,38 +1,3 @@ -.product-import-introduction { - - h1, h2, h3, h4, h5, h6 { - margin: 1.5em 0 1em; - } - - h6 { - font-size: 1em; - } - - p { - margin-bottom: 1em; - } - - span.category { - display: inline-block; - background-color: #f3f3f3; - padding: 0.4em 0.8em; - margin: 0 0.4em 0.5em 0; - } - - table { - - &.product-import-columns tr:hover td { - background-color: transparent; - } - - thead th { - text-transform: none; - font-size: 100%; - text-align: left; - } - } -} - div.panel-section { .neutral { @@ -315,3 +280,33 @@ div.progress-bar { transition: width 0.5s ease-in-out; } } + +#upload-sidebar { + float: right; + background-color: lighten(#eff5fc, 2.5%); + border: 1px solid lighten(#cee1f4, 2.5%); + width: 50%; + padding: 0 1.5em 1.5em; + + h4, h5, h6, p { + margin: 1.25em 0 1em; + } + + a.download { + display: block; + font-size: 1.05em; + margin-bottom: 0.5em; + + i { + margin-right: 0.25em; + } + } + + span.category { + display: inline-block; + background-color: lighten(#5498da, 10%); + color: white; + padding: 0.3em 0.6em; + margin: 0 0.4em 0.5em 0; + } +} diff --git a/app/controllers/admin/product_import_controller.rb b/app/controllers/admin/product_import_controller.rb index f2b1972a9c..88d9623b3a 100644 --- a/app/controllers/admin/product_import_controller.rb +++ b/app/controllers/admin/product_import_controller.rb @@ -4,6 +4,12 @@ module Admin class ProductImportController < Spree::Admin::BaseController before_filter :validate_upload_presence, except: %i[index guide validate_data] + def index + @product_categories = Spree::Taxon.order('name ASC').pluck(:name).uniq + @tax_categories = Spree::TaxCategory.order('name ASC').pluck(:name) + @shipping_categories = Spree::ShippingCategory.order('name ASC').pluck(:name) + end + def import # Save uploaded file to tmp directory @filepath = save_uploaded_file(params[:file]) diff --git a/app/views/admin/product_import/_upload_sidebar.html.haml b/app/views/admin/product_import/_upload_sidebar.html.haml new file mode 100644 index 0000000000..54c5829b29 --- /dev/null +++ b/app/views/admin/product_import/_upload_sidebar.html.haml @@ -0,0 +1,30 @@ +#upload-sidebar + %h5= t('admin.product_import.index.csv_templates') + + %a.download{href: '/product_list_template.csv'} + %i.icon-external-link + = t('admin.product_import.index.product_list_template') + + %a.download{href: '/inventory_template.csv'} + %i.icon-external-link + = t('admin.product_import.index.inventory_template') + + %h5= t('admin.product_import.index.category_values') + + %p + %strong= t('admin.product_import.index.product_categories') + + - @product_categories.each do |pc| + %span.category= pc + + %p + %strong= t('admin.product_import.index.tax_categories') + + - @tax_categories.each do |tc| + %span.category= tc + + %p + %strong= t('admin.product_import.index.shipping_categories') + + - @shipping_categories.each do |sc| + %span.category= sc \ No newline at end of file diff --git a/app/views/admin/product_import/index.html.haml b/app/views/admin/product_import/index.html.haml index fd17684ef0..3ff03f08c1 100644 --- a/app/views/admin/product_import/index.html.haml +++ b/app/views/admin/product_import/index.html.haml @@ -3,4 +3,6 @@ = render partial: 'spree/admin/shared/product_sub_menu' += render 'upload_sidebar' + = render 'upload_form' diff --git a/config/locales/en.yml b/config/locales/en.yml index 67c8d17fd3..c9f944a7d2 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -470,6 +470,13 @@ en: inventories: Inventories import: Import upload: Upload + csv_templates: CSV Templates + product_list_template: Download Product List template + inventory_template: Download Inventory template + category_values: Available Category Values + product_categories: Product Categories + tax_categories: Tax Categories + shipping_categories: Shipping Categories import: review: Review proceed: Proceed From 4d68723fe388350fd5fc977bbb6e9e5eb8574739 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 16 Jul 2018 09:24:32 +1000 Subject: [PATCH 085/125] Reference existing translation: closed order cycle https://github.com/openfoodfoundation/openfoodnetwork/issues/2465 Viewing a customers subscription could display a translation missing error. --- .../subscriptions/controllers/orders_panel_controller.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/subscriptions/controllers/orders_panel_controller.js.coffee b/app/assets/javascripts/admin/subscriptions/controllers/orders_panel_controller.js.coffee index 16d133059e..1c22669903 100644 --- a/app/assets/javascripts/admin/subscriptions/controllers/orders_panel_controller.js.coffee +++ b/app/assets/javascripts/admin/subscriptions/controllers/orders_panel_controller.js.coffee @@ -16,7 +16,7 @@ angular.module("admin.subscriptions").controller "OrdersPanelController", ($scop oc = OrderCycles.byID[id] return t('js.subscriptions.close_date_not_set') unless oc?.orders_close_at? closes_at = moment(oc.orders_close_at) - text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscription.closed') + text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscriptions.closed') "#{text} #{closes_at.fromNow()}" $scope.stateText = (state) -> t("spree.order_state.#{state}") From 4a444542100bdfa6f666a7c4e25c9398183770f3 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Tue, 19 Jun 2018 15:04:58 +0100 Subject: [PATCH 086/125] fixed number rounding issue in product bulk edit --- .../javascripts/admin/services/bulk_products.js.coffee | 7 ++++++- .../unit/admin/services/bulk_products_spec.js.coffee | 7 +++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/services/bulk_products.js.coffee b/app/assets/javascripts/admin/services/bulk_products.js.coffee index 022345e9d8..a1a41b4763 100644 --- a/app/assets/javascripts/admin/services/bulk_products.js.coffee +++ b/app/assets/javascripts/admin/services/bulk_products.js.coffee @@ -66,8 +66,13 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher, variantUnitValue: (product, variant) -> if variant.unit_value? if product.variant_unit_scale - variant.unit_value / product.variant_unit_scale + @divideAsInteger variant.unit_value, product.variant_unit_scale else variant.unit_value else null + + # forces integer division to avoid javascript floating point imprecision + # using one billion as the multiplier so that it works for numbers with up to 9 decimal places + divideAsInteger: (a, b) -> + (a * 1000000000) / (b * 1000000000) diff --git a/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee b/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee index fc46c2a30d..95bdd63ba7 100644 --- a/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee +++ b/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee @@ -160,6 +160,13 @@ describe "BulkProducts service", -> BulkProducts.loadVariantUnitValues product, product.variants[0] expect(product.variants[0].unit_value_with_description).toEqual '2.5' + it "converts values from base value to chosen unit without breaking precision", -> + product = + variant_unit_scale: 0.001 + variants: [{id: 1, unit_value: 0.35}] + BulkProducts.loadVariantUnitValues product, product.variants[0] + expect(product.variants[0].unit_value_with_description).toEqual '350' + it "displays a unit_value of zero", -> product = variant_unit_scale: 1.0 From c16f4203f93dbc85da917251a2434c4beaeea25d Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 9 Jul 2018 14:50:05 +0800 Subject: [PATCH 087/125] Rename enterprise "Relationships" to "Permissions" This only updates en* translations, and does not affect URLs and other back-end references. --- config/locales/en.yml | 4 ++-- spec/features/admin/enterprise_relationships_spec.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 67c8d17fd3..7e653ea078 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1911,7 +1911,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using you_have_no_orders_yet: "You have no orders yet" running_balance: "Running balance" outstanding_balance: "Outstanding balance" - admin_entreprise_relationships: "Enterprise Relationships" + admin_entreprise_relationships: "Enterprise Permissions" admin_entreprise_relationships_everything: "Everything" admin_entreprise_relationships_permits: "permits" admin_entreprise_relationships_seach_placeholder: "Search" @@ -2036,7 +2036,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using order_cycle: "Order Cycle" order_cycles: "Order Cycles" enterprises: "Enterprises" - enterprise_relationships: "Enterprise relationships" + enterprise_relationships: "Enterprise permissions" remove_tax: "Remove tax" enterprise_terms_of_service: "Enterprise Terms of Service" enterprises_require_tos: "Enterprises must accept Terms of Service" diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb index 85a0a87ee2..c40b8e8f3b 100644 --- a/spec/features/admin/enterprise_relationships_spec.rb +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -20,7 +20,7 @@ feature %q{ # When I go to the relationships page click_link 'Enterprises' - click_link 'Relationships' + click_link 'Permissions' # Then I should see the relationships within('table#enterprise-relationships') do From 18206c9369afcd95be517f8f41af1d50719bf9e5 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 11:42:07 +0100 Subject: [PATCH 088/125] Remove old view file --- app/views/admin/product_import/save.html.haml | 63 ------------------- 1 file changed, 63 deletions(-) delete mode 100644 app/views/admin/product_import/save.html.haml diff --git a/app/views/admin/product_import/save.html.haml b/app/views/admin/product_import/save.html.haml deleted file mode 100644 index 4d88bef979..0000000000 --- a/app/views/admin/product_import/save.html.haml +++ /dev/null @@ -1,63 +0,0 @@ -- content_for :page_title do - #{t('admin.product_import.title')} - -= render partial: 'spree/admin/shared/product_sub_menu' - -%h5= t('admin.product_import.save.final_results') -%br - -%div.post-save-results{ng: {app: 'admin.productImport'}} - - - if @importer.products_created_count > 0 - %p - %i.fa{ng: {class: "{'fa-info-circle': #{@importer.products_created_count} == 0, 'fa-check-circle': #{@importer.products_created_count} != 0}"}} - %strong.created-count= @importer.products_created_count - = t('admin.product_import.save.products_created') - - - if @importer.products_updated_count > 0 - %p - %i.fa{ng: {class: "{'fa-info-circle': #{@importer.products_updated_count} == 0, 'fa-check-circle': #{@importer.products_updated_count} != 0}"}} - %strong.updated-count= @importer.products_updated_count - = t('admin.product_import.save.products_updated') - - - if @importer.inventory_created_count > 0 - %p - %i.fa{ng: {class: "{'fa-info-circle': #{@importer.inventory_created_count} == 0, 'fa-check-circle': #{@importer.inventory_created_count} != 0}"}} - %strong.inv-created-count= @importer.inventory_created_count - = t('admin.product_import.save.inventory_created') - - - if @importer.inventory_updated_count > 0 - %p - %i.fa{ng: {class: "{'fa-info-circle': #{@importer.inventory_updated_count} == 0, 'fa-check-circle': #{@importer.inventory_updated_count} != 0}"}} - %strong.inv-updated-count= @importer.inventory_updated_count - = t('admin.product_import.save.inventory_updated') - - - if @importer.products_reset_count > 0 - %p - %i.fa.fa-info-circle - %strong.reset-count= @importer.products_reset_count - - if @import_into == 'inventories' - = t('admin.product_import.save.inventory_reset') - - else - = t('admin.product_import.save.products_reset') - - %br - - - if @importer.errors.count == 0 - %p= t('admin.product_import.save.all_saved', { num: "#{@importer.total_saved_count}" }) - - else - %p= t('admin.product_import.save.total_saved', { num: "#{@importer.total_saved_count}" }) - %br - %h5= t('admin.product_import.save.save_errors') - - @importer.errors.full_messages.each do |error| - %p.save-error -  -  #{error} - - %br - - if @importer.total_saved_count > 0 - - if @import_into == 'inventories' - %a.button{href: main_app.admin_inventory_path}= t('admin.product_import.save.view_inventory') - - else - %a.button{href: admin_products_path + '?latest_import=true'}= t('admin.product_import.save.view_products') - - %a.button{href: main_app.admin_product_import_path}= t('admin.back') From b37bea35fa211c49f1fa539b9d7150d137e98f9a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 11:43:31 +0100 Subject: [PATCH 089/125] Use relative translation keys --- .../product_import/_save_results.html.haml | 26 +++++++++---------- config/locales/en.yml | 2 +- spec/features/admin/product_import_spec.rb | 8 +++--- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/app/views/admin/product_import/_save_results.html.haml b/app/views/admin/product_import/_save_results.html.haml index 901bb466e1..90cf847468 100644 --- a/app/views/admin/product_import/_save_results.html.haml +++ b/app/views/admin/product_import/_save_results.html.haml @@ -1,5 +1,5 @@ -%h5= t('admin.product_import.save.final_results') +%h5= t('.final_results') %br %div.post-save-results @@ -8,45 +8,45 @@ %i.fa{ng: {class: "{'fa-info-circle': updates.products_created == 0, 'fa-check-circle': updates.products_created > 0}"}} %strong.created-count {{ updates.products_created }} - = t('admin.product_import.save.products_created') + = t('.products_created') %p{ng: {show: 'updates.products_updated'}} %i.fa{ng: {class: "{'fa-info-circle': updates.products_updated == 0, 'fa-check-circle': updates.products_updated > 0}"}} %strong.updated-count {{ updates.products_updated }} - = t('admin.product_import.save.products_updated') + = t('.products_updated') %p{ng: {show: 'updates.inventory_created'}} %i.fa{ng: {class: "{'fa-info-circle': updates.inventory_created == 0, 'fa-check-circle': updates.inventory_created > 0}"}} %strong.inv-created-count {{ updates.inventory_created }} - = t('admin.product_import.save.inventory_created') + = t('.inventory_created') %p{ng: {show: 'updates.inventory_updated'}} %i.fa{ng: {class: "{'fa-info-circle': updates.inventory_updated == 0, 'fa-check-circle': updates.inventory_updated > 0}"}} %strong.inv-updated-count {{ updates.inventory_updated }} - = t('admin.product_import.save.inventory_updated') + = t('.inventory_updated') %p{ng: {show: 'updates.products_reset'}} %i.fa.fa-info-circle %strong.reset-count {{ updates.products_reset }} - if @import_into == 'inventories' - = t('admin.product_import.save.inventory_reset') + = t('.inventory_reset') - else - = t('admin.product_import.save.products_reset') + = t('.products_reset') %br %p{ng: {show: 'update_errors.length == 0'}} - = t('admin.product_import.save.all_saved') + = t('.all_saved') %div{ng: {show: 'update_errors.length > 0'}} - %p {{ updated_total }} #{t('admin.product_import.save.some_saved')} + %p {{ updated_total }} #{t('.some_saved')} %br - %h5= t('admin.product_import.save.save_errors') + %h5= t('.save_errors') %p.save-error{ng: {repeat: 'error in update_errors'}}  -  {{ error }} @@ -54,10 +54,10 @@ %br %div{ng: {show: 'updated_total > 0'}} %a.button.view{href: main_app.admin_inventory_path, ng: {show: 'updates.inventory_created > 0 || updates.inventory_updated > 0'}} - = t('admin.product_import.save.view_inventory') + = t('.view_inventory') %a.button.view{href: admin_products_path, ng: {show: 'updates.products_created > 0 || updates.products_updated > 0'}} - = t('admin.product_import.save.view_products') + = t('.view_products') %a.button{href: main_app.admin_product_import_path} - = t('admin.product_import.save.import_again') + = t('.import_again') diff --git a/config/locales/en.yml b/config/locales/en.yml index ebe1c524bb..4c550c9d07 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -505,7 +505,7 @@ en: inventory_to_reset: Existing inventory items will have their stock reset to zero line: Line item_line: Item line - save: + save_results: final_results: Import final results products_created: Products created products_updated: Products updated diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index faedb012b7..4ea5076eac 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -72,7 +72,7 @@ feature "Product Import", js: true do wait_until { page.find("a.button.view").present? } - click_link I18n.t('admin.product_import.save.view_products') + click_link I18n.t('admin.product_import.save_results.view_products') expect(page).to have_content 'Bulk Edit Products' wait_until { page.find("#p_#{potatoes.id}").present? } @@ -174,7 +174,7 @@ feature "Product Import", js: true do potatoes = Spree::Product.find_by_name('Potatoes') expect(potatoes.variants.first.import_date).to be_within(1.minute).of Time.zone.now - click_link I18n.t('admin.product_import.save.view_products') + click_link I18n.t('admin.product_import.save_results.view_products') wait_until { page.find("#p_#{carrots.id}").present? } @@ -251,7 +251,7 @@ feature "Product Import", js: true do expect(Float(cabbage_override.price)).to eq 1.50 expect(cabbage_override.count_on_hand).to eq 2001 - click_link I18n.t('admin.product_import.save.view_inventory') + click_link I18n.t('admin.product_import.save_results.view_inventory') expect(page).to have_content 'Inventory' select enterprise2.name, from: "hub_id", visible: false @@ -437,6 +437,6 @@ feature "Product Import", js: true do wait_until { page.find("button.view_results:not([disabled='disabled'])").present? } find('button.view_results').trigger 'click' - expect(page).to have_content I18n.t('admin.product_import.save.final_results') + expect(page).to have_content I18n.t('admin.product_import.save_results.final_results') end end From c7deae42538b920b999e255e86a4710e841c9271 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 12:49:20 +0100 Subject: [PATCH 090/125] Remove category field from inventory specs --- spec/models/product_importer_spec.rb | 32 ++++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/models/product_importer_spec.rb b/spec/models/product_importer_spec.rb index 465b9809b0..73c7423cc3 100644 --- a/spec/models/product_importer_spec.rb +++ b/spec/models/product_importer_spec.rb @@ -296,10 +296,10 @@ describe ProductImport::ProductImporter do describe "importing items into inventory" do before do csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "producer", "category", "on_hand", "price", "units"] - csv << ["Beans", "Another Enterprise", "User Enterprise", "Vegetables", "5", "3.20", "500"] - csv << ["Sprouts", "Another Enterprise", "User Enterprise", "Vegetables", "6", "6.50", "500"] - csv << ["Cabbage", "Another Enterprise", "User Enterprise", "Vegetables", "2001", "1.50", "500"] + csv << ["name", "supplier", "producer", "on_hand", "price", "units", "unit_type"] + csv << ["Beans", "Another Enterprise", "User Enterprise", "5", "3.20", "500", "g"] + csv << ["Sprouts", "Another Enterprise", "User Enterprise", "6", "6.50", "500", "g"] + csv << ["Cabbage", "Another Enterprise", "User Enterprise", "2001", "1.50", "500", "g"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') @@ -422,8 +422,8 @@ describe ProductImport::ProductImporter do it "allows creating inventories for producers that a user's hub has permission for" do csv_data = CSV.generate do |csv| - csv << ["name", "producer", "supplier", "category", "on_hand", "price", "units"] - csv << ["Beans", "User Enterprise", "Another Enterprise", "Vegetables", "777", "3.20", "500"] + csv << ["name", "producer", "supplier", "on_hand", "price", "units", "unit_type"] + csv << ["Beans", "User Enterprise", "Another Enterprise", "777", "3.20", "500", "g"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') @@ -449,9 +449,9 @@ describe ProductImport::ProductImporter do it "does not allow creating inventories for producers that a user's hubs don't have permission for" do csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "category", "on_hand", "price", "units"] - csv << ["Beans", "User Enterprise", "Vegetables", "5", "3.20", "500"] - csv << ["Sprouts", "User Enterprise", "Vegetables", "6", "6.50", "500"] + csv << ["name", "supplier", "on_hand", "price", "units", "unit_type"] + csv << ["Beans", "User Enterprise", "5", "3.20", "500", "g"] + csv << ["Sprouts", "User Enterprise", "6", "6.50", "500", "g"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') @@ -515,9 +515,9 @@ describe ProductImport::ProductImporter do it "can reset all inventory items for an enterprise that are not present in the uploaded file to zero stock" do csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "producer", "category", "on_hand", "price", "units"] - csv << ["Beans", "Another Enterprise", "User Enterprise", "Vegetables", "6", "3.20", "500"] - csv << ["Sprouts", "Another Enterprise", "User Enterprise", "Vegetables", "7", "6.50", "500"] + csv << ["name", "supplier", "producer", "on_hand", "price", "units", "unit_type"] + csv << ["Beans", "Another Enterprise", "User Enterprise", "6", "3.20", "500", "g"] + csv << ["Sprouts", "Another Enterprise", "User Enterprise", "7", "6.50", "500", "g"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') @@ -617,10 +617,10 @@ describe ProductImport::ProductImporter do it "can overwrite fields with selected defaults when importing to inventory" do csv_data = CSV.generate do |csv| - csv << ["name", "producer", "supplier", "category", "on_hand", "price", "units"] - csv << ["Beans", "User Enterprise", "Another Enterprise", "Vegetables", "", "3.20", "500"] - csv << ["Sprouts", "User Enterprise", "Another Enterprise", "Vegetables", "7", "6.50", "500"] - csv << ["Cabbage", "User Enterprise", "Another Enterprise", "Vegetables", "", "1.50", "500"] + csv << ["name", "producer", "supplier", "on_hand", "price", "units", "unit_type"] + csv << ["Beans", "User Enterprise", "Another Enterprise", "", "3.20", "500", "g"] + csv << ["Sprouts", "User Enterprise", "Another Enterprise", "7", "6.50", "500", "g"] + csv << ["Cabbage", "User Enterprise", "Another Enterprise", "", "1.50", "500", "g"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') From 5737c9803d116f24e7dc833778463169fb860226 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 12:59:52 +0100 Subject: [PATCH 091/125] Add unit_type field to inventory template --- public/inventory_template.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/inventory_template.csv b/public/inventory_template.csv index 68e0fce918..dd7329a89c 100644 --- a/public/inventory_template.csv +++ b/public/inventory_template.csv @@ -1 +1 @@ -producer,supplier,name,display_name,units,price,on_hand +producer,supplier,name,display_name,units,unit_type,price,on_hand From 5e142205bd10b890630fdbfe45bacbfd54df81a1 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 13:35:23 +0100 Subject: [PATCH 092/125] Use relative translation keys --- .../admin/product_import/import.html.haml | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/views/admin/product_import/import.html.haml b/app/views/admin/product_import/import.html.haml index 7f96c7f907..e74e8c4692 100644 --- a/app/views/admin/product_import/import.html.haml +++ b/app/views/admin/product_import/import.html.haml @@ -7,16 +7,16 @@ - if @importer.item_count == 0 #and @importer.invalid_count %h5 - = t('admin.product_import.import.no_valid_entries') + = t('.no_valid_entries') %p - = t('admin.product_import.import.none_to_save') + = t('.none_to_save') %br - else .settings-section{ng: {show: 'step == "settings"'}} = render 'import_options' if @importer.table_headings %br %a.button.proceed{href: '', ng: {click: 'confirmSettings()'}} - = t('admin.product_import.import.proceed') + = t('.proceed') %a.button{href: main_app.admin_product_import_path} #{t('admin.cancel')} .progress-interface{ng: {show: 'step == "import"'}} @@ -27,9 +27,9 @@ .progress-bar %span.progress-track{class: 'ng-binding', style: "width:{{percentage}}"} %button.start_import{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; import_url = '#{main_app.admin_product_import_process_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}} - = t('admin.product_import.index.import') + = t('.import') %button.review{ng: {click: 'viewResults()', disabled: '!finished'}} - = t('admin.product_import.import.review') + = t('.review') %p.red {{ exception }} @@ -44,13 +44,13 @@ %p= t('admin.product_import.import.fix_before_import') %div{ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0'}} %br - %h5= t('admin.product_import.import.no_errors') - %p= t('admin.product_import.import.save_all_imported?') + %h5= t('.no_errors') + %p= t('.save_all_imported?') %br = hidden_field_tag :filepath, @filepath = hidden_field_tag "settings[import_into]", @import_into - %a.button.proceed{href: '', ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0', click: 'acceptResults()'}}= t('admin.product_import.import.proceed') + %a.button.proceed{href: '', ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0', click: 'acceptResults()'}}= t('.proceed') %a.button{href: main_app.admin_product_import_path}= t('admin.cancel') @@ -60,13 +60,13 @@ .progress-interface{ng: {show: 'step == "save"'}} %span.filename - #{t('admin.product_import.import.save_imported')} ({{ percentage }}) + #{t('.save_imported')} ({{ percentage }}) .progress-bar{} %span.progress-track{ng: {style: "{'width':percentage}"}} %button.start_save{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; save_url = '#{main_app.admin_product_import_save_async_path}'; reset_url = '#{main_app.admin_product_import_reset_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}} - = t('admin.product_import.import.save') + = t('.save') %button.view_results{ng: {click: 'finalResults()', disabled: '!finished'}} - = t('admin.product_import.import.results') + = t('.results') %p.red {{ exception }} From 23cbcda0c3fdb885b30ebe38819cfd73be51b6ac Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 18 Jul 2018 14:40:46 +0100 Subject: [PATCH 093/125] Allow preferred_mails_from and preferred_mail_bcc to be set from configs --- config/application.yml.example | 4 ++++ db/seeds.rb | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/config/application.yml.example b/config/application.yml.example index 03b33f9f11..266fe6b41e 100644 --- a/config/application.yml.example +++ b/config/application.yml.example @@ -29,6 +29,10 @@ MAIL_PORT: 25 SMTP_USERNAME: 'ofn' SMTP_PASSWORD: 'f00d' +# Optional mail settings +# MAILS_FROM: hello@example.com +# MAIL_BCC: manager@example.com + # SingleSignOn login for Discourse # # DISCOURSE_SSO_SECRET should be a random string. It must be the same as provided to your Discourse instance. diff --git a/db/seeds.rb b/db/seeds.rb index d54987f68f..e20112c710 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -43,8 +43,8 @@ def create_mail_method preferred_smtp_username: ENV.fetch('SMTP_USERNAME'), preferred_smtp_password: ENV.fetch('SMTP_PASSWORD'), preferred_secure_connection_type: 'None', - preferred_mails_from: "no-reply@#{ENV.fetch('MAIL_DOMAIN')}", - preferred_mail_bcc: '', + preferred_mails_from: ENV.fetch('MAILS_FROM', "no-reply@#{ENV.fetch('MAIL_DOMAIN')}"), + preferred_mail_bcc: ENV.fetch('MAIL_BCC', ''), preferred_intercept_email: '' ).call end From 583f16b38db6f4f8b1dcd6a07e1d7ffca534c658 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Thu, 14 Jun 2018 15:46:21 +0100 Subject: [PATCH 094/125] Add guest label to admin customers index --- app/assets/stylesheets/admin/customers.css.scss | 11 +++++++++++ app/views/admin/customers/index.html.haml | 4 +++- config/locales/en.yml | 1 + 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/admin/customers.css.scss b/app/assets/stylesheets/admin/customers.css.scss index e3c427649c..81e6f0140c 100644 --- a/app/assets/stylesheets/admin/customers.css.scss +++ b/app/assets/stylesheets/admin/customers.css.scss @@ -1,3 +1,14 @@ .tag-with-rules { color: black; } + +table#customers.index { + + tr.customer { + + .guest-label { + color: #999; + display: block; + } + } +} \ No newline at end of file diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index bb4c94a56c..9a269b5a99 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -75,7 +75,9 @@ %tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy:predicate:reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" } -# %td.bulk -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } - %td.email{ 'ng-show' => 'columns.email.visible', "ng-bind" => '::customer.email' } + %td.email{ 'ng-show' => 'columns.email.visible'} + %span{ 'ng-bind' => '::customer.email' } + %span.guest-label{ 'ng-show' => 'customer.user_id == null' }= t('.guest_label') %td.name{ 'ng-show' => 'columns.name.visible'} %input{ type: 'text', name: 'name', ng: { model: 'customer.name' }, 'obj-for-update' => 'customer', 'attr-for-update' => 'name'} %td.code{ 'ng-show' => 'columns.code.visible' } diff --git a/config/locales/en.yml b/config/locales/en.yml index 6481ef8316..3cf795c2e9 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -376,6 +376,7 @@ en: update_address: 'Update Address' confirm_delete: 'Sure to delete?' search_by_email: "Search by email/code..." + guest_label: 'Guest checkout' destroy: has_associated_orders: 'Delete failed: customer has associated orders with his shop' From 75e52a7a91ea837362739b3037bee50350185083 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley Date: Sat, 16 Jun 2018 15:15:16 +0100 Subject: [PATCH 095/125] CSS tweaks fo guest flag --- app/assets/stylesheets/admin/customers.css.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/stylesheets/admin/customers.css.scss b/app/assets/stylesheets/admin/customers.css.scss index 81e6f0140c..d70078d02a 100644 --- a/app/assets/stylesheets/admin/customers.css.scss +++ b/app/assets/stylesheets/admin/customers.css.scss @@ -9,6 +9,8 @@ table#customers.index { .guest-label { color: #999; display: block; + font-size: 0.85em; + margin-top: 0.15em; } } } \ No newline at end of file From 24ff5555bef1a8f6f17380bdba7c481da1310aa2 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 27 Jun 2018 16:55:36 +0100 Subject: [PATCH 096/125] Create admin SCSS colour palette --- app/assets/stylesheets/admin/account.css.scss | 2 +- .../admin/advanced_settings.css.scss | 4 +- app/assets/stylesheets/admin/alert.css.scss | 12 ++-- .../stylesheets/admin/{all.css => all.scss} | 4 +- .../admin/change_type_form.css.scss | 10 ++-- .../admin/components/alert-box.css.scss | 10 ++-- .../admin/components/alert_row.css.scss | 2 +- .../admin/components/dialogs.css.scss | 4 +- .../admin/components/jquery_dialog.scss | 2 +- .../admin/components/save_bar.scss | 6 +- .../admin/components/states_decorator.scss | 2 +- .../admin/components/trial_progess_bar.scss | 2 +- .../admin/components/wizard_progress.css.scss | 2 +- .../stylesheets/admin/customers.css.scss | 4 +- .../stylesheets/admin/dashboard_item.css.scss | 58 +++++++++---------- .../stylesheets/admin/dropdown.css.scss | 2 +- .../admin/enterprise_console.css.scss | 4 +- .../admin/enterprise_index_panels.css.scss | 6 +- .../stylesheets/admin/enterprises.css.scss | 2 +- .../admin/index_panel_buttons.css.scss | 2 +- .../stylesheets/admin/index_panels.css.scss | 6 +- .../admin/openfoodnetwork.css.scss | 14 ++--- .../stylesheets/admin/order_cycles.scss | 2 +- app/assets/stylesheets/admin/orders.css.scss | 8 +-- .../stylesheets/admin/product_import.css.scss | 4 +- .../stylesheets/admin/products.css.scss | 10 ++-- app/assets/stylesheets/admin/reports.css.scss | 2 +- app/assets/stylesheets/admin/select2.css.scss | 8 +-- .../stylesheets/admin/side_menu.css.scss | 2 +- .../stylesheets/admin/sidebar-item.css.scss | 26 ++++----- .../stylesheets/admin/tag_rules.css.scss | 6 +- .../stylesheets/admin/typography.css.scss | 2 +- .../stylesheets/admin/variables.css.scss | 10 ++++ .../admin/variant_overrides.css.scss | 2 +- 34 files changed, 127 insertions(+), 115 deletions(-) rename app/assets/stylesheets/admin/{all.css => all.scss} (93%) create mode 100644 app/assets/stylesheets/admin/variables.css.scss diff --git a/app/assets/stylesheets/admin/account.css.scss b/app/assets/stylesheets/admin/account.css.scss index 7d58147d91..fedd079786 100644 --- a/app/assets/stylesheets/admin/account.css.scss +++ b/app/assets/stylesheets/admin/account.css.scss @@ -12,6 +12,6 @@ table.invoice_summary { .invoice_title { .balance { - color: #9fc820; + color: $spree-green; } } diff --git a/app/assets/stylesheets/admin/advanced_settings.css.scss b/app/assets/stylesheets/admin/advanced_settings.css.scss index 6b48e8ce11..7f1aa3a8c8 100644 --- a/app/assets/stylesheets/admin/advanced_settings.css.scss +++ b/app/assets/stylesheets/admin/advanced_settings.css.scss @@ -1,6 +1,6 @@ #advanced_settings { - background-color: #eff5fc; - border: 1px solid #cee1f4; + background-color: $spree-light-blue; + border: 1px solid $pale-blue; margin-bottom: 20px; .row{ diff --git a/app/assets/stylesheets/admin/alert.css.scss b/app/assets/stylesheets/admin/alert.css.scss index b516867a96..267e7a8580 100644 --- a/app/assets/stylesheets/admin/alert.css.scss +++ b/app/assets/stylesheets/admin/alert.css.scss @@ -1,12 +1,12 @@ .alert { - border: 3px solid #919191; + border: 3px solid $medium-grey; border-radius: 6px; margin-bottom: 20px; - color: #919191; + color: $medium-grey; padding: 5px 10px; h6 { - color: #919191; + color: $medium-grey; } .message { @@ -14,11 +14,11 @@ } &:hover { - border-color: #DA5354; - color: #DA5354; + border-color: $warning-red; + color: $warning-red; h6 { - color: #DA5354; + color: $warning-red; } } } diff --git a/app/assets/stylesheets/admin/all.css b/app/assets/stylesheets/admin/all.scss similarity index 93% rename from app/assets/stylesheets/admin/all.css rename to app/assets/stylesheets/admin/all.scss index 47bf928477..80acf2e1e5 100644 --- a/app/assets/stylesheets/admin/all.css +++ b/app/assets/stylesheets/admin/all.scss @@ -12,5 +12,7 @@ *= require shared/ng-tags-input.min *= require_self - *= require_tree . */ + +@import 'variables'; +@import '*'; diff --git a/app/assets/stylesheets/admin/change_type_form.css.scss b/app/assets/stylesheets/admin/change_type_form.css.scss index 0153d701e8..87b43ff1a2 100644 --- a/app/assets/stylesheets/admin/change_type_form.css.scss +++ b/app/assets/stylesheets/admin/change_type_form.css.scss @@ -6,12 +6,12 @@ margin: 2em 0 0 0; &, & * { - color: #5498da; + color: $spree-blue; } } .description { - background-color: #eff5fc; + background-color: $spree-light-blue; margin-top: -2em; padding: 4em 2em 2em 1em; @@ -21,7 +21,7 @@ } .admin-cta { - border: 1px solid #5498da; + border: 1px solid $spree-blue; @include border-radius(3px); @@ -65,14 +65,14 @@ &:after { border-color: rgba(136, 183, 213, 0); - border-top-color: #5498da; + border-top-color: $spree-blue; border-width: 12px; margin-left: -12px; } &:hover { &:after { - border-top-color: #9fc820; + border-top-color: $spree-green; } } diff --git a/app/assets/stylesheets/admin/components/alert-box.css.scss b/app/assets/stylesheets/admin/components/alert-box.css.scss index dcd89adf25..c9708d27bc 100644 --- a/app/assets/stylesheets/admin/components/alert-box.css.scss +++ b/app/assets/stylesheets/admin/components/alert-box.css.scss @@ -4,7 +4,7 @@ position: relative; display: block; background-color: #eff5dc; - border: 1px solid #9fc820; + border: 1px solid $spree-green; color: #666; margin-top: 1em; margin-bottom: 1em; @@ -22,21 +22,21 @@ } &.ok { - border: 1px solid #9fc820; + border: 1px solid $spree-green; background-color: #fbffee; - color: #9fc820; + color: $spree-green; font-weight: bold; a.button { padding: 3px 10px; background-color: #a7c44d; &:hover { - background-color: #9fc820; + background-color: $spree-green; } } a.close { - color: #9fc820; + color: $spree-green; } } diff --git a/app/assets/stylesheets/admin/components/alert_row.css.scss b/app/assets/stylesheets/admin/components/alert_row.css.scss index 4c74afc56f..c8c41651a5 100644 --- a/app/assets/stylesheets/admin/components/alert_row.css.scss +++ b/app/assets/stylesheets/admin/components/alert_row.css.scss @@ -1,7 +1,7 @@ .alert-row{ margin-bottom: 10px; font-weight: bold; - background-color: #eff5fc; + background-color: $spree-light-blue; .column, .columns { padding-top: 8px; diff --git a/app/assets/stylesheets/admin/components/dialogs.css.scss b/app/assets/stylesheets/admin/components/dialogs.css.scss index 0ddaeb2e24..298f8e1239 100644 --- a/app/assets/stylesheets/admin/components/dialogs.css.scss +++ b/app/assets/stylesheets/admin/components/dialogs.css.scss @@ -21,7 +21,7 @@ &.error { .message { .icon { - color: #da5354; + color: $warning-red; } } } @@ -29,7 +29,7 @@ &.info { .message { .icon { - color: #5498da; + color: $spree-blue; } } } diff --git a/app/assets/stylesheets/admin/components/jquery_dialog.scss b/app/assets/stylesheets/admin/components/jquery_dialog.scss index ecdb0f0f7d..3bfddb8762 100644 --- a/app/assets/stylesheets/admin/components/jquery_dialog.scss +++ b/app/assets/stylesheets/admin/components/jquery_dialog.scss @@ -63,7 +63,7 @@ light: #ccc &:hover { &:before { - color: #da5354; + color: $warning-red; } } diff --git a/app/assets/stylesheets/admin/components/save_bar.scss b/app/assets/stylesheets/admin/components/save_bar.scss index 4b63a50bc8..70f906119f 100644 --- a/app/assets/stylesheets/admin/components/save_bar.scss +++ b/app/assets/stylesheets/admin/components/save_bar.scss @@ -6,11 +6,11 @@ left: 0; padding: 8px 8px; font-weight: bold; - background-color: #eff5fc; - color: #5498da; + background-color: $spree-light-blue; + color: $spree-blue; h5 { - color: #5498da; + color: $spree-blue; } input { diff --git a/app/assets/stylesheets/admin/components/states_decorator.scss b/app/assets/stylesheets/admin/components/states_decorator.scss index e64a192c09..c32fdfde86 100644 --- a/app/assets/stylesheets/admin/components/states_decorator.scss +++ b/app/assets/stylesheets/admin/components/states_decorator.scss @@ -2,7 +2,7 @@ @extend .state; &.active { - background-color: #9fc820; + background-color: $spree-green; &, a { color: #ffffff; } } diff --git a/app/assets/stylesheets/admin/components/trial_progess_bar.scss b/app/assets/stylesheets/admin/components/trial_progess_bar.scss index 049c1f1f3d..c544304715 100644 --- a/app/assets/stylesheets/admin/components/trial_progess_bar.scss +++ b/app/assets/stylesheets/admin/components/trial_progess_bar.scss @@ -5,6 +5,6 @@ width: 100vw; padding: 8px 10px; font-weight: bold; - background-color: #5498da; + background-color: $spree-blue; color: white; } diff --git a/app/assets/stylesheets/admin/components/wizard_progress.css.scss b/app/assets/stylesheets/admin/components/wizard_progress.css.scss index b3df36081e..f226580177 100644 --- a/app/assets/stylesheets/admin/components/wizard_progress.css.scss +++ b/app/assets/stylesheets/admin/components/wizard_progress.css.scss @@ -1,5 +1,5 @@ $color_unselected: #d9d9d9; -$color_selected: #5498da; +$color_selected: $spree-blue; ul.wizard-progress { list-style: none; diff --git a/app/assets/stylesheets/admin/customers.css.scss b/app/assets/stylesheets/admin/customers.css.scss index d70078d02a..f1284b4725 100644 --- a/app/assets/stylesheets/admin/customers.css.scss +++ b/app/assets/stylesheets/admin/customers.css.scss @@ -7,10 +7,10 @@ table#customers.index { tr.customer { .guest-label { - color: #999; + color: $medium-grey; display: block; font-size: 0.85em; margin-top: 0.15em; } } -} \ No newline at end of file +} diff --git a/app/assets/stylesheets/admin/dashboard_item.css.scss b/app/assets/stylesheets/admin/dashboard_item.css.scss index f314500031..239dd3c5fc 100644 --- a/app/assets/stylesheets/admin/dashboard_item.css.scss +++ b/app/assets/stylesheets/admin/dashboard_item.css.scss @@ -15,22 +15,22 @@ div.dashboard_item { border-radius: 10px; &.green { - background-color: #9fc820; + background-color: $spree-green; } &.red { - background-color: #DA5354; + background-color: $warning-red; } &.orange { - background-color: #DA7F52; + background-color: $warning-orange; } } div.header { height: 50px; border-radius: 6px 6px 0px 0px; - border: 1px solid #5498da; + border: 1px solid $spree-blue; position: relative; a[ofn-with-tip] { @@ -40,20 +40,20 @@ div.dashboard_item { } &.red { - border-color: #DA5354; + border-color: $warning-red; border-width: 3px; h3 { - color: #DA5354; + color: $warning-red; } } &.orange { - border-color: #DA7F52; + border-color: $warning-orange; border-width: 3px; h3 { - color: #DA7F52; + color: $warning-orange; } } @@ -72,7 +72,7 @@ div.dashboard_item { .tabs { height: 30px; - border: solid #5498da; + border: solid $spree-blue; border-width: 0px 0px 1px 0px; margin-top: 3px; @@ -80,19 +80,19 @@ div.dashboard_item { cursor: pointer; height: 30px; color: #fff; - background-color: #5498da; + background-color: $spree-blue; padding: 5px 5px 0px 5px; text-align: center; font-weight: bold; - border: solid #5498da; + border: solid $spree-blue; border-width: 1px 1px 0px 1px; &:hover { - background-color: #9fc820; + background-color: $spree-green; } &.selected { - color: #5498da; + color: $spree-blue; background-color: #fff; } } @@ -105,7 +105,7 @@ div.dashboard_item { } .list-title { - border: solid #5498da; + border: solid $spree-blue; border-width: 0px 1px 0px 1px; span { @@ -120,7 +120,7 @@ div.dashboard_item { } .list-item { - border: solid #5498da; + border: solid $spree-blue; border-width: 0px 1px 0px 1px; height: 38px; @@ -142,28 +142,28 @@ div.dashboard_item { } .icon-warning-sign { - color: #DA7F52; + color: $warning-orange; font-size: 30px; } .icon-remove-sign { - color: #DA5354; + color: $warning-red; font-size: 30px; } .icon-ok-sign { - color: #9fc820; + color: $spree-green; font-size: 30px; } &.orange { - color: #DA7F52; - border: solid #DA7F52; + color: $warning-orange; + border: solid $warning-orange; } &.red { - color: #DA5354; - border: solid #DA5354; + color: $warning-red; + border: solid $warning-red; } &.orange, &.red { @@ -175,13 +175,13 @@ div.dashboard_item { } &.odd { - background-color: #eff5fc; + background-color: $spree-light-blue; } &.even, &.odd { &:hover { color: #ffffff; - background-color: #9fc820; + background-color: $spree-green; .icon-arrow-right { color: #fff; @@ -201,7 +201,7 @@ div.dashboard_item { .text-icon { &.green { - color: #9fc820; + color: $spree-green; background-color: #fff; } } @@ -216,19 +216,19 @@ div.dashboard_item { text-align: center; &.orange { - background-color: #DA7F52; + background-color: $warning-orange; } &.blue { - background-color: #5498da; + background-color: $spree-blue; } &.red { - background-color: #DA5354; + background-color: $warning-red; } &:hover { - background-color: #9fc820; + background-color: $spree-green; } &.bottom { diff --git a/app/assets/stylesheets/admin/dropdown.css.scss b/app/assets/stylesheets/admin/dropdown.css.scss index b848bc3c2c..4a991cbffe 100644 --- a/app/assets/stylesheets/admin/dropdown.css.scss +++ b/app/assets/stylesheets/admin/dropdown.css.scss @@ -1,6 +1,6 @@ #content-header .ofn-drop-down { border: none; - background-color: #5498da; + background-color: $spree-blue; color: #fff; float: none; margin-left: 3px; diff --git a/app/assets/stylesheets/admin/enterprise_console.css.scss b/app/assets/stylesheets/admin/enterprise_console.css.scss index afca3d9261..adfff995a4 100644 --- a/app/assets/stylesheets/admin/enterprise_console.css.scss +++ b/app/assets/stylesheets/admin/enterprise_console.css.scss @@ -6,9 +6,9 @@ span.unavailable, span.available { } span.available { - color: #9fc820; + color: $spree-green; } span.unavailable { - color: #DA5354; + color: $warning-red; } \ No newline at end of file diff --git a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss index 750509c63b..7d95b9b8e2 100644 --- a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss +++ b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss @@ -19,7 +19,7 @@ } &:hover { &:after { - border-top-color: #9fc820; + border-top-color: $spree-green; } } &.disabled{ @@ -60,7 +60,7 @@ .status-ok { margin: 30px 0px; i.icon-ok-sign { - color: #9fc820; + color: $spree-green; font-size: 1.5rem; } } @@ -76,7 +76,7 @@ font-size: 1.5rem; &.issue{ - color: #da5354; + color: $warning-red; } &.warning{ diff --git a/app/assets/stylesheets/admin/enterprises.css.scss b/app/assets/stylesheets/admin/enterprises.css.scss index c389913773..c77d61e7e8 100644 --- a/app/assets/stylesheets/admin/enterprises.css.scss +++ b/app/assets/stylesheets/admin/enterprises.css.scss @@ -1,6 +1,6 @@ form[name="enterprise_form"] { div.row.warning { - color: #DA7F52; + color: $warning-orange; } table.managers { diff --git a/app/assets/stylesheets/admin/index_panel_buttons.css.scss b/app/assets/stylesheets/admin/index_panel_buttons.css.scss index 4cfcde1b23..499313079c 100644 --- a/app/assets/stylesheets/admin/index_panel_buttons.css.scss +++ b/app/assets/stylesheets/admin/index_panel_buttons.css.scss @@ -5,7 +5,7 @@ tbody.panel-ctrl { cursor: pointer; margin-bottom: 10px; font-size: 1.3rem; - background-color: #DA5354; + background-color: $warning-red; &:hover { background-color: #CD4E4F; } diff --git a/app/assets/stylesheets/admin/index_panels.css.scss b/app/assets/stylesheets/admin/index_panels.css.scss index e47ad151eb..c8ea698820 100644 --- a/app/assets/stylesheets/admin/index_panels.css.scss +++ b/app/assets/stylesheets/admin/index_panels.css.scss @@ -26,7 +26,7 @@ tbody.panel-ctrl { font-size: 2rem; -webkit-font-smoothing: antialiased; content: "\f071"; - color: #da5354; + color: $warning-red; } &.status { @@ -37,7 +37,7 @@ tbody.panel-ctrl { i.issue::before { content: "\f071"; - color: #da5354; + color: $warning-red; } i.warning::before { @@ -47,7 +47,7 @@ tbody.panel-ctrl { i.ok::before { content: "\f058"; - color: #9fc820; + color: $spree-green; } } diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index 348b85820a..e1473a1756 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -20,7 +20,7 @@ table .blank-action { } text-angular .ta-editor { - border: 1px solid #cee1f4; + border: 1px solid $pale-blue; border-radius: 3px; } @@ -33,7 +33,7 @@ text-angular .ta-editor { } span.error, div.error:not(.flash) { - color: #DA5354; + color: $warning-red; } /* Fix conflict between Spree and elRTE's styles */ @@ -43,7 +43,7 @@ span.error, div.error:not(.flash) { } input.red, a.button.red, button.red { - background-color: #DA5354; + background-color: $warning-red; margin-right: 5px; color: #ffffff; } @@ -51,7 +51,7 @@ input.red, a.button.red, button.red { a.button.red { &:not(:hover) { color: #fff; - background-color: #DA5354; + background-color: $warning-red; } } @@ -204,15 +204,15 @@ table#listing_enterprise_groups { // TODO: remove this, use class below #no_results { font-weight:bold; - color: #DA5354; + color: $warning-red; } .no-results { font-weight:bold; - color: #DA5354; + color: $warning-red; h1, h2, h3, h4, h5, h6 { - color: #DA5354; + color: $warning-red; } } diff --git a/app/assets/stylesheets/admin/order_cycles.scss b/app/assets/stylesheets/admin/order_cycles.scss index 4eebb90c8d..a0585b1cbc 100644 --- a/app/assets/stylesheets/admin/order_cycles.scss +++ b/app/assets/stylesheets/admin/order_cycles.scss @@ -47,7 +47,7 @@ } &:hover { - background-color: #cee1f4; + background-color: $pale-blue; } } } diff --git a/app/assets/stylesheets/admin/orders.css.scss b/app/assets/stylesheets/admin/orders.css.scss index 23cb9d8fff..15998ec433 100644 --- a/app/assets/stylesheets/admin/orders.css.scss +++ b/app/assets/stylesheets/admin/orders.css.scss @@ -8,20 +8,20 @@ input.show-dirty { &.ng-dirty { border: solid 1px orange; &.update-error { - border: solid 1px #DA5354; + border: solid 1px $warning-red; } } } input, div { &.update-error { - border: solid 1px #DA5354; + border: solid 1px $warning-red; } } input, div { &.update-success { - border: solid 1px #9fc820; + border: solid 1px $spree-green; } } @@ -31,7 +31,7 @@ input, div { div#group_buy_calculation { border-radius: 3px; - background-color: #eff5fc; + background-color: $spree-light-blue; div { margin-bottom: 5px; span, h6 { diff --git a/app/assets/stylesheets/admin/product_import.css.scss b/app/assets/stylesheets/admin/product_import.css.scss index 79265c9231..9d75342ace 100644 --- a/app/assets/stylesheets/admin/product_import.css.scss +++ b/app/assets/stylesheets/admin/product_import.css.scss @@ -4,7 +4,7 @@ div.panel-section { color: #bfbfbf; } .warning { - color: #da5354; + color: $warning-red; } .success { color: #86d83a; @@ -175,7 +175,7 @@ table.import-settings { span.header-error { font-size: 0.85em; - color: #da5354; + color: $warning-red; } .select2-search { diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss index b8ae95a779..c146b6be3f 100644 --- a/app/assets/stylesheets/admin/products.css.scss +++ b/app/assets/stylesheets/admin/products.css.scss @@ -4,13 +4,13 @@ tbody.odd { tr.product { td { background-color: white; } } - tr.variant.odd { td { background-color: lighten(#eff5fc, 3); } } + tr.variant.odd { td { background-color: lighten($spree-light-blue, 3); } } tr.variant.even { td { background-color: white; } } } tbody.even { - tr.product { td { background-color: darken(#eff5fc, 1); } } - tr.variant.odd { td { background-color: lighten(#eff5fc, 2); } } - tr.variant.even { td { background-color: darken(#eff5fc, 1); } } + tr.product { td { background-color: darken($spree-light-blue, 1); } } + tr.variant.odd { td { background-color: lighten($spree-light-blue, 2); } } + tr.variant.even { td { background-color: darken($spree-light-blue, 1); } } } tbody tr.product td.actions { background-color: transparent; } @@ -20,7 +20,7 @@ tbody tr.variant td { padding: 5px 10px; } th.left-actions, td.left-actions { background-color: transparent !important; border: none !important; - border-right: 1px solid #cee1f4 !important; + border-right: 1px solid $pale-blue !important; } #status-message { diff --git a/app/assets/stylesheets/admin/reports.css.scss b/app/assets/stylesheets/admin/reports.css.scss index 13df70de8b..fb94f683a2 100644 --- a/app/assets/stylesheets/admin/reports.css.scss +++ b/app/assets/stylesheets/admin/reports.css.scss @@ -3,7 +3,7 @@ } .report__message { margin-top: 2em; - border: 1px solid #cee1f4; + border: 1px solid $pale-blue; border-radius: .5em; padding: .5em; text-align: center; diff --git a/app/assets/stylesheets/admin/select2.css.scss b/app/assets/stylesheets/admin/select2.css.scss index f94515a54c..90fd4e2b97 100644 --- a/app/assets/stylesheets/admin/select2.css.scss +++ b/app/assets/stylesheets/admin/select2.css.scss @@ -15,12 +15,12 @@ .select2-choice{ background-color: #ffffff; font-weight: normal; - border: 1px solid #5498da !important; - color: #5498da !important; + border: 1px solid $spree-blue !important; + color: $spree-blue !important; .select2-arrow { &:before { - color: #5498da; + color: $spree-blue; font-size: 1rem; font-weight: 400; content: '\25be'; @@ -32,7 +32,7 @@ &:hover, &.select2-container-active { .select2-choice{ color: #ffffff !important; - background-color: #5498da !important; + background-color: $spree-blue !important; .select2-arrow { &:before { diff --git a/app/assets/stylesheets/admin/side_menu.css.scss b/app/assets/stylesheets/admin/side_menu.css.scss index 921b9dee52..398787b7b8 100644 --- a/app/assets/stylesheets/admin/side_menu.css.scss +++ b/app/assets/stylesheets/admin/side_menu.css.scss @@ -22,7 +22,7 @@ } &.selected { - background-color: #5498da; + background-color: $spree-blue; color: #ffffff; } } diff --git a/app/assets/stylesheets/admin/sidebar-item.css.scss b/app/assets/stylesheets/admin/sidebar-item.css.scss index a3baa7b6e0..b9d34b27f1 100644 --- a/app/assets/stylesheets/admin/sidebar-item.css.scss +++ b/app/assets/stylesheets/admin/sidebar-item.css.scss @@ -12,11 +12,11 @@ div.sidebar_item { position: relative; &.blue { - background-color: #5498da; + background-color: $spree-blue; } &.red { - background-color: #DA5354; + background-color: $warning-red; } } @@ -26,10 +26,10 @@ div.sidebar_item { overflow-x: hidden; &.red { - color: #DA5354; + color: $warning-red; .list-item { - border: solid #DA5354; + border: solid $warning-red; border-width: 0px 3px 0px 3px; a.alpha, span.alpha { @@ -40,13 +40,13 @@ div.sidebar_item { background-color: #fcf6ef; &:hover { - background-color: #9fc820; + background-color: $spree-green; } } } a { - color: #DA5354; + color: $warning-red; } } } @@ -57,7 +57,7 @@ div.sidebar_item { font-size: 20px; } - border: solid #5498da; + border: solid $spree-blue; border-width: 0px 1px 0px 1px; a.alpha, span.alpha { @@ -75,7 +75,7 @@ div.sidebar_item { } .icon-remove-sign { - color: #DA5354; + color: $warning-red; font-size: 18px; } @@ -84,13 +84,13 @@ div.sidebar_item { } &.odd { - background-color: #eff5fc; + background-color: $spree-light-blue; } &.even, &.odd { &:hover { color: #ffffff; - background-color: #9fc820; + background-color: $spree-green; a { color: #ffffff; @@ -107,15 +107,15 @@ div.sidebar_item { border-radius: 0px; &.blue { - background-color: #5498da; + background-color: $spree-blue; } &.red { - background-color: #DA5354; + background-color: $warning-red; } &:hover { - background-color: #9fc820; + background-color: $spree-green; } } } diff --git a/app/assets/stylesheets/admin/tag_rules.css.scss b/app/assets/stylesheets/admin/tag_rules.css.scss index 05decd6027..8650f11c22 100644 --- a/app/assets/stylesheets/admin/tag_rules.css.scss +++ b/app/assets/stylesheets/admin/tag_rules.css.scss @@ -21,13 +21,13 @@ tags-input { .customer_tag, .default_rules { background-color: #ffffff; - border: 1px solid #cee1f4; + border: 1px solid $pale-blue; margin-bottom: 40px; .header { padding: 8px 10px; - background-color: #eff5fc; - border-bottom: 1px solid #cee1f4; + background-color: $spree-light-blue; + border-bottom: 1px solid $pale-blue; table { padding: 0px; diff --git a/app/assets/stylesheets/admin/typography.css.scss b/app/assets/stylesheets/admin/typography.css.scss index 761058fb1d..ae68f03323 100644 --- a/app/assets/stylesheets/admin/typography.css.scss +++ b/app/assets/stylesheets/admin/typography.css.scss @@ -9,7 +9,7 @@ } .text-red { - color: #DA5354; + color: $warning-red; } diff --git a/app/assets/stylesheets/admin/variables.css.scss b/app/assets/stylesheets/admin/variables.css.scss new file mode 100644 index 0000000000..d4c6bf522e --- /dev/null +++ b/app/assets/stylesheets/admin/variables.css.scss @@ -0,0 +1,10 @@ +// Admin variables and colours + +$spree-green: #9fc820; +$spree-blue: #5498da; +$spree-light-blue: #eff5fc; + +$warning-red: #da5354; +$warning-orange: #da7f52; +$medium-grey: #919191; +$pale-blue: #cee1f4; diff --git a/app/assets/stylesheets/admin/variant_overrides.css.scss b/app/assets/stylesheets/admin/variant_overrides.css.scss index d4e3e4aaac..c01673b292 100644 --- a/app/assets/stylesheets/admin/variant_overrides.css.scss +++ b/app/assets/stylesheets/admin/variant_overrides.css.scss @@ -4,5 +4,5 @@ } button.hide:hover { - background-color: #DA5354; + background-color: $warning-red; } From 456e05d5d26b1b1fbc7305a756475ff4ab9aeadd Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 7 Jul 2018 19:04:08 +0100 Subject: [PATCH 097/125] Include subfolders in scss import --- app/assets/stylesheets/admin/all.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/admin/all.scss b/app/assets/stylesheets/admin/all.scss index 80acf2e1e5..c6b7412c79 100644 --- a/app/assets/stylesheets/admin/all.scss +++ b/app/assets/stylesheets/admin/all.scss @@ -15,4 +15,4 @@ */ @import 'variables'; -@import '*'; +@import '**/*'; From e3162b0a14fbfd199965b90aed78e34c9d0bde59 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 16 Jul 2018 17:19:09 +0100 Subject: [PATCH 098/125] Change import method to fix missing variable error on asset precompilation --- app/assets/stylesheets/admin/account.css.scss | 2 ++ app/assets/stylesheets/admin/advanced_settings.css.scss | 2 ++ app/assets/stylesheets/admin/alert.css.scss | 2 ++ app/assets/stylesheets/admin/change_type_form.css.scss | 1 + .../stylesheets/admin/components/alert-box.css.scss | 1 + .../stylesheets/admin/components/alert_row.css.scss | 2 ++ app/assets/stylesheets/admin/components/dialogs.css.scss | 2 ++ .../stylesheets/admin/components/jquery_dialog.scss | 2 ++ app/assets/stylesheets/admin/components/save_bar.scss | 2 ++ .../stylesheets/admin/components/states_decorator.scss | 2 ++ .../stylesheets/admin/components/trial_progess_bar.scss | 2 ++ .../stylesheets/admin/components/wizard_progress.css.scss | 2 ++ app/assets/stylesheets/admin/customers.css.scss | 2 ++ app/assets/stylesheets/admin/dashboard_item.css.scss | 2 ++ app/assets/stylesheets/admin/dropdown.css.scss | 2 ++ app/assets/stylesheets/admin/enterprise_console.css.scss | 2 ++ .../stylesheets/admin/enterprise_index_panels.css.scss | 2 ++ app/assets/stylesheets/admin/enterprises.css.scss | 2 ++ app/assets/stylesheets/admin/index_panel_buttons.css.scss | 2 ++ app/assets/stylesheets/admin/index_panels.css.scss | 2 ++ app/assets/stylesheets/admin/openfoodnetwork.css.scss | 2 ++ app/assets/stylesheets/admin/order_cycles.scss | 2 ++ app/assets/stylesheets/admin/orders.css.scss | 2 ++ app/assets/stylesheets/admin/product_import.css.scss | 8 +++++--- app/assets/stylesheets/admin/products.css.scss | 2 ++ app/assets/stylesheets/admin/reports.css.scss | 2 ++ app/assets/stylesheets/admin/select2.css.scss | 2 ++ app/assets/stylesheets/admin/side_menu.css.scss | 2 ++ app/assets/stylesheets/admin/sidebar-item.css.scss | 2 ++ app/assets/stylesheets/admin/tag_rules.css.scss | 2 ++ app/assets/stylesheets/admin/typography.css.scss | 2 ++ app/assets/stylesheets/admin/variant_overrides.css.scss | 2 ++ 32 files changed, 65 insertions(+), 3 deletions(-) diff --git a/app/assets/stylesheets/admin/account.css.scss b/app/assets/stylesheets/admin/account.css.scss index fedd079786..9cba996673 100644 --- a/app/assets/stylesheets/admin/account.css.scss +++ b/app/assets/stylesheets/admin/account.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .row.invoice_title { margin-bottom: 0px; } diff --git a/app/assets/stylesheets/admin/advanced_settings.css.scss b/app/assets/stylesheets/admin/advanced_settings.css.scss index 7f1aa3a8c8..84666363a8 100644 --- a/app/assets/stylesheets/admin/advanced_settings.css.scss +++ b/app/assets/stylesheets/admin/advanced_settings.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + #advanced_settings { background-color: $spree-light-blue; border: 1px solid $pale-blue; diff --git a/app/assets/stylesheets/admin/alert.css.scss b/app/assets/stylesheets/admin/alert.css.scss index 267e7a8580..3894447936 100644 --- a/app/assets/stylesheets/admin/alert.css.scss +++ b/app/assets/stylesheets/admin/alert.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .alert { border: 3px solid $medium-grey; border-radius: 6px; diff --git a/app/assets/stylesheets/admin/change_type_form.css.scss b/app/assets/stylesheets/admin/change_type_form.css.scss index 87b43ff1a2..97ef5b40e5 100644 --- a/app/assets/stylesheets/admin/change_type_form.css.scss +++ b/app/assets/stylesheets/admin/change_type_form.css.scss @@ -1,5 +1,6 @@ @import "../darkswarm/branding"; @import "../darkswarm/mixins"; +@import "variables"; #change_type { section { diff --git a/app/assets/stylesheets/admin/components/alert-box.css.scss b/app/assets/stylesheets/admin/components/alert-box.css.scss index c9708d27bc..09daf7bd70 100644 --- a/app/assets/stylesheets/admin/components/alert-box.css.scss +++ b/app/assets/stylesheets/admin/components/alert-box.css.scss @@ -1,4 +1,5 @@ @import "../../darkswarm/mixins"; +@import "../variables"; .alert-box { position: relative; diff --git a/app/assets/stylesheets/admin/components/alert_row.css.scss b/app/assets/stylesheets/admin/components/alert_row.css.scss index c8c41651a5..8f07c1b054 100644 --- a/app/assets/stylesheets/admin/components/alert_row.css.scss +++ b/app/assets/stylesheets/admin/components/alert_row.css.scss @@ -1,3 +1,5 @@ +@import "../variables"; + .alert-row{ margin-bottom: 10px; font-weight: bold; diff --git a/app/assets/stylesheets/admin/components/dialogs.css.scss b/app/assets/stylesheets/admin/components/dialogs.css.scss index 298f8e1239..64f9bebc9d 100644 --- a/app/assets/stylesheets/admin/components/dialogs.css.scss +++ b/app/assets/stylesheets/admin/components/dialogs.css.scss @@ -1,3 +1,5 @@ +@import "../variables"; + #info-dialog, #confirm-dialog { .message { .text, .icon { diff --git a/app/assets/stylesheets/admin/components/jquery_dialog.scss b/app/assets/stylesheets/admin/components/jquery_dialog.scss index 3bfddb8762..79a12f7d4f 100644 --- a/app/assets/stylesheets/admin/components/jquery_dialog.scss +++ b/app/assets/stylesheets/admin/components/jquery_dialog.scss @@ -1,3 +1,5 @@ +@import "../variables"; + /** Main colors: dark: #545454 diff --git a/app/assets/stylesheets/admin/components/save_bar.scss b/app/assets/stylesheets/admin/components/save_bar.scss index 70f906119f..e5082cfafe 100644 --- a/app/assets/stylesheets/admin/components/save_bar.scss +++ b/app/assets/stylesheets/admin/components/save_bar.scss @@ -1,3 +1,5 @@ +@import "../variables"; + #save-bar { position: fixed; width: 100%; diff --git a/app/assets/stylesheets/admin/components/states_decorator.scss b/app/assets/stylesheets/admin/components/states_decorator.scss index c32fdfde86..4733f5367d 100644 --- a/app/assets/stylesheets/admin/components/states_decorator.scss +++ b/app/assets/stylesheets/admin/components/states_decorator.scss @@ -1,3 +1,5 @@ +@import "../variables"; + .state { @extend .state; diff --git a/app/assets/stylesheets/admin/components/trial_progess_bar.scss b/app/assets/stylesheets/admin/components/trial_progess_bar.scss index c544304715..bfcc743c58 100644 --- a/app/assets/stylesheets/admin/components/trial_progess_bar.scss +++ b/app/assets/stylesheets/admin/components/trial_progess_bar.scss @@ -1,3 +1,5 @@ +@import "../variables"; + #trial_progress_bar { position: fixed; left: 0px; diff --git a/app/assets/stylesheets/admin/components/wizard_progress.css.scss b/app/assets/stylesheets/admin/components/wizard_progress.css.scss index f226580177..25bd3a19db 100644 --- a/app/assets/stylesheets/admin/components/wizard_progress.css.scss +++ b/app/assets/stylesheets/admin/components/wizard_progress.css.scss @@ -1,3 +1,5 @@ +@import "../variables"; + $color_unselected: #d9d9d9; $color_selected: $spree-blue; diff --git a/app/assets/stylesheets/admin/customers.css.scss b/app/assets/stylesheets/admin/customers.css.scss index f1284b4725..0a10d9de06 100644 --- a/app/assets/stylesheets/admin/customers.css.scss +++ b/app/assets/stylesheets/admin/customers.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .tag-with-rules { color: black; } diff --git a/app/assets/stylesheets/admin/dashboard_item.css.scss b/app/assets/stylesheets/admin/dashboard_item.css.scss index 239dd3c5fc..5cc670a238 100644 --- a/app/assets/stylesheets/admin/dashboard_item.css.scss +++ b/app/assets/stylesheets/admin/dashboard_item.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + div.dashboard_item { margin-bottom: 30px; diff --git a/app/assets/stylesheets/admin/dropdown.css.scss b/app/assets/stylesheets/admin/dropdown.css.scss index 4a991cbffe..8c612f60e3 100644 --- a/app/assets/stylesheets/admin/dropdown.css.scss +++ b/app/assets/stylesheets/admin/dropdown.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + #content-header .ofn-drop-down { border: none; background-color: $spree-blue; diff --git a/app/assets/stylesheets/admin/enterprise_console.css.scss b/app/assets/stylesheets/admin/enterprise_console.css.scss index adfff995a4..d475f3dc25 100644 --- a/app/assets/stylesheets/admin/enterprise_console.css.scss +++ b/app/assets/stylesheets/admin/enterprise_console.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + span.unavailable, span.available { font-weight: bold; i { diff --git a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss index 7d95b9b8e2..69940e2eb1 100644 --- a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss +++ b/app/assets/stylesheets/admin/enterprise_index_panels.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .enterprise_package_panel, .enterprise_producer_panel { .info { p { diff --git a/app/assets/stylesheets/admin/enterprises.css.scss b/app/assets/stylesheets/admin/enterprises.css.scss index c77d61e7e8..c12c8bb53f 100644 --- a/app/assets/stylesheets/admin/enterprises.css.scss +++ b/app/assets/stylesheets/admin/enterprises.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + form[name="enterprise_form"] { div.row.warning { color: $warning-orange; diff --git a/app/assets/stylesheets/admin/index_panel_buttons.css.scss b/app/assets/stylesheets/admin/index_panel_buttons.css.scss index 499313079c..50e174eb37 100644 --- a/app/assets/stylesheets/admin/index_panel_buttons.css.scss +++ b/app/assets/stylesheets/admin/index_panel_buttons.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + tbody.panel-ctrl { tr.panel-row { > td { diff --git a/app/assets/stylesheets/admin/index_panels.css.scss b/app/assets/stylesheets/admin/index_panels.css.scss index c8ea698820..a7e797bea1 100644 --- a/app/assets/stylesheets/admin/index_panels.css.scss +++ b/app/assets/stylesheets/admin/index_panels.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + tbody.panel-ctrl { td.panel-toggle{ -webkit-touch-callout: none; diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index e1473a1756..a08221b722 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + input[type="submit"], input[type="button"], button, .button { cursor: pointer; } diff --git a/app/assets/stylesheets/admin/order_cycles.scss b/app/assets/stylesheets/admin/order_cycles.scss index a0585b1cbc..8fe71529fd 100644 --- a/app/assets/stylesheets/admin/order_cycles.scss +++ b/app/assets/stylesheets/admin/order_cycles.scss @@ -1,3 +1,5 @@ +@import "variables"; + #schedule-dialog { table { border: none; diff --git a/app/assets/stylesheets/admin/orders.css.scss b/app/assets/stylesheets/admin/orders.css.scss index 15998ec433..46e6b8aa0f 100644 --- a/app/assets/stylesheets/admin/orders.css.scss +++ b/app/assets/stylesheets/admin/orders.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + input, div { &.update-pending { border: solid 1px orange; diff --git a/app/assets/stylesheets/admin/product_import.css.scss b/app/assets/stylesheets/admin/product_import.css.scss index 9d75342ace..91d7e70297 100644 --- a/app/assets/stylesheets/admin/product_import.css.scss +++ b/app/assets/stylesheets/admin/product_import.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + div.panel-section { .neutral { @@ -283,8 +285,8 @@ div.progress-bar { #upload-sidebar { float: right; - background-color: lighten(#eff5fc, 2.5%); - border: 1px solid lighten(#cee1f4, 2.5%); + background-color: lighten($spree-light-blue, 2.5%); + border: 1px solid lighten($pale-blue, 2.5%); width: 50%; padding: 0 1.5em 1.5em; @@ -304,7 +306,7 @@ div.progress-bar { span.category { display: inline-block; - background-color: lighten(#5498da, 10%); + background-color: lighten($spree-blue, 10%); color: white; padding: 0.3em 0.6em; margin: 0 0.4em 0.5em 0; diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.css.scss index c146b6be3f..933f43a00b 100644 --- a/app/assets/stylesheets/admin/products.css.scss +++ b/app/assets/stylesheets/admin/products.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + #product_distributors_field span { display: block; } diff --git a/app/assets/stylesheets/admin/reports.css.scss b/app/assets/stylesheets/admin/reports.css.scss index fb94f683a2..1d105eb65b 100644 --- a/app/assets/stylesheets/admin/reports.css.scss +++ b/app/assets/stylesheets/admin/reports.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .report__table { margin-top: 2em; } diff --git a/app/assets/stylesheets/admin/select2.css.scss b/app/assets/stylesheets/admin/select2.css.scss index 90fd4e2b97..0acf00c088 100644 --- a/app/assets/stylesheets/admin/select2.css.scss +++ b/app/assets/stylesheets/admin/select2.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .select2-container { .select2-choice { .select2-search-choice-close { diff --git a/app/assets/stylesheets/admin/side_menu.css.scss b/app/assets/stylesheets/admin/side_menu.css.scss index 398787b7b8..8cb912814d 100644 --- a/app/assets/stylesheets/admin/side_menu.css.scss +++ b/app/assets/stylesheets/admin/side_menu.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .side_menu { border-right: 2px solid #f6f6f6; border-top: 2px solid #f6f6f6; diff --git a/app/assets/stylesheets/admin/sidebar-item.css.scss b/app/assets/stylesheets/admin/sidebar-item.css.scss index b9d34b27f1..9d7047976f 100644 --- a/app/assets/stylesheets/admin/sidebar-item.css.scss +++ b/app/assets/stylesheets/admin/sidebar-item.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + div.sidebar_item { margin-bottom: 30px; diff --git a/app/assets/stylesheets/admin/tag_rules.css.scss b/app/assets/stylesheets/admin/tag_rules.css.scss index 8650f11c22..b1bbc1f0e0 100644 --- a/app/assets/stylesheets/admin/tag_rules.css.scss +++ b/app/assets/stylesheets/admin/tag_rules.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + tags-input { &.limit-reached { input, span.input { diff --git a/app/assets/stylesheets/admin/typography.css.scss b/app/assets/stylesheets/admin/typography.css.scss index ae68f03323..12c683d820 100644 --- a/app/assets/stylesheets/admin/typography.css.scss +++ b/app/assets/stylesheets/admin/typography.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .text-normal { font-size: 1.0rem; font-weight: 300; diff --git a/app/assets/stylesheets/admin/variant_overrides.css.scss b/app/assets/stylesheets/admin/variant_overrides.css.scss index c01673b292..f74e15ecb9 100644 --- a/app/assets/stylesheets/admin/variant_overrides.css.scss +++ b/app/assets/stylesheets/admin/variant_overrides.css.scss @@ -1,3 +1,5 @@ +@import "variables"; + .variant-override-unit { float: right; font-style: italic; From 8246893652ac0df3fe2ddfb542624763b553154b Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Mon, 2 Jul 2018 14:40:47 +0100 Subject: [PATCH 099/125] Added notice for unexpected mail in confirmation instructions mail (HugsDaniel) --- app/assets/stylesheets/mail/email.css.scss | 6 ++++++ app/mailers/spree/user_mailer_decorator.rb | 3 +++ .../spree/user_mailer/confirmation_instructions.html.haml | 5 ++++- config/locales/en.yml | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mail/email.css.scss b/app/assets/stylesheets/mail/email.css.scss index a474a30da1..e6eabf665f 100644 --- a/app/assets/stylesheets/mail/email.css.scss +++ b/app/assets/stylesheets/mail/email.css.scss @@ -55,6 +55,12 @@ p.callout { color: #0096ad; } +p.notice { + font-style: italic; + font-size: 12px; + margin-top: 20px; +} + table.social { background-color: #ebebeb; diff --git a/app/mailers/spree/user_mailer_decorator.rb b/app/mailers/spree/user_mailer_decorator.rb index 778f4d421a..3921d3c648 100644 --- a/app/mailers/spree/user_mailer_decorator.rb +++ b/app/mailers/spree/user_mailer_decorator.rb @@ -9,6 +9,9 @@ Spree::UserMailer.class_eval do # overriding `Devise::Mailer.confirmation_instructions`. def confirmation_instructions(user, _opts) @user = user + @instance = Spree::Config[:site_name] + @contact = ContentConfig.footer_email + subject = t('spree.user_mailer.confirmation_instructions.subject') mail(to: user.email, from: from_address, diff --git a/app/views/spree/user_mailer/confirmation_instructions.html.haml b/app/views/spree/user_mailer/confirmation_instructions.html.haml index 960ec7a51d..1085bced91 100644 --- a/app/views/spree/user_mailer/confirmation_instructions.html.haml +++ b/app/views/spree/user_mailer/confirmation_instructions.html.haml @@ -1,7 +1,7 @@ %h3 = t :email_signup_greeting %p.lead - = t :email_signup_welcome, sitename: Spree::Config[:site_name] + = t :email_signup_welcome, sitename: @instance %p= t :email_confirmation_activate_account %p.callout @@ -13,3 +13,6 @@ = render 'shared/mailers/signoff' = render 'shared/mailers/social_and_contact' + +%p.notice + = t :email_confirmation_notice_unexpected, sitename: @instance, contact: @contact diff --git a/config/locales/en.yml b/config/locales/en.yml index 6481ef8316..22d5a35892 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1354,6 +1354,7 @@ To activate your Profile we need to confirm this email address." email_confirmation_link_label: "Confirm this email address »" email_confirmation_help_html: "After confirming your email you can access your administration account for this enterprise. See the %{link} to find out more about %{sitename}'s features and to start using your profile or online store." + email_confirmation_notice_unexpected: "You received this message because you signed up on %{sitename}, or were invited to sign up by someone you probably know. If you don't understand why you are receiving this email, please write to %{contact}." email_social: "Connect with Us:" email_contact: "Email us:" email_signoff: "Cheers," From 8a3a617870adc7e240f087d95cda8121ebaf83d2 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 19 Jul 2018 10:44:43 +1000 Subject: [PATCH 100/125] DRY specs with new EmbeddedPagesHelper --- .../consumer/shopping/embedded_groups_spec.rb | 11 +---------- .../consumer/shopping/embedded_shopfronts_spec.rb | 9 +-------- spec/support/embedded_pages_helper.rb | 11 +++++++++++ 3 files changed, 13 insertions(+), 18 deletions(-) create mode 100644 spec/support/embedded_pages_helper.rb diff --git a/spec/features/consumer/shopping/embedded_groups_spec.rb b/spec/features/consumer/shopping/embedded_groups_spec.rb index 6df7734d6d..b53f12c2eb 100644 --- a/spec/features/consumer/shopping/embedded_groups_spec.rb +++ b/spec/features/consumer/shopping/embedded_groups_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' feature "Using embedded shopfront functionality", js: true do + include OpenFoodNetwork::EmbeddedPagesHelper describe 'embedded groups' do let(:enterprise) { create(:distributor_enterprise) } @@ -68,14 +69,4 @@ feature "Using embedded shopfront functionality", js: true do end end end - - private - - def on_embedded_page - expect(page).to have_selector "iframe" - - within_frame :frame do - yield - end - end end diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index da99492945..1b965db512 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' feature "Using embedded shopfront functionality", js: true do + include OpenFoodNetwork::EmbeddedPagesHelper include AuthenticationWorkflow include WebHelper include ShopWorkflow @@ -107,14 +108,6 @@ feature "Using embedded shopfront functionality", js: true do private - def on_embedded_page - expect(page).to have_selector "iframe" - - within_frame :frame do - yield - end - end - def login_with_modal expect(page).to have_selector 'div.login-modal', visible: true diff --git a/spec/support/embedded_pages_helper.rb b/spec/support/embedded_pages_helper.rb new file mode 100644 index 0000000000..2e8e53b843 --- /dev/null +++ b/spec/support/embedded_pages_helper.rb @@ -0,0 +1,11 @@ +module OpenFoodNetwork + module EmbeddedPagesHelper + def on_embedded_page + expect(page).to have_selector "iframe" + + within_frame :frame do + yield + end + end + end +end From 962c54b606e509e0002f96fbedf23ad0f92e2ebd Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 19 Jul 2018 10:45:33 +1000 Subject: [PATCH 101/125] Remove unnecessary expectation The `iframe` is rendered in pure HTML and should always be there. --- spec/support/embedded_pages_helper.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/support/embedded_pages_helper.rb b/spec/support/embedded_pages_helper.rb index 2e8e53b843..5eed420394 100644 --- a/spec/support/embedded_pages_helper.rb +++ b/spec/support/embedded_pages_helper.rb @@ -1,8 +1,6 @@ module OpenFoodNetwork module EmbeddedPagesHelper def on_embedded_page - expect(page).to have_selector "iframe" - within_frame :frame do yield end From d952276e2aaa8a04ad6b7b4543f3f00fd8b84bf4 Mon Sep 17 00:00:00 2001 From: Margaret Williford Date: Sat, 14 Jul 2018 16:18:30 -0600 Subject: [PATCH 102/125] move footer logo sizing from html to css --- app/assets/stylesheets/darkswarm/footer.scss | 1 + app/views/shared/_footer.html.haml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/footer.scss b/app/assets/stylesheets/darkswarm/footer.scss index c9255b71b1..6a7f12dda6 100644 --- a/app/assets/stylesheets/darkswarm/footer.scss +++ b/app/assets/stylesheets/darkswarm/footer.scss @@ -36,6 +36,7 @@ footer { img { margin-top: 36px; + width: 120px; } } diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 6b04cedb5a..d18d7d03e3 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -3,7 +3,7 @@ .row .small-12.columns.text-center .logo - %img{src: "/assets/logo-white-notext.png", width: "120px"} + %img{src: "/assets/logo-white-notext.png"} .row .small-12.medium-8.medium-offset-2.columns.text-center .alert-box From 512e9746721eea6d40362d67e6e4f63b9f698ea6 Mon Sep 17 00:00:00 2001 From: Margaret Williford Date: Sat, 14 Jul 2018 19:43:43 -0600 Subject: [PATCH 103/125] move width setting for tagline logo image from HTML to CSS --- app/assets/stylesheets/darkswarm/home_tagline.css.scss | 2 +- app/views/home/_tagline.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/home_tagline.css.scss b/app/assets/stylesheets/darkswarm/home_tagline.css.scss index b278f79e25..ffe4204869 100644 --- a/app/assets/stylesheets/darkswarm/home_tagline.css.scss +++ b/app/assets/stylesheets/darkswarm/home_tagline.css.scss @@ -34,7 +34,7 @@ max-width: 45%; @media all and (min-height: 500px) { - max-width: 80%; + max-width: 250px; } margin-bottom: 2rem; diff --git a/app/views/home/_tagline.html.haml b/app/views/home/_tagline.html.haml index 817afdd051..7685455b3f 100644 --- a/app/views/home/_tagline.html.haml +++ b/app/views/home/_tagline.html.haml @@ -3,7 +3,7 @@ .small-12.text-center.columns %h1 / TODO: Rohan - logo asset & width is content manageable: - %img{src: "/assets/logo-white-notext.png", width: "250", title: Spree::Config.site_name} + %img{src: "/assets/logo-white-notext.png", title: Spree::Config.site_name} %br/ %a.button.transparent{href: "/shops"} = t :home_shop From 5f4115fbd9ece7128dae5a17cfb6261b7db76925 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 20 Jul 2018 16:56:12 +1000 Subject: [PATCH 104/125] Remove unused gem newrelic-rpm --- .gitignore | 1 - Gemfile | 1 - Gemfile.lock | 4 +--- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index f295094890..060eb24f85 100644 --- a/.gitignore +++ b/.gitignore @@ -32,7 +32,6 @@ public/stylesheets public/images public/spree config/abr.yml -config/newrelic.yml config/initializers/feature_toggle.rb config/initializers/db2fog.rb NERD_tree* diff --git a/Gemfile b/Gemfile index 962666d6b9..6c6ebf43fe 100644 --- a/Gemfile +++ b/Gemfile @@ -38,7 +38,6 @@ gem 'simple_form', github: 'RohanM/simple_form' gem 'unicorn' gem 'angularjs-rails', '1.5.5' gem 'bugsnag' -gem 'newrelic_rpm' gem 'haml' gem 'sass', "~> 3.3" gem 'sass-rails', '~> 3.2.3', groups: [:default, :assets] diff --git a/Gemfile.lock b/Gemfile.lock index 0a1c11e147..3002dd93aa 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -487,7 +487,6 @@ GEM multi_xml (0.6.0) multipart-post (2.0.0) nenv (0.3.0) - newrelic_rpm (3.12.0.288) nokogiri (1.6.8.1) mini_portile2 (~> 2.1.0) notiffany (0.1.1) @@ -763,7 +762,6 @@ DEPENDENCIES letter_opener (>= 1.4.1) listen (= 3.0.8) momentjs-rails - newrelic_rpm nokogiri (>= 1.6.7.1) oauth2 (~> 1.2.0) ofn-qz! @@ -815,4 +813,4 @@ RUBY VERSION ruby 2.1.5p273 BUNDLED WITH - 1.16.1 + 1.16.2 From 44fe3de732f669e86270bb8ae44d61100941cc38 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 20 Jul 2018 09:08:03 +0200 Subject: [PATCH 105/125] Make CodeClimate config more strict There's no point of using Code Climate if most of its checks are disabled. Now it scores our codebase with an A and reports just 2 code smells, 64 duplications and 14 other issues. That couldn't farther from reality. If we care about the architecture and maintainability of our app, this is a must. To transition towards enabling all default checks, I started with scss-lint, duplication and method-complexity. This doesn't mean will have to fix them all straight away as we'll add the current violations to the `.rubocop_todo.yml` but it'll point us the parts where we should focus our efforts. --- .codeclimate.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index 14569f6b0f..e892e73274 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -4,7 +4,7 @@ plugins: enabled: true channel: "rubocop-0-55" scss-lint: - enabled: false + enabled: true duplication: enabled: true exclude_patterns: @@ -16,9 +16,9 @@ checks: complex-logic: enabled: true file-lines: - enabled: false + enabled: true method-complexity: - enabled: false + enabled: true method-count: enabled: false method-lines: @@ -35,3 +35,4 @@ exclude_patterns: - "spec/**/*" - "vendor/**/*" - "app/assets/javascripts/shared/*" +- "app/assets/javascripts/jquery-migrate-1.0.0.js" From 7d790a7d591226f440ab63db29016ab0a7719c7a Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 20 Jul 2018 18:58:37 +0200 Subject: [PATCH 106/125] Update .rubocop_todo.yml --- .rubocop_todo.yml | 229 ++++++++++++++++++++-------------------------- 1 file changed, 99 insertions(+), 130 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 445f0dbc35..b9bd3d0908 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 1400` -# on 2018-05-08 14:46:01 +1000 using RuboCop version 0.55.0. +# on 2018-07-20 18:57:26 +0200 using RuboCop version 0.55.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -14,7 +14,7 @@ Bundler/OrderedGems: Exclude: - 'Gemfile' -# Offense count: 124 +# Offense count: 116 # Cop supports --auto-correct. Layout/AlignArray: Exclude: @@ -119,7 +119,7 @@ Layout/ElseAlignment: - 'app/serializers/api/admin/order_cycle_serializer.rb' - 'lib/open_food_network/sales_tax_report.rb' -# Offense count: 209 +# Offense count: 205 # Cop supports --auto-correct. Layout/EmptyLines: Exclude: @@ -173,7 +173,6 @@ Layout/EmptyLines: - 'app/models/spree/shipping_method_decorator.rb' - 'app/models/spree/tax_rate_decorator.rb' - 'app/models/spree/taxon_decorator.rb' - - 'app/models/spree/variant_decorator.rb' - 'app/serializers/api/enterprise_serializer.rb' - 'lib/open_food_network/cached_products_renderer.rb' - 'lib/open_food_network/enterprise_fee_applicator.rb' @@ -193,6 +192,7 @@ Layout/EmptyLines: - 'lib/open_food_network/sales_tax_report.rb' - 'lib/open_food_network/scope_product_to_hub.rb' - 'lib/open_food_network/scope_variant_to_hub.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/core/controller_helpers/order_decorator.rb' - 'lib/tasks/cache.rake' - 'lib/tasks/dev.rake' @@ -217,7 +217,6 @@ Layout/EmptyLines: - 'spec/features/admin/order_cycles_spec.rb' - 'spec/features/admin/orders_spec.rb' - 'spec/features/admin/payment_method_spec.rb' - - 'spec/features/admin/product_import_spec.rb' - 'spec/features/admin/products_spec.rb' - 'spec/features/admin/reports_spec.rb' - 'spec/features/admin/shipping_methods_spec.rb' @@ -282,6 +281,7 @@ Layout/EmptyLinesAroundBlockBody: - 'lib/spree/money_decorator.rb' - 'lib/tasks/dev.rake' - 'lib/tasks/users.rake' + - 'spec/controllers/admin/order_cycles_controller_spec.rb' - 'spec/controllers/admin/tag_rules_controller_spec.rb' - 'spec/controllers/cart_controller_spec.rb' - 'spec/controllers/spree/admin/orders_controller_spec.rb' @@ -294,6 +294,7 @@ Layout/EmptyLinesAroundBlockBody: - 'spec/features/admin/orders_spec.rb' - 'spec/features/admin/reports_spec.rb' - 'spec/features/admin/variant_overrides_spec.rb' + - 'spec/features/consumer/shopping/embedded_groups_spec.rb' - 'spec/features/consumer/shopping/embedded_shopfronts_spec.rb' - 'spec/features/consumer/shopping/shopping_spec.rb' - 'spec/features/consumer/shopping/variant_overrides_spec.rb' @@ -321,7 +322,7 @@ Layout/EmptyLinesAroundBlockBody: - 'spec/support/matchers/select2_matchers.rb' - 'spec/support/matchers/table_matchers.rb' -# Offense count: 27 +# Offense count: 26 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only @@ -332,7 +333,6 @@ Layout/EmptyLinesAroundClassBody: - 'app/controllers/admin/enterprise_fees_controller.rb' - 'app/controllers/admin/inventory_items_controller.rb' - 'app/controllers/admin/invoice_settings_controller.rb' - - 'app/controllers/admin/product_import_controller.rb' - 'app/controllers/admin/tag_rules_controller.rb' - 'app/controllers/api/enterprises_controller.rb' - 'app/controllers/application_controller.rb' @@ -364,7 +364,7 @@ Layout/EndAlignment: - 'app/serializers/api/admin/for_order_cycle/supplied_product_serializer.rb' - 'app/serializers/api/admin/order_cycle_serializer.rb' -# Offense count: 53 +# Offense count: 49 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Layout/ExtraSpacing: @@ -405,37 +405,29 @@ Layout/ExtraSpacing: - 'spec/spec_helper.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 2 +# Offense count: 1 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle, IndentationWidth. +# SupportedStyles: consistent, special_for_inner_method_call, special_for_inner_method_call_in_parentheses +Layout/FirstParameterIndentation: + Exclude: + - 'spec/controllers/spree/admin/orders/customer_details_controller_spec.rb' + +# Offense count: 6 # Cop supports --auto-correct. # Configuration parameters: IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_brackets Layout/IndentArray: EnforcedStyle: consistent -# Offense count: 52 +# Offense count: 51 # Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle, IndentationWidth. +# Configuration parameters: IndentationWidth. # SupportedStyles: special_inside_parentheses, consistent, align_braces Layout/IndentHash: - Exclude: - - 'app/controllers/admin/accounts_and_billing_settings_controller.rb' - - 'app/controllers/admin/business_model_configuration_controller.rb' - - 'app/controllers/checkout_controller.rb' - - 'app/controllers/spree/admin/search_controller_decorator.rb' - - 'app/jobs/finalize_account_invoices.rb' - - 'app/jobs/update_account_invoices.rb' - - 'app/jobs/update_billable_periods.rb' - - 'app/models/spree/order_decorator.rb' - - 'spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb' - - 'spec/controllers/admin/business_model_configuration_controller_spec.rb' - - 'spec/controllers/admin/order_cycles_controller_spec.rb' - - 'spec/features/admin/accounts_and_billing_settings_spec.rb' - - 'spec/features/admin/business_model_configuration_spec.rb' - - 'spec/features/admin/tax_settings_spec.rb' - - 'spec/lib/open_food_network/order_cycle_form_applicator_spec.rb' - - 'spec/support/request/authentication_workflow.rb' + EnforcedStyle: consistent -# Offense count: 20 +# Offense count: 19 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: normal, rails @@ -471,15 +463,13 @@ Layout/IndentationWidth: - 'spec/models/enterprise_spec.rb' - 'spec/models/spree/calculator/flexi_rate_spec.rb' -# Offense count: 51 +# Offense count: 46 # Cop supports --auto-correct. Layout/LeadingCommentSpace: Exclude: - 'Gemfile' - 'app/models/billable_period.rb' - 'app/models/content_configuration.rb' - - 'app/models/product_importer.rb' - - 'app/models/spreadsheet_entry.rb' - 'app/models/spree/inventory_unit_decorator.rb' - 'app/models/spree/taxon_decorator.rb' - 'app/overrides/add_capture_order_shortcut.rb' @@ -523,7 +513,7 @@ Layout/MultilineBlockLayout: - 'spec/models/spree/variant_spec.rb' - 'spec/serializers/enterprise_serializer_spec.rb' -# Offense count: 6 +# Offense count: 4 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: symmetrical, new_line, same_line @@ -532,7 +522,6 @@ Layout/MultilineHashBraceLayout: - 'app/controllers/spree/admin/products_controller_decorator.rb' - 'app/models/billable_period.rb' - 'lib/spree/product_filters.rb' - - 'spec/controllers/admin/order_cycles_controller_spec.rb' - 'spec/support/request/authentication_workflow.rb' # Offense count: 7 @@ -557,7 +546,7 @@ Layout/MultilineMethodCallIndentation: - 'spec/lib/open_food_network/cached_products_renderer_spec.rb' - 'spec/serializers/variant_serializer_spec.rb' -# Offense count: 32 +# Offense count: 30 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, IndentationWidth. # SupportedStyles: aligned, indented @@ -568,7 +557,6 @@ Layout/MultilineOperationIndentation: - 'app/controllers/spree/admin/shipping_methods_controller_decorator.rb' - 'app/helpers/enterprises_helper.rb' - 'app/models/producer_property.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/ability_decorator.rb' - 'app/models/spree/product_set.rb' - 'app/models/variant_override_set.rb' @@ -588,7 +576,7 @@ Layout/SpaceAfterColon: - 'spec/models/variant_override_spec.rb' - 'spec/spec_helper.rb' -# Offense count: 85 +# Offense count: 83 # Cop supports --auto-correct. Layout/SpaceAfterComma: Exclude: @@ -596,7 +584,6 @@ Layout/SpaceAfterComma: - 'app/controllers/spree/admin/products_controller_decorator.rb' - 'app/controllers/spree/orders_controller_decorator.rb' - 'app/models/column_preference.rb' - - 'app/models/product_importer.rb' - 'lib/discourse/single_sign_on.rb' - 'lib/open_food_network/accounts_and_billing_settings_validator.rb' - 'lib/open_food_network/business_model_configuration_validator.rb' @@ -628,7 +615,7 @@ Layout/SpaceAfterSemicolon: Exclude: - 'spec/controllers/spree/admin/base_controller_spec.rb' -# Offense count: 65 +# Offense count: 62 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: space, no_space @@ -647,7 +634,6 @@ Layout/SpaceAroundEqualsInParameterDefault: - 'app/models/exchange.rb' - 'app/models/model_set.rb' - 'app/models/order_cycle_set.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/calculator/per_item_decorator.rb' - 'app/models/spree/payment_decorator.rb' - 'app/models/spree/payment_method_decorator.rb' @@ -665,6 +651,7 @@ Layout/SpaceAroundEqualsInParameterDefault: - 'lib/open_food_network/permissions.rb' - 'lib/open_food_network/scope_variant_to_hub.rb' - 'lib/open_food_network/tag_rule_applicator.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/money_decorator.rb' - 'spec/features/admin/enterprise_relationships_spec.rb' - 'spec/features/admin/reports_spec.rb' @@ -673,21 +660,20 @@ Layout/SpaceAroundEqualsInParameterDefault: - 'spec/support/request/distribution_helper.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 59 +# Offense count: 57 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment. Layout/SpaceAroundOperators: Exclude: - - 'app/controllers/admin/product_import_controller.rb' - 'app/controllers/checkout_controller.rb' - 'app/helpers/admin/business_model_configuration_helper.rb' - 'app/jobs/update_billable_periods.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/address_decorator.rb' - 'app/overrides/remove_search_bar.rb' - 'app/overrides/remove_side_bar.rb' - 'app/overrides/replace_shipping_address_form_with_distributor_details.rb' - 'app/serializers/api/enterprise_serializer.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/product_filters.rb' - 'spec/controllers/admin/enterprises_controller_spec.rb' - 'spec/controllers/cart_controller_spec.rb' @@ -732,7 +718,7 @@ Layout/SpaceInLambdaLiteral: - 'app/models/spree/product_decorator.rb' - 'app/models/spree/variant_decorator.rb' -# Offense count: 129 +# Offense count: 130 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBrackets. # SupportedStyles: space, no_space, compact @@ -752,8 +738,9 @@ Layout/SpaceInsideArrayLiteralBrackets: - 'spec/jobs/update_billable_periods_spec.rb' - 'spec/lib/open_food_network/order_grouper_spec.rb' - 'spec/lib/open_food_network/users_and_enterprises_report_spec.rb' + - 'spec/models/spree/order_spec.rb' -# Offense count: 192 +# Offense count: 194 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # SupportedStyles: space, no_space @@ -807,7 +794,7 @@ Layout/SpaceInsideBlockBraces: - 'spec/spec_helper.rb' - 'spec/support/cancan_helper.rb' -# Offense count: 786 +# Offense count: 798 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. # SupportedStyles: space, no_space, compact @@ -839,7 +826,6 @@ Layout/SpaceInsideHashLiteralBraces: - 'app/models/enterprise_group.rb' - 'app/models/enterprise_relationship.rb' - 'app/models/producer_property.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/gateway/stripe_connect.rb' - 'app/models/spree/order_populator_decorator.rb' - 'app/models/spree/product_decorator.rb' @@ -855,6 +841,7 @@ Layout/SpaceInsideHashLiteralBraces: - 'lib/open_food_network/reports/rule.rb' - 'lib/open_food_network/sales_tax_report.rb' - 'lib/open_food_network/variant_and_line_item_naming.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/tasks/users.rake' - 'spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb' - 'spec/controllers/admin/business_model_configuration_controller_spec.rb' @@ -900,6 +887,7 @@ Layout/SpaceInsideHashLiteralBraces: - 'spec/models/exchange_spec.rb' - 'spec/models/model_set_spec.rb' - 'spec/models/product_distribution_spec.rb' + - 'spec/models/product_importer_spec.rb' - 'spec/models/spree/ability_spec.rb' - 'spec/models/spree/gateway/stripe_connect_spec.rb' - 'spec/models/spree/image_spec.rb' @@ -953,7 +941,7 @@ Layout/Tab: - 'spec/lib/spree/product_filters_spec.rb' - 'spec/models/spree/line_item_spec.rb' -# Offense count: 62 +# Offense count: 60 # Cop supports --auto-correct. # Configuration parameters: AllowInHeredoc. Layout/TrailingWhitespace: @@ -969,7 +957,6 @@ Layout/TrailingWhitespace: - 'app/views/json/_producer.rabl' - 'app/views/json/partials/_producer.rabl' - 'spec/controllers/admin/column_preferences_controller_spec.rb' - - 'spec/controllers/shop_controller_spec.rb' - 'spec/features/admin/enterprise_user_spec.rb' - 'spec/features/admin/variant_overrides_spec.rb' - 'spec/helpers/enterprises_helper_spec.rb' @@ -985,10 +972,14 @@ Layout/TrailingWhitespace: - 'spec/views/json/producers.json.rabl_spec.rb' # Offense count: 1 -# Cop supports --auto-correct. -Lint/DeprecatedClassMethods: +Lint/AmbiguousOperator: Exclude: - - 'app/controllers/admin/product_import_controller.rb' + - 'spec/controllers/spree/admin/payments_controller_spec.rb' + +# Offense count: 2 +Lint/BooleanSymbol: + Exclude: + - 'spec/features/consumer/shopping/embedded_groups_spec.rb' # Offense count: 4 Lint/DuplicateMethods: @@ -1016,16 +1007,16 @@ Lint/InheritException: - 'lib/open_food_network/cached_products_renderer.rb' - 'lib/open_food_network/products_renderer.rb' +# Offense count: 1 +Lint/InterpolationCheck: + Exclude: + - 'spec/features/consumer/shopping/embedded_groups_spec.rb' + # Offense count: 1 Lint/LiteralAsCondition: Exclude: - 'lib/open_food_network/rack_request_blocker.rb' -# Offense count: 1 -Lint/NonLocalExitFromIterator: - Exclude: - - 'app/models/product_importer.rb' - # Offense count: 1 # Cop supports --auto-correct. Lint/ScriptPermission: @@ -1039,7 +1030,7 @@ Lint/ShadowingOuterLocalVariable: - 'app/models/spree/product_set.rb' - 'spec/models/model_set_spec.rb' -# Offense count: 6 +# Offense count: 7 # Cop supports --auto-correct. Lint/StringConversionInInterpolation: Exclude: @@ -1049,13 +1040,14 @@ Lint/StringConversionInInterpolation: - 'app/helpers/injection_helper.rb' - 'app/helpers/spree/products_helper_decorator.rb' - 'app/serializers/api/admin/tag_rule_serializer.rb' + - 'spec/features/admin/product_import_spec.rb' # Offense count: 2 Lint/UnderscorePrefixedVariableName: Exclude: - 'spec/support/cancan_helper.rb' -# Offense count: 125 +# Offense count: 123 # Cop supports --auto-correct. # Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. Lint/UnusedBlockArgument: @@ -1066,7 +1058,6 @@ Lint/UnusedBlockArgument: - 'app/controllers/spree/orders_controller_decorator.rb' - 'app/models/column_preference.rb' - 'app/models/model_set.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/order_decorator.rb' - 'app/models/spree/order_populator_decorator.rb' - 'lib/open_food_network/bulk_coop_report.rb' @@ -1080,6 +1071,7 @@ Lint/UnusedBlockArgument: - 'lib/open_food_network/reports/bulk_coop_allocation_report.rb' - 'lib/open_food_network/reports/bulk_coop_supplier_report.rb' - 'lib/open_food_network/sales_tax_report.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'spec/lib/open_food_network/order_grouper_spec.rb' - 'spec/support/cancan_helper.rb' - 'spec/support/delayed_job_helper.rb' @@ -1118,7 +1110,7 @@ Lint/UselessAccessModifier: - 'lib/open_food_network/reports/bulk_coop_report.rb' - 'spec/lib/open_food_network/reports/report_spec.rb' -# Offense count: 315 +# Offense count: 288 # Configuration parameters: CheckForMethodsWithNoSideEffects. Lint/Void: Exclude: @@ -1143,9 +1135,7 @@ Lint/Void: - 'spec/features/admin/enterprises_spec.rb' - 'spec/features/admin/order_cycles_spec.rb' - 'spec/features/admin/payment_method_spec.rb' - - 'spec/features/admin/product_import_spec.rb' - 'spec/features/admin/products_spec.rb' - - 'spec/features/admin/reports_spec.rb' - 'spec/features/admin/shipping_methods_spec.rb' - 'spec/features/admin/variant_overrides_spec.rb' - 'spec/features/admin/variants_spec.rb' @@ -1181,15 +1171,14 @@ Lint/Void: - 'spec/serializers/enterprise_serializer_spec.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 945 +# Offense count: 998 # Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: - Max: 773 + Max: 776 -# Offense count: 8 +# Offense count: 7 Naming/AccessorMethodName: Exclude: - - 'app/models/product_importer.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/order_decorator.rb' - 'spec/support/request/shop_workflow.rb' @@ -1221,7 +1210,7 @@ Naming/MemoizedInstanceVariableName: - 'app/controllers/spree/admin/payments_controller_decorator.rb' - 'lib/open_food_network/address_finder.rb' -# Offense count: 25 +# Offense count: 22 # Configuration parameters: NamePrefix, NamePrefixBlacklist, NameWhitelist, MethodDefinitionMacros. # NamePrefix: is_, has_, have_ # NamePrefixBlacklist: is_, has_, have_ @@ -1234,8 +1223,6 @@ Naming/PredicateName: - 'app/models/enterprise.rb' - 'app/models/enterprise_relationship.rb' - 'app/models/order_cycle.rb' - - 'app/models/product_importer.rb' - - 'app/models/spreadsheet_entry.rb' - 'app/models/spree/ability_decorator.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/line_item_decorator.rb' @@ -1263,10 +1250,11 @@ Naming/UncommunicativeMethodParamName: - 'app/services/subscription_validator.rb' - 'lib/open_food_network/property_merge.rb' - 'lib/open_food_network/reports/bulk_coop_report.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'spec/lib/open_food_network/reports/report_spec.rb' - 'spec/mailers/producer_mailer_spec.rb' -# Offense count: 4 +# Offense count: 3 # Configuration parameters: EnforcedStyle. # SupportedStyles: snake_case, camelCase Naming/VariableName: @@ -1331,24 +1319,26 @@ Performance/StringReplacement: - 'app/helpers/spree/admin/navigation_helper_decorator.rb' - 'app/models/spree/preferences/file_configuration.rb' -# Offense count: 4 +# Offense count: 5 # Cop supports --auto-correct. Performance/UnneededSort: Exclude: + - 'app/models/spree/product_decorator.rb' - 'spec/features/admin/order_cycles_spec.rb' -# Offense count: 203 +# Offense count: 206 # Cop supports --auto-correct. Rails/ActiveRecordAliases: Exclude: - 'app/controllers/admin/bulk_line_items_controller.rb' - 'app/controllers/admin/enterprises_controller.rb' - - 'app/controllers/admin/order_cycles_controller.rb' - 'app/controllers/admin/subscriptions_controller.rb' + - 'app/controllers/api/customers_controller.rb' - 'app/controllers/api/enterprises_controller.rb' - 'app/controllers/api/product_images_controller.rb' - 'app/controllers/checkout_controller.rb' - 'app/controllers/spree/admin/line_items_controller_decorator.rb' + - 'app/controllers/spree/credit_cards_controller.rb' - 'app/controllers/spree/orders_controller_decorator.rb' - 'app/helpers/i18n_helper.rb' - 'app/jobs/subscription_placement_job.rb' @@ -1366,7 +1356,6 @@ Rails/ActiveRecordAliases: - 'lib/open_food_network/order_cycle_form_applicator.rb' - 'lib/open_food_network/subscription_payment_updater.rb' - 'lib/stripe/profile_storer.rb' - - 'spec/controllers/admin/customers_controller_spec.rb' - 'spec/controllers/admin/proxy_orders_controller_spec.rb' - 'spec/controllers/admin/subscriptions_controller_spec.rb' - 'spec/controllers/line_items_controller_spec.rb' @@ -1388,6 +1377,7 @@ Rails/ActiveRecordAliases: - 'spec/jobs/update_billable_periods_spec.rb' - 'spec/lib/open_food_network/products_cache_refreshment_spec.rb' - 'spec/lib/open_food_network/products_cache_spec.rb' + - 'spec/lib/open_food_network/proxy_order_syncer_spec.rb' - 'spec/models/customer_spec.rb' - 'spec/models/enterprise_caching_spec.rb' - 'spec/models/exchange_spec.rb' @@ -1395,6 +1385,7 @@ Rails/ActiveRecordAliases: - 'spec/models/producer_property_spec.rb' - 'spec/models/proxy_order_spec.rb' - 'spec/models/spree/adjustment_spec.rb' + - 'spec/models/spree/credit_card_spec.rb' - 'spec/models/spree/line_item_spec.rb' - 'spec/models/spree/order_spec.rb' - 'spec/models/spree/product_spec.rb' @@ -1490,7 +1481,7 @@ Rails/HasManyOrHasOneDependent: - 'app/models/spree/variant_decorator.rb' - 'app/models/subscription.rb' -# Offense count: 43 +# Offense count: 45 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: numeric, symbolic @@ -1505,6 +1496,7 @@ Rails/HttpStatus: - 'app/controllers/admin/manager_invitations_controller.rb' - 'app/controllers/admin/tag_rules_controller.rb' - 'app/controllers/admin/variant_overrides_controller.rb' + - 'app/controllers/api/customers_controller.rb' - 'app/controllers/api/enterprises_controller.rb' - 'app/controllers/application_controller.rb' - 'app/controllers/checkout_controller.rb' @@ -1519,7 +1511,7 @@ Rails/HttpStatus: - 'app/controllers/stripe/callbacks_controller.rb' - 'app/controllers/stripe/webhooks_controller.rb' -# Offense count: 11 +# Offense count: 6 Rails/OutputSafety: Exclude: - 'app/controllers/spree/admin/reports_controller_decorator.rb' @@ -1544,7 +1536,7 @@ Rails/Presence: Exclude: - 'app/serializers/api/admin/customer_serializer.rb' -# Offense count: 5 +# Offense count: 4 # Cop supports --auto-correct. # Configuration parameters: NotNilAndNotEmpty, NotBlank, UnlessBlank. Rails/Present: @@ -1561,7 +1553,7 @@ Rails/ReadWriteAttribute: Exclude: - 'app/models/enterprise.rb' -# Offense count: 45 +# Offense count: 47 # Configuration parameters: Include. # Include: app/models/**/*.rb Rails/ScopeArgs: @@ -1580,12 +1572,11 @@ Rails/ScopeArgs: - 'app/models/spree/shipping_method_decorator.rb' - 'app/models/spree/variant_decorator.rb' -# Offense count: 18 +# Offense count: 17 # Configuration parameters: EnforcedStyle. # SupportedStyles: strict, flexible Rails/TimeZone: Exclude: - - 'app/controllers/admin/product_import_controller.rb' - 'app/controllers/api/statuses_controller.rb' - 'app/jobs/heartbeat_job.rb' - 'app/models/enterprise_relationship.rb' @@ -1622,7 +1613,7 @@ Rails/Validation: - 'app/models/spree/variant_decorator.rb' - 'app/models/variant_override.rb' -# Offense count: 35 +# Offense count: 20 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: always, conditionals @@ -1635,8 +1626,6 @@ Style/AndOr: - 'app/controllers/spree/orders_controller_decorator.rb' - 'app/helpers/discourse_helper.rb' - 'app/helpers/spree/admin/navigation_helper_decorator.rb' - - 'app/models/product_importer.rb' - - 'app/models/spreadsheet_entry.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/order_decorator.rb' - 'app/models/spree/product_set.rb' @@ -1682,6 +1671,7 @@ Style/BracesAroundHashParameters: - 'lib/open_food_network/order_cycle_form_applicator.rb' - 'lib/open_food_network/reports/rule.rb' - 'lib/open_food_network/variant_and_line_item_naming.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb' - 'spec/controllers/admin/business_model_configuration_controller_spec.rb' - 'spec/controllers/admin/enterprises_controller_spec.rb' @@ -1732,7 +1722,7 @@ Style/CaseEquality: - 'app/helpers/angular_form_helper.rb' - 'spec/models/spree/payment_spec.rb' -# Offense count: 87 +# Offense count: 86 # Cop supports --auto-correct. # Configuration parameters: AutoCorrect, EnforcedStyle. # SupportedStyles: nested, compact @@ -1743,7 +1733,6 @@ Style/ClassAndModuleChildren: - 'app/controllers/admin/business_model_configuration_controller.rb' - 'app/controllers/admin/cache_settings_controller.rb' - 'app/controllers/admin/invoice_settings_controller.rb' - - 'app/controllers/admin/product_import_controller.rb' - 'app/controllers/spree/store_controller_decorator.rb' - 'app/helpers/angular_form_helper.rb' - 'app/models/calculator/flat_percent_per_item.rb' @@ -1833,16 +1822,20 @@ Style/ClassVars: Exclude: - 'lib/open_food_network/rack_request_blocker.rb' -# Offense count: 4 +# Offense count: 3 # Cop supports --auto-correct. Style/ColonMethodCall: Exclude: - 'app/controllers/admin/enterprises_controller.rb' - 'app/controllers/application_controller.rb' - - 'app/controllers/spree/admin/products_controller_decorator.rb' - 'lib/discourse/single_sign_on.rb' -# Offense count: 12 +# Offense count: 1 +Style/CommentedKeyword: + Exclude: + - 'app/controllers/application_controller.rb' + +# Offense count: 10 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions. # SupportedStyles: assign_to_condition, assign_inside_condition @@ -1872,14 +1865,6 @@ Style/EachWithObject: - 'lib/open_food_network/enterprise_fee_calculator.rb' - 'lib/open_food_network/products_renderer.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: EnforcedStyle. -# SupportedStyles: empty, nil, both -Style/EmptyElse: - Exclude: - - 'app/models/spreadsheet_entry.rb' - # Offense count: 2 # Cop supports --auto-correct. Style/EmptyLiteral: @@ -1916,7 +1901,7 @@ Style/FormatStringToken: - 'lib/open_food_network/sales_tax_report.rb' - 'spec/models/enterprise_spec.rb' -# Offense count: 88 +# Offense count: 83 # Configuration parameters: MinBodyLength. Style/GuardClause: Exclude: @@ -1945,7 +1930,6 @@ Style/GuardClause: - 'app/models/enterprise.rb' - 'app/models/enterprise_group.rb' - 'app/models/producer_property.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/classification_decorator.rb' - 'app/models/spree/order_decorator.rb' - 'app/models/spree/order_populator_decorator.rb' @@ -1967,7 +1951,7 @@ Style/GuardClause: - 'spec/support/request/distribution_helper.rb' - 'spec/support/request/shop_workflow.rb' -# Offense count: 1040 +# Offense count: 970 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys @@ -2014,7 +1998,6 @@ Style/HashSyntax: - 'app/models/open_food_network/calculator/weight.rb' - 'app/models/order_cycle.rb' - 'app/models/product_distribution.rb' - - 'app/models/product_importer.rb' - 'app/models/spree/address_decorator.rb' - 'app/models/spree/adjustment_decorator.rb' - 'app/models/spree/classification_decorator.rb' @@ -2097,6 +2080,7 @@ Style/HashSyntax: - 'spec/features/admin/subscriptions_spec.rb' - 'spec/features/admin/variant_overrides_spec.rb' - 'spec/features/consumer/account/cards_spec.rb' + - 'spec/features/consumer/shopping/embedded_groups_spec.rb' - 'spec/features/consumer/shopping/products_spec.rb' - 'spec/features/consumer/shopping/shopping_spec.rb' - 'spec/jobs/subscription_placement_job_spec.rb' @@ -2127,7 +2111,7 @@ Style/HashSyntax: - 'spec/support/request/web_helper.rb' - 'spec/support/seeds.rb' -# Offense count: 4 +# Offense count: 3 Style/IfInsideElse: Exclude: - 'app/controllers/admin/column_preferences_controller.rb' @@ -2155,20 +2139,19 @@ Style/LineEndConcatenation: - 'lib/spree/core/controller_helpers/respond_with_decorator.rb' - 'spec/controllers/spree/admin/base_controller_spec.rb' -# Offense count: 11 +# Offense count: 9 # Cop supports --auto-correct. # Configuration parameters: IgnoredMethods. Style/MethodCallWithoutArgsParentheses: Exclude: - 'app/controllers/spree/admin/payment_methods_controller_decorator.rb' - - 'app/models/product_importer.rb' - 'app/views/json/_groups.rabl' - 'spec/controllers/spree/orders_controller_spec.rb' - 'spec/features/consumer/registration_spec.rb' - 'spec/models/spree/payment_method_spec.rb' - 'spec/support/request/ui_component_helper.rb' -# Offense count: 14 +# Offense count: 13 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline @@ -2181,7 +2164,6 @@ Style/MethodDefParentheses: - 'lib/open_food_network/distribution_change_validator.rb' - 'lib/open_food_network/feature_toggle.rb' - 'lib/open_food_network/group_buy_report.rb' - - 'lib/open_food_network/order_and_distributor_report.rb' - 'spec/support/request/authentication_workflow.rb' - 'spec/support/request/ui_component_helper.rb' - 'spec/support/request/web_helper.rb' @@ -2235,23 +2217,21 @@ Style/NestedTernaryOperator: - 'app/views/spree/api/products/bulk_show.v1.rabl' - 'app/views/spree/api/variants/bulk_show.v1.rabl' -# Offense count: 3 +# Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, MinBodyLength. # SupportedStyles: skip_modifier_ifs, always Style/Next: Exclude: - - 'app/models/product_importer.rb' - 'lib/tasks/data.rake' -# Offense count: 9 +# Offense count: 7 # Cop supports --auto-correct. Style/NilComparison: Exclude: - 'lib/discourse/single_sign_on.rb' - 'lib/open_food_network/order_grouper.rb' - 'spec/features/admin/enterprise_fees_spec.rb' - - 'spec/features/admin/product_import_spec.rb' - 'spec/features/consumer/shopping/shopping_spec.rb' - 'spec/models/order_cycle_spec.rb' - 'spec/models/spree/order_spec.rb' @@ -2270,7 +2250,7 @@ Style/NumericLiteralPrefix: Exclude: - 'spec/features/admin/order_cycles_spec.rb' -# Offense count: 12 +# Offense count: 13 # Cop supports --auto-correct. # Configuration parameters: Strict. Style/NumericLiterals: @@ -2291,6 +2271,7 @@ Style/NumericPredicate: - 'app/models/spree/order_decorator.rb' - 'lib/open_food_network/integrity_checker.rb' - 'lib/open_food_network/rack_request_blocker.rb' + - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/money_decorator.rb' # Offense count: 2 @@ -2306,14 +2287,13 @@ Style/ParenthesesAroundCondition: Exclude: - 'app/controllers/checkout_controller.rb' -# Offense count: 4 +# Offense count: 2 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: short, verbose Style/PreferredHashMethods: Exclude: - 'app/controllers/spree/orders_controller_decorator.rb' - - 'app/models/product_importer.rb' - 'spec/controllers/spree/admin/orders_controller_spec.rb' # Offense count: 18 @@ -2359,14 +2339,13 @@ Style/RedundantParentheses: - 'spec/controllers/admin/enterprises_controller_spec.rb' - 'spec/features/admin/bulk_product_update_spec.rb' -# Offense count: 13 +# Offense count: 10 # Cop supports --auto-correct. # Configuration parameters: AllowMultipleReturnValues. Style/RedundantReturn: Exclude: - 'app/controllers/admin/enterprise_fees_controller.rb' - 'app/controllers/admin/enterprises_controller.rb' - - 'app/controllers/admin/product_import_controller.rb' - 'app/controllers/spree/credit_cards_controller.rb' - 'app/models/enterprise_fee.rb' - 'app/models/spree/adjustment_decorator.rb' @@ -2374,7 +2353,7 @@ Style/RedundantReturn: - 'app/models/spree/order_populator_decorator.rb' - 'app/serializers/api/admin/enterprise_serializer.rb' -# Offense count: 114 +# Offense count: 98 # Cop supports --auto-correct. Style/RedundantSelf: Exclude: @@ -2385,8 +2364,6 @@ Style/RedundantSelf: - 'app/models/open_food_network/calculator/weight.rb' - 'app/models/order_cycle.rb' - 'app/models/producer_property.rb' - - 'app/models/product_importer.rb' - - 'app/models/spreadsheet_entry.rb' - 'app/models/spree/address_decorator.rb' - 'app/models/spree/calculator/flat_percent_item_total_decorator.rb' - 'app/models/spree/calculator/flexi_rate_decorator.rb' @@ -2409,7 +2386,7 @@ Style/RedundantSelf: - 'lib/open_food_network/reports/report.rb' - 'lib/open_food_network/variant_and_line_item_naming.rb' -# Offense count: 13 +# Offense count: 12 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, AllowInnerSlashes. # SupportedStyles: slashes, percent_r, mixed @@ -2424,7 +2401,7 @@ Style/RegexpLiteral: - 'lib/discourse/single_sign_on.rb' - 'spec/models/content_configuration_spec.rb' -# Offense count: 6 +# Offense count: 4 # Cop supports --auto-correct. Style/RescueModifier: Exclude: @@ -2508,15 +2485,7 @@ Style/TrailingUnderscoreVariable: Exclude: - 'lib/open_food_network/option_value_namer.rb' -# Offense count: 1 -# Cop supports --auto-correct. -# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. -# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym -Style/TrivialAccessors: - Exclude: - - 'app/models/product_importer.rb' - -# Offense count: 6 +# Offense count: 3 # Cop supports --auto-correct. Style/UnlessElse: Exclude: @@ -2569,7 +2538,7 @@ Style/UnneededPercentQ: - 'spec/features/consumer/producers_spec.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 6392 +# Offense count: 6631 # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Metrics/LineLength: From 745390dcd55133b2c1b19d0176fea6daf9c6e76e Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Sun, 8 Jul 2018 16:40:43 +0800 Subject: [PATCH 107/125] Wrap rows in customer index with TBODY tag --- app/views/admin/customers/index.html.haml | 43 ++++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 9a269b5a99..8e42bf830a 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -72,27 +72,28 @@ %th.actions Ask?  %input{ :type => 'checkbox', 'ng-model' => "confirmDelete" } - %tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy:predicate:reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" } - -# %td.bulk - -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } - %td.email{ 'ng-show' => 'columns.email.visible'} - %span{ 'ng-bind' => '::customer.email' } - %span.guest-label{ 'ng-show' => 'customer.user_id == null' }= t('.guest_label') - %td.name{ 'ng-show' => 'columns.name.visible'} - %input{ type: 'text', name: 'name', ng: { model: 'customer.name' }, 'obj-for-update' => 'customer', 'attr-for-update' => 'name'} - %td.code{ 'ng-show' => 'columns.code.visible' } - %input{ type: 'text', name: 'code', ng: {model: 'customer.code', change: 'checkForDuplicateCodes()'}, "obj-for-update" => "customer", "attr-for-update" => "code" } - %i.icon-warning-sign{ ng: {if: 'duplicate'} } - = t('.duplicate_code') - %td.tags{ 'ng-show' => 'columns.tags.visible' } - .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} - %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } - %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } - %a{ id: 'bill-address-link', href: 'javascript:void(0)', "ng-bind" => "customer.bill_address ? customer.bill_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } - %td.ship_address{ 'ng-show' => 'columns.ship_address.visible' } - %a{ id: 'ship-address-link', href: 'javascript:void(0)', "ng-bind" => "customer.ship_address ? customer.ship_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } - %td.actions - %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } + %tbody + %tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy:predicate:reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" } + -# %td.bulk + -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } + %td.email{ 'ng-show' => 'columns.email.visible'} + %span{ 'ng-bind' => '::customer.email' } + %span.guest-label{ 'ng-show' => 'customer.user_id == null' }= t('.guest_label') + %td.name{ 'ng-show' => 'columns.name.visible'} + %input{ type: 'text', name: 'name', ng: { model: 'customer.name' }, 'obj-for-update' => 'customer', 'attr-for-update' => 'name'} + %td.code{ 'ng-show' => 'columns.code.visible' } + %input{ type: 'text', name: 'code', ng: {model: 'customer.code', change: 'checkForDuplicateCodes()'}, "obj-for-update" => "customer", "attr-for-update" => "code" } + %i.icon-warning-sign{ ng: {if: 'duplicate'} } + = t('.duplicate_code') + %td.tags{ 'ng-show' => 'columns.tags.visible' } + .tag_watcher{ 'obj-for-update' => "customer", "attr-for-update" => "tag_list"} + %tags_with_translation{ object: 'customer', 'find-tags' => 'findTags(query)' } + %td.bill_address{ 'ng-show' => 'columns.bill_address.visible' } + %a{ id: 'bill-address-link', href: 'javascript:void(0)', "ng-bind" => "customer.bill_address ? customer.bill_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } + %td.ship_address{ 'ng-show' => 'columns.ship_address.visible' } + %a{ id: 'ship-address-link', href: 'javascript:void(0)', "ng-bind" => "customer.ship_address ? customer.ship_address.address1 : '#{t('admin.customers.index.edit')}' | limitTo: 15", 'edit-address-dialog' => true } + %td.actions + %a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" } -# %show-more.text-center{ data: "filteredCustomers", limit: "customerLimit", increment: "20" } %div.text-center{ ng: { show: "filteredCustomers.length > customerLimit" } } From 9f09861d8b72f00af3baecf0e94fa55bb9fbfb6d Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Sun, 8 Jul 2018 17:32:16 +0800 Subject: [PATCH 108/125] Change sorting to be done in ascending order first Currently, we always toggle "reverse" when triggering a sort. If "reverse" is initially set to false, triggering a sort for the first time then toggles this to true. The effect is that, the first time that sorting is done, the rows are sorted in reverse order. This is not intuitive - they should be sorted in ascending order first. --- .../admin/index_utils/controllers/columns_controller.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee b/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee index 39556983b3..b51b26d633 100644 --- a/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee +++ b/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee @@ -1,4 +1,4 @@ angular.module("admin.indexUtils").controller "ColumnsCtrl", ($scope, Columns) -> $scope.columns = Columns.columns $scope.predicate = "" - $scope.reverse = false + $scope.reverse = true From 822b2c929af05db5e6c815f92870d805be9c0034 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 5 Jul 2018 18:15:33 +0800 Subject: [PATCH 109/125] Fix frontend sorting in "Customers" index The scope for customersCtrl did not have access to the sorting preferences stored in the nested ColumnsCtrl scope. To address this, the page has been changed to use a new set of sorting preferences declared in the customersCtrl scope itself. Also, these sorting preferences are now stored in an object. This enables the parent scope to see changes to the sorting preferences which are done via the nested ColumnsCtrl scope, The "Bulk Order Management" page is also affected by the same scoping issue. Once this page is fixed, we can remove remnants of the sorting preferences initialized in ColumnsCtrl. --- .../controllers/customers_controller.js.coffee | 3 +++ app/views/admin/customers/index.html.haml | 8 ++++---- spec/features/admin/customers_spec.rb | 15 +++++++++++++++ 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee index d4ba6383d8..ada3eb2b0e 100644 --- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee +++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee @@ -6,6 +6,9 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt $scope.customerLimit = 20 $scope.customers = Customers.all $scope.columns = Columns.columns + $scope.sorting = + predicate: "" + reverse: true $scope.confirmRefresh = (event) -> event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning")) diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 8e42bf830a..035e0c1570 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -61,11 +61,11 @@ -# %th.bulk -# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.email'; reverse = !reverse" }=t('admin.email') + %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.email'; sorting.reverse = !sorting.reverse" }=t('admin.email') %th.name{ 'ng-show' => 'columns.name.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.name'; reverse = !reverse" }=t('admin.name') + %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.name'; sorting.reverse = !sorting.reverse" }=t('admin.name') %th.code{ 'ng-show' => 'columns.code.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'customer.code'; reverse = !reverse" }=t('admin.customers.index.code') + %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.code'; sorting.reverse = !sorting.reverse" }=t('admin.customers.index.code') %th.tags{ 'ng-show' => 'columns.tags.visible' }=t('admin.tags') %th.bill_address{ 'ng-show' => 'columns.bill_address.visible' }=t('admin.customers.index.bill_address') %th.ship_address{ 'ng-show' => 'columns.ship_address.visible' }=t('admin.customers.index.ship_address') @@ -73,7 +73,7 @@ Ask?  %input{ :type => 'checkbox', 'ng-model' => "confirmDelete" } %tbody - %tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy:predicate:reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" } + %tr.customer{ 'ng-repeat' => "customer in filteredCustomers = ( customers | filter:quickSearch | orderBy: sorting.predicate:sorting.reverse ) | limitTo:customerLimit track by customer.id", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "c_{{customer.id}}" } -# %td.bulk -# %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'customer.checked' } %td.email{ 'ng-show' => 'columns.email.visible'} diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index cfbbd9e0e5..14c85d3504 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -48,6 +48,21 @@ feature 'Customers' do expect(page).to have_selector "tr#c_#{customer2.id}" fill_in "quick_search", with: "" + # Sorting when the header of a sortable column is clicked + customer_emails = [customer1.email, customer2.email].sort + within "#customers thead" do + click_on "Email" + end + expect(page).to have_selector("#customers .customer:nth-child(1) .email", text: customer_emails[0]) + expect(page).to have_selector("#customers .customer:nth-child(2) .email", text: customer_emails[1]) + + # Then sorting in reverse when the header is clicked again + within "#customers thead" do + click_on "Email" + end + expect(page).to have_selector("#customers .customer:nth-child(1) .email", text: customer_emails[1]) + expect(page).to have_selector("#customers .customer:nth-child(2) .email", text: customer_emails[0]) + # Toggling columns expect(page).to have_selector "th.email" expect(page).to have_content customer1.email From 2bba72c5a95193200684bdad351c04590e039703 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 6 Jul 2018 17:26:02 +0800 Subject: [PATCH 110/125] Fix frontend sorting in "Bulk Order Management" --- .../line_items_controller.js.coffee | 3 ++ .../admin/orders/bulk_management.html.haml | 20 +++++------ .../admin/bulk_order_management_spec.rb | 34 +++++++++++++++++++ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee index 29b0d4c4db..4ddee58c48 100644 --- a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee +++ b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee @@ -10,6 +10,9 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $scope.selectedUnitsVariant = {} $scope.sharedResource = false $scope.columns = Columns.columns + $scope.sorting = + predicate: "" + reverse: true $scope.confirmRefresh = -> LineItems.allSaved() || confirm(t("unsaved_changes_warning")) diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml index 9efb7b4e28..b3474b99c3 100644 --- a/app/views/spree/admin/orders/bulk_management.html.haml +++ b/app/views/spree/admin/orders/bulk_management.html.haml @@ -118,31 +118,31 @@ %th.bulk %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.order_no{ 'ng-show' => 'columns.order_no.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.number'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.number'; sorting.reverse = !sorting.reverse" } = t("admin.orders.bulk_management.order_no") %th.full_name{ 'ng-show' => 'columns.full_name.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.full_name'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.full_name'; sorting.reverse = !sorting.reverse" } = t("admin.name") %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.email'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.email'; sorting.reverse = !sorting.reverse" } = t("admin.email") %th.phone{ 'ng-show' => 'columns.phone.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.phone'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.phone'; sorting.reverse = !sorting.reverse" } = t("admin.phone") %th.date{ 'ng-show' => 'columns.order_date.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.completed_at'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.completed_at'; sorting.reverse = !sorting.reverse" } = t("admin.orders.bulk_management.order_date") %th.producer{ 'ng-show' => 'columns.producer.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'supplier.name'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'supplier.name'; sorting.reverse = !sorting.reverse" } = t("admin.producer") %th.order_cycle{ 'ng-show' => 'columns.order_cycle.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.order_cycle.name'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.order_cycle.name'; sorting.reverse = !sorting.reverse" } = t("admin.order_cycle") %th.hub{ 'ng-show' => 'columns.hub.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'order.distributor.name'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.distributor.name'; sorting.reverse = !sorting.reverse" } = t("admin.shop") %th.variant{ 'ng-show' => 'columns.variant.visible' } - %a{ :href => '', 'ng-click' => "predicate = 'units_variant.full_name'; reverse = !reverse" } + %a{ :href => '', 'ng-click' => "sorting.predicate = 'units_variant.full_name'; sorting.reverse = !sorting.reverse" } = t("admin.orders.bulk_management.product_unit") %th.quantity{ 'ng-show' => 'columns.quantity.visible' } = t("admin.quantity") @@ -157,7 +157,7 @@ = t("admin.orders.bulk_management.ask") %input{ :type => 'checkbox', 'ng-model' => "confirmDelete" } - %tr.line_item{ 'ng-repeat' => "line_item in filteredLineItems = ( lineItems | filter:quickSearch | selectFilter:supplierFilter:distributorFilter:orderCycleFilter | variantFilter:selectedUnitsProduct:selectedUnitsVariant:sharedResource | orderBy:predicate:reverse )", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "li_{{line_item.id}}" } + %tr.line_item{ 'ng-repeat' => "line_item in filteredLineItems = ( lineItems | filter:quickSearch | selectFilter:supplierFilter:distributorFilter:orderCycleFilter | variantFilter:selectedUnitsProduct:selectedUnitsVariant:sharedResource | orderBy:sorting.predicate:sorting.reverse )", 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'", :id => "li_{{line_item.id}}" } %td.bulk %input{ :type => "checkbox", :name => 'bulk', 'ng-model' => 'line_item.checked', 'ignore-dirty' => true } %td.order_no{ 'ng-show' => 'columns.order_no.visible' } {{ line_item.order.number }} diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb index 81b2845e04..f028776121 100644 --- a/spec/features/admin/bulk_order_management_spec.rb +++ b/spec/features/admin/bulk_order_management_spec.rb @@ -82,6 +82,40 @@ feature %q{ expect(page).to have_selector "td.max", text: li2.max_quantity.to_s, :visible => true end end + + describe "sorting of line items" do + let!(:o1) { create(:order_with_distributor, state: 'complete', completed_at: Time.zone.now) } + let!(:o2) { create(:order_with_distributor, state: 'complete', completed_at: Time.zone.now) } + let!(:li1) { create(:line_item, order: o1) } + let!(:li2) { create(:line_item, order: o2) } + + before do + visit spree.admin_bulk_order_management_path + end + + it "sorts by customer name when the customer name header is clicked" do + customer_names = [o1.name, o2.name].sort + + within "#listing_orders thead" do + click_on "Name" + end + + expect(page).to have_selector("#listing_orders .line_item:nth-child(1) .full_name", text: customer_names[0]) + expect(page).to have_selector("#listing_orders .line_item:nth-child(2) .full_name", text: customer_names[1]) + end + + it "sorts by customer name in reverse when the customer name header is clicked twice" do + customer_names = [o1.name, o2.name].sort.reverse + + within "#listing_orders thead" do + click_on "Name" + click_on "Name" + end + + expect(page).to have_selector("#listing_orders .line_item:nth-child(1) .full_name", text: customer_names[1]) + expect(page).to have_selector("#listing_orders .line_item:nth-child(2) .full_name", text: customer_names[0]) + end + end end context "altering line item properties" do From 8b6b694244bb31ab53ecbbe2f4b8c4c0f9561f23 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 6 Jul 2018 17:26:54 +0800 Subject: [PATCH 111/125] Remove unused sorting preferences in ColumnsCtrl --- .../admin/index_utils/controllers/columns_controller.js.coffee | 2 -- .../index_utils/controllers/columns_controller_spec.js.coffee | 2 -- 2 files changed, 4 deletions(-) diff --git a/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee b/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee index b51b26d633..9ee04a4f19 100644 --- a/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee +++ b/app/assets/javascripts/admin/index_utils/controllers/columns_controller.js.coffee @@ -1,4 +1,2 @@ angular.module("admin.indexUtils").controller "ColumnsCtrl", ($scope, Columns) -> $scope.columns = Columns.columns - $scope.predicate = "" - $scope.reverse = true diff --git a/spec/javascripts/unit/admin/index_utils/controllers/columns_controller_spec.js.coffee b/spec/javascripts/unit/admin/index_utils/controllers/columns_controller_spec.js.coffee index 5fd79e71bf..5e01fdcc35 100644 --- a/spec/javascripts/unit/admin/index_utils/controllers/columns_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/index_utils/controllers/columns_controller_spec.js.coffee @@ -13,5 +13,3 @@ describe "ColumnsCtrl", -> it "initialises data", -> expect(scope.columns).toEqual Columns.columns - expect(scope.predicate).toEqual "" - expect(scope.reverse).toEqual false From 55d0b1dfc539bc4a66b7ad0ebc321f7b08d0cddc Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 19 Jul 2018 03:36:57 +0800 Subject: [PATCH 112/125] Generalize sorting through SortOptions service --- .../controllers/customers_controller.js.coffee | 6 ++---- .../index_utils/services/sort_options.js.coffee | 4 ++++ .../controllers/line_items_controller.js.coffee | 6 ++---- .../services/sort_options_spec.js.coffee | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee create mode 100644 spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee diff --git a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee index ada3eb2b0e..c8967780dc 100644 --- a/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee +++ b/app/assets/javascripts/admin/customers/controllers/customers_controller.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, pendingChanges, shops, availableCountries) -> +angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filter, Customers, TagRuleResource, CurrentShop, RequestMonitor, Columns, SortOptions, pendingChanges, shops, availableCountries) -> $scope.shops = shops $scope.availableCountries = availableCountries $scope.RequestMonitor = RequestMonitor @@ -6,9 +6,7 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt $scope.customerLimit = 20 $scope.customers = Customers.all $scope.columns = Columns.columns - $scope.sorting = - predicate: "" - reverse: true + $scope.sorting = SortOptions $scope.confirmRefresh = (event) -> event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning")) diff --git a/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee new file mode 100644 index 0000000000..5c3f38fef4 --- /dev/null +++ b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee @@ -0,0 +1,4 @@ +angular.module("admin.indexUtils").factory 'SortOptions', -> + new class SortOptions + predicate: "" + reverse: true diff --git a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee index 4ddee58c48..ecc567c7cc 100644 --- a/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee +++ b/app/assets/javascripts/admin/line_items/controllers/line_items_controller.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) -> +angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $http, $q, StatusMessage, Columns, SortOptions, Dereferencer, Orders, LineItems, Enterprises, OrderCycles, VariantUnitManager, RequestMonitor) -> $scope.initialized = false $scope.RequestMonitor = RequestMonitor $scope.filteredLineItems = [] @@ -10,9 +10,7 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout, $scope.selectedUnitsVariant = {} $scope.sharedResource = false $scope.columns = Columns.columns - $scope.sorting = - predicate: "" - reverse: true + $scope.sorting = SortOptions $scope.confirmRefresh = -> LineItems.allSaved() || confirm(t("unsaved_changes_warning")) diff --git a/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee b/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee new file mode 100644 index 0000000000..90fd34cf02 --- /dev/null +++ b/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee @@ -0,0 +1,15 @@ +describe "SortOptions service", -> + SortOptions = null + + beforeEach -> + module 'admin.indexUtils' + inject (_SortOptions_) -> + SortOptions = _SortOptions_ + + describe "initialising predicate", -> + it "sets predicate to blank", -> + expect(SortOptions.predicate).toEqual "" + + describe "initialising reverse", -> + it "sets reverse to true", -> + expect(SortOptions.reverse).toBe true From 5179f7fd636867d442e667eb8bfc75dad416d73f Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 09:25:55 +0800 Subject: [PATCH 113/125] Move logic for toggling by column into SortOptions --- .../services/sort_options.js.coffee | 4 ++++ app/views/admin/customers/index.html.haml | 6 +++--- .../admin/orders/bulk_management.html.haml | 18 +++++++++--------- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee index 5c3f38fef4..770a09ac84 100644 --- a/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee +++ b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee @@ -2,3 +2,7 @@ angular.module("admin.indexUtils").factory 'SortOptions', -> new class SortOptions predicate: "" reverse: true + + toggle: (predicate) -> + @predicate = predicate + @reverse = !@reverse diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 035e0c1570..0a1fb012dc 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -61,11 +61,11 @@ -# %th.bulk -# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.email'; sorting.reverse = !sorting.reverse" }=t('admin.email') + %a{ :href => '', 'ng-click' => "sorting.toggle('customer.email')" }=t('admin.email') %th.name{ 'ng-show' => 'columns.name.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.name'; sorting.reverse = !sorting.reverse" }=t('admin.name') + %a{ :href => '', 'ng-click' => "sorting.toggle('customer.name')" }=t('admin.name') %th.code{ 'ng-show' => 'columns.code.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'customer.code'; sorting.reverse = !sorting.reverse" }=t('admin.customers.index.code') + %a{ :href => '', 'ng-click' => "sorting.toggle('customer.code')" }=t('admin.customers.index.code') %th.tags{ 'ng-show' => 'columns.tags.visible' }=t('admin.tags') %th.bill_address{ 'ng-show' => 'columns.bill_address.visible' }=t('admin.customers.index.bill_address') %th.ship_address{ 'ng-show' => 'columns.ship_address.visible' }=t('admin.customers.index.ship_address') diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml index b3474b99c3..50aa10634f 100644 --- a/app/views/spree/admin/orders/bulk_management.html.haml +++ b/app/views/spree/admin/orders/bulk_management.html.haml @@ -118,31 +118,31 @@ %th.bulk %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.order_no{ 'ng-show' => 'columns.order_no.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.number'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.number')" } = t("admin.orders.bulk_management.order_no") %th.full_name{ 'ng-show' => 'columns.full_name.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.full_name'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.full_name')" } = t("admin.name") %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.email'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.email')" } = t("admin.email") %th.phone{ 'ng-show' => 'columns.phone.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.phone'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.phone')" } = t("admin.phone") %th.date{ 'ng-show' => 'columns.order_date.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.completed_at'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.completed_at')" } = t("admin.orders.bulk_management.order_date") %th.producer{ 'ng-show' => 'columns.producer.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'supplier.name'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('supplier.name')" } = t("admin.producer") %th.order_cycle{ 'ng-show' => 'columns.order_cycle.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.order_cycle.name'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.order_cycle.name')" } = t("admin.order_cycle") %th.hub{ 'ng-show' => 'columns.hub.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'order.distributor.name'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('order.distributor.name')" } = t("admin.shop") %th.variant{ 'ng-show' => 'columns.variant.visible' } - %a{ :href => '', 'ng-click' => "sorting.predicate = 'units_variant.full_name'; sorting.reverse = !sorting.reverse" } + %a{ :href => '', 'ng-click' => "sorting.toggle('units_variant.full_name')" } = t("admin.orders.bulk_management.product_unit") %th.quantity{ 'ng-show' => 'columns.quantity.visible' } = t("admin.quantity") From 47608525c64a5b45db8c7041f0543a3ecd372e47 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 09:27:16 +0800 Subject: [PATCH 114/125] Reset reverse when clicking another column to sort --- .../services/sort_options.js.coffee | 2 +- .../services/sort_options_spec.js.coffee | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee index 770a09ac84..36f1bc4d4d 100644 --- a/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee +++ b/app/assets/javascripts/admin/index_utils/services/sort_options.js.coffee @@ -4,5 +4,5 @@ angular.module("admin.indexUtils").factory 'SortOptions', -> reverse: true toggle: (predicate) -> + @reverse = (@predicate == predicate) && !@reverse @predicate = predicate - @reverse = !@reverse diff --git a/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee b/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee index 90fd34cf02..6c4b068bc4 100644 --- a/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee +++ b/spec/javascripts/unit/admin/index_utils/services/sort_options_spec.js.coffee @@ -13,3 +13,32 @@ describe "SortOptions service", -> describe "initialising reverse", -> it "sets reverse to true", -> expect(SortOptions.reverse).toBe true + + describe "sorting by a column", -> + describe "when selecting Column A once", -> + it "sorts by Column A", -> + SortOptions.toggle("column.a") + expect(SortOptions.predicate).toEqual "column.a" + expect(SortOptions.reverse).toBe false + + describe "when selecting Column A twice", -> + it "sorts by Column A in reverse order", -> + SortOptions.toggle("column.a") + SortOptions.toggle("column.a") + expect(SortOptions.predicate).toEqual "column.a" + expect(SortOptions.reverse).toBe true + + describe "when selecting Column A once then selecting Column B once", -> + it "sorts by Column B", -> + SortOptions.toggle("column.a") + SortOptions.toggle("column.b") + expect(SortOptions.predicate).toEqual "column.b" + expect(SortOptions.reverse).toBe false + + describe "when selecting Column A twice then selecting Column B once", -> + it "sorts by Column B in reverse order", -> + SortOptions.toggle("column.a") + SortOptions.toggle("column.a") + SortOptions.toggle("column.b") + expect(SortOptions.predicate).toEqual "column.b" + expect(SortOptions.reverse).toBe false From 89ac558f3786c05a51529e1ca378ffa20bc7808d Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 11:45:07 +0800 Subject: [PATCH 115/125] Fix wrong sort predicates in customer index --- app/views/admin/customers/index.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/admin/customers/index.html.haml b/app/views/admin/customers/index.html.haml index 0a1fb012dc..6477357d63 100644 --- a/app/views/admin/customers/index.html.haml +++ b/app/views/admin/customers/index.html.haml @@ -61,11 +61,11 @@ -# %th.bulk -# %input{ :type => "checkbox", :name => 'toggle_bulk', 'ng-click' => 'toggleAllCheckboxes()', 'ng-checked' => "allBoxesChecked()" } %th.email{ 'ng-show' => 'columns.email.visible' } - %a{ :href => '', 'ng-click' => "sorting.toggle('customer.email')" }=t('admin.email') + %a{ :href => '', 'ng-click' => "sorting.toggle('email')" }=t('admin.email') %th.name{ 'ng-show' => 'columns.name.visible' } - %a{ :href => '', 'ng-click' => "sorting.toggle('customer.name')" }=t('admin.name') + %a{ :href => '', 'ng-click' => "sorting.toggle('name')" }=t('admin.name') %th.code{ 'ng-show' => 'columns.code.visible' } - %a{ :href => '', 'ng-click' => "sorting.toggle('customer.code')" }=t('admin.customers.index.code') + %a{ :href => '', 'ng-click' => "sorting.toggle('code')" }=t('admin.customers.index.code') %th.tags{ 'ng-show' => 'columns.tags.visible' }=t('admin.tags') %th.bill_address{ 'ng-show' => 'columns.bill_address.visible' }=t('admin.customers.index.bill_address') %th.ship_address{ 'ng-show' => 'columns.ship_address.visible' }=t('admin.customers.index.ship_address') From bd200c885b6d59bd09360759385e75048c486dbf Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 13:15:26 +0100 Subject: [PATCH 116/125] Move options to first page --- .../controllers/import_options_form.js.coffee | 25 +++++------------ app/models/product_import/entry_processor.rb | 4 +-- app/models/product_import/entry_validator.rb | 2 +- .../product_import/_import_options.html.haml | 19 +++++-------- .../product_import/_upload_form.html.haml | 27 ++++++++++++++++--- config/locales/en.yml | 6 +++-- spec/models/product_importer_spec.rb | 4 +-- 7 files changed, 44 insertions(+), 43 deletions(-) diff --git a/app/assets/javascripts/admin/product_import/controllers/import_options_form.js.coffee b/app/assets/javascripts/admin/product_import/controllers/import_options_form.js.coffee index 965692c86d..79764ecc30 100644 --- a/app/assets/javascripts/admin/product_import/controllers/import_options_form.js.coffee +++ b/app/assets/javascripts/admin/product_import/controllers/import_options_form.js.coffee @@ -2,37 +2,24 @@ angular.module("admin.productImport").controller "ImportOptionsFormCtrl", ($scop $scope.initForm = () -> $scope.settings = {} if $scope.settings == undefined - $scope.settings[$scope.supplierId] = { - import_into: 'product_list' - defaults: - count_on_hand: - mode: 'overwrite_all' - on_hand: - mode: 'overwrite_all' - tax_category_id: - mode: 'overwrite_all' - shipping_category_id: - mode: 'overwrite_all' - available_on: - mode: 'overwrite_all' + $scope.settings = { + import_into: 'product_list', + reset_all_absent: false } $scope.import_into = 'product_list' - $scope.updateImportInto = () -> - $scope.import_into = $scope.settings[$scope.supplierId]['import_into'] - $scope.$watch 'settings', (updated) -> ProductImportService.updateSettings(updated) , true - $scope.toggleResetAbsent = (id) -> - checked = $scope.settings[id]['reset_all_absent'] + $scope.toggleResetAbsent = -> + checked = $scope.settings['reset_all_absent'] confirmed = confirm t('js.product_import.confirmation') if checked if confirmed or !checked ProductImportService.updateResetAbsent($scope.supplierId, $scope.reset_counts[$scope.supplierId], checked) else - $scope.settings[id]['reset_all_absent'] = false + $scope.settings['reset_all_absent'] = false $scope.resetTotal = ProductImportService.resetTotal diff --git a/app/models/product_import/entry_processor.rb b/app/models/product_import/entry_processor.rb index 509a21fd43..23d0b88ddf 100644 --- a/app/models/product_import/entry_processor.rb +++ b/app/models/product_import/entry_processor.rb @@ -109,7 +109,7 @@ module ProductImport end def import_into_inventory?(entry) - entry.supplier_id && @import_settings[:settings][entry.supplier_id.to_s]['import_into'] == 'inventories' + entry.supplier_id && @import_settings[:settings]['import_into'] == 'inventories' end def save_new_inventory_item(entry) @@ -228,7 +228,7 @@ module ProductImport end def import_into_inventory_by_supplier?(supplier_id) - @import_settings[:settings] && @import_settings[:settings][supplier_id.to_s] && @import_settings[:settings][supplier_id.to_s]['import_into'] == 'inventories' + @import_settings[:settings] && @import_settings[:settings][supplier_id.to_s] && @import_settings[:settings]['import_into'] == 'inventories' end end end diff --git a/app/models/product_import/entry_validator.rb b/app/models/product_import/entry_validator.rb index 8ffb2edf2c..d3632911ad 100644 --- a/app/models/product_import/entry_validator.rb +++ b/app/models/product_import/entry_validator.rb @@ -221,7 +221,7 @@ module ProductImport end def import_into_inventory?(entry) - entry.supplier_id && @import_settings[:settings][entry.supplier_id.to_s]['import_into'] == 'inventories' + entry.supplier_id && @import_settings[:settings]['import_into'] == 'inventories' end def validate_inventory_item(entry, variant_override) diff --git a/app/views/admin/product_import/_import_options.html.haml b/app/views/admin/product_import/_import_options.html.haml index 3c79357e46..c03f16237a 100644 --- a/app/views/admin/product_import/_import_options.html.haml +++ b/app/views/admin/product_import/_import_options.html.haml @@ -3,38 +3,31 @@ - @importer.suppliers_index.each do |name, supplier_id| - if name and supplier_id and @importer.permission_by_id?(supplier_id) - %div.panel-section.import-settings{ng: {controller: 'DropdownPanelsCtrl'}} + %div.panel-section.import-settings %div.panel-header{ng: {click: 'togglePanel()', class: '{active: active}'}} - %div.header-caret - %i{ng: {class: "{'icon-chevron-down': active, 'icon-chevron-right': !active}"}} - %div.header-icon.neutral - %i.fa.fa-edit + %div.header-icon.success + %i.fa.fa-check-circle %div.header-description = name - %div.panel-content{ng: {hide: '!active'}} - = render 'options_form', supplier_id: supplier_id, name: name - elsif name and supplier_id - %div.panel-section.import-settings{ng: {controller: 'DropdownPanelsCtrl'}} + %div.panel-section.import-settings %div.panel-header - %div.header-caret %div.header-icon.error %i.fa.fa-warning %div.header-description = name %span.header-error= " - #{t('admin.product_import.import.no_permission')}" - elsif name - %div.panel-section.import-settings{ng: {controller: 'DropdownPanelsCtrl'}} + %div.panel-section.import-settings %div.panel-header - %div.header-caret %div.header-icon.error %i.fa.fa-warning %div.header-description = name %span.header-error= " - #{t('admin.product_import.import.not_found')}" - else - %div.panel-section.import-settings{ng: {controller: 'DropdownPanelsCtrl'}} + %div.panel-section.import-settings %div.panel-header - %div.header-caret %div.header-icon.error %i.fa.fa-warning %div.header-description diff --git a/app/views/admin/product_import/_upload_form.html.haml b/app/views/admin/product_import/_upload_form.html.haml index 008f027139..00aa4a6cd4 100644 --- a/app/views/admin/product_import/_upload_form.html.haml +++ b/app/views/admin/product_import/_upload_form.html.haml @@ -1,11 +1,30 @@ -%div{ng: {app: 'admin.productImport'}} +%div{ng: {app: 'admin.productImport', controller: 'ImportOptionsFormCtrl', init: "initForm()"}} - %h5= t('admin.product_import.index.select_file') - %br = form_tag main_app.admin_product_import_path, multipart: true, class: 'product-import' do - %label #{t('admin.product_import.index.spreadsheet')} + + %h6= t('admin.product_import.index.choose_import_type') + %br + = select_tag "import_into", options_for_select({"#{t('admin.product_import.index.product_list')}" => :product_list, "#{t('admin.product_import.index.inventories')}" => :inventories}), {class: 'select2 select2-no-search', 'ng-model' => 'settings.import_into'} + %br + %br + %br + + %h6= t('admin.product_import.index.select_file') %br = file_field_tag :file %br %br + %br + + %h6= t('admin.product_import.import.reset_absent?') + %br + = hidden_field_tag "settings[reset_all_absent]", 0 + = check_box_tag "settings[reset_all_absent]", 1, false, 'ng-model' => 'settings.reset_all_absent' + %span= t('admin.product_import.import.reset_absent_tip') + %br + %br + %br + = submit_tag "#{t('admin.product_import.index.upload')}" + %br + %br diff --git a/config/locales/en.yml b/config/locales/en.yml index 870ff898d1..c3f51fd2f5 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -466,7 +466,8 @@ en: index: select_file: Select a spreadsheet to upload spreadsheet: Spreadsheet - import_into: "Import into:" + choose_import_type: Select import type + import_into: Import type product_list: Product list inventories: Inventories import: Import @@ -496,7 +497,8 @@ en: not_found: enterprise could not be found in database no_name: No name blank_supplier: some products have blank supplier name - reset_absent?: Reset absent products? + reset_absent?: Reset absent products + reset_absent_tip: Set stock to zero for all exiting products not present in the file overwrite_all: Overwrite all overwrite_empty: Overwrite if empty default_stock: Set stock level diff --git a/spec/models/product_importer_spec.rb b/spec/models/product_importer_spec.rb index 73c7423cc3..aeaf1c2eae 100644 --- a/spec/models/product_importer_spec.rb +++ b/spec/models/product_importer_spec.rb @@ -44,7 +44,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'product_list'}} + settings = {'import_into' => 'product_list'} @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) end after { File.delete('/tmp/test-m.csv') } @@ -131,7 +131,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'product_list'}} + settings = {'import_into' => 'product_list'} @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) end after { File.delete('/tmp/test-m.csv') } From 67767f86eb60e88e590b65096a06b1f6afd4d95c Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sun, 15 Jul 2018 16:26:40 +0100 Subject: [PATCH 117/125] Change import and reset logic to work with first page --- .../import_form_controller.js.coffee | 29 ++--- app/models/product_import/entry_processor.rb | 24 ++-- app/models/product_import/product_importer.rb | 2 +- .../product_import/_options_form.html.haml | 66 ---------- .../product_import/_upload_form.html.haml | 6 +- .../admin/product_import/import.html.haml | 3 + spec/features/admin/product_import_spec.rb | 109 ++++++----------- spec/models/product_importer_spec.rb | 115 ++---------------- 8 files changed, 83 insertions(+), 271 deletions(-) delete mode 100644 app/views/admin/product_import/_options_form.html.haml diff --git a/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee b/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee index b3d3e2d824..8f031cf4ab 100644 --- a/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee +++ b/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee @@ -3,6 +3,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.entries = {} $scope.update_counts = {} $scope.reset_counts = {} + $scope.importSettings = null $scope.updates = {} $scope.updated_total = 0 @@ -72,20 +73,21 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt 'end': end 'filepath': $scope.filepath 'settings': $scope.importSettings - ).success((data, status, headers, config) -> + ).success((data, status) -> angular.merge($scope.entries, angular.fromJson(data['entries'])) $scope.sortUpdates(data['reset_counts']) $scope.updateProgress() - ).error((data, status, headers, config) -> + ).error((data, status) -> $scope.exception = data console.error(data) ) - $scope.importSettings = null - $scope.getSettings = () -> - $scope.importSettings = ProductImportService.getSettings() + $scope.importSettings = { + reset_all_absent: document.getElementsByName('settings[reset_all_absent]')[0].value, + import_into: document.getElementsByName('settings[import_into]')[0].value + } $scope.sortUpdates = (data) -> angular.forEach data, (value, key) -> @@ -104,7 +106,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt 'end': end 'filepath': $scope.filepath 'settings': $scope.importSettings - ).success((data, status, headers, config) -> + ).success((data, status) -> $scope.sortResults(data['results']) angular.forEach data['updated_ids'], (id) -> @@ -114,7 +116,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.update_errors.push(error) $scope.updateProgress() - ).error((data, status, headers, config) -> + ).error((data, status) -> $scope.exception = data console.error(data) ) @@ -129,10 +131,11 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.updated_total += value $scope.resetAbsent = () -> + return unless $scope.importSettings['reset_all_absent'] enterprises_to_reset = [] - angular.forEach $scope.importSettings, (settings, enterprise) -> - if settings['reset_all_absent'] - enterprises_to_reset.push(enterprise) + + angular.forEach $scope.reset_counts, (count, enterprise_id) -> + enterprises_to_reset.push(enterprise_id) if enterprises_to_reset.length && $scope.updated_ids.length $http( @@ -144,11 +147,9 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt 'reset_absent': true, 'updated_ids': $scope.updated_ids, 'enterprises_to_reset': enterprises_to_reset - ).success((data, status, headers, config) -> - console.log(data) + ).success((data, status) -> $scope.updates.products_reset = data - - ).error((data, status, headers, config) -> + ).error((data, status) -> console.error(data) ) diff --git a/app/models/product_import/entry_processor.rb b/app/models/product_import/entry_processor.rb index 23d0b88ddf..a07b527338 100644 --- a/app/models/product_import/entry_processor.rb +++ b/app/models/product_import/entry_processor.rb @@ -38,7 +38,7 @@ module ProductImport next unless supplier_id && permission_by_id?(supplier_id) products_count = - if import_into_inventory_by_supplier?(supplier_id) + if importing_into_inventory? VariantOverride.where('variant_overrides.hub_id IN (?)', supplier_id).count else Spree::Variant. @@ -57,19 +57,21 @@ module ProductImport def reset_absent_items # For selected enterprises; set stock to zero for all products/inventory # that were not listed in the newly uploaded spreadsheet - return if total_saved_count.zero? || @updated_ids.empty? || !@import_settings.key?(:settings) + return unless data_for_stock_reset? suppliers_to_reset_products = [] suppliers_to_reset_inventories = [] - @import_settings[:settings].each do |enterprise_id, settings| - suppliers_to_reset_products.push enterprise_id if settings['reset_all_absent'] && permission_by_id?(enterprise_id) && !import_into_inventory_by_supplier?(enterprise_id) - suppliers_to_reset_inventories.push enterprise_id if settings['reset_all_absent'] && permission_by_id?(enterprise_id) && import_into_inventory_by_supplier?(enterprise_id) + settings = @import_settings[:settings] + + @import_settings[:enterprises_to_reset].each do |enterprise_id| + suppliers_to_reset_products.push Integer(enterprise_id) if settings['reset_all_absent'] && permission_by_id?(enterprise_id) && !importing_into_inventory? + suppliers_to_reset_inventories.push Integer(enterprise_id) if settings['reset_all_absent'] && permission_by_id?(enterprise_id) && importing_into_inventory? end unless suppliers_to_reset_inventories.empty? @products_reset_count += VariantOverride. where('variant_overrides.hub_id IN (?) - AND variant_overrides.id NOT IN (?)', suppliers_to_reset_inventories, @updated_ids). + AND variant_overrides.id NOT IN (?)', suppliers_to_reset_inventories, @import_settings[:updated_ids]). update_all(count_on_hand: 0) end @@ -79,7 +81,7 @@ module ProductImport where('spree_products.supplier_id IN (?) AND spree_variants.id NOT IN (?) AND spree_variants.is_master = false - AND spree_variants.deleted_at IS NULL', suppliers_to_reset_products, @updated_ids). + AND spree_variants.deleted_at IS NULL', suppliers_to_reset_products, @import_settings[:updated_ids]). update_all(count_on_hand: 0) end @@ -89,6 +91,10 @@ module ProductImport private + def data_for_stock_reset? + @import_settings[:settings] && @import_settings[:updated_ids] && @import_settings[:enterprises_to_reset] + end + def save_to_inventory(entry) save_new_inventory_item entry if entry.validates_as? 'new_inventory_item' save_existing_inventory_item entry if entry.validates_as? 'existing_inventory_item' @@ -227,8 +233,8 @@ module ProductImport @editable_enterprises.value?(Integer(supplier_id)) end - def import_into_inventory_by_supplier?(supplier_id) - @import_settings[:settings] && @import_settings[:settings][supplier_id.to_s] && @import_settings[:settings]['import_into'] == 'inventories' + def importing_into_inventory? + @import_settings[:settings] && @import_settings[:settings]['import_into'] == 'inventories' end end end diff --git a/app/models/product_import/product_importer.rb b/app/models/product_import/product_importer.rb index 24618cfd05..2dc12a9e74 100644 --- a/app/models/product_import/product_importer.rb +++ b/app/models/product_import/product_importer.rb @@ -6,7 +6,7 @@ module ProductImport include ActiveModel::Conversion include ActiveModel::Validations - attr_reader :updated_ids + attr_reader :updated_ids, :import_settings def initialize(file, current_user, import_settings = {}) unless file.is_a?(File) diff --git a/app/views/admin/product_import/_options_form.html.haml b/app/views/admin/product_import/_options_form.html.haml deleted file mode 100644 index 5e4383de35..0000000000 --- a/app/views/admin/product_import/_options_form.html.haml +++ /dev/null @@ -1,66 +0,0 @@ -%table.import-settings{ng: {controller: 'ImportOptionsFormCtrl', init: "supplierId = #{supplier_id}; initForm()"}} - %tr.import-into - %td.description - Import Into: - %td - %td - = select_tag "settings[#{supplier_id}][import_into]", options_for_select({"Product List" => :product_list, "Inventories" => :inventories}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['import_into']", 'ng-change' => "updateImportInto()"} - %td - - %tr.stock-level.inventory{ng: {show: 'import_into == "inventories"'}} - %td.description - = t('admin.product_import.import.default_stock') - %td - = check_box_tag "settings[#{supplier_id}][defaults][count_on_hand][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['active']" - %td - = select_tag "settings[#{supplier_id}][defaults][count_on_hand][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']"} - %td - = number_field_tag "settings[#{supplier_id}][defaults][count_on_hand][value]", 0, 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['count_on_hand']['active']", 'ng-model' => "settings[#{supplier_id}]['defaults']['count_on_hand']['value']" - - %tr.stock-level.productlist{ng: {show: 'import_into == "product_list"'}} - %td.description - = t('admin.product_import.import.default_stock') - %td - = check_box_tag "settings[#{supplier_id}][defaults][on_hand][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['on_hand']['active']" - %td - = select_tag "settings[#{supplier_id}][defaults][on_hand][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['on_hand']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['on_hand']['active']"} - %td - = number_field_tag "settings[#{supplier_id}][defaults][on_hand][value]", 0, 'ng-model' => "settings[#{supplier_id}]['defaults']['on_hand']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['on_hand']['active']" - - %tr.tax-category{ng: {show: 'import_into == "product_list"'}} - %td.description - = t('admin.product_import.import.default_tax_cat') - %td - = check_box_tag "settings[#{supplier_id}][defaults][tax_category_id][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['tax_category_id']['active']" - %td - = select_tag "settings[#{supplier_id}][defaults][tax_category_id][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['tax_category_id']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['tax_category_id']['active']"} - %td - = select_tag "settings[#{supplier_id}][defaults][tax_category_id][value]", options_for_select(@tax_categories.map {|tc| [tc.name, tc.id]}), {prompt: 'None', class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['tax_category_id']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['tax_category_id']['active']"} - - %tr.shipping-category{ng: {show: 'import_into == "product_list"'}} - %td.description - = t('admin.product_import.import.default_shipping_cat') - %td - = check_box_tag "settings[#{supplier_id}][defaults][shipping_category_id][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['shipping_category_id']['active']" - %td - = select_tag "settings[#{supplier_id}][defaults][shipping_category_id][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['shipping_category_id']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['shipping_category_id']['active']"} - %td - = select_tag "settings[#{supplier_id}][defaults][shipping_category_id][value]", options_for_select(@shipping_categories.map {|sc| [sc.name, sc.id]}), {prompt: 'None', class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['shipping_category_id']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['shipping_category_id']['active']"} - - %tr.available-date{ng: {show: 'import_into == "product_list"'}} - %td.description - = t('admin.product_import.import.default_available_date') - %td - = check_box_tag "settings[#{supplier_id}][defaults][available_on][active]", 1, false, 'ng-model' => "settings[#{supplier_id}]['defaults']['available_on']['active']" - %td - = select_tag "settings[#{supplier_id}][defaults][available_on][mode]", options_for_select({"#{t('admin.product_import.import.overwrite_all')}" => :overwrite_all, "#{t('admin.product_import.import.overwrite_empty')}" => :overwrite_empty}), {class: 'select2 fullwidth select2-no-search', 'ng-model' => "settings[#{supplier_id}]['defaults']['available_on']['mode']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['available_on']['active']"} - %td - = text_field_tag "settings[#{supplier_id}][defaults][available_on][value]", nil, {class: 'datepicker', placeholder: 'Today', 'ng-model' => "settings[#{supplier_id}]['defaults']['available_on']['value']", 'ng-disabled' => "!settings[#{supplier_id}]['defaults']['available_on']['active']"} - - %tr.reset-absent - %td.description - = t('admin.product_import.import.reset_absent?') - %td - = check_box_tag "settings[#{supplier_id}][reset_all_absent]", 1, false, :'ng-model' => "settings[#{supplier_id}]['reset_all_absent']", :'ng-change' => "toggleResetAbsent('#{supplier_id}')" - %td - %td diff --git a/app/views/admin/product_import/_upload_form.html.haml b/app/views/admin/product_import/_upload_form.html.haml index 00aa4a6cd4..8649a04780 100644 --- a/app/views/admin/product_import/_upload_form.html.haml +++ b/app/views/admin/product_import/_upload_form.html.haml @@ -4,7 +4,7 @@ %h6= t('admin.product_import.index.choose_import_type') %br - = select_tag "import_into", options_for_select({"#{t('admin.product_import.index.product_list')}" => :product_list, "#{t('admin.product_import.index.inventories')}" => :inventories}), {class: 'select2 select2-no-search', 'ng-model' => 'settings.import_into'} + = select_tag "settings[import_into]", options_for_select({"#{t('admin.product_import.index.product_list')}" => :product_list, "#{t('admin.product_import.index.inventories')}" => :inventories}), {class: 'select2 select2-no-search', 'ng-model' => 'settings.import_into'} %br %br %br @@ -18,8 +18,8 @@ %h6= t('admin.product_import.import.reset_absent?') %br - = hidden_field_tag "settings[reset_all_absent]", 0 - = check_box_tag "settings[reset_all_absent]", 1, false, 'ng-model' => 'settings.reset_all_absent' + = hidden_field_tag "settings[reset_all_absent]", nil + = check_box_tag "settings[reset_all_absent]", true, false, 'ng-model' => 'settings.reset_all_absent' %span= t('admin.product_import.import.reset_absent_tip') %br %br diff --git a/app/views/admin/product_import/import.html.haml b/app/views/admin/product_import/import.html.haml index e74e8c4692..7a4326e3d8 100644 --- a/app/views/admin/product_import/import.html.haml +++ b/app/views/admin/product_import/import.html.haml @@ -5,6 +5,9 @@ .import-wrapper{ng: {app: 'admin.productImport', controller: 'ImportFormCtrl', init: "supplier_product_counts = #{@importer.supplier_products.to_json}"}} + = hidden_field_tag "settings[reset_all_absent]", @importer.import_settings['reset_all_absent'], 'ng-model' => "importSettings[reset_all_absent]" + = hidden_field_tag "settings[import_into]", @importer.import_settings['import_into'], 'ng-model' => "importSettings[import_into]" + - if @importer.item_count == 0 #and @importer.invalid_count %h5 = t('.no_valid_entries') diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index c4a504fba4..5e3feac8d9 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -195,6 +195,39 @@ feature "Product Import", js: true do expect(page).to_not have_field "product_name", with: product2.name end + it "can reset product stock to zero for products not present in the CSV" do + csv_data = CSV.generate do |csv| + csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type"] + csv << ["Carrots", "User Enterprise", "Vegetables", "500", "3.20", "500", "g"] + end + File.write('/tmp/test.csv', csv_data) + + visit main_app.admin_product_import_path + + attach_file 'file', '/tmp/test.csv' + + check "settings_reset_all_absent" + + click_button 'Upload' + + expect(page).to have_selector 'a.button.proceed', visible: true + click_link 'Proceed' + + import_data + + expect(page).to have_selector 'a.button.proceed', visible: true + click_link 'Proceed' + + save_data + + expect(page).to have_selector '.created-count', text: '1' + expect(page).to have_selector '.reset-count', text: '3' + + expect(Spree::Product.find_by_name('Carrots').on_hand).to eq 500 + expect(Spree::Product.find_by_name('Cabbage').on_hand).to eq 0 + expect(Spree::Product.find_by_name('Beans').on_hand).to eq 0 + end + it "can import items into inventory" do csv_data = CSV.generate do |csv| csv << ["name", "supplier", "producer", "category", "on_hand", "price", "units"] @@ -205,14 +238,10 @@ feature "Product Import", js: true do File.write('/tmp/test.csv', csv_data) visit main_app.admin_product_import_path + select2_select I18n.t('admin.product_import.index.inventories'), from: "settings_import_into" attach_file 'file', '/tmp/test.csv' click_button 'Upload' - within 'div.import-settings' do - find('div.header-description').click # Import settings tab - select 'Inventories', from: "settings_#{enterprise2.id.to_s}_import_into", visible: false - end - expect(page).to have_selector 'a.button.proceed', visible: true click_link 'Proceed' @@ -259,76 +288,6 @@ feature "Product Import", js: true do expect(page).to have_content 'Cabbage' end end - - it "can override import fields via the import settings tab" do - csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type", "tax_category", "shipping_category"] - csv << ["Carrots", "User Enterprise", "Vegetables", "5", "3.20", "500", "g", tax_category.name, shipping_category.name] - csv << ["Pumpkin", "User Enterprise", "Vegetables", "3", "3.50", "1", "kg", tax_category.name, ""] - csv << ["Spinach", "User Enterprise", "Vegetables", "7", "3.60", "1", "kg", "", shipping_category.name] - end - File.write('/tmp/test.csv', csv_data) - - visit main_app.admin_product_import_path - - expect(page).to have_content "Select a spreadsheet to upload" - attach_file 'file', '/tmp/test.csv' - click_button 'Upload' - - within 'div.import-settings' do - find('div.panel-header').click - - within 'tr.stock-level.productlist' do - find('input[type="checkbox"]').click - select 'Overwrite all', from: "settings_#{enterprise.id}_defaults_on_hand_mode", visible: false - fill_in "settings_#{enterprise.id}_defaults_on_hand_value", with: 9000 - end - - within 'tr.tax-category' do - find('input[type="checkbox"]').click - select 'Overwrite if empty', from: "settings_#{enterprise.id}_defaults_tax_category_id_mode", visible: false - select tax_category2.name, from: "settings_#{enterprise.id}_defaults_tax_category_id_value", visible: false - end - - within 'tr.shipping-category' do - find('input[type="checkbox"]').click - select 'Overwrite all', from: "settings_#{enterprise.id}_defaults_shipping_category_id_mode", visible: false - select shipping_category.name, from: "settings_#{enterprise.id}_defaults_shipping_category_id_value", visible: false - end - end - - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - - import_data - - expect(page).to have_selector '.item-count', text: "3" - expect(page).to have_selector '.create-count', text: "3" - expect(page).to_not have_selector '.update-count' - - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - - save_data - - expect(page).to have_selector '.created-count', text: '3' - expect(page).to_not have_selector '.updated-count' - - carrots = Spree::Product.find_by_name('Carrots') - expect(carrots.tax_category).to eq tax_category - expect(carrots.shipping_category).to eq shipping_category - expect(carrots.count_on_hand).to eq 9000 - - pumpkin = Spree::Product.find_by_name('Pumpkin') - expect(pumpkin.tax_category).to eq tax_category - expect(pumpkin.shipping_category).to eq shipping_category - expect(pumpkin.count_on_hand).to eq 9000 - - spinach = Spree::Product.find_by_name('Spinach') - expect(spinach.tax_category).to eq tax_category2 - expect(spinach.shipping_category).to eq shipping_category - expect(spinach.count_on_hand).to eq 9000 - end end describe "when dealing with uploaded files" do diff --git a/spec/models/product_importer_spec.rb b/spec/models/product_importer_spec.rb index aeaf1c2eae..4df09d328c 100644 --- a/spec/models/product_importer_spec.rb +++ b/spec/models/product_importer_spec.rb @@ -303,7 +303,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise2.id.to_s => {'import_into' => 'inventories'}} + settings = {'import_into' => 'inventories'} @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) end after { File.delete('/tmp/test-m.csv') } @@ -341,54 +341,6 @@ describe ProductImport::ProductImporter do end end - describe "importing items into inventory and product list simultaneously" do - before do - csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "producer", "category", "on_hand", "price", "units", "unit_type"] - csv << ["Beans", "Another Enterprise", "User Enterprise", "Vegetables", "5", "3.20", "500", ""] - csv << ["Sprouts", "Another Enterprise", "User Enterprise", "Vegetables", "6", "6.50", "500", ""] - csv << ["Garbanzos", "User Enterprise", "", "Vegetables", "2001", "1.50", "500", "g"] - end - File.write('/tmp/test-m.csv', csv_data) - file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'product_list'}, enterprise2.id.to_s => {'import_into' => 'inventories'}} - @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) - end - after { File.delete('/tmp/test-m.csv') } - - it "validates entries" do - @importer.validate_entries - entries = JSON.parse(@importer.entries_json) - - expect(filter('valid', entries)).to eq 3 - expect(filter('invalid', entries)).to eq 0 - expect(filter('create_inventory', entries)).to eq 2 - expect(filter('create_product', entries)).to eq 1 - end - - it "saves and updates inventory" do - @importer.save_entries - - expect(@importer.inventory_created_count).to eq 2 - expect(@importer.products_created_count).to eq 1 - expect(@importer.updated_ids).to be_a(Array) - expect(@importer.updated_ids.count).to eq 3 - - beans_override = VariantOverride.where(variant_id: product2.variants.first.id, hub_id: enterprise2.id).first - sprouts_override = VariantOverride.where(variant_id: product3.variants.first.id, hub_id: enterprise2.id).first - garbanzos = Spree::Product.where(name: "Garbanzos").first - - expect(Float(beans_override.price)).to eq 3.20 - expect( beans_override.count_on_hand).to eq 5 - - expect(Float(sprouts_override.price)).to eq 6.50 - expect(sprouts_override.count_on_hand).to eq 6 - - expect(Float(garbanzos.price)).to eq 1.50 - expect(garbanzos.count_on_hand).to eq 2001 - end - end - describe "handling enterprise permissions" do after { File.delete('/tmp/test-m.csv') } @@ -400,7 +352,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'product_list'}, enterprise2.id.to_s => {'import_into' => 'product_list'}} + settings = {'import_into' => 'product_list'} @importer = ProductImport::ProductImporter.new(file, user, start: 1, end: 100, settings: settings) @importer.validate_entries @@ -427,7 +379,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise2.id.to_s => {'import_into' => 'inventories'}} + settings = {'import_into' => 'inventories'} @importer = ProductImport::ProductImporter.new(file, user2, start: 1, end: 100, settings: settings) @importer.validate_entries @@ -455,7 +407,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'inventories'}} + settings = {'import_into' => 'inventories'} @importer = ProductImport::ProductImporter.new(file, user2, start: 1, end: 100, settings: settings) @importer.validate_entries @@ -484,7 +436,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise.id.to_s => {'import_into' => 'product_list', 'reset_all_absent' => true}} + settings = {'import_into' => 'product_list', 'reset_all_absent' => true} @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) @importer.validate_entries @@ -502,7 +454,9 @@ describe ProductImport::ProductImporter do expect(@importer.updated_ids).to be_a(Array) expect(@importer.updated_ids.count).to eq 2 - @importer.reset_absent(@importer.updated_ids) + updated_ids = @importer.updated_ids + @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, updated_ids: updated_ids, enterprises_to_reset: [enterprise.id], settings: settings) + @importer.reset_absent(updated_ids) expect(@importer.products_reset_count).to eq 2 @@ -521,7 +475,7 @@ describe ProductImport::ProductImporter do end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') - settings = {enterprise2.id.to_s => {'import_into' => 'inventories', 'reset_all_absent' => true}} + settings = {'import_into' => 'inventories', 'reset_all_absent' => true} @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, settings: settings) @importer.validate_entries @@ -537,7 +491,9 @@ describe ProductImport::ProductImporter do expect(@importer.updated_ids).to be_a(Array) expect(@importer.updated_ids.count).to eq 2 - @importer.reset_absent(@importer.updated_ids) + updated_ids = @importer.updated_ids + @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, updated_ids: updated_ids, enterprises_to_reset: [enterprise2.id], settings: settings) + @importer.reset_absent(updated_ids) # expect(@importer.products_reset_count).to eq 1 @@ -614,53 +570,6 @@ describe ProductImport::ProductImporter do expect(potatoes.shipping_category_id).to eq shipping_category.id expect(potatoes.available_on).to be_within(1.day).of(Time.zone.local(2020, 1, 1)) end - - it "can overwrite fields with selected defaults when importing to inventory" do - csv_data = CSV.generate do |csv| - csv << ["name", "producer", "supplier", "on_hand", "price", "units", "unit_type"] - csv << ["Beans", "User Enterprise", "Another Enterprise", "", "3.20", "500", "g"] - csv << ["Sprouts", "User Enterprise", "Another Enterprise", "7", "6.50", "500", "g"] - csv << ["Cabbage", "User Enterprise", "Another Enterprise", "", "1.50", "500", "g"] - end - File.write('/tmp/test-m.csv', csv_data) - file = File.new('/tmp/test-m.csv') - - import_settings = {enterprise2.id.to_s => { - 'import_into' => 'inventories', - 'defaults' => { - 'count_on_hand' => { - 'active' => true, - 'mode' => 'overwrite_empty', - 'value' => '9000' - } - } - }} - - @importer = ProductImport::ProductImporter.new(file, admin, start: 1, end: 100, import_into: 'inventories', settings: import_settings) - - @importer.validate_entries - entries = JSON.parse(@importer.entries_json) - - expect(filter('valid', entries)).to eq 3 - expect(filter('invalid', entries)).to eq 0 - expect(filter('create_inventory', entries)).to eq 2 - expect(filter('update_inventory', entries)).to eq 1 - - @importer.save_entries - - expect(@importer.inventory_created_count).to eq 2 - expect(@importer.inventory_updated_count).to eq 1 - expect(@importer.updated_ids).to be_a(Array) - expect(@importer.updated_ids.count).to eq 3 - - beans_override = VariantOverride.where(variant_id: product2.variants.first.id, hub_id: enterprise2.id).first - sprouts_override = VariantOverride.where(variant_id: product3.variants.first.id, hub_id: enterprise2.id).first - cabbage_override = VariantOverride.where(variant_id: product4.variants.first.id, hub_id: enterprise2.id).first - - expect(beans_override.count_on_hand).to eq 9000 - expect(sprouts_override.count_on_hand).to eq 7 - expect(cabbage_override.count_on_hand).to eq 9000 - end end end From 14480b920e998755bd7b3c45b85977d7970ca144 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Wed, 18 Jul 2018 18:51:31 +0200 Subject: [PATCH 118/125] Fix script/setup by making it less clever Now we ask the dev to create the "ofn" user as precondition. This is way easier than developing a script that fits all possible setups. It also stops requiring a particlar Postgres version. Although in production we use 9.5 it is very unlikely we will use any version-specific feature in the near future. This should make it a bit easier for new devs to set up their environment. --- GETTING_STARTED.md | 10 +++++++++- script/setup | 25 +++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index 384d8c6043..8e9c087b76 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -40,7 +40,15 @@ Fetch the latest version of `master` from `upstream` (ie. the main repo): ### Get it running -When ready, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot. +First, you need to create the database user the app will use by manually typing the following in your terminal: + +```sh +$ sudo -u postgres psql -c "CREATE USER ofn WITH SUPERUSER CREATEDB PASSWORD 'f00d'" +``` + +This will create the "ofn" user as superuser and allowing it to create databases. + +Once done, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot. If you run into any other issues getting your local environment up and running please consult [the wiki](wiki). diff --git a/script/setup b/script/setup index 9a593474f0..e03015ada2 100755 --- a/script/setup +++ b/script/setup @@ -1,6 +1,14 @@ #!/usr/bin/env sh # Set up Rails app. Run this script immediately after cloning the codebase. +# +# First, you need to create the database user the app will use by manually +# typing the following in your terminal: +# +# $ sudo -u postgres psql -c "CREATE USER ofn WITH SUPERUSER CREATEDB PASSWORD 'f00d'" +# +# This will create the "ofn" user as superuser and allowing it to create +# databases. # Exit if any command fails set -e @@ -11,10 +19,6 @@ NO_COLOR='\033[0m' RUBY_VERSION=$(cat .ruby-version) NODE_VERSION=$(cat .node-version) -POSTGRESQL_VERSION='9.5' - -DB_USER='ofn' -DB_PASSWORD='f00d' # Check ruby version if ! ruby --version | grep $RUBY_VERSION > /dev/null; then @@ -27,12 +31,6 @@ if ! node --version | grep $NODE_VERSION > /dev/null; then printf "${RED}Open Food Network requires node ${NODE_VERSION}${NO_COLOR}. Have a look at: https://github.com/nodenv/nodenv\n" fi -# Check postgresql version -if ! psql -V | grep $POSTGRESQL_VERSION > /dev/null; then - printf "${RED}Open Food Network requires postgresql ${POSTGRESQL_VERSION}${NO_COLOR}\n" - exit 1 -fi - # Set up Ruby dependencies via Bundler if ! command -v bundle > /dev/null; then gem install bundler @@ -48,11 +46,6 @@ if [ ! -f config/application.yml ]; then printf "${YELLOW}Copied config/application.yml Make sure to fill it with the appropriate configuration values.\n\n${NO_COLOR}" fi -# Create the development database user -if ! psql -c '\du' -t | grep $DB_USER > /dev/null; then - psql -c "CREATE USER ${DB_USER} WITH SUPERUSER PASSWORD '${DB_PASSWORD}';" -fi - # Set up the database for both development and test # Confirming the default user and password Spree prompts printf '\n\n' | bundle exec rake db:setup db:test:prepare @@ -65,7 +58,7 @@ printf '\n' printf "${YELLOW}WELCOME TO OPEN FOOD NETWORK!\n" printf '\n' -printf "To login as Spree default user, use:" +printf "To login as the Spree default user, use:" printf '\n' printf '\n' printf ' email: spree@example.com\n' From 5db5bc65c048396365a64bd2d6930c83fd19c3fd Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 24 Jul 2018 11:18:54 +1000 Subject: [PATCH 119/125] Add communications links to README This was originally proposed by Kirsten in: https://github.com/openfoodfoundation/openfoodnetwork/pull/2478 --- README.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0c75996004..d1bf86b655 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,15 @@ The Open Food Network is an online marketplace for local food. It enables a network of independent online food stores that connect farmers and food hubs (including coops, online farmers' markets, independent food businesses etc); with individuals and local businesses. It gives farmers and food hubs an easier and fairer way to distribute their food. -Supported by the Open Food Foundation, we are proudly open source and not-for-profit - we're trying to seriously disrupt the concentration of power in global agri-food systems, and we need as many smart people working together on this as possible. +Supported by the Open Food Foundation and a network of global affiliates, we are proudly open source and not-for-profit - we're trying to seriously disrupt the concentration of power in global agri-food systems, and we need as many smart people working together on this as possible. We're part of global movement - get involved! -* Join the conversation [on Slack](slack). Make sure you introduce yourself in the #general channel -* Head to [https://openfoodnetwork.org](https://openfoodnetwork.org) for more information about the global OFN project -* Check out the [User Guide](https://guide.openfoodnetwork.org/) for a list of features and tutorials +* Fill in this [short survey](survey) to tell us who you are and what you want to do with OFN. +* Join the conversation [on Slack](slack). Make sure you introduce yourself in the #general channel. +* Head to [https://openfoodnetwork.org](https://openfoodnetwork.org) for more information about the global OFN project. +* Check out the [User Guide](https://guide.openfoodnetwork.org/) for a list of features and tutorials. +* Join our [discussion forum](https://community.openfoodnetwork.org). ## Contributing @@ -49,7 +51,8 @@ We also have a [Super Admin Guide](super-admin-guide) to help with configuration Copyright (c) 2012 - 2018 Open Food Foundation, released under the AGPL licence. -[slack]: https://join.slack.com/t/openfoodnetwork/shared_invite/enQtMzU2Mjk5MDc2MjA5LTM4ZTAzZjIwNzIxMmU5ODFiNWY1MTU2ZWUyNzQwNjdjNTY0N2VhY2UwOGU4ZmVjNzYyZDU2NjY3NzZkZmQwYjk +[survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit# +[slack]: https://openfoodnetwork.org/slack-invite [contributor-guide]: https://ofn-user-guide.gitbook.io/ofn-contributor-guide/who-are-we [ofn-install]: https://github.com/openfoodfoundation/ofn-install [super-admin-guide]: https://ofn-user-guide.gitbook.io/ofn-super-admin-guide From ae5fd864d14440998b7353e6788099ddddc38150 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 23 Jul 2018 12:43:00 +0100 Subject: [PATCH 120/125] Fix embedded shopfront menu responsiveness --- .../darkswarm/embedded_shopfront.css.scss | 143 ++++++++++++++---- app/views/shared/menu/_large_menu.html.haml | 12 +- 2 files changed, 123 insertions(+), 32 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss b/app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss index bc02417b55..760b77d89a 100644 --- a/app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss +++ b/app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss @@ -1,27 +1,78 @@ @import "typography"; +$large-menu-height: 4.6875rem; +$medium-menu-height: 3rem; +$gutter-width: 0.9375rem; + +nav.top-bar ul.left li.powered-by { + display: none; +} + body.embedded { nav.top-bar { - ul.left, ul.center, ul.right li.current_hub { + overflow: visible; + padding: 0 $gutter-width; + + ul.left li.ofn-logo, ul.center, ul.right li.current_hub { display: none; } + ul.left { + float: left; + width: auto; + + li { + line-height: $large-menu-height; + height: $large-menu-height; + vertical-align: top; + } + + li.powered-by { + display: inline-block; + opacity: 0.6; + + img { + height: 1.8em; + margin: 0px 0.4em 0.4em 0px; + } + + span, a { + font-family: "Oswald", sans-serif; + font-size: 1rem; + font-weight: 300; + color: #555; + padding: 0 !important; + } + + a:hover { + color: #000; + } + } + } + ul.right { width: auto !important; + li { float: left; - line-height: 4.6875rem; - height: 4.6875rem; + line-height: $large-menu-height; + height: $large-menu-height; vertical-align: top; - } - li.powered-by { - display: inline-block; + + &.cart { + + div.joyride-tip-guide { // Cart Dropdown + top: 75px; + overflow: visible; + } + } } } &.show-for-large-up { display: inherit !important; } + &.show-for-medium-down { display: none !important; } @@ -46,28 +97,68 @@ body.embedded { #group-page header { display: none; } + + @media all and (max-width: 640px) { + nav.top-bar { + height: 3.4rem; + padding: 0.2rem $gutter-width; + line-height: $medium-menu-height; + + ul.left li, ul.right li { + line-height: $medium-menu-height; + + i, span { + line-height: $medium-menu-height; + } + } + + ul.right li.cart div.joyride-tip-guide { + width: 95%; + top: 51px; + + h5 { + margin-bottom: 0.6rem; + } + + .joyride-content-wrapper { + line-height: 2rem; + + table tr.product-cart { + padding: 0; + + td{ + padding: 0 12px; + } + } + } + + .buttons { + + .button { + padding: 0.4rem 0.6rem !important; + } + } + } + } + } + + @media all and (max-width: 480px) { + ul.left li.powered-by span { + display: none; + } + + ul.right { + + li.cart { + + div.joyride-tip-guide { + width: 95%; + } + } + } + } } -nav.top-bar ul.right li.powered-by { - display: none; - margin-right: 0.4rem; - opacity: 0.6; - - img { - height: 1.8em; - margin: 0px 0.4em 0.4em 0px; - } - span, a { - font-family: "Oswald", sans-serif; - font-size: 1rem; - font-weight: 300; - color: #555; - padding: 0 !important; - } - a:hover { - color: #000; - } -} .powered-by-embedded { opacity: 0.6; diff --git a/app/views/shared/menu/_large_menu.html.haml b/app/views/shared/menu/_large_menu.html.haml index 96f4ad5691..fac607057a 100644 --- a/app/views/shared/menu/_large_menu.html.haml +++ b/app/views/shared/menu/_large_menu.html.haml @@ -4,6 +4,12 @@ %li.ofn-logo %a{href: root_path} %img{src: ContentConfig.logo.url} + %li.powered-by + %img{src: '/favicon.ico'} + %span + = t 'powered_by' + %a{href: '/'} + = t 'title' %ul.center %li %a{href: main_app.shops_path} @@ -54,12 +60,6 @@ = t 'label_about' %ul.right - %li.powered-by - %img{src: '/favicon.ico'} - %span - = t 'powered_by' - %a{href: '/'} - = t 'title' - if OpenFoodNetwork::I18nConfig.selectable_locales.count > 1 %li.language-switcher.has-dropdown %a{href: '#'} From f0f9662957d5f5639126b82ed682e4a5de4bd27c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Mon, 23 Jul 2018 16:16:04 +1000 Subject: [PATCH 121/125] Update gem i18n-js to pick up locale changes We had some problems recently with changes in en.yml not being picked up by i18n-js to be included in all.js. There have been some patches for the current version that have an impact on that: https://github.com/fnando/i18n-js/commit/578555f57ece1cf226ef004118e60738502b859a https://github.com/fnando/i18n-js/commit/db3cdf82aaa33a0be558214d82e89a27204380a4 https://github.com/fnando/i18n-js/commit/a88b206644a14b0de7bbb58e0ba1baab93737a8e Trying it out locally, the updated i18n-js gem works while the old version doesn't update the Javascript translations when new keys are added. To reproduce the issue, you can add a new key in `en.yml` and reference it from an Angular template in `app/assets/javascripts/`. The old version complained about a missing translation until you ran: ``` bundle exec rake tmp:cache:clear ``` We don't need to do that any more. --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 3002dd93aa..dac1b3d220 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -439,8 +439,8 @@ GEM multi_json (~> 1.0) multi_xml i18n (0.6.11) - i18n-js (3.0.0) - i18n (~> 0.6, >= 0.6.6) + i18n-js (3.0.11) + i18n (>= 0.6.6, < 2) immigrant (0.1.6) activerecord (>= 3.0) foreigner (>= 1.2.1) From 2ceb969925969d210c216f8d953f492728f0ed12 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 26 Jul 2018 10:52:56 +1000 Subject: [PATCH 122/125] Style recently merged code We enabled more Rubocop checks and code that was merged around the same time, didn't comply with the new checks. --- app/controllers/spree/admin/search_controller_decorator.rb | 2 +- spec/features/consumer/shopping/embedded_shopfronts_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/spree/admin/search_controller_decorator.rb b/app/controllers/spree/admin/search_controller_decorator.rb index d0069fd2ae..7fb5659415 100644 --- a/app/controllers/spree/admin/search_controller_decorator.rb +++ b/app/controllers/spree/admin/search_controller_decorator.rb @@ -10,7 +10,7 @@ Spree::Admin::SearchController.class_eval do :ship_address_lastname_start => params[:q], :bill_address_firstname_start => params[:q], :bill_address_lastname_start => params[:q] - }).result.limit(10) + }).result.limit(10) end render json: @users, each_serializer: Api::Admin::UserSerializer diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 1b965db512..2476bdabd9 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -107,7 +107,7 @@ feature "Using embedded shopfront functionality", js: true do end private - + def login_with_modal expect(page).to have_selector 'div.login-modal', visible: true From a16058f52a8f0474c93b244e1e74f377f62e38e0 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Tue, 24 Jul 2018 20:39:34 +1000 Subject: [PATCH 123/125] Fix link syntax errors in REAME.md and GETTING_STARTED.md --- GETTING_STARTED.md | 6 +++--- README.md | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index 8e9c087b76..f1dd8679aa 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -73,9 +73,9 @@ Then the tests can be run with: bundle exec rspec spec -The project is configured to use [Zeus](zeus) to reduce the pre-test startup time while Rails loads. See the [Zeus GitHub page](zeus) for usage instructions. +The project is configured to use [Zeus][zeus] to reduce the pre-test startup time while Rails loads. See the [Zeus GitHub page][zeus] for usage instructions. -Once [npm dependencies are installed](karma), AngularJS tests can be run with: +Once [npm dependencies are installed][karma], AngularJS tests can be run with: ./script/karma run @@ -87,7 +87,7 @@ If you want karma to automatically rerun the tests on file modification, use: Do not forget to run `rake tmp:cache:clear` after locales are updated to reload I18n js translations. ### Rubocop -The project is configured to use [rubocop](rubocop) to automatically check for style and syntax errors. +The project is configured to use [rubocop][rubocop] to automatically check for style and syntax errors. You can run rubocop against your changes using: diff --git a/README.md b/README.md index d1bf86b655..6b71fdb766 100644 --- a/README.md +++ b/README.md @@ -11,22 +11,22 @@ Supported by the Open Food Foundation and a network of global affiliates, we are We're part of global movement - get involved! * Fill in this [short survey](survey) to tell us who you are and what you want to do with OFN. -* Join the conversation [on Slack](slack). Make sure you introduce yourself in the #general channel. +* Join the conversation [on Slack][slack-invite]. Make sure you introduce yourself in the #general channel * Head to [https://openfoodnetwork.org](https://openfoodnetwork.org) for more information about the global OFN project. * Check out the [User Guide](https://guide.openfoodnetwork.org/) for a list of features and tutorials. * Join our [discussion forum](https://community.openfoodnetwork.org). ## Contributing -If you are interested in contributing to the OFN in any capacity, please introducing yourself [on Slack](slack), and have a look through our [Contributor Guide](contributor-guide) +If you are interested in contributing to the OFN in any capacity, please introducing yourself [on Slack][slack-invite], and have a look through our [Contributor Guide][contributor-guide] Our [GETTING_STARTED](GETTING_STARTED.md) and [CONTRIBUTING](CONTRIBUTING.md) guides are the best place to start for developers looking to set up a development environment and make contributions to the codebase. ## Provisioning -If you're interested in provisioning a server, see [ofn-install](ofn-install) for the project's Ansible playbooks. +If you're interested in provisioning a server, see [ofn-install][ofn-install] for the project's Ansible playbooks. -We also have a [Super Admin Guide](super-admin-guide) to help with configuration of new servers. +We also have a [Super Admin Guide][super-admin-guide] to help with configuration of new servers. ## Credits @@ -52,7 +52,7 @@ We also have a [Super Admin Guide](super-admin-guide) to help with configuration Copyright (c) 2012 - 2018 Open Food Foundation, released under the AGPL licence. [survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit# -[slack]: https://openfoodnetwork.org/slack-invite +[slack-invite]: https://openfoodnetwork.org/slack-invite [contributor-guide]: https://ofn-user-guide.gitbook.io/ofn-contributor-guide/who-are-we [ofn-install]: https://github.com/openfoodfoundation/ofn-install [super-admin-guide]: https://ofn-user-guide.gitbook.io/ofn-super-admin-guide From eb89b74022293589cfc0c1841686f94e88fe4660 Mon Sep 17 00:00:00 2001 From: Rob H Date: Fri, 27 Jul 2018 12:48:37 +1000 Subject: [PATCH 124/125] Fix syntax error in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b71fdb766..f65b505a1c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Supported by the Open Food Foundation and a network of global affiliates, we are We're part of global movement - get involved! -* Fill in this [short survey](survey) to tell us who you are and what you want to do with OFN. +* Fill in this [short survey][survey] to tell us who you are and what you want to do with OFN. * Join the conversation [on Slack][slack-invite]. Make sure you introduce yourself in the #general channel * Head to [https://openfoodnetwork.org](https://openfoodnetwork.org) for more information about the global OFN project. * Check out the [User Guide](https://guide.openfoodnetwork.org/) for a list of features and tutorials. From 7f26b1494b736dcf201a4d1f8329f73d8796b2ba Mon Sep 17 00:00:00 2001 From: Rob H Date: Fri, 27 Jul 2018 12:49:18 +1000 Subject: [PATCH 125/125] Fix syntax error in GETTING_STARTED.md --- GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index f1dd8679aa..e68259d57f 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -50,7 +50,7 @@ This will create the "ofn" user as superuser and allowing it to create databases Once done, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot. -If you run into any other issues getting your local environment up and running please consult [the wiki](wiki). +If you run into any other issues getting your local environment up and running please consult [the wiki][wiki]. If still you get stuck do not hesitate to open an issue reporting the full output of the script.