From f0a20988263b9f37878884034adacc308916b1d1 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 25 May 2016 09:45:47 +0100 Subject: [PATCH 01/77] Adding text generation to new business model features --- .../business_model_configuration_helper.rb | 27 +- config/locales/en-GB.yml | 3 + config/locales/en.yml | 3 + ...usiness_model_configuration_helper_spec.rb | 587 +++++++++++++++--- 4 files changed, 540 insertions(+), 80 deletions(-) diff --git a/app/helpers/admin/business_model_configuration_helper.rb b/app/helpers/admin/business_model_configuration_helper.rb index dcfebb1969..b1a2f1ac12 100644 --- a/app/helpers/admin/business_model_configuration_helper.rb +++ b/app/helpers/admin/business_model_configuration_helper.rb @@ -2,13 +2,15 @@ module Admin module BusinessModelConfigurationHelper def monthly_bill_description plus = monthly_bill_includes_fixed? && monthly_bill_includes_rate? ? " + " : "" + ts = trial_description.empty? ? "": " " + ms = minimum_description.empty? ? "": " " if fixed_description.empty? && rate_description.empty? t(:free).upcase - elsif monthly_bill_includes_cap? && monthly_bill_includes_rate? # only care about cap if there is a rate too - "#{fixed_description}#{plus}#{rate_description}{joiner}#{cap_description} #{t(:per_month).upcase}#{tax_description.upcase}" + elsif monthly_bill_includes_rate_limits? && monthly_bill_includes_rate? # only care about cap/min-bill-to if there is a rate too + "#{trial_description}#{ts}#{fixed_description}#{plus}#{rate_description}#{ms}#{minimum_description}#{cap_description} #{t(:per_month).upcase}#{tax_description.upcase}" else - "#{fixed_description}#{plus}#{rate_description} #{t(:per_month).upcase}#{tax_description.upcase}" + "#{trial_description}#{ts}#{fixed_description}#{plus}#{rate_description} #{t(:per_month).upcase}#{tax_description.upcase}" end end @@ -26,13 +28,22 @@ module Admin def cap_description cap_amount = Spree::Money.new(Spree::Config[:account_invoices_monthly_cap], { currency: Spree::Config[:currency] }).rounded - monthly_bill_includes_cap? ? "#{t(:capped_at_cap, cap: cap_amount).upcase}" : "" + monthly_bill_includes_cap? ? ", #{t(:capped_at_cap, cap: cap_amount).upcase}" : "" end def tax_description Spree::Config[:account_invoices_tax_rate] > 0 ? ", #{t(:plus_tax).upcase}" : "" end + def trial_description + Spree::Config[:shop_trial_length_days] > 0 ? "#{t(:free_trial).upcase} #{t(:then).upcase}" : "" + end + + def minimum_description + mbt_amount = Spree::Money.new(Spree::Config[:minimum_billable_turnover], { currency: Spree::Config[:currency] }).rounded + monthly_bill_includes_min_turnover? ? "#{t(:min_bill_turnover_desc, mbt_amount: mbt_amount).upcase}" : "" + end + def monthly_bill_includes_fixed? Spree::Config[:account_invoices_monthly_fixed] > 0 end @@ -44,5 +55,13 @@ module Admin def monthly_bill_includes_cap? Spree::Config[:account_invoices_monthly_cap] > 0 end + + def monthly_bill_includes_min_turnover? + Spree::Config[:minimum_billable_turnover] > 1 + end + + def monthly_bill_includes_rate_limits? + monthly_bill_includes_min_turnover? || monthly_bill_includes_cap? + end end end diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 58441e9934..f3623c6709 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -51,10 +51,13 @@ en-GB: capped_at_cap: "capped at %{cap}" per_month: "per month" free: "free" + free_trial: "free trial" plus_tax: "plus GST" total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)" + min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}" say_no: "No" say_yes: "Yes" + then: then sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By" diff --git a/config/locales/en.yml b/config/locales/en.yml index 34c4f4d4e9..da3265ef67 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -57,10 +57,13 @@ en: capped_at_cap: "capped at %{cap}" per_month: "per month" free: "free" + free_trial: "free trial" plus_tax: "plus GST" total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)" + min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}" say_no: "No" say_yes: "Yes" + then: then sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By" diff --git a/spec/helpers/admin/business_model_configuration_helper_spec.rb b/spec/helpers/admin/business_model_configuration_helper_spec.rb index a10771cba7..6f035c05e5 100644 --- a/spec/helpers/admin/business_model_configuration_helper_spec.rb +++ b/spec/helpers/admin/business_model_configuration_helper_spec.rb @@ -2,135 +2,570 @@ require 'spec_helper' describe Admin::BusinessModelConfigurationHelper do describe "describing monthly bills for enterprises" do - context "when tax is applied to the service change" do - before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } - context "when a fixed cost is included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + context "when there is no free trial" do + before { Spree::Config.set(:shop_trial_length_days, 0) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES{joiner}CAPPED AT $20 PER MONTH, PLUS GST" } + context "when tax is applied to the service change" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } + + context "when minimum billable turnover is zero" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES PER MONTH, PLUS GST" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when minimum billable turnover is £100" do + before { Spree::Config.set(:minimum_billable_turnover, 100) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end end - context "when a fixed cost is not included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + context "when tax is not applied to the service change" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.0) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + context "when minimum billable turnover is zero" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES{joiner}CAPPED AT $20 PER MONTH, PLUS GST" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH, PLUS GST" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when minimum billable turnover is £100" do + before { Spree::Config.set(:minimum_billable_turnover, 100) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end end end - context "when tax is applied to the service change" do - before { Spree::Config.set(:account_invoices_tax_rate, 0.0) } - context "when a fixed cost is included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + context "when there is a 30 day free trial" do + before { Spree::Config.set(:shop_trial_length_days, 30) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + context "when tax is applied to the service change" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.1) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES{joiner}CAPPED AT $20 PER MONTH" } + context "when minimum billable turnover is zero" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } + + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES PER MONTH" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when minimum billable turnover is £100" do + before { Spree::Config.set(:minimum_billable_turnover, 100) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end end - context "when a fixed cost is not included" do - before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + context "when tax is not applied to the service change" do + before { Spree::Config.set(:account_invoices_tax_rate, 0.0) } - context "when a percentage of turnover is included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + context "when minimum billable turnover is zero" do + before { Spree::Config.set(:minimum_billable_turnover, 0) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES{joiner}CAPPED AT $20 PER MONTH" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end - context "when a percentage of turnover is not included" do - before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + context "when minimum billable turnover is £100" do + before { Spree::Config.set(:minimum_billable_turnover, 100) } - context "when the bill is capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE" } + context "when a fixed cost is included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 10) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + end + end end - context "when the bill is not capped" do - before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE" } + context "when a fixed cost is not included" do + before { Spree::Config.set(:account_invoices_monthly_fixed, 0) } + + context "when a percentage of turnover is included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + end + end + + context "when a percentage of turnover is not included" do + before { Spree::Config.set(:account_invoices_monthly_rate, 0) } + + context "when the bill is capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 20) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + + context "when the bill is not capped" do + before { Spree::Config.set(:account_invoices_monthly_cap, 0) } + it { expect(helper.monthly_bill_description).to eq "FREE" } + end + end end end end From e284ad62b2cb43fddb8a925f039c9bf3c68175ed Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 17 Jun 2016 17:03:47 +1000 Subject: [PATCH 02/77] Inject only relative enterprises into shopfront Other shops displayed in producer modals are lazy loaded when opening their modal. --- .../directives/enterprise_modal.js.coffee | 12 +++++++--- .../darkswarm/services/dereferencer.js.coffee | 6 +++-- .../services/enterprise_resource.js.coffee | 8 +++++++ .../darkswarm/services/enterprises.js.coffee | 24 ++++++++++++++++--- app/controllers/enterprises_controller.rb | 15 ++++++++++-- app/helpers/injection_helper.rb | 4 ++++ app/views/enterprises/shop.html.haml | 2 +- config/routes.rb | 1 + 8 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee diff --git a/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee index fa6378afe2..099f2a39e4 100644 --- a/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/enterprise_modal.js.coffee @@ -1,9 +1,15 @@ -Darkswarm.directive "enterpriseModal", ($modal)-> +Darkswarm.directive "enterpriseModal", ($modal, Enterprises, EnterpriseResource) -> restrict: 'E' replace: true template: "" transclude: true - link: (scope, elem, attrs, ctrl)-> - elem.on "click", (ev)=> + link: (scope, elem, attrs, ctrl) -> + elem.on "click", (ev) => ev.stopPropagation() + params = + id: scope.enterprise.id + EnterpriseResource.relatives params, (data) => + Enterprises.addEnterprises data + scope.enterprise = Enterprises.enterprises_by_id[scope.enterprise.id] + Enterprises.dereferenceEnterprise scope.enterprise scope.modalInstance = $modal.open(controller: ctrl, templateUrl: 'enterprise_modal.html', scope: scope) diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee index 2061f95ea1..dbe092b0be 100644 --- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee +++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee @@ -1,6 +1,8 @@ Darkswarm.factory 'Dereferencer', -> new class Dereferencer - dereference: (array, data)-> + dereference: (array, data) -> if array for object, i in array - array[i] = data[object.id] + key = undefined + key = object.id if object + array[i] = data[key] diff --git a/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee b/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee new file mode 100644 index 0000000000..e66ec7c176 --- /dev/null +++ b/app/assets/javascripts/darkswarm/services/enterprise_resource.js.coffee @@ -0,0 +1,8 @@ +Darkswarm.factory 'EnterpriseResource', ($resource) -> + $resource('/enterprise/:id.json', {}, { + 'relatives': + method: 'GET' + url: '/enterprises/:id/relatives.json' + isArray: true + cache: true + }) diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 2dddfbc7ef..b030c6e723 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope)-> +Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, visibleFilter, Matcher, Geo, $rootScope) -> new class Enterprises enterprises_by_id: {} constructor: -> @@ -20,14 +20,32 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, if CurrentHub.hub?.id CurrentHub.hub = @enterprises_by_id[CurrentHub.hub.id] for enterprise in @enterprises - Dereferencer.dereference enterprise.hubs, @enterprises_by_id - Dereferencer.dereference enterprise.producers, @enterprises_by_id + @dereferenceEnterprise enterprise + + dereferenceEnterprise: (enterprise) -> + # keep a backup of enterprise ids + # in case we dereference again after adding more enterprises + if enterprise.hub_references + enterprise.hubs = enterprise.hub_references.slice() + else + enterprise.hub_references = enterprise.hubs.slice() + if enterprise.producer_references + enterprise.producers = enterprise.producer_references.slice() + else + enterprise.producer_references = enterprise.producers.slice() + Dereferencer.dereference enterprise.hubs, @enterprises_by_id + Dereferencer.dereference enterprise.producers, @enterprises_by_id dereferenceTaxons: -> for enterprise in @enterprises Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id + addEnterprises: (new_enterprises) -> + return unless new_enterprises && new_enterprises.length + for enterprise in new_enterprises + @enterprises_by_id[enterprise.id] = enterprise + flagMatching: (query) -> for enterprise in @enterprises enterprise.matches_name_query = if query? && query.length > 0 diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 7f627ec73a..83d7c42f62 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -1,3 +1,5 @@ +require 'open_food_network/enterprise_injection_data' + class EnterprisesController < BaseController layout "darkswarm" helper Spree::ProductsHelper @@ -11,11 +13,21 @@ class EnterprisesController < BaseController respond_to :js, only: :permalink_checker + def relatives + respond_to do |format| + format.json do + enterprises = Enterprise.find(params[:id]).andand.relatives.activated + render(json: enterprises, + each_serializer: Api::EnterpriseSerializer, + data: OpenFoodNetwork::EnterpriseInjectionData.new) + end + end + end def check_permalink return render text: params[:permalink], status: 409 if Enterprise.find_by_permalink params[:permalink] - path = Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" ) + path = Rails.application.routes.recognize_path("/#{params[:permalink].to_s}") if path && path[:controller] == "cms_content" render text: params[:permalink], status: 200 else @@ -23,7 +35,6 @@ class EnterprisesController < BaseController end end - private def clean_permalink diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index 50b9c93fca..d76f37bf62 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -5,6 +5,10 @@ module InjectionHelper inject_json_ams "enterprises", Enterprise.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data end + def inject_shop_enterprises + inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data + end + def inject_group_enterprises inject_json_ams "group_enterprises", @group.enterprises.activated.all, Api::EnterpriseSerializer, enterprise_injection_data end diff --git a/app/views/enterprises/shop.html.haml b/app/views/enterprises/shop.html.haml index d635f68164..569009db09 100644 --- a/app/views/enterprises/shop.html.haml +++ b/app/views/enterprises/shop.html.haml @@ -5,7 +5,7 @@ - content_for(:image) do = current_distributor.logo.url -= inject_enterprises += inject_shop_enterprises %shop.darkswarm - content_for :order_cycle_form do diff --git a/config/routes.rb b/config/routes.rb index f1b96de181..cd7c7780c4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,6 +55,7 @@ Openfoodnetwork::Application.routes.draw do member do get :shop + get :relatives end end get '/:id/shop', to: 'enterprises#shop', as: 'enterprise_shop' From 08fdc8a5bd6907da7a482009af7870f0e01e3720 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 29 Jun 2016 12:30:43 +1000 Subject: [PATCH 03/77] Load producers of all or selected order cycles into shop --- .../filters/filter_products.js.coffee | 6 +++--- .../darkswarm/services/dereferencer.js.coffee | 18 +++++++++++++----- .../darkswarm/services/enterprises.js.coffee | 18 +++++++----------- app/helpers/injection_helper.rb | 7 ++++++- app/models/enterprise.rb | 16 ++++++++++++++++ .../consumer/shopping/shopping_spec.rb | 18 +++++++++--------- spec/support/request/shop_workflow.rb | 9 +++++++++ 7 files changed, 63 insertions(+), 29 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee index c01a941659..f65c8854dc 100644 --- a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee @@ -1,7 +1,7 @@ -Darkswarm.filter 'products', (Matcher)-> - (products, text)-> +Darkswarm.filter 'products', (Matcher) -> + (products, text) -> products ||= [] text ?= "" - products.filter (product)=> + products.filter (product) => propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name] Matcher.match propertiesToMatch, text diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee index dbe092b0be..40f195c6f5 100644 --- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee +++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee @@ -1,8 +1,16 @@ Darkswarm.factory 'Dereferencer', -> new class Dereferencer dereference: (array, data) -> - if array - for object, i in array - key = undefined - key = object.id if object - array[i] = data[key] + @dereference_from(array, array, data) + + dereference_from: (source, target, data) -> + unreferenced = [] + if source && target + for object, i in source + key = if object then object.id else undefined + if data.hasOwnProperty(key) + target[i] = data[key] + else + delete target[i] + unreferenced[i] = source[i] + unreferenced diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index b030c6e723..6473b58442 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -23,18 +23,14 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, @dereferenceEnterprise enterprise dereferenceEnterprise: (enterprise) -> - # keep a backup of enterprise ids + # keep unreferenced enterprise ids # in case we dereference again after adding more enterprises - if enterprise.hub_references - enterprise.hubs = enterprise.hub_references.slice() - else - enterprise.hub_references = enterprise.hubs.slice() - if enterprise.producer_references - enterprise.producers = enterprise.producer_references.slice() - else - enterprise.producer_references = enterprise.producers.slice() - Dereferencer.dereference enterprise.hubs, @enterprises_by_id - Dereferencer.dereference enterprise.producers, @enterprises_by_id + hubs = enterprise.unreferenced_hubs || enterprise.hubs + enterprise.unreferenced_hubs = + Dereferencer.dereference_from hubs, enterprise.hubs, @enterprises_by_id + producers = enterprise.unreferenced_producers || enterprise.producers + enterprise.unreferenced_producers = + Dereferencer.dereference_from producers, enterprise.producers, @enterprises_by_id dereferenceTaxons: -> for enterprise in @enterprises diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index d76f37bf62..6432597632 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -6,7 +6,12 @@ module InjectionHelper end def inject_shop_enterprises - inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data + ocs = if current_order_cycle + [current_order_cycle] + else + OrderCycle.not_closed.with_distributor(current_distributor) + end + inject_json_ams "enterprises", current_distributor.relatives_and_oc_producers(ocs).activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data end def inject_group_enterprises diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 554529d7f2..eca5a44da2 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -220,6 +220,22 @@ class Enterprise < ActiveRecord::Base ", self.id, self.id) end + def relatives_and_oc_producers(order_cycles) + enterprise_ids = [] + order_cycles.each do |oc| + enterprise_ids += oc.exchanges.incoming.pluck :sender_id + end + Enterprise.where(" + enterprises.id IN + (SELECT child_id FROM enterprise_relationships WHERE enterprise_relationships.parent_id=?) + OR enterprises.id IN + (SELECT parent_id FROM enterprise_relationships WHERE enterprise_relationships.child_id=?) + OR enterprises.id IN + (?) + OR enterprises.id = ? + ", id, id, enterprise_ids, id) + end + def relatives_including_self Enterprise.where(id: relatives.pluck(:id) | [id]) end diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 7dc9f474da..b449b4d083 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -34,7 +34,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "shows the producers for a distributor" do exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) - exchange.variants << variant + add_variant_to_order_cycle(exchange, variant) visit shop_path find("#tab_producers a").click @@ -68,7 +68,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "shows products after selecting an order cycle" do variant.update_attribute(:display_name, "kitten") variant.update_attribute(:display_as, "rabbit") - exchange1.variants << variant ## add product to exchange + add_variant_to_order_cycle(exchange1, variant) visit shop_path page.should_not have_content product.name Spree::Order.last.order_cycle.should == nil @@ -89,8 +89,8 @@ feature "As a consumer I want to shop with a distributor", js: true do it "shows the correct fees after selecting and changing an order cycle" do enterprise_fee = create(:enterprise_fee, amount: 1001) exchange2.enterprise_fees << enterprise_fee - exchange2.variants << variant - exchange1.variants << variant + add_variant_to_order_cycle(exchange2, variant) + add_variant_to_order_cycle(exchange1, variant) # -- Selecting an order cycle visit shop_path @@ -116,8 +116,8 @@ feature "As a consumer I want to shop with a distributor", js: true do describe "declining to clear the cart" do before do - exchange2.variants << variant - exchange1.variants << variant + add_variant_to_order_cycle(exchange2, variant) + add_variant_to_order_cycle(exchange1, variant) visit shop_path select "turtles", from: "order_cycle_id" @@ -147,9 +147,9 @@ feature "As a consumer I want to shop with a distributor", js: true do before do exchange.update_attribute :pickup_time, "frogs" - exchange.variants << variant - exchange.variants << variant1 - exchange.variants << variant2 + add_variant_to_order_cycle(exchange, variant) + add_variant_to_order_cycle(exchange, variant1) + add_variant_to_order_cycle(exchange, variant2) order.order_cycle = oc1 end diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index 279ead2630..d7654617e1 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -29,6 +29,15 @@ module ShopWorkflow end def add_variant_to_order_cycle(exchange, variant) + oc = exchange.order_cycle + supplier = variant.product.supplier + # An order cycle needs an incoming exchange for a supplier + # before having its products. Otherwise the data will be inconsistent and + # and not all needed enterprises are loaded into the shop page. + if oc.exchanges.from_enterprise(supplier).incoming.empty? + create(:exchange, order_cycle: oc, incoming: true, + sender: supplier, receiver: oc.coordinator) + end exchange.variants << variant end From c253d73d1195bf501c52c7282b4e8bcb26751075 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 29 Jun 2016 15:46:51 +1000 Subject: [PATCH 04/77] Refactoring with feedback on pr #1073 --- .../darkswarm/services/dereferencer.js.coffee | 2 +- app/controllers/enterprises_controller.rb | 3 ++- app/models/enterprise.rb | 25 +++++++++---------- spec/support/request/shop_workflow.rb | 23 ++++++++++------- 4 files changed, 29 insertions(+), 24 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee index 40f195c6f5..b4817e0e2d 100644 --- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee +++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee @@ -7,7 +7,7 @@ Darkswarm.factory 'Dereferencer', -> unreferenced = [] if source && target for object, i in source - key = if object then object.id else undefined + key = object?.id if data.hasOwnProperty(key) target[i] = data[key] else diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 83d7c42f62..70d240abd1 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -16,7 +16,8 @@ class EnterprisesController < BaseController def relatives respond_to do |format| format.json do - enterprises = Enterprise.find(params[:id]).andand.relatives.activated + enterprise = Enterprise.find(params[:id]) + enterprises = enterprise.andand.relatives.andand.activated render(json: enterprises, each_serializer: Api::EnterpriseSerializer, data: OpenFoodNetwork::EnterpriseInjectionData.new) diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index eca5a44da2..ef11c97e49 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -176,6 +176,16 @@ class Enterprise < ActiveRecord::Base joins(:enterprise_roles).where('enterprise_roles.user_id = ?', user.id) end } + scope :relatives_of_one_union_others, lambda { |one, others| + where(" + enterprises.id IN + (SELECT child_id FROM enterprise_relationships WHERE enterprise_relationships.parent_id=?) + OR enterprises.id IN + (SELECT parent_id FROM enterprise_relationships WHERE enterprise_relationships.child_id=?) + OR enterprises.id IN + (?) + ", one, one, others) + } # Force a distinct count to work around relation count issue https://github.com/rails/rails/issues/5554 def self.distinct_count @@ -221,19 +231,8 @@ class Enterprise < ActiveRecord::Base end def relatives_and_oc_producers(order_cycles) - enterprise_ids = [] - order_cycles.each do |oc| - enterprise_ids += oc.exchanges.incoming.pluck :sender_id - end - Enterprise.where(" - enterprises.id IN - (SELECT child_id FROM enterprise_relationships WHERE enterprise_relationships.parent_id=?) - OR enterprises.id IN - (SELECT parent_id FROM enterprise_relationships WHERE enterprise_relationships.child_id=?) - OR enterprises.id IN - (?) - OR enterprises.id = ? - ", id, id, enterprise_ids, id) + enterprise_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id + Enterprise.relatives_of_one_union_others(id, enterprise_ids) end def relatives_including_self diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index d7654617e1..01c24bee05 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -29,19 +29,24 @@ module ShopWorkflow end def add_variant_to_order_cycle(exchange, variant) - oc = exchange.order_cycle - supplier = variant.product.supplier - # An order cycle needs an incoming exchange for a supplier - # before having its products. Otherwise the data will be inconsistent and - # and not all needed enterprises are loaded into the shop page. - if oc.exchanges.from_enterprise(supplier).incoming.empty? - create(:exchange, order_cycle: oc, incoming: true, - sender: supplier, receiver: oc.coordinator) - end + ensure_supplier_exchange(exchange, variant.product.supplier) exchange.variants << variant end def set_order_cycle(order, order_cycle) order.update_attribute(:order_cycle, order_cycle) end + + private + + # An order cycle needs an incoming exchange for a supplier + # before having its products. Otherwise the data will be inconsistent and + # and not all needed enterprises are loaded into the shop page. + def ensure_supplier_exchange(exchange, supplier) + oc = exchange.order_cycle + if oc.exchanges.from_enterprise(supplier).incoming.empty? + create(:exchange, order_cycle: oc, incoming: true, + sender: supplier, receiver: oc.coordinator) + end + end end From 320db21d5c4e41e4f370be3ffbbae113eefe4849 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 29 Jun 2016 16:30:11 +0100 Subject: [PATCH 05/77] =?UTF-8?q?Updating=20spec=20with=20$=20(not=20?= =?UTF-8?q?=C2=A3)=20for=20automated=20testing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...usiness_model_configuration_helper_spec.rb | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/spec/helpers/admin/business_model_configuration_helper_spec.rb b/spec/helpers/admin/business_model_configuration_helper_spec.rb index 6f035c05e5..632aec302b 100644 --- a/spec/helpers/admin/business_model_configuration_helper_spec.rb +++ b/spec/helpers/admin/business_model_configuration_helper_spec.rb @@ -20,12 +20,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES PER MONTH, PLUS GST" } end end @@ -34,12 +34,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } end end end @@ -52,7 +52,7 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do @@ -77,7 +77,7 @@ describe Admin::BusinessModelConfigurationHelper do end end - context "when minimum billable turnover is £100" do + context "when minimum billable turnover is $100" do before { Spree::Config.set(:minimum_billable_turnover, 100) } context "when a fixed cost is included" do @@ -88,12 +88,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH, PLUS GST" } end end @@ -102,12 +102,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH, PLUS GST" } end end end @@ -120,12 +120,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH, PLUS GST" } end end @@ -160,12 +160,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES PER MONTH" } end end @@ -174,12 +174,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } end end end @@ -192,7 +192,7 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do @@ -217,7 +217,7 @@ describe Admin::BusinessModelConfigurationHelper do end end - context "when minimum billable turnover is £100" do + context "when minimum billable turnover is $100" do before { Spree::Config.set(:minimum_billable_turnover, 100) } context "when a fixed cost is included" do @@ -228,12 +228,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH" } end end @@ -242,12 +242,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "£10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "$10 PER MONTH" } end end end @@ -260,12 +260,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH" } end end @@ -304,12 +304,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES PER MONTH, PLUS GST" } end end @@ -318,12 +318,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH, PLUS GST" } end end end @@ -336,7 +336,7 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do @@ -361,7 +361,7 @@ describe Admin::BusinessModelConfigurationHelper do end end - context "when minimum billable turnover is £100" do + context "when minimum billable turnover is $100" do before { Spree::Config.set(:minimum_billable_turnover, 100) } context "when a fixed cost is included" do @@ -372,12 +372,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH, PLUS GST" } end end @@ -386,12 +386,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH, PLUS GST" } end end end @@ -404,12 +404,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH, PLUS GST" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH, PLUS GST" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH, PLUS GST" } end end @@ -444,12 +444,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES PER MONTH" } end end @@ -458,12 +458,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH" } end end end @@ -476,7 +476,7 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do @@ -501,7 +501,7 @@ describe Admin::BusinessModelConfigurationHelper do end end - context "when minimum billable turnover is £100" do + context "when minimum billable turnover is $100" do before { Spree::Config.set(:minimum_billable_turnover, 100) } context "when a fixed cost is included" do @@ -512,12 +512,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 + 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH" } end end @@ -526,12 +526,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN £10 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN $10 PER MONTH" } end end end @@ -544,12 +544,12 @@ describe Admin::BusinessModelConfigurationHelper do context "when the bill is capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 20) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100, CAPPED AT £20 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS $100, CAPPED AT $20 PER MONTH" } end context "when the bill is not capped" do before { Spree::Config.set(:account_invoices_monthly_cap, 0) } - it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS £100 PER MONTH" } + it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS $100 PER MONTH" } end end From e8b83bef416c58a4f17a6de3819c9ed5996a6fde Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 30 Jun 2016 11:54:59 +1000 Subject: [PATCH 06/77] Simplify responding to search --- .../darkswarm/directives/map_search.js.coffee | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index e67ce529a5..3e546b82b3 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -29,18 +29,11 @@ Darkswarm.directive 'mapSearch', ($timeout)-> google.maps.event.addListener searchBox, "places_changed", -> places = searchBox.getPlaces() - return if places.length is 0 - # For each place, get the icon, place name, and location. - markers = [] - bounds = new google.maps.LatLngBounds() - for place in places - #map.setCenter place.geometry.location + for place in places when place.geometry.viewport? map.fitBounds place.geometry.viewport - #map.fitBounds bounds # Bias the SearchBox results towards places that are within the bounds of the # current map's viewport. google.maps.event.addListener map, "bounds_changed", -> bounds = map.getBounds() searchBox.setBounds bounds - From 54028f4e7ea6d3c8586298b23a361d7c40c7dd7d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 30 Jun 2016 12:03:48 +1000 Subject: [PATCH 07/77] Split directive into functions --- .../darkswarm/directives/map_search.js.coffee | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index 3e546b82b3..cb9dce98b4 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -1,18 +1,27 @@ -Darkswarm.directive 'mapSearch', ($timeout)-> +Darkswarm.directive 'mapSearch', ($timeout) -> # Install a basic search field in a map restrict: 'E' require: '^googleMap' replace: true template: '' - link: (scope, elem, attrs, ctrl)-> + scope: {} + link: (scope, elem, attrs, ctrl) -> $timeout => map = ctrl.getMap() - # Use OSM tiles server - map.mapTypes.set 'OSM', new (google.maps.ImageMapType)( + # Does this *really* belong here? It's not about search. + scope.useOsmTiles map + + searchBox = scope.createSearchBox map + scope.respondToSearch map, searchBox + scope.biasResults map, searchBox + + + scope.useOsmTiles = (map) -> + map.mapTypes.set 'OSM', new google.maps.ImageMapType getTileUrl: (coord, zoom) -> # "Wrap" x (logitude) at 180th meridian properly - # NB: Don't touch coord.x because coord param is by reference, and changing its x property breakes something in Google's lib + # NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib tilesPerGlobe = 1 << zoom x = coord.x % tilesPerGlobe if x < 0 @@ -21,19 +30,22 @@ Darkswarm.directive 'mapSearch', ($timeout)-> 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png' tileSize: new (google.maps.Size)(256, 256) name: 'OpenStreetMap' - maxZoom: 18) + maxZoom: 18 - input = (document.getElementById("pac-input")) + scope.createSearchBox = (map) -> + input = document.getElementById("pac-input") map.controls[google.maps.ControlPosition.TOP_LEFT].push input - searchBox = new google.maps.places.SearchBox((input)) + return new google.maps.places.SearchBox(input) + scope.respondToSearch = (map, searchBox) -> google.maps.event.addListener searchBox, "places_changed", -> places = searchBox.getPlaces() for place in places when place.geometry.viewport? map.fitBounds place.geometry.viewport - # Bias the SearchBox results towards places that are within the bounds of the - # current map's viewport. + # Bias the SearchBox results towards places that are within the bounds of the + # current map's viewport. + scope.biasResults = (map, searchBox) -> google.maps.event.addListener map, "bounds_changed", -> bounds = map.getBounds() searchBox.setBounds bounds From f586dbc3e19acd8b8fbafb832dfb7e3bea8d61a7 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 30 Jun 2016 12:14:47 +1000 Subject: [PATCH 08/77] Extract OSM tile setup to own directive --- .../directives/map_osm_tiles.js.coffee | 21 +++++++++++++++++++ .../darkswarm/directives/map_search.js.coffee | 18 ---------------- app/views/groups/show.html.haml | 1 + app/views/map/index.html.haml | 1 + 4 files changed, 23 insertions(+), 18 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee diff --git a/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee new file mode 100644 index 0000000000..9df5fd0d4b --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee @@ -0,0 +1,21 @@ +Darkswarm.directive 'mapOsmTiles', ($timeout) -> + restrict: 'E' + require: '^googleMap' + scope: {} + link: (scope, elem, attrs, ctrl) -> + $timeout => + map = ctrl.getMap() + + map.mapTypes.set 'OSM', new google.maps.ImageMapType + getTileUrl: (coord, zoom) -> + # "Wrap" x (logitude) at 180th meridian properly + # NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib + tilesPerGlobe = 1 << zoom + x = coord.x % tilesPerGlobe + if x < 0 + x = tilesPerGlobe + x + # Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll + 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png' + tileSize: new (google.maps.Size)(256, 256) + name: 'OpenStreetMap' + maxZoom: 18 diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index cb9dce98b4..6f8aef6dc8 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -9,29 +9,11 @@ Darkswarm.directive 'mapSearch', ($timeout) -> $timeout => map = ctrl.getMap() - # Does this *really* belong here? It's not about search. - scope.useOsmTiles map - searchBox = scope.createSearchBox map scope.respondToSearch map, searchBox scope.biasResults map, searchBox - scope.useOsmTiles = (map) -> - map.mapTypes.set 'OSM', new google.maps.ImageMapType - getTileUrl: (coord, zoom) -> - # "Wrap" x (logitude) at 180th meridian properly - # NB: Don't touch coord.x because coord param is by reference, and changing its x property breaks something in Google's lib - tilesPerGlobe = 1 << zoom - x = coord.x % tilesPerGlobe - if x < 0 - x = tilesPerGlobe + x - # Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll - 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png' - tileSize: new (google.maps.Size)(256, 256) - name: 'OpenStreetMap' - maxZoom: 18 - scope.createSearchBox = (map) -> input = document.getElementById("pac-input") map.controls[google.maps.ControlPosition.TOP_LEFT].push input diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index af497a4195..a21bdb7460 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -40,6 +40,7 @@ .map-container %map{"ng-if" => "(isActive(\'/map\') && (mapShowed = true)) || mapShowed"} %google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"} + %map-osm-tiles %map-search %markers{models: "mapMarkers", fit: "true", coords: "'self'", icon: "'icon'", click: "'reveal'"} diff --git a/app/views/map/index.html.haml b/app/views/map/index.html.haml index e4a22e540c..75bb99f9d7 100644 --- a/app/views/map/index.html.haml +++ b/app/views/map/index.html.haml @@ -6,6 +6,7 @@ .map-container{"fill-vertical" => true} %map{"ng-controller" => "MapCtrl"} %google-map{options: "map.additional_options", center: "map.center", zoom: "map.zoom", styles: "map.styles", draggable: "true"} + %map-osm-tiles %map-search %markers{models: "OfnMap.enterprises", fit: "true", coords: "'self'", icon: "'icon'", click: "'reveal'"} From a9a68151ec3f96c00e9f57bfe1b7eae425319897 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 30 Jun 2016 12:15:40 +1000 Subject: [PATCH 09/77] Syntax --- .../javascripts/darkswarm/directives/map_osm_tiles.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee index 9df5fd0d4b..0dcda8f59a 100644 --- a/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_osm_tiles.js.coffee @@ -16,6 +16,6 @@ Darkswarm.directive 'mapOsmTiles', ($timeout) -> x = tilesPerGlobe + x # Wrap y (latitude) in a like manner if you want to enable vertical infinite scroll 'http://tile.openstreetmap.org/' + zoom + '/' + x + '/' + coord.y + '.png' - tileSize: new (google.maps.Size)(256, 256) + tileSize: new google.maps.Size(256, 256) name: 'OpenStreetMap' maxZoom: 18 From e6bdd2303d6b5653b77f274d3bf60cc1df0c6294 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 1 Jul 2016 13:32:14 +1000 Subject: [PATCH 10/77] Extract showing search result --- .../darkswarm/directives/map_search.js.coffee | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index 6f8aef6dc8..7a3e633384 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -10,7 +10,7 @@ Darkswarm.directive 'mapSearch', ($timeout) -> map = ctrl.getMap() searchBox = scope.createSearchBox map - scope.respondToSearch map, searchBox + scope.bindSearchResponse map, searchBox scope.biasResults map, searchBox @@ -19,11 +19,16 @@ Darkswarm.directive 'mapSearch', ($timeout) -> map.controls[google.maps.ControlPosition.TOP_LEFT].push input return new google.maps.places.SearchBox(input) - scope.respondToSearch = (map, searchBox) -> - google.maps.event.addListener searchBox, "places_changed", -> - places = searchBox.getPlaces() - for place in places when place.geometry.viewport? - map.fitBounds place.geometry.viewport + scope.bindSearchResponse = (map, searchBox) -> + google.maps.event.addListener searchBox, "places_changed", => + scope.showSearchResult map, searchBox + + scope.showSearchResult = (map, searchBox) -> + places = searchBox.getPlaces() + for place in places when place.geometry.viewport? + map.fitBounds place.geometry.viewport + scope.$apply -> + model.$setViewValue elem.val() # Bias the SearchBox results towards places that are within the bounds of the # current map's viewport. From 34b2f72ae8ecd3cafa80f34e074208103fef2938 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 1 Jul 2016 15:30:55 +1000 Subject: [PATCH 11/77] When query changed (typing or autocomplete), update URL. When page loads, perform query search. --- .../darkswarm/directives/map_search.js.coffee | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index 7a3e633384..a074539a23 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -1,23 +1,33 @@ -Darkswarm.directive 'mapSearch', ($timeout) -> +Darkswarm.directive 'mapSearch', ($timeout, Search) -> # Install a basic search field in a map restrict: 'E' - require: '^googleMap' + require: ['^googleMap', 'ngModel'] replace: true - template: '' + template: '' scope: {} - link: (scope, elem, attrs, ctrl) -> + + controller: ($scope) -> + $scope.query = Search.search() + + $scope.$watch 'query', (query) -> + Search.search query + + + link: (scope, elem, attrs, ctrls) -> + [ctrl, model] = ctrls + scope.input = document.getElementById("pac-input") + $timeout => map = ctrl.getMap() searchBox = scope.createSearchBox map scope.bindSearchResponse map, searchBox scope.biasResults map, searchBox - + scope.performUrlSearch map scope.createSearchBox = (map) -> - input = document.getElementById("pac-input") - map.controls[google.maps.ControlPosition.TOP_LEFT].push input - return new google.maps.places.SearchBox(input) + map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input + return new google.maps.places.SearchBox(scope.input) scope.bindSearchResponse = (map, searchBox) -> google.maps.event.addListener searchBox, "places_changed", => @@ -30,6 +40,12 @@ Darkswarm.directive 'mapSearch', ($timeout) -> scope.$apply -> model.$setViewValue elem.val() + # When the map loads, and we have a search from ?query, perform that search + scope.performUrlSearch = (map) -> + google.maps.event.addListener map, "tilesloaded", => + google.maps.event.trigger(scope.input, 'focus'); + google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13}); + # Bias the SearchBox results towards places that are within the bounds of the # current map's viewport. scope.biasResults = (map, searchBox) -> From d6f21b24dac649b52082cb2ab6b52a6ea710803e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 11:04:36 +1000 Subject: [PATCH 12/77] Add specs for producers and shops search by URL --- spec/features/consumer/producers_spec.rb | 69 ++++++++++-------- spec/features/consumer/shops_spec.rb | 90 ++++++++++++++---------- 2 files changed, 91 insertions(+), 68 deletions(-) diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 634350af18..5c89a23529 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -27,45 +27,54 @@ feature %q{ producer1.set_producer_property 'Local', 'Victoria' producer2.set_producer_property 'Fair Trade', 'FT123' - - visit producers_path end - it "filters by taxon" do - toggle_filters - - toggle_filter 'Vegetables' - - page.should_not have_content producer1.name - page.should have_content producer2.name - - toggle_filter 'Vegetables' - toggle_filter 'Fruit' - - page.should have_content producer1.name - page.should_not have_content producer2.name + it "searches by URL" do + visit producers_path(anchor: "/?query=xyzzy") + expect(page).to have_content "Sorry, no results found for xyzzy" end - it "shows all producers with expandable details" do - page.should have_content producer1.name - expand_active_table_node producer1.name + context "on the producers page" do + before do + visit producers_path + end - # -- Taxons - page.should have_content 'Fruit' + it "filters by taxon" do + toggle_filters - # -- Properties - page.should have_content 'Organic' # Product property - page.should have_content 'Local' # Producer property - end + toggle_filter 'Vegetables' - it "doesn't show invisible producers" do - page.should_not have_content invisible_producer.name - end + page.should_not have_content producer1.name + page.should have_content producer2.name - it "links to places to buy produce" do - expand_active_table_node producer1.name - page.should have_link shop.name + toggle_filter 'Vegetables' + toggle_filter 'Fruit' + + page.should have_content producer1.name + page.should_not have_content producer2.name + end + + it "shows all producers with expandable details" do + page.should have_content producer1.name + expand_active_table_node producer1.name + + # -- Taxons + page.should have_content 'Fruit' + + # -- Properties + page.should have_content 'Organic' # Product property + page.should have_content 'Local' # Producer property + end + + it "doesn't show invisible producers" do + page.should_not have_content invisible_producer.name + end + + it "links to places to buy produce" do + expand_active_table_node producer1.name + page.should have_link shop.name + end end diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index 8b1a709462..0c5d3d7e09 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -14,56 +14,70 @@ feature 'Shops', js: true do before do producer.set_producer_property 'Organic', 'NASAA 12345' - visit shops_path end - it "shows hubs" do - page.should have_content distributor.name - expand_active_table_node distributor.name - page.should have_content "OUR PRODUCERS" + it "searches by URL" do + visit shops_path(anchor: "/?query=xyzzy") + expect(page).to have_content "Sorry, no results found for xyzzy" end - it "does not show invisible hubs" do - page.should_not have_content invisible_distributor.name - end - it "should not show hubs that are not in an order cycle" do - create(:simple_product, distributors: [d1, d2]) - visit shops_path - page.should have_no_selector 'hub.inactive' - page.should have_no_selector 'hub', text: d2.name - end + context "on the shops path" do + before do + visit shops_path + end - it "should show closed shops after clicking the button" do - create(:simple_product, distributors: [d1, d2]) - visit shops_path - click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' }) - page.should have_selector 'hub.inactive', text: d2.name - end - - it "should link to the hub page" do - follow_active_table_node distributor.name - expect(page).to have_current_path enterprise_shop_path(distributor) - end - - describe "hub producer modal" do - let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) } - let!(:taxon) { create(:taxon, name: 'Fruit') } - let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } - - it "should show hub producer modals" do + it "shows hubs" do + page.should have_content distributor.name expand_active_table_node distributor.name - expect(page).to have_content producer.name - open_enterprise_modal producer - modal_should_be_open_for producer + page.should have_content "OUR PRODUCERS" + end - within ".reveal-modal" do - expect(page).to have_content 'Fruit' # Taxon - expect(page).to have_content 'Organic' # Producer property + it "does not show invisible hubs" do + page.should_not have_content invisible_distributor.name + end + + it "should not show hubs that are not in an order cycle" do + create(:simple_product, distributors: [d1, d2]) + visit shops_path + page.should have_no_selector 'hub.inactive' + page.should have_no_selector 'hub', text: d2.name + end + + it "should show closed shops after clicking the button" do + create(:simple_product, distributors: [d1, d2]) + visit shops_path + click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' }) + page.should have_selector 'hub.inactive', text: d2.name + end + + it "should link to the hub page" do + follow_active_table_node distributor.name + expect(page).to have_current_path enterprise_shop_path(distributor) + end + + describe "hub producer modal" do + let!(:product) { create(:simple_product, supplier: producer, taxons: [taxon]) } + let!(:taxon) { create(:taxon, name: 'Fruit') } + let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], coordinator: create(:distributor_enterprise), variants: [product.variants.first]) } + + it "should show hub producer modals" do + expand_active_table_node distributor.name + expect(page).to have_content producer.name + open_enterprise_modal producer + modal_should_be_open_for producer + + within ".reveal-modal" do + expect(page).to have_content 'Fruit' # Taxon + expect(page).to have_content 'Organic' # Producer property + end end end end + + private + def click_link_and_ensure(link_text, check) # Buttons appear to be unresponsive for a while, so keep clicking them until content appears using_wait_time 0.5 do From f09cd9e47730dac322fe721e58b45173df0125aa Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 11:04:53 +1000 Subject: [PATCH 13/77] Allow groups to be searched by URL --- .../darkswarm/controllers/groups_controller.js.coffee | 6 +++++- spec/features/consumer/groups_spec.rb | 6 +++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee index 8fd47c49f8..91cbe0bf54 100644 --- a/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/groups_controller.js.coffee @@ -1,3 +1,7 @@ -Darkswarm.controller "GroupsCtrl", ($scope, Groups) -> +Darkswarm.controller "GroupsCtrl", ($scope, Groups, Search) -> $scope.Groups = Groups $scope.order = 'position' + $scope.query = Search.search() + + $scope.$watch "query", (query)-> + Search.search query diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb index e51ac39ea2..5ea96ac17e 100644 --- a/spec/features/consumer/groups_spec.rb +++ b/spec/features/consumer/groups_spec.rb @@ -12,8 +12,8 @@ feature 'Groups', js: true do page.should have_content group.name end - it "renders enterprise modals for groups" do - visit groups_path - page.should have_content group.name + it "searches by URL" do + visit groups_path(anchor: "/?query=xyzzy") + expect(page).to have_content "No groups found" end end From f984871b23e262fa00a67ae6b7765c62073d4b9c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 6 Jul 2016 11:14:13 +1000 Subject: [PATCH 14/77] Inject only needed enterprises into cart and checkout --- app/helpers/injection_helper.rb | 4 ++++ app/models/enterprise.rb | 4 ++-- app/views/checkout/edit.html.haml | 2 +- app/views/spree/orders/edit.html.haml | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index 6432597632..032aee2cf7 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -5,6 +5,10 @@ module InjectionHelper inject_json_ams "enterprises", Enterprise.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data end + def inject_enterprise_and_relatives + inject_json_ams "enterprises", current_distributor.relatives_including_self.activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data + end + def inject_shop_enterprises ocs = if current_order_cycle [current_order_cycle] diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index ef11c97e49..3802468ee9 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -231,8 +231,8 @@ class Enterprise < ActiveRecord::Base end def relatives_and_oc_producers(order_cycles) - enterprise_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id - Enterprise.relatives_of_one_union_others(id, enterprise_ids) + oc_producer_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id + Enterprise.relatives_of_one_union_others(id, oc_producer_ids) end def relatives_including_self diff --git a/app/views/checkout/edit.html.haml b/app/views/checkout/edit.html.haml index f0bef536db..b3d30ed442 100644 --- a/app/views/checkout/edit.html.haml +++ b/app/views/checkout/edit.html.haml @@ -1,7 +1,7 @@ - content_for(:title) do = t :checkout_title -= inject_enterprises += inject_enterprise_and_relatives .darkswarm.footer-pad - content_for :order_cycle_form do diff --git a/app/views/spree/orders/edit.html.haml b/app/views/spree/orders/edit.html.haml index 2fa5c043db..3417eb5e6a 100644 --- a/app/views/spree/orders/edit.html.haml +++ b/app/views/spree/orders/edit.html.haml @@ -1,7 +1,7 @@ - content_for(:title) do = t :orders_edit_title -= inject_enterprises += inject_enterprise_and_relatives .darkswarm - content_for :order_cycle_form do From d3c423f7ce7f75751c0e042227a6c00fb86a94ce Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 11:56:41 +1000 Subject: [PATCH 15/77] Only perform URL search once, not every time map tiles change --- .../javascripts/darkswarm/directives/map_search.js.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee index a074539a23..af82766d62 100644 --- a/app/assets/javascripts/darkswarm/directives/map_search.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/map_search.js.coffee @@ -42,7 +42,7 @@ Darkswarm.directive 'mapSearch', ($timeout, Search) -> # When the map loads, and we have a search from ?query, perform that search scope.performUrlSearch = (map) -> - google.maps.event.addListener map, "tilesloaded", => + google.maps.event.addListenerOnce map, "idle", => google.maps.event.trigger(scope.input, 'focus'); google.maps.event.trigger(scope.input, 'keydown', {keyCode: 13}); From f733c7f20795090dd2d875ca32f2906d3aed722d Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 6 Jul 2016 12:45:12 +1000 Subject: [PATCH 16/77] Include shop enterprise on shop front --- app/helpers/injection_helper.rb | 2 +- app/models/enterprise.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/helpers/injection_helper.rb b/app/helpers/injection_helper.rb index 032aee2cf7..6db2e583bc 100644 --- a/app/helpers/injection_helper.rb +++ b/app/helpers/injection_helper.rb @@ -15,7 +15,7 @@ module InjectionHelper else OrderCycle.not_closed.with_distributor(current_distributor) end - inject_json_ams "enterprises", current_distributor.relatives_and_oc_producers(ocs).activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data + inject_json_ams "enterprises", current_distributor.plus_relatives_and_oc_producers(ocs).activated.includes(address: :state).all, Api::EnterpriseSerializer, enterprise_injection_data end def inject_group_enterprises diff --git a/app/models/enterprise.rb b/app/models/enterprise.rb index 3802468ee9..80414d5116 100644 --- a/app/models/enterprise.rb +++ b/app/models/enterprise.rb @@ -230,9 +230,9 @@ class Enterprise < ActiveRecord::Base ", self.id, self.id) end - def relatives_and_oc_producers(order_cycles) + def plus_relatives_and_oc_producers(order_cycles) oc_producer_ids = Exchange.in_order_cycle(order_cycles).incoming.pluck :sender_id - Enterprise.relatives_of_one_union_others(id, oc_producer_ids) + Enterprise.relatives_of_one_union_others(id, oc_producer_ids | [id]) end def relatives_including_self From 13c8f0a230bc24ddbc5a43ea4d69604897ae0453 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 15:29:04 +1000 Subject: [PATCH 17/77] Improve spec reliability It seems that the success message on the customers page is disappearing before the spec can detect it. This seems unlikely since it's present for 3 s, but this is my best theory right now. --- .../admin/index_utils/directives/obj_for_update.js.coffee | 2 +- spec/features/admin/customers_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee b/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee index 81cf58fd1e..18c800ce7f 100644 --- a/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee +++ b/app/assets/javascripts/admin/index_utils/directives/obj_for_update.js.coffee @@ -24,7 +24,7 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi scope.savedValue = value scope.success = -> - switchClass( element, "update-success", ["update-pending", "update-error"], 3000 ) + switchClass( element, "update-success", ["update-pending", "update-error"], 5000 ) scope.pending = -> switchClass( element, "update-pending", ["update-error", "update-success"], false ) diff --git a/spec/features/admin/customers_spec.rb b/spec/features/admin/customers_spec.rb index 61caae507f..89893860df 100644 --- a/spec/features/admin/customers_spec.rb +++ b/spec/features/admin/customers_spec.rb @@ -60,7 +60,7 @@ feature 'Customers' do create(:order, customer: customer1) expect{ within "tr#c_#{customer1.id}" do - find("a.delete-customer").click + find("a.delete-customer").trigger('click') end expect(page).to have_selector "#info-dialog .text", text: "Delete failed: customer has associated orders" click_button "OK" @@ -115,7 +115,7 @@ feature 'Customers' do expect(customer1.tag_list).to eq [] end - it "prevents duplicate codes from being saved" do + it "prevents duplicate codes from being saved", retry: 3 do select2_select managed_distributor1.name, from: "shop_id" within "tr#c_#{customer1.id}" do From b5a9a1b6bf37021d0234c53084b454ed6732d54b Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 16:14:25 +1000 Subject: [PATCH 18/77] Add translation for business_model_configuration --- config/locales/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index e103001337..253b76a106 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -64,6 +64,7 @@ en: free: "free" plus_tax: "plus GST" total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)" + business_model_configuration: "Business model configuration" say_no: "No" say_yes: "Yes" From e3732849347a2c30fe634a6acd4727b52b6bab00 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 6 Jul 2016 16:14:32 +1000 Subject: [PATCH 19/77] Fix intermittent spec failure --- spec/features/admin/business_model_configuration_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/features/admin/business_model_configuration_spec.rb b/spec/features/admin/business_model_configuration_spec.rb index 05d5367437..ab5e4fd2e7 100644 --- a/spec/features/admin/business_model_configuration_spec.rb +++ b/spec/features/admin/business_model_configuration_spec.rb @@ -42,6 +42,7 @@ feature 'Business Model Configuration' do click_button "Update" + expect(page).to have_content "Business model configuration has been successfully updated!" expect(Spree::Config.account_invoices_monthly_fixed).to eq 10 expect(Spree::Config.account_invoices_monthly_rate).to eq 0.05 expect(Spree::Config.account_invoices_monthly_cap).to eq 30 From 8e73a2e0d6dc7bbc069927e848ea9bbf889be623 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 6 Jul 2016 16:20:07 +1000 Subject: [PATCH 20/77] Dereference enterprises and taxons later --- .../darkswarm/services/dereferencer.js.coffee | 4 +++- .../darkswarm/services/enterprises.js.coffee | 23 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee index b4817e0e2d..5265cf7e99 100644 --- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee +++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee @@ -7,10 +7,12 @@ Darkswarm.factory 'Dereferencer', -> unreferenced = [] if source && target for object, i in source + # skip empty entries in sparse array + continue unless source.hasOwnProperty(i) key = object?.id if data.hasOwnProperty(key) target[i] = data[key] else delete target[i] - unreferenced[i] = source[i] + unreferenced[i] = object unreferenced diff --git a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee index 6473b58442..73dbd1627b 100644 --- a/app/assets/javascripts/darkswarm/services/enterprises.js.coffee +++ b/app/assets/javascripts/darkswarm/services/enterprises.js.coffee @@ -9,7 +9,6 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, @enterprises_by_id[enterprise.id] = enterprise # Replace enterprise and taxons ids with actual objects. @dereferenceEnterprises() - @dereferenceTaxons() @visible_enterprises = visibleFilter @enterprises @producers = @visible_enterprises.filter (enterprise)-> enterprise.category in ["producer_hub", "producer_shop", "producer"] @@ -23,19 +22,19 @@ Darkswarm.factory 'Enterprises', (enterprises, CurrentHub, Taxons, Dereferencer, @dereferenceEnterprise enterprise dereferenceEnterprise: (enterprise) -> + @dereferenceProperty(enterprise, 'hubs', @enterprises_by_id) + @dereferenceProperty(enterprise, 'producers', @enterprises_by_id) + @dereferenceProperty(enterprise, 'taxons', Taxons.taxons_by_id) + @dereferenceProperty(enterprise, 'supplied_taxons', Taxons.taxons_by_id) + + dereferenceProperty: (enterprise, property, data) -> # keep unreferenced enterprise ids # in case we dereference again after adding more enterprises - hubs = enterprise.unreferenced_hubs || enterprise.hubs - enterprise.unreferenced_hubs = - Dereferencer.dereference_from hubs, enterprise.hubs, @enterprises_by_id - producers = enterprise.unreferenced_producers || enterprise.producers - enterprise.unreferenced_producers = - Dereferencer.dereference_from producers, enterprise.producers, @enterprises_by_id - - dereferenceTaxons: -> - for enterprise in @enterprises - Dereferencer.dereference enterprise.taxons, Taxons.taxons_by_id - Dereferencer.dereference enterprise.supplied_taxons, Taxons.taxons_by_id + enterprise.unreferenced |= {} + collection = enterprise[property] + unreferenced = enterprise.unreferenced[property] || collection + enterprise.unreferenced[property] = + Dereferencer.dereference_from unreferenced, collection, data addEnterprises: (new_enterprises) -> return unless new_enterprises && new_enterprises.length From 0ff1c95c3df495d8e35bd250e17f830bb1f56d97 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 13 Jul 2016 12:08:11 +1000 Subject: [PATCH 21/77] Keep unreferenced entries when dereferencing in js --- app/assets/javascripts/darkswarm/services/dereferencer.js.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee index 5265cf7e99..b68a716a4d 100644 --- a/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee +++ b/app/assets/javascripts/darkswarm/services/dereferencer.js.coffee @@ -13,6 +13,5 @@ Darkswarm.factory 'Dereferencer', -> if data.hasOwnProperty(key) target[i] = data[key] else - delete target[i] unreferenced[i] = object unreferenced From e693f71775e8a3e19698f0645757db5678d37b1b Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 13 Jul 2016 13:54:32 +1000 Subject: [PATCH 22/77] Inject only needed enterprises into order confirmation page --- app/views/spree/orders/show.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/orders/show.html.haml b/app/views/spree/orders/show.html.haml index 438a611a68..a802d451ea 100644 --- a/app/views/spree/orders/show.html.haml +++ b/app/views/spree/orders/show.html.haml @@ -1,7 +1,7 @@ - content_for(:title) do = t :orders_show_title -= inject_enterprises += inject_enterprise_and_relatives if current_distributor.present? .darkswarm - content_for :order_cycle_form do From af6d0ec107be635a2018c3ee63c885fcc39402d8 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 13 Jul 2016 13:54:55 +1000 Subject: [PATCH 23/77] Remove unused code from order confirmation page --- app/views/spree/orders/show.html.haml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/views/spree/orders/show.html.haml b/app/views/spree/orders/show.html.haml index a802d451ea..e4cb3b1980 100644 --- a/app/views/spree/orders/show.html.haml +++ b/app/views/spree/orders/show.html.haml @@ -4,14 +4,6 @@ = inject_enterprise_and_relatives if current_distributor.present? .darkswarm - - content_for :order_cycle_form do - %strong.avenir - = t :orders_show_time - - if @order.order_cycle - = @order.order_cycle.pickup_time_for(@order.distributor) - - else - = @order.distributor.next_collection_at - = render "shopping_shared/details" if current_distributor.present? %fieldset#order_summary.footer-pad{"data-hook" => ""} From c6bd5484132520c3a3940147f1251ed9f3d6dbf2 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 15 Jul 2016 11:19:19 +1000 Subject: [PATCH 24/77] Don't trigger deployment for transifex branch --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ef54e640c8..d932c1631c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,7 +45,7 @@ script: after_success: - > - if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a -n "$GITHUB_API_SECRET" ]; then + if [ "$GITHUB_DEPLOY" = "true" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$TRAVIS_BRANCH" -a "$TRAVIS_BRANCH" != "transifex" -a -n "$GITHUB_API_SECRET" ]; then description="`git show "$TRAVIS_BRANCH" -s --oneline --no-color`" data="{ \"ref\":\"$TRAVIS_BRANCH\", From ddb54d1924369fba41568fce3489cd993168d211 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 15 Jul 2016 17:43:26 +1000 Subject: [PATCH 25/77] Delete fee on payment method if payment invalid PayPalExpress is always creating two payments. The first one is invalidated and the second one succeeds. Without deleting the old fee on the invalidated payment, the order lists the fee twice. --- app/helpers/checkout_helper.rb | 1 + app/models/spree/payment_decorator.rb | 7 ++++++- app/views/checkout/_summary.html.haml | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/helpers/checkout_helper.rb b/app/helpers/checkout_helper.rb index 66d98d7862..6359cb01bd 100644 --- a/app/helpers/checkout_helper.rb +++ b/app/helpers/checkout_helper.rb @@ -6,6 +6,7 @@ module CheckoutHelper # Remove empty tax adjustments and (optionally) shipping fees adjustments.reject! { |a| a.originator_type == 'Spree::TaxRate' && a.amount == 0 } adjustments.reject! { |a| a.originator_type == 'Spree::ShippingMethod' } if exclude.include? :shipping + adjustments.reject! { |a| a.originator_type == 'Spree::PaymentMethod' } if exclude.include? :payment adjustments.reject! { |a| a.source_type == 'Spree::LineItem' } if exclude.include? :line_item enterprise_fee_adjustments = adjustments.select { |a| a.originator_type == 'EnterpriseFee' && a.source_type != 'Spree::LineItem' } diff --git a/app/models/spree/payment_decorator.rb b/app/models/spree/payment_decorator.rb index d178e1de54..dbee3cfd0f 100644 --- a/app/models/spree/payment_decorator.rb +++ b/app/models/spree/payment_decorator.rb @@ -5,7 +5,12 @@ module Spree after_save :ensure_correct_adjustment, :update_order def ensure_correct_adjustment - if adjustment + # Don't charge for invalid payments. + # PayPalExpress always creates a payment that is invalidated later. + # Unknown: What about failed payments? + if state == "invalid" + adjustment.andand.destroy + elsif adjustment adjustment.originator = payment_method adjustment.label = adjustment_label adjustment.save diff --git a/app/views/checkout/_summary.html.haml b/app/views/checkout/_summary.html.haml index a3b61c5ded..0fec419556 100644 --- a/app/views/checkout/_summary.html.haml +++ b/app/views/checkout/_summary.html.haml @@ -9,7 +9,7 @@ = t :checkout_cart_total %td.cart-total.text-right= display_checkout_subtotal(@order) - - checkout_adjustments_for(current_order, exclude: [:shipping, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment| + - checkout_adjustments_for(current_order, exclude: [:shipping, :payment, :line_item]).reject{ |a| a.amount == 0 }.each do |adjustment| %tr %th= adjustment.label %td.text-right= adjustment.display_amount.to_html From 477d48e9da3d29b4354d0e9d0fd553c3add1930f Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 15 Jul 2016 19:46:47 +1000 Subject: [PATCH 26/77] Updating translations for config/locales/nb.yml [skip ci] --- config/locales/nb.yml | 418 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 397 insertions(+), 21 deletions(-) diff --git a/config/locales/nb.yml b/config/locales/nb.yml index 59fa27ffa8..8bb9e243c1 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -1,4 +1,9 @@ nb: + activerecord: + attributes: + spree/order: + payment_state: Betalingsstatus + shipment_state: Sendingsstatus devise: failure: invalid: | @@ -10,11 +15,16 @@ nb: not_confirmed: Din epostadresse kan ikke bekreftes. Kanskje du allerede har fullført dette steget? confirmation_sent: "Bekreftelse på epost er sendt!" confirmation_not_sent: "Kunne ikke sende bekreftelse på epost." - home: "OFN" + enterprise_mailer: + confirmation_instructions: + subject: "Vennligst bekreft e-postadressen til %{enterprise}" + welcome: + subject: "%{enterprise} er nå på %{sitename}" title: Open Food Network welcome_to: 'Velkommen til ' + site_meta_description: "Vi begynner fra grunnen. Med bønder og dyrkere klare til å fortelle sine historier, stolt og virkelig. Med distributører klare til å koble mennesker med produkter på en rettferdig og ærlig måte. Med kunder som tror på at ukentlige innkjøpsrutiner kan..." search_by_name: Søk på navn eller sted... - producers: Norske Produsenter + producers: 'Norske Produsenter' producers_join: Norske produsenter er nå velkommen til å bli med i Open Food Network. charges_sales_tax: MVA-pliktig? print_invoice: "Skriv ut Faktura" @@ -36,7 +46,131 @@ nb: free: "gratis" plus_tax: "pluss MVA" total_monthly_bill_incl_tax: "Total månedlig regning (Inkl. Avgift)" - sort_order_cycles_on_shopfront_by: "Sorter Bestillingsrunder i Nettbutikk etter" + business_model_configuration: "Utforming av forretningsmodell" + say_no: "Nei" + say_yes: "Ja" + sort_order_cycles_on_shopfront_by: "Sorter Bestillingsrunder i Butikkvindu etter" + admin: + date: Dato + email: Epost + name: Navn + on_hand: Tilgjengelig + on_demand: Ved forespørsel + on_demand?: Ved forespørsel? + order_cycle: Bestillingsrunde + phone: Telefon + price: Pris + producer: Produsent + product: Produkt + quantity: Mengde + shop: Butikk + sku: SKU + tags: Merker + variant: Variant + quick_search: Hurtigsøk + clear_all: Fjern Alt + start_date: "Startdato" + end_date: "Sluttdato" + columns: Kolonner + actions: Handlinger + viewing: "Viser: %{current_view_name}" + whats_this: Hva er dette? + tag_has_rules: "Gjeldende regler for denne merkelappen: %{num}" + has_one_rule: "har én regel" + has_n_rules: "har %{num} regler" + customers: + index: + add_customer: "Legge til kunde" + new_customer: "Ny kunder" + customer_placeholder: "customer@example.org" + valid_email_error: Vennligst oppgi en gyldig epostadresse + add_a_new_customer_for: Legge til en ny kunde for %{shop_name} + code: kode + duplicate_code: "Denne koden er allerede brukt." + products: + bulk_edit: + unit: Enhet + display_as: Vis som + category: Kategori + tax_category: Avgiftskategori + inherits_properties?: Arver Egenskaper? + available_on: Tilgjengelig på + av_on: "Til. på" + variant_overrides: + index: + title: Varelager + description: Bruk denne siden til å administrere varelager for dine bedrifter. Eventuelle produktdetaljer satt her vil overstyre de som er satt på 'Produkter'-siden + enable_reset?: Aktiver Nullstilling av Varebeholdning + inherit?: Arve? + add: Legg til + hide: Skjul + select_a_shop: Velg en butikk + review_now: Sjekk nå + new_products_alert_message: Det er %{new_product_count} nye produkter tilgjengelig for å legge til ditt varelager. + currently_empty: Ditt varelager er tomt + no_matching_products: Ingen samsvarende produkter funnet i ditt varelager + no_hidden_products: Ingen produkter har blitt skjult for dette varelageret + no_matching_hidden_products: Ingen skjulte produkter oppfyller søkekriteriene + no_new_products: Ingen nye produkter er tilgjengelige for å legge til dette varelageret + no_matching_new_products: Ingen nye produkter oppfyller søkekriteriene dine + inventory_powertip: Dette er ditt varelager. For å legge til lageret, velg 'Nye Produkter' fra Visningslisten. + hidden_powertip: Disse produktene har blitt skjult fra ditt varelager og vil ikke være tilgjengelig for å legge til din butikk. Du kan klikke "Legg til" for å legge et produkt til ditt varelager. + new_powertip: Disse produktene er tilgjengelige for å bli lagt til ditt varelager. Klikk "Legg til" for å legge et produkt til lageret ditt, eller "Skjul" for å skjule det fra visning. Du kan alltids ombestemme deg senere! + orders: + bulk_management: + tip: "Bruk denne siden for å endre produktantall på tvers av flere bestillinger. Produkter kan også fjernes fra bestillinger helt, hvis påkrevd." + shared: "Delt Ressurs?" + order_no: "Bestillingsnr." + order_date: "Bestillingsdato" + max: "Max" + product_unit: "Produkt: Enhet" + weight_volume: "Vekt/Volum" + ask: "Spør?" + page_title: "Bulk Order Management" + actions_delete: "Slett Valgte" + loading: "Laster bestillinger" + no_results: "Fant ingen bestillinger." + group_buy_unit_size: "Gruppekjøp Enhetsstørrelse" + total_qtt_ordered: "Totalt Antall Bestilt" + max_qtt_ordered: "Max Antall Bestilt" + current_fulfilled_units: "Nåværende Oppfylte Enheter" + max_fulfilled_units: "Max Oppfylte Enheter" + order_error: "Noen feil må løses før du kan oppdatere bestillinger.\nAlle felt med røde kanter inneholder feil." + variants_without_unit_value: "ADVARSEL: Noen varianter mangler enhetsverdi" + order_cycles: + edit: + choose_products_from: "Velg Produkter Fra:" + enterprise: + select_outgoing_oc_products_from: Velg utgående bestillingsrundeprodukter fra + enterprises: + index: + producer?: Produsent? + package: Pakke + status: Status + manage: Administrer + form: + primary_details: + shopfront_requires_login: "Krever butikk innlogging?" + shopfront_requires_login_tip: "Velg om kunder må logge inn for å se butikken eller ikke." + shopfront_requires_login_false: "Offentlig" + shopfront_requires_login_true: "Krev at kunder logger inn" + home: + hubs: + show_closed_shops: "Vis stengte butikker" + hide_closed_shops: "Skjul stengte butikker" + show_on_map: "Vis alle på kartet" + shared: + register_call: + selling_on_ofn: "Interessert i å bli med i Open Food Network?" + register: "Registrer her" + shop: + messages: + login: "innlogging" + register: "registrer" + contact: "kontakt" + require_customer_login: "Denne butikken er kun for kunder." + require_login_html: "Vennligst %{login} hvis du allerede har en konto. Hvis ikke, %{register} for å bli kunde." + require_customer_html: "Vennligst %{contact} %{enterprise} for å bli kunde." invoice_column_item: "Vare" invoice_column_qty: "Mengde" invoice_column_tax: "MVA" @@ -73,8 +207,6 @@ nb: terms_of_service: "Vilkår" on_demand: Ved forespørsel none: Ingen - alert_selling_on_ofn: "Interessert i å selge mat gjennom Open Food Network?" - alert_start_here: "Start her" label_shops: "Butikker" label_map: "Kart" label_producers: "Produsenter" @@ -87,8 +219,9 @@ nb: label_administration: "Administrasjon" label_admin: "Admin" label_account: "Konto" - label_more: "Mer" + label_more: "Vis mer" label_less: "Vis mindre" + label_notices: "Meldinger" items: "varer" cart_headline: "Din handlekurv" total: "Sum" @@ -188,12 +321,15 @@ nb: order_delivery_on: Levering på order_delivery_address: Leveringsadresse order_special_instructions: "Dine kommentarer:" + order_pickup_time: Klar for henting order_pickup_instructions: Henteinstruksjoner order_produce: Varer order_total_price: Sum order_includes_tax: (inkludert MVA) order_payment_paypal_successful: Din betaling via PayPal har blitt godkjent. order_hub_info: Hub info + unsaved_changes_warning: "Ulagrede endringer finnes og vil gå tapt hvis du fortsetter." + unsaved_changes_error: "Felt med røde kanter inneholder feil." products: "Produkter" products_in: "i %{oc}" products_at: "hos %{distributor}" @@ -246,6 +382,11 @@ nb: email_signup_shop_html: "Du kan begynne å handle på nett nå på %{link}." email_signup_text: "Takk for at du ble med i nettverket. Hvis du er kunde ser vi frem til å vise deg mange fantastiske bønder, flotte mathubs og deilig mat! Hvis du er produsent eller selskap er vi glade for å ha deg som en del av nettverket." email_signup_help_html: "Vi tar i mot alle dine spørsmål og tilbakemeldinger; du kan bruke Send tilbakemelding-knappen på nettsiden eller sende oss en epost på" + producer_mail_greeting: "Kjære" + producer_mail_text_before: "Alle dine kunderbestillinger er klar." + producer_mail_order_text: "Her er en oppsummering av bestillingene:" + producer_mail_delivery_instructions: "Henting / leveringsdetaljer :" + producer_mail_signoff: "Med vennlig hilsen" shopping_oc_closed: Stengt for bestilling shopping_oc_closed_description: "Vent til neste runde åpner (eller kontakt oss direkte for å se om vi tar i mot sene bestillinger)" shopping_oc_last_closed: "Den siste runden stengte for %{distance_of_time} siden" @@ -284,6 +425,11 @@ nb: products_cart_empty: "Handlekurv tom" products_edit_cart: "Rediger handlekurv" products_from: fra + products_change: "Ingen endringer å lagre." + products_update_error: "Lagring mislyktes med følgende feilmelding(er):" + products_update_error_msg: "Lagring mislyktes." + products_update_error_data: "Lagring mislyktes på grunn av ugyldige data:" + products_changes_saved: "Endringene er lagret." search_no_results_html: "Beklager, ingen treff på %{query}. Prøv på nytt?" components_profiles_popover: "Profiler har ikke butikkvindu på Open Food Network men kan ha sin egen fysiske butikk eller nettbutikk et annet sted" components_profiles_show: "Vis profiler" @@ -291,6 +437,7 @@ nb: components_filters_clearfilters: "Fjern alle filtre" groups_title: Grupper groups_headline: Grupper / regioner + groups_text: "Hver prodsent er unik. Hver forretning har noe annet å tilby. Våre grupper er kollektiv av produsenter, hubs og distributører som deler noe i fellesskap som lokasjon, bondens marked eller filosofi. Dette gjør din handleopplevelse enklere. Så utforsk våre grupper og la de gjøre forberedelsene for deg." groups_search: "Søk på navn eller nøkkelord" groups_no_groups: "Fant ingen grupper" groups_about: "Om oss" @@ -306,17 +453,17 @@ nb: groups_signup_headline: Bli med som gruppe groups_signup_intro: "Vi er en fantastisk plattform for samarbeidende markedsføring, den enkleste måten for medlemmer og interessenter å nå nye markeder. Vi er non-profit, rimelig og enkel." groups_signup_email: Send oss epost - groups_signup_motivation1: Vi forvandler matsystemer rettferdig. - groups_signup_motivation2: Det er grunnen til at vi står opp om morgenen. Vi er en global non-profit, basert på åpen kildekode. We opptrer rettferdig. Du kan alltid stole på oss. + groups_signup_motivation1: Vi skaper et rettferdig matsystem. + groups_signup_motivation2: Dette er grunnen til at vi står opp om morgenen. Vi er en global non-profit, basert på åpen kildekode. Vi opptrer rettferdig. Du kan stole på oss. groups_signup_motivation3: Vi vet du har gode ideer og vi ønsker å hjelpe. Vi deler vår kunnskap, våre nettverk og ressurser. Vi vet at isolasjon ikke skaper endring så vi vil samarbeide med deg. groups_signup_motivation4: Vi møter deg der du er. groups_signup_motivation5: Du kan være en allianse av mathubs, produsenter eller distributører, i industri eller lokale myndigheter. groups_signup_motivation6: Uansett din rolle i den lokale matkjeden, vi ønsker å hjelpe. Hvis du lurer på hvordan Open Food Network vil se ut eller hva de gjør i din del av verden, la oss snakke sammen. groups_signup_motivation7: Vi gir matkjeden mer mening. groups_signup_motivation8: Du trenger å aktivere og tilrettelegge for dine nettverk, vi tilbyr en plattform for samtale og handling. Du trenger ekte engasjement. Vi hjelper til med å nå alle aktører, alle interessenter, alle sektorer. - groups_signup_motivation9: Du trenger flere ressurser. We kommer med all erfaring vi kan bære. Du trenger samarbeid. Vi kobler deg med et globalt nettverk med likesinnede. + groups_signup_motivation9: Du trenger flere ressurser. Vi kommer med all erfaring vi kan bære. Du trenger samarbeid. Vi kobler deg med et globalt nettverk med likesinnede. groups_signup_pricing: Gruppekonto - groups_signup_studies: Brukerundersøkelser + groups_signup_studies: Eksempler groups_signup_contact: Klar for å snakke sammen? groups_signup_contact_text: "Ta kontakt for å oppdage hva OFN kan gjøre for deg:" groups_signup_detail: "Her er detaljene." @@ -331,7 +478,7 @@ nb: modal_how: "Slik fungerer det" modal_how_shop: Handle på Open Food Network modal_how_shop_explained: Søk etter en mathub nær deg for å begynne å handle! Du kan se detaljer for hver mathub for å se hvilke godbiter som finnes, og klikk deg videre for å handle. (Du kan kun handle hos en mathub om gangen). - modal_how_pickup: Henting, levering og transportkostnader + modal_how_pickup: Henting, levering og fraktkostnader modal_how_pickup_explained: Noen mathubs leverer på døren, mens andre krever at du henter varene du har kjøpt. Du kan se hvilke alternativ som er tilgjengelige på hjemmesiden, og velge hvilket du ønsker på handle- og betalingssidene. Levering koster mer, og prisene varierer fra hub til hub. Hver mathub er en forretning med uavhengig drift og logistikk - så variasjoner mellom hubs er naturlig. modal_how_more: Finn ut mer modal_how_more_explained: "Hvis du ønsker å lære mer om Open Food Network, hvordan det fungerer og ta del, sjekk ut:" @@ -377,8 +524,10 @@ nb: products_item: Vare products_description: Beskrivelse products_variant: Variant - products_availabel: Tilgjengelig? - products_price: Pris + products_quantity: Mengde + products_available: Tilgjengelig? + products_producer: "Produsent" + products_price: "Pris" register_title: Registrer shops_title: Butikker shops_headline: Handling på en ny måte. @@ -400,7 +549,7 @@ nb: orders_edit_checkout: Kassen orders_form_empty_cart: "Tøm handlekurv" orders_form_subtotal: Delsum varer - orders_form_admin: Admin og håndtering + orders_form_admin: Administrasjon og håndtering orders_form_total: Total orders_oc_expired_headline: Bestillinger stengt for denne runden orders_oc_expired_text: "Beklager, bestillinger for denne runden stengte for %{time} siden! Kontakt din hub direkte for å høre om de tar i mot sene bestillinger." @@ -420,15 +569,17 @@ nb: products_oc_is: "Din bestillingsrunde for denne bestillingen er %{name}." products_oc_error: "Vennligst fullfør din bestilling hos %{link} før du handler i en annen bestillingsrunde." products_oc_current: "din nåværende bestillingsrunde" - products_quantity: Mengde products_max_quantity: Max mengde products_distributor: Distributør products_distributor_info: Når du velger en distributør for din bestilling, vil deres adresse og hentetider vises her. + shop_trial_length: "Lengden av prøveperioden (dager)" + shop_trial_expires_in: "Din prøveperiode på butikkfront går ut om " + shop_trial_expired_notice: "Gode nyheter! Vi har bestemt å forlenge butikkprøveperioder inntil ytterligere beskjed." password: Passord remember_me: Husk meg are_you_sure: "er du sikker?" orders_open: Åpen for bestilling - closing: "stenger" + closing: "Stenger " going_back_to_home_page: "Tar deg tilbake til hjemmesiden" creating: Oppretter updating: oppdatering @@ -477,8 +628,7 @@ nb: who_is_managing_enterprise: "Hvem er ansvarlig for å administrere %{enterprise}?" enterprise_contact: "Primærkontakt" enterprise_contact_required: "Du må oppgi en primærkontakt." - enterprise_email: "Epostadresse" - enterprise_email_required: "Du må oppgi en gyldig epostadresse" + enterprise_email_address: "Epostadresse" enterprise_phone: "Telefonnummer" back: "Tilbake" continue: "Fortsett" @@ -553,7 +703,7 @@ nb: registration_type_producer: "Ja, jeg er en produsent" registration_type_no_producer: "Nei, jeg er ikke en produsent" registration_type_error: "Vennligst velg en. Er du produsent?" - registration_type_producer_help: "Produsenter lager masse god mat og drikke. Du er en produsent hvis du dyrker, driver med hysdyrhold, brygger, baker, fermenterer, melker eller former." + registration_type_producer_help: "Produsenter lager deilige ting å spise og/eller drikke. Du er en produsent hvis du dyrker det, driver med det, brygger det, baker det, fermenterer det, melker det eller former det." registration_type_no_producer_help: "Hvis du ikke er en produsent, er du sannsynligvis noen som selger og distribuerer mat. Du kan være en hub, samvirke, kjøpegruppe, forhandler, grossist eller annet." create_profile: "Opprett profil" registration_images_headline: "Takk!" @@ -584,7 +734,6 @@ nb: bulk: "Bulk" shop_variant_quantity_min: "min" shop_variant_quantity_max: "max" - contact: "Kontakt" follow: "Følg" shop_for_products_html: "Handle produkter fra %{enterprise} på:" change_shop: "Endre butikk til:" @@ -594,7 +743,234 @@ nb: sales_fee: "Salgsgebyr" packing_fee: "Pakkegebyr" transport_fee: "Transportgebyr" - fundraising_fee: "Pengeinnsamlingsgebyr" + fundraising_fee: "innsamlingsaksjon" price_graph: "Prisgraf" included_tax: "inkludert avgift" + balance: "Balanse" + transaction: "Transaksjon" + transaction_date: "Dato" + payment_state: "Betallingsstatus" + shipping_state: "Leveringsstatus" + value: "Verdi" + balance_due: "Balanse forfaller" + credit: "Kreditt" + Paid: "Betalt" + Ready: "Klar" + you_have_no_orders_yet: "Du har ingen bestilinger enda" + running_balance: "Løpende balanse" + outstanding_balance: "Utestående balanse" + admin_entreprise_relationships: "Bedriftsrelasjoner" + admin_entreprise_relationships_everything: "Alt" + admin_entreprise_relationships_permits: "tillater" + admin_entreprise_relationships_seach_placeholder: "Søk" + admin_entreprise_relationships_button_create: "Opprett" + admin_entreprise_groups: "Bedriftsgrupper" + admin_entreprise_groups_name: "Navn" + admin_entreprise_groups_owner: "Eier" + admin_entreprise_groups_on_front_page: "På forsiden?" + admin_entreprise_groups_entreprise: "Bedrifter" + admin_entreprise_groups_data_powertip: "Hovedbrukeren ansvarlig for denne gruppen." + admin_entreprise_groups_data_powertip_logo: "Dette er logoen for gruppen" + admin_entreprise_groups_data_powertip_promo_image: "Dette bildet vises på toppen av Gruppens profil" + admin_entreprise_groups_contact: "Kontakt" + admin_entreprise_groups_contact_phone_placeholder: "eks: 987 123 654" + admin_entreprise_groups_contact_address1_placeholder: "eks: Gårdsvei 12" + admin_entreprise_groups_contact_city: "Område" + admin_entreprise_groups_contact_city_placeholder: "f.eks. Nesodden" + admin_entreprise_groups_contact_zipcode: "Postnummer" + admin_entreprise_groups_contact_zipcode_placeholder: "f.eks. 1450" + admin_entreprise_groups_contact_state_id: "Fylke" + admin_entreprise_groups_contact_country_id: "Land" + admin_entreprise_groups_web: "Nettressurser" + admin_entreprise_groups_web_twitter: "f.eks. @alt_lokalt" + admin_entreprise_groups_web_website_placeholder: "f.eks. www.truffles.com" + admin_order_cycles: "Administrasjon Bestillingsrunder" + open: "Åpne" + close: "Steng" + supplier: "Leverandør" + coordinator: "Koordinator" + distributor: "Distributør" + fee_type: "Avfgiftstype" + tax_category: "Avgiftskategori" + calculator: "Kalkulator" + calculator_values: "Kalkulatorverdier" + new_order_cycles: "Nye Bestillingsrunder" + select_a_coordinator_for_your_order_cycle: "Velg en koordinator for denne syklus" + edit_order_cycle: "Endre Bestillingsrunde" + roles: "Roller" + update: "Oppdater" + add_producer_property: "Legg til produsentegenskap" + admin_settings: "Innstillinger" + update_invoice: "Oppdater Fakturaer" + finalise_invoice: "Sluttfør Fakturaer" + finalise_user_invoices: "Sluttfør Brukerfakturaer" + finalise_user_invoice_explained: "Bruk denne knappen til å sluttføre alle fakturaer i systemet for forrige kalendermåned. Denne oppgaven kan settes opp til å kjøres automatisk hver måned." + manually_run_task: "Gjør Oppgave Manuelt" + update_user_invoices: "Oppdater Brukerfakturaer" + update_user_invoice_explained: "Bruk denne knappen til umiddelbart å oppdatere fakturaer for måneden frem til i dag for hver bedriftsbruker i systemet. Denne oppgaven kan settes opp til å kjøres automatisk hver natt." + auto_finalise_invoices: "Auto-sluttfør fakturaer månedlig på den 2. kl. 01:30" + auto_update_invoices: "Auto-oppdater fakturaer hver natt kl. 01:00" + in_progress: "Pågår" + started_at: "Startet" + queued: "Satt i kø" + scheduled_for: "Planlagt for" + customers: "Kunder" + please_select_hub: "Vennligst velg en Hub" + loading_customers: "Laster Kunder" + no_customers_found: "Fant ingen kunder" + go: "Gå" + hub: "Hub" + accounts_administration_distributor: "bokføringsadministrasjon distributør" + accounts_and_billing: "Bokføring & Fakturering" + producer: "Produsent" + product: "Produkt" + price: "Pris" + on_hand: "På lager" + save_changes: "Lagre Endringer" + spree_admin_overview_enterprises_header: "Mine Bedrifter" + spree_admin_overview_enterprises_footer: "ADMINISTRER MINE BEDRIFTER" + spree_admin_enterprises_hubs_name: "Navn" + spree_admin_enterprises_create_new: "OPPRETT NY" + spree_admin_enterprises_shipping_methods: "Leveringsmetoder" + spree_admin_enterprises_fees: "Bedriftsavgift" + spree_admin_enterprises_none_create_a_new_enterprise: "OPPRETT NY BEDRIFT" + spree_admin_enterprises_none_text: "Du har ingen bedrifter ennå" + spree_admin_enterprises_producers_name: "Navn" + spree_admin_enterprises_producers_total_products: "Alle Produkter" + spree_admin_enterprises_producers_active_products: "Aktive Produkter" + spree_admin_enterprises_producers_order_cycles: "Produkter i Bestillingsrunder" + spree_admin_enterprises_tabs_hubs: "HUBS" + spree_admin_enterprises_tabs_producers: "PRODUSENTER" + spree_admin_enterprises_producers_manage_order_cycles: "ADMINISTRER BESTILLINGSRUNDER" + spree_admin_enterprises_producers_manage_products: "ADMINISTRER PRODUKTER" + spree_admin_enterprises_producers_orders_cycle_text: "Du har ingen aktive bestillingsrunder." + spree_admin_enterprises_any_active_products_text: "Du har ingen aktive produkter." + spree_admin_enterprises_create_new_product: "OPPRETT NYTT PRODUKT" + spree_admin_order_cycles: "Bestillingsrunder" + spree_admin_order_cycles_tip: "Bestillingsrunder bestemmer når og hvor dine produkter er tilgjengelig til kunder." + dashbord: "Dashboard" + spree_admin_single_enterprise_alert_mail_confirmation: "Vennligst bekreft epostadressen for" + spree_admin_single_enterprise_alert_mail_sent: "Vi har sendt epost til" + spree_admin_overview_action_required: "Handling Nødvendig" + spree_admin_overview_check_your_inbox: "Vennligst sjekk innboksen din for nærmere instruksjoner. Takk!" + change_package: "Endre Pakke" + spree_admin_single_enterprise_hint: "Hint: For å hjelpe folk til å finne deg, skru på din synlighet under" + your_profil_live: "Din profil live" + on_ofn_map: "på Open Food Network kartet" + see: "Se" + live: "live" + manage: "Administrer" + resend: "Send på nytt" + add_and_manage_products: "Legg til & administrer produkter" + add_and_manage_order_cycles: "Legg til & administrer bestillingsrunder" + manage_order_cycles: "Administrer bestillingsrunder" + manage_products: "Administrer produkter" + edit_profile_details: "Endre profildetaljer" + edit_profile_details_etc: "Endre din profilbeskrivelse, bilder, osv." + order_cycle: "Bestillingsrunde" remove_tax: "Fjern avgift" + tax_settings: "Avgiftsinnstillinger" + products_require_tax_category: "produkter krever avgiftskategori" + admin_shared_address_1: "Adresse" + admin_shared_address_2: "Adresse (forts.)" + admin_share_city: "By" + admin_share_zipcode: "Postnummer" + admin_share_country: "Land" + admin_share_state: "Fylke" + hub_sidebar_hubs: "Hubs" + hub_sidebar_none_available: "Ingen Tilgjengelig" + hub_sidebar_manage: "Administrer" + hub_sidebar_at_least: "Minst én hub må være valgt" + hub_sidebar_blue: "blå" + hub_sidebar_red: "rød" + shop_trial_in_progress: "Din prøveperiode på butikkfront går ut om %{days}." + shop_trial_expired: "Gode nyheter! Vi har bestemt å forlenge butikkprøveperioder inntil ytterligere beskjed (sannsynligvis rundt mars 2015)." + report_customers_distributor: "Distributør" + report_customers_supplier: "Leverandør" + report_customers_cycle: "Bestillingsrunde" + report_customers_type: "Rapporttype" + report_customers_csv: "Last ned som csv" + report_producers: "Produsenter:" + report_type: "Rapporttype:" + report_hubs: "Hubs:" + report_payment: "Betalingsmetoder:" + report_distributor: "Distributør:" + report_payment_by: 'Betalinger Etter Type:' + report_itemised_payment: 'Betalingstotaler etter Artikkel' + report_payment_totals: 'Betalingstotaler' + report_all: 'alle' + report_order_cycle: "Bestillingsrunde:" + report_entreprises: "Bedrifter:" + report_users: "Brukere:" + initial_invoice_number: "Første fakturanummer:" + invoice_date: "Fakturadato:" + due_date: "Tidsfrist:" + account_code: "Kontokode:" + equals: "Tilsvarer" + contains: "inneholder" + discount: "Rabatt" + filter_products: "Filtrer Produkter" + delete_product_variant: "Den siste varianten kan ikke slettes!" + progress: "fremdrift" + saving: "Lagrer.." + success: "vellykket" + failure: "feil" + unsaved_changes_confirmation: "Ulagrede endringer vil gå tapt. Fortsett likevel?" + one_product_unsaved: "Endringer i ett produkt er fortsatt ulagret." + products_unsaved: "Endringer i %{n} produkter er fortsatt ulagret." + is_already_manager: "er allerede administrator!" + no_change_to_save: "Ingen endring å lagre" + add_manager: "Legg til administrator" + users: "Brukere" + about: "Om" + images: "Bilder" + web: "Nett" + primary_details: "Primærdetaljer" + adrdress: "Adresse" + contact: "Kontakt" + social: "Sosial" + business_details: "Forretningsdetaljer" + properties: "Egenskaper" + shipping_methods: "Leveringsmetoder" + payment_methods: "Betalingsmetoder" + payment_method_fee: "Transaksjongebyr" + enterprise_fees: "Bedriftsavgifter" + inventory_settings: "Beholdningsinnstillinger" + tag_rules: "Regler merkelapper" + shop_preferences: "Butikkvalg" + validation_msg_relationship_already_established: "^Den relasjonen er allerede etablert." + validation_msg_at_least_one_hub: "^Minst én hub må være valgt" + validation_msg_product_category_cant_be_blank: "^Produktkategori kan ikke være blank" + validation_msg_tax_category_cant_be_blank: "^Avgiftskategori kan ikke være blank" + validation_msg_is_associated_with_an_exising_customer: "er assosiert med en eksisterende kunde" + spree: + shipment_states: + backorder: restordre + partial: delvis + pending: ventende + ready: klar + shipped: sendt + payment_states: + balance_due: balanse forfaller + completed: fullført + checkout: kasse + credit_owed: kreditt skyldt + failed: feilet + paid: betalt + pending: ventende + processing: behandler + void: ugyldig + invalid: ugyldig + order_state: + address: adresse + adjustments: justeringer + awaiting_return: avventer retur + canceled: avbrutt + cart: ' handlekurv' + complete: fullført + confirm: bekreft + delivery: levering + payment: betaling + resumed: gjenopptatt + returned: returnert + skrill: skrill From e57c06c610d5e7b9059b75010acf1cd4a648235a Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 20 Jul 2016 16:07:35 +1000 Subject: [PATCH 27/77] Use require_relative introduced in Ruby 1.9.2 The new `require_relative` command is much shorter and easier to read then the previous: -require File.expand_path('../config/application', __FILE__) +require_relative 'config/application' --- Rakefile | 2 +- config/application.rb | 2 +- config/environment.rb | 2 +- lib/tasks/dev.rake | 4 ++-- script/delayed_job | 2 +- script/rails | 2 +- spec/spec_helper.rb | 2 +- test/test_helper.rb | 2 +- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Rakefile b/Rakefile index 9ed55e022e..b462be57e6 100644 --- a/Rakefile +++ b/Rakefile @@ -2,7 +2,7 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require_relative 'config/application' Openfoodnetwork::Application.load_tasks diff --git a/config/application.rb b/config/application.rb index 6ffee13160..a763f54718 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,4 +1,4 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' require 'rails/all' diff --git a/config/environment.rb b/config/environment.rb index 9f6b854161..f3522b8759 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,5 @@ # Load the rails application -require File.expand_path('../application', __FILE__) +require_relative 'application' # Initialize the rails application Openfoodnetwork::Application.initialize! diff --git a/lib/tasks/dev.rake b/lib/tasks/dev.rake index bfa57a07dd..ee8c698c7b 100644 --- a/lib/tasks/dev.rake +++ b/lib/tasks/dev.rake @@ -5,8 +5,8 @@ namespace :openfoodnetwork do desc 'load sample data' task :load_sample_data => :environment do - require File.expand_path('../../../spec/factories', __FILE__) - require File.expand_path('../../../spec/support/spree/init', __FILE__) + require_relative '../../spec/factories' + require_relative '../../spec/support/spree/init' task_name = "openfoodnetwork:dev:load_sample_data" # -- Shipping / payment information diff --git a/script/delayed_job b/script/delayed_job index edf195985f..cecd9acddd 100755 --- a/script/delayed_job +++ b/script/delayed_job @@ -1,5 +1,5 @@ #!/usr/bin/env ruby -require File.expand_path(File.join(File.dirname(__FILE__), '..', 'config', 'environment')) +require_relative '../config/environment' require 'delayed/command' Delayed::Command.new(ARGV).daemonize diff --git a/script/rails b/script/rails index f8da2cffd4..dc40bb7e84 100755 --- a/script/rails +++ b/script/rails @@ -2,5 +2,5 @@ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. APP_PATH = File.expand_path('../../config/application', __FILE__) -require File.expand_path('../../config/boot', __FILE__) +require_relative '../config/boot' require 'rails/commands' diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f4c5b73fac..c7a7f8e790 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,7 +8,7 @@ Knapsack.tracker.config({enable_time_offset_warning: false}) unless ENV['CI'] Knapsack::Adapters::RSpecAdapter.bind ENV["RAILS_ENV"] ||= 'test' -require File.expand_path("../../config/environment", __FILE__) +require_relative "../config/environment" require 'rspec/rails' require 'capybara' require 'database_cleaner' diff --git a/test/test_helper.rb b/test/test_helper.rb index 8bf1192ffe..7d57a78563 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,5 +1,5 @@ ENV["RAILS_ENV"] = "test" -require File.expand_path('../../config/environment', __FILE__) +require_relative '../config/environment' require 'rails/test_help' class ActiveSupport::TestCase From 2b7da4738c55179374715d183672c41b5fd6e6a9 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 22 Jul 2016 00:59:57 +1000 Subject: [PATCH 28/77] Updating translations for config/locales/nb.yml [skip ci] --- config/locales/nb.yml | 117 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 109 insertions(+), 8 deletions(-) diff --git a/config/locales/nb.yml b/config/locales/nb.yml index 8bb9e243c1..b42643b74e 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -1,5 +1,22 @@ +# English language file +# --------------------- +# +# This is the source language file maintained by the Australian OFN team. +# 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 +# +# - uploading the file to Transifex or +# - opening a pull request at GitHub. +# +# +# See http://community.openfoodnetwork.org/t/localisation-ofn-in-your-language/397 + nb: activerecord: + # Overridden here due to a bug in spree i18n (Issue #870) attributes: spree/order: payment_state: Betalingsstatus @@ -20,12 +37,13 @@ nb: subject: "Vennligst bekreft e-postadressen til %{enterprise}" welcome: subject: "%{enterprise} er nå på %{sitename}" + home: "OFN" title: Open Food Network welcome_to: 'Velkommen til ' site_meta_description: "Vi begynner fra grunnen. Med bønder og dyrkere klare til å fortelle sine historier, stolt og virkelig. Med distributører klare til å koble mennesker med produkter på en rettferdig og ærlig måte. Med kunder som tror på at ukentlige innkjøpsrutiner kan..." search_by_name: Søk på navn eller sted... producers: 'Norske Produsenter' - producers_join: Norske produsenter er nå velkommen til å bli med i Open Food Network. + producers_join: Norske produsenter er nå velkommen til å bli med i Open Food Network. #FIXME charges_sales_tax: MVA-pliktig? print_invoice: "Skriv ut Faktura" send_invoice: "Send Faktura" @@ -44,13 +62,20 @@ nb: capped_at_cap: "tak på %{cap}" per_month: "pr. måned" free: "gratis" + free_trial: "gratis prøveperiode" plus_tax: "pluss MVA" total_monthly_bill_incl_tax: "Total månedlig regning (Inkl. Avgift)" + min_bill_turnover_desc: "når omsettning overstiger %{mbt_amount}" business_model_configuration: "Utforming av forretningsmodell" say_no: "Nei" say_yes: "Ja" + then: vil + sort_order_cycles_on_shopfront_by: "Sorter Bestillingsrunder i Butikkvindu etter" + + admin: + # Common properties / models date: Dato email: Epost name: Navn @@ -67,17 +92,23 @@ nb: sku: SKU tags: Merker variant: Variant + + # General form elements quick_search: Hurtigsøk clear_all: Fjern Alt start_date: "Startdato" end_date: "Sluttdato" + columns: Kolonner actions: Handlinger viewing: "Viser: %{current_view_name}" + whats_this: Hva er dette? + tag_has_rules: "Gjeldende regler for denne merkelappen: %{num}" has_one_rule: "har én regel" has_n_rules: "har %{num} regler" + customers: index: add_customer: "Legge til kunde" @@ -87,6 +118,7 @@ nb: add_a_new_customer_for: Legge til en ny kunde for %{shop_name} code: kode duplicate_code: "Denne koden er allerede brukt." + products: bulk_edit: unit: Enhet @@ -96,6 +128,7 @@ nb: inherits_properties?: Arver Egenskaper? available_on: Tilgjengelig på av_on: "Til. på" + variant_overrides: index: title: Varelager @@ -116,6 +149,7 @@ nb: inventory_powertip: Dette er ditt varelager. For å legge til lageret, velg 'Nye Produkter' fra Visningslisten. hidden_powertip: Disse produktene har blitt skjult fra ditt varelager og vil ikke være tilgjengelig for å legge til din butikk. Du kan klikke "Legg til" for å legge et produkt til ditt varelager. new_powertip: Disse produktene er tilgjengelige for å bli lagt til ditt varelager. Klikk "Legg til" for å legge et produkt til lageret ditt, eller "Skjul" for å skjule det fra visning. Du kan alltids ombestemme deg senere! + orders: bulk_management: tip: "Bruk denne siden for å endre produktantall på tvers av flere bestillinger. Produkter kan også fjernes fra bestillinger helt, hvis påkrevd." @@ -137,11 +171,14 @@ nb: max_fulfilled_units: "Max Oppfylte Enheter" order_error: "Noen feil må løses før du kan oppdatere bestillinger.\nAlle felt med røde kanter inneholder feil." variants_without_unit_value: "ADVARSEL: Noen varianter mangler enhetsverdi" + order_cycles: edit: choose_products_from: "Velg Produkter Fra:" + enterprise: select_outgoing_oc_products_from: Velg utgående bestillingsrundeprodukter fra + enterprises: index: producer?: Produsent? @@ -154,6 +191,7 @@ nb: shopfront_requires_login_tip: "Velg om kunder må logge inn for å se butikken eller ikke." shopfront_requires_login_false: "Offentlig" shopfront_requires_login_true: "Krev at kunder logger inn" + home: hubs: show_closed_shops: "Vis stengte butikker" @@ -171,16 +209,19 @@ nb: require_customer_login: "Denne butikken er kun for kunder." require_login_html: "Vennligst %{login} hvis du allerede har en konto. Hvis ikke, %{register} for å bli kunde." require_customer_html: "Vennligst %{contact} %{enterprise} for å bli kunde." + + # Printable Invoice Columns invoice_column_item: "Vare" invoice_column_qty: "Mengde" invoice_column_tax: "MVA" invoice_column_price: "Pris" - logo: "Logo (640x130)" - logo_mobile: "Mobil logo (75x26)" - logo_mobile_svg: "Mobil logo (SVG)" + + logo: "Logo (640x130)" #FIXME + logo_mobile: "Mobil logo (75x26)" #FIXME + logo_mobile_svg: "Mobil logo (SVG)" #FIXME home_hero: "Heltebilde" home_show_stats: "Vis statistikk" - footer_logo: "Logo (220x76)" + footer_logo: "Logo (220x76)" #FIXME footer_facebook_url: "Facebook URL" footer_twitter_url: "Twitter URL" footer_instagram_url: "Instagram URL" @@ -191,6 +232,7 @@ nb: footer_links_md: "Linker" footer_about_url: "Om URL" footer_tos_url: "Vilkår URL" + name: Navn first_name: Fornavn last_name: Etternavn @@ -207,6 +249,7 @@ nb: terms_of_service: "Vilkår" on_demand: Ved forespørsel none: Ingen + label_shops: "Butikker" label_map: "Kart" label_producers: "Produsenter" @@ -222,6 +265,7 @@ nb: label_more: "Vis mer" label_less: "Vis mindre" label_notices: "Meldinger" + items: "varer" cart_headline: "Din handlekurv" total: "Sum" @@ -229,9 +273,11 @@ nb: cart_updating: "Oppdaterer handlekurv..." cart_empty: "Handlekurven er tom" cart_edit: "Rediger handlekurv" + card_number: Kortnummer card_securitycode: "Sikkerhetskode" card_expiry_date: Utløpsdato + ofn_cart_headline: "Gjeldende handlekurv for:" ofn_cart_distributor: "Distributør:" ofn_cart_oc: "Bestillingsrunde:" @@ -240,36 +286,45 @@ nb: ofn_cart_product: "Produkt:" ofn_cart_quantitiy: "Antall:" ofn_cart_send: "Kjøp" + ie_warning_headline: "Din nettleser er for gammel :-(" ie_warning_text: "For den beste opplevelsen med Open Food Network anbefaler vi på det sterkeste å oppgradere nettleseren din:" ie_warning_chrome: Last ned Chrome ie_warning_firefox: Last ned Firefox ie_warning_ie: Oppgrader Internet Explorer ie_warning_other: "Kan ikke oppgradere nettleseren din? Prøv Open Food Network på smart-telefonen din :-)" + footer_global_headline: "OFN Globalt" footer_global_home: "Hjem" footer_global_news: "Nyheter" footer_global_about: "Om" footer_global_contact: "Kontakt" + footer_sites_headline: "OFN nettsteder" footer_sites_developer: "Utvikler" footer_sites_community: "Forum" footer_sites_userguide: "Brukerhåndbok" + footer_secure: "Sikker og klarert." footer_secure_text: "Open Food Network bruker SSL-kryptering (2048 bit RSA) overalt for å holde handlingen og betalingen din privat. Våre servere lagrer ikke kortopplysninger og betalinger behandles av PCI-kompatible tjenester." + footer_contact_headline: "Hold kontakten" footer_contact_email: "Send oss en epost" + footer_nav_headline: "Naviger" footer_join_headline: "Bli med" footer_join_producers: "Bli med som Produsent" footer_join_hubs: "Bli med som Hub" footer_join_groups: "Bli med som Gruppe" footer_join_partners: "Samarbeidspartnere" + footer_legal_call: "Les våre" footer_legal_tos: "Vilkår og betingelser" footer_legal_visit: "Finn oss på" footer_legal_text_html: "Open Food Network er en plattform med fri og åpen kildekode. Vårt innhold er lisensiert med %{content_license} og vår kode med %{code_license}." + home_shop: Handle nå + brandstory_headline: "Food, unincorporated." brandstory_intro: "Noen ganger er det best å fikse systemet ved å starte et nytt..." brandstory_part1: "Vi begynner fra grunnen. Med bønder og dyrkere klare til å fortelle sine historier, stolt og virkelig. Med distributører klare til å koble mennesker med produkter på en rettferdig og ærlig måte. Med kjøpere som tror på at ukentlige innkjøpsrutiner kan bidra til å forandre verden." @@ -278,6 +333,7 @@ nb: brandstory_part4: "Det fungerer overalt. Det forandrer alt." brandstory_part5_strong: "Vi kaller det Open Food Network." brandstory_part6: "Alle er vi glad i mat. Nå kan vi elske vårt matsystem også." + system_headline: "Slik fungerer det." system_step1: "1. Søk" system_step1_text: "Søk blant våre mangfoldige, uavhengige butikker for lokal mat i sesong. Søk i nabolag og matkategori, eller om du foretrekker levering eller å hente selv." @@ -285,13 +341,16 @@ nb: system_step2_text: "Endre dine kjøpevaner med rimelig lokal mat fra mangfoldige produsenter og hubs. Oppdag historiene bak maten din og de som lager den!" system_step3: "3. Hent / Få det levert" system_step3_text: "Vent på din levering, eller besøk produsenten eller hub'en for en mer personlig kobling til maten din. Mathandling så mangfoldig slik det var ment fra naturens side." + cta_headline: "Handling som gjør verden til et bedre sted." cta_label: "Jeg er klar" + stats_headline: "Vi skaper et nytt matsystem." stats_producers: "matprodusenter" stats_shops: "matbutikker" stats_shoppers: "matkunder" stats_orders: "matbestillinger" + checkout_title: Kasse checkout_now: Gå til kassen checkout_order_ready: Bestilling klar for @@ -313,6 +372,7 @@ nb: checkout_shipping_price: Levering checkout_total_price: Sum checkout_back_to_cart: "Tilbake til Handlekurv" + order_paid: BETALT order_not_paid: IKKE BETALT order_total: Sum bestilling @@ -328,12 +388,15 @@ nb: order_includes_tax: (inkludert MVA) order_payment_paypal_successful: Din betaling via PayPal har blitt godkjent. order_hub_info: Hub info + unsaved_changes_warning: "Ulagrede endringer finnes og vil gå tapt hvis du fortsetter." unsaved_changes_error: "Felt med røde kanter inneholder feil." + products: "Produkter" products_in: "i %{oc}" products_at: "hos %{distributor}" products_elsewhere: "Produkter funnet andre steder" + email_welcome: "Velkommen" email_confirmed: "Takk for at du bekrefter din epostadresse" email_registered: "er nå en del av" @@ -351,6 +414,7 @@ nb: email_contact: "Send oss en epost:" email_signoff: "Mvh," email_signature: "%{sitename} Team" + email_confirm_customer_greeting: "Hei %{name}," email_confirm_customer_intro_html: "Takk for at du handler hos %{distributor}!" email_confirm_customer_number_html: "Ordrebekreftelse #%{number}" @@ -375,6 +439,7 @@ nb: email_shipping_collection_time: "Klar for henting:" email_shipping_collection_instructions: "Henteinstruksjoner:" email_special_instructions: "Dine kommentarer:" + email_signup_greeting: Hei! email_signup_welcome: "Velkommen til %{sitename}!" email_signup_login: Din innlogging @@ -382,11 +447,14 @@ nb: email_signup_shop_html: "Du kan begynne å handle på nett nå på %{link}." email_signup_text: "Takk for at du ble med i nettverket. Hvis du er kunde ser vi frem til å vise deg mange fantastiske bønder, flotte mathubs og deilig mat! Hvis du er produsent eller selskap er vi glade for å ha deg som en del av nettverket." email_signup_help_html: "Vi tar i mot alle dine spørsmål og tilbakemeldinger; du kan bruke Send tilbakemelding-knappen på nettsiden eller sende oss en epost på" + producer_mail_greeting: "Kjære" producer_mail_text_before: "Alle dine kunderbestillinger er klar." producer_mail_order_text: "Her er en oppsummering av bestillingene:" producer_mail_delivery_instructions: "Henting / leveringsdetaljer :" + producer_mail_text_after: "" producer_mail_signoff: "Med vennlig hilsen" + shopping_oc_closed: Stengt for bestilling shopping_oc_closed_description: "Vent til neste runde åpner (eller kontakt oss direkte for å se om vi tar i mot sene bestillinger)" shopping_oc_last_closed: "Den siste runden stengte for %{distance_of_time} siden" @@ -398,9 +466,11 @@ nb: shopping_contact_social: "Følg" shopping_groups_part_of: "er en del av:" shopping_producers_of_hub: "%{hub}s produsenter:" + enterprises_next_closing: "Neste runde stenger" enterprises_ready_for: "Klar til" enterprises_choose: "Velg når du ønsker din bestilling:" + hubs_buy: "Handle:" hubs_shopping_here: "Handler her" hubs_orders_closed: "Stengt for bestilling" @@ -416,6 +486,7 @@ nb: hubs_intro: Handle lokalt hubs_distance: Nærmest hubs_distance_filter: "Vis meg butikker nær %{location}" + products_clear_all: Fjern alt products_showing: "Viser:" products_with: med @@ -430,17 +501,21 @@ nb: products_update_error_msg: "Lagring mislyktes." products_update_error_data: "Lagring mislyktes på grunn av ugyldige data:" products_changes_saved: "Endringene er lagret." + search_no_results_html: "Beklager, ingen treff på %{query}. Prøv på nytt?" + components_profiles_popover: "Profiler har ikke butikkvindu på Open Food Network men kan ha sin egen fysiske butikk eller nettbutikk et annet sted" components_profiles_show: "Vis profiler" components_filters_nofilters: "Ingen filter" components_filters_clearfilters: "Fjern alle filtre" + groups_title: Grupper groups_headline: Grupper / regioner groups_text: "Hver prodsent er unik. Hver forretning har noe annet å tilby. Våre grupper er kollektiv av produsenter, hubs og distributører som deler noe i fellesskap som lokasjon, bondens marked eller filosofi. Dette gjør din handleopplevelse enklere. Så utforsk våre grupper og la de gjøre forberedelsene for deg." groups_search: "Søk på navn eller nøkkelord" groups_no_groups: "Fant ingen grupper" groups_about: "Om oss" + groups_producers: "Våre produsenter" groups_hubs: "Våre hubs" groups_contact_web: Kontakt @@ -467,14 +542,18 @@ nb: groups_signup_contact: Klar for å snakke sammen? groups_signup_contact_text: "Ta kontakt for å oppdage hva OFN kan gjøre for deg:" groups_signup_detail: "Her er detaljene." + login_invalid: "Ugyldig epost eller passord" + modal_hubs: "Mathubs" modal_hubs_abstract: Våre hubs er kontaktpunkt mellom deg og menneskene som lager maten din! modal_hubs_content1: Du kan søke etter en passende hub på lokasjon eller navn. Noen hubs har flere hentepunkt hvor du kan plukke opp det du har kjøpt, og noen tilbyr også levering. Hver mathub er en butikk med uavhengig drift og logistikk - så det vil være forskjeller mellom huber. modal_hubs_content2: Du kan kun handle hos en hub om gangen. + modal_groups: "Grupper / Regioner" modal_groups_content1: Dette er organisasjonene og hub-koblingene som utgjør Open Food Network. modal_groups_content2: Noen grupper er klynger basert på lokalnivå eller regionnivå, andre har ingen geografiske likheter. + modal_how: "Slik fungerer det" modal_how_shop: Handle på Open Food Network modal_how_shop_explained: Søk etter en mathub nær deg for å begynne å handle! Du kan se detaljer for hver mathub for å se hvilke godbiter som finnes, og klikk deg videre for å handle. (Du kan kun handle hos en mathub om gangen). @@ -482,8 +561,10 @@ nb: modal_how_pickup_explained: Noen mathubs leverer på døren, mens andre krever at du henter varene du har kjøpt. Du kan se hvilke alternativ som er tilgjengelige på hjemmesiden, og velge hvilket du ønsker på handle- og betalingssidene. Levering koster mer, og prisene varierer fra hub til hub. Hver mathub er en forretning med uavhengig drift og logistikk - så variasjoner mellom hubs er naturlig. modal_how_more: Finn ut mer modal_how_more_explained: "Hvis du ønsker å lære mer om Open Food Network, hvordan det fungerer og ta del, sjekk ut:" + modal_producers: "Produsenter" modal_producers_explained: "Våre produsenter lager all den herlige maten du kan handle på Open Food Network." + ocs_choice_hub: "Hub:" ocs_choice_oc: "Bestillingsrunde:" ocs_choice_text: "Du har ennå ikke valgt hvor du vil handle fra." @@ -502,6 +583,7 @@ nb: ocs_when_closing: "Stenger" ocs_when_choose: "Velg Bestillingsrunde" ocs_list: "Listevisning" + producers_about: Om oss producers_buy: Handle producers_contact: Kontakt @@ -521,6 +603,8 @@ nb: producers_signup_cta_headline: Bli med nå! producers_signup_cta_action: Bli med nå producers_signup_detail: Detaljene. + producer: Producer + products_item: Vare products_description: Beskrivelse products_variant: Variant @@ -528,7 +612,9 @@ nb: products_available: Tilgjengelig? products_producer: "Produsent" products_price: "Pris" + register_title: Registrer + shops_title: Butikker shops_headline: Handling på en ny måte. shops_text: Mat gror i syklus, bønder høster i syklus, og vi bestiller mat i syklus. Hvis du møter en stengt bestillingsrunde, sjekk igjen snart. @@ -541,6 +627,7 @@ nb: shops_signup_help: Vi er klar til å hjelpe. shops_signup_help_text: Du trenger bedre resultater. Du trenger nye kunder og logistikkpartnere. Du trenger å få din historie fortalt hos grossister, i dagligvaren og rundt kjøkkenbordet. shops_signup_detail: Detaljene. + orders_fees: Gebyrer... orders_edit_title: Handlekurv orders_edit_headline: Din handlekurv @@ -560,6 +647,7 @@ nb: orders_show_title: Ordrebekreftelse orders_show_time: Bestilling klar for orders_show_number: Ordrebekreftelse + products_cart_distributor_choice: "Distributør for bestillingen:" products_cart_distributor_change: "Din distributør for denne ordren vil bli endret til %{name} hvis du legger til dette produktet i handlekurven din." products_cart_distributor_is: "Din distributør for denne ordren er %{name}." @@ -572,9 +660,13 @@ nb: products_max_quantity: Max mengde products_distributor: Distributør products_distributor_info: Når du velger en distributør for din bestilling, vil deres adresse og hentetider vises her. + shop_trial_length: "Lengden av prøveperioden (dager)" shop_trial_expires_in: "Din prøveperiode på butikkfront går ut om " shop_trial_expired_notice: "Gode nyheter! Vi har bestemt å forlenge butikkprøveperioder inntil ytterligere beskjed." + + + # keys used in javascript password: Passord remember_me: Husk meg are_you_sure: "er du sikker?" @@ -625,6 +717,7 @@ nb: forgot_password: "Glemt passord?" password_reset_sent: "En epost med instruksjoner om å nullstille passordet har blitt sendt!" reset_password: "Tilbakestill passord" + registration_greeting: "Greetings!" who_is_managing_enterprise: "Hvem er ansvarlig for å administrere %{enterprise}?" enterprise_contact: "Primærkontakt" enterprise_contact_required: "Du må oppgi en primærkontakt." @@ -734,6 +827,7 @@ nb: bulk: "Bulk" shop_variant_quantity_min: "min" shop_variant_quantity_max: "max" + contact: "Contact" follow: "Følg" shop_for_products_html: "Handle produkter fra %{enterprise} på:" change_shop: "Endre butikk til:" @@ -746,9 +840,10 @@ nb: fundraising_fee: "innsamlingsaksjon" price_graph: "Prisgraf" included_tax: "inkludert avgift" + remove_tax: "Remove tax" balance: "Balanse" transaction: "Transaksjon" - transaction_date: "Dato" + transaction_date: "Dato" #Transaction is only in key to avoid conflict with :date payment_state: "Betallingsstatus" shipping_state: "Leveringsstatus" value: "Verdi" @@ -790,6 +885,8 @@ nb: supplier: "Leverandør" coordinator: "Koordinator" distributor: "Distributør" + product: "Products" + enterprise_fees: "Enterprise Fees" fee_type: "Avfgiftstype" tax_category: "Avgiftskategori" calculator: "Kalkulator" @@ -839,6 +936,7 @@ nb: spree_admin_enterprises_producers_total_products: "Alle Produkter" spree_admin_enterprises_producers_active_products: "Aktive Produkter" spree_admin_enterprises_producers_order_cycles: "Produkter i Bestillingsrunder" + spree_admin_enterprises_producers_order_cycles_title: "" spree_admin_enterprises_tabs_hubs: "HUBS" spree_admin_enterprises_tabs_producers: "PRODUSENTER" spree_admin_enterprises_producers_manage_order_cycles: "ADMINISTRER BESTILLINGSRUNDER" @@ -884,7 +982,7 @@ nb: hub_sidebar_blue: "blå" hub_sidebar_red: "rød" shop_trial_in_progress: "Din prøveperiode på butikkfront går ut om %{days}." - shop_trial_expired: "Gode nyheter! Vi har bestemt å forlenge butikkprøveperioder inntil ytterligere beskjed (sannsynligvis rundt mars 2015)." + shop_trial_expired: "Gode nyheter! Vi har bestemt å forlenge butikkprøveperioder inntil ytterligere beskjed (sannsynligvis rundt mars 2015)." #FIXME report_customers_distributor: "Distributør" report_customers_supplier: "Leverandør" report_customers_cycle: "Bestillingsrunde" @@ -918,12 +1016,14 @@ nb: unsaved_changes_confirmation: "Ulagrede endringer vil gå tapt. Fortsett likevel?" one_product_unsaved: "Endringer i ett produkt er fortsatt ulagret." products_unsaved: "Endringer i %{n} produkter er fortsatt ulagret." + add_manager: "Add a manager" is_already_manager: "er allerede administrator!" no_change_to_save: "Ingen endring å lagre" add_manager: "Legg til administrator" - users: "Brukere" + users: "Brukere" about: "Om" images: "Bilder" + contact: "Contact" web: "Nett" primary_details: "Primærdetaljer" adrdress: "Adresse" @@ -943,6 +1043,7 @@ nb: validation_msg_product_category_cant_be_blank: "^Produktkategori kan ikke være blank" validation_msg_tax_category_cant_be_blank: "^Avgiftskategori kan ikke være blank" validation_msg_is_associated_with_an_exising_customer: "er assosiert med en eksisterende kunde" + spree: shipment_states: backorder: restordre From 84c434c2798c82b77ea363c2387d813323a70847 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 22 Jul 2016 11:25:49 +1000 Subject: [PATCH 30/77] Remove unused/broken multi-cart feature and views This removes ten old overrides of the Spree view. Since the Spree view is not used any more and got completely replaced by custom views, the overrides were just adding noise to the code base. --- app/overrides/add_multi_cart_to_home.rb | 9 ----- app/overrides/order_cycle_selection.rb | 14 -------- app/overrides/sidebar_home_index.rb | 7 ---- app/overrides/sidebar_product_index.rb | 7 ---- app/overrides/sidebar_taxons_show.rb | 7 ---- .../split_products_by_distributor_on_home.rb | 5 --- ...roducts_by_distributor_on_products_home.rb | 5 --- ...ducts_by_distributor_on_products_search.rb | 5 --- ..._products_by_distributor_on_taxons_show.rb | 5 --- ...ange_product_render_logic.html.haml.deface | 7 ---- .../open_food_network/cart/_show.html.haml | 34 ------------------- app/views/order_cycles/_choice.html.haml | 18 ---------- .../order_cycles/_orders_closed.html.haml | 17 ---------- .../order_cycles/_orders_current.html.haml | 12 ------- app/views/order_cycles/_orders_open.html.haml | 12 ------- app/views/order_cycles/_selection.html.haml | 15 -------- app/views/spree/_sidebar.html.haml | 4 --- app/views/spree/shared/_multi_cart.html.haml | 3 -- .../_products_by_distribution.html.haml | 16 --------- config/locales/en.yml | 19 ----------- lib/open_food_network/feature_toggle.rb | 1 - 21 files changed, 222 deletions(-) delete mode 100644 app/overrides/add_multi_cart_to_home.rb delete mode 100644 app/overrides/order_cycle_selection.rb delete mode 100644 app/overrides/sidebar_home_index.rb delete mode 100644 app/overrides/sidebar_product_index.rb delete mode 100644 app/overrides/sidebar_taxons_show.rb delete mode 100644 app/overrides/split_products_by_distributor_on_home.rb delete mode 100644 app/overrides/split_products_by_distributor_on_products_home.rb delete mode 100644 app/overrides/split_products_by_distributor_on_products_search.rb delete mode 100644 app/overrides/split_products_by_distributor_on_taxons_show.rb delete mode 100644 app/overrides/spree/products/index/change_product_render_logic.html.haml.deface delete mode 100644 app/views/open_food_network/cart/_show.html.haml delete mode 100644 app/views/order_cycles/_choice.html.haml delete mode 100644 app/views/order_cycles/_orders_closed.html.haml delete mode 100644 app/views/order_cycles/_orders_current.html.haml delete mode 100644 app/views/order_cycles/_orders_open.html.haml delete mode 100644 app/views/order_cycles/_selection.html.haml delete mode 100644 app/views/spree/_sidebar.html.haml delete mode 100644 app/views/spree/shared/_multi_cart.html.haml delete mode 100644 app/views/spree/shared/_products_by_distribution.html.haml diff --git a/app/overrides/add_multi_cart_to_home.rb b/app/overrides/add_multi_cart_to_home.rb deleted file mode 100644 index e11cfaa728..0000000000 --- a/app/overrides/add_multi_cart_to_home.rb +++ /dev/null @@ -1,9 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/products/index", - :insert_after => "[data-hook='homepage_products']", - :partial => 'spree/shared/multi_cart.html', - :name => 'multi_cart_home') - -Deface::Override.new(:virtual_path => "spree/home/index", - :insert_after => "[data-hook='homepage_products']", - :partial => 'spree/shared/multi_cart.html', - :name => 'multi_cart_products') diff --git a/app/overrides/order_cycle_selection.rb b/app/overrides/order_cycle_selection.rb deleted file mode 100644 index 7ad4025bac..0000000000 --- a/app/overrides/order_cycle_selection.rb +++ /dev/null @@ -1,14 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/home/index", - :insert_before => "[data-hook='homepage_products']", - :partial => "order_cycles/selection", - :name => "order_cycle_selection_home") - -Deface::Override.new(:virtual_path => "spree/products/index", - :insert_before => "[data-hook='homepage_products']", - :partial => "order_cycles/selection", - :name => "order_cycle_selection_products") - -Deface::Override.new(:virtual_path => "spree/taxons/show", - :insert_top => "[data-hook='homepage_products']", - :partial => "order_cycles/selection", - :name => "order_cycle_selection_taxon") diff --git a/app/overrides/sidebar_home_index.rb b/app/overrides/sidebar_home_index.rb deleted file mode 100644 index 7965478336..0000000000 --- a/app/overrides/sidebar_home_index.rb +++ /dev/null @@ -1,7 +0,0 @@ -# In sidebar, always render both taxonomies and filters - -Deface::Override.new(:virtual_path => "spree/home/index", - :replace => "[data-hook='homepage_sidebar_navigation']", - :partial => 'spree/sidebar', - :name => 'sidebar_home_index', - :original => 'f5a06c5f558ec681c172ad62ddcf8f84ad0a99c4') \ No newline at end of file diff --git a/app/overrides/sidebar_product_index.rb b/app/overrides/sidebar_product_index.rb deleted file mode 100644 index 94fdd92b95..0000000000 --- a/app/overrides/sidebar_product_index.rb +++ /dev/null @@ -1,7 +0,0 @@ -# In sidebar, always render both taxonomies and filters - -Deface::Override.new(:virtual_path => "spree/products/index", - :replace => "[data-hook='homepage_sidebar_navigation']", - :partial => 'spree/sidebar', - :name => 'sidebar_product_index', - :original => 'd9d1b3d18721e1c68eeaac898ca006bf8afb176c') \ No newline at end of file diff --git a/app/overrides/sidebar_taxons_show.rb b/app/overrides/sidebar_taxons_show.rb deleted file mode 100644 index 510b24ef1d..0000000000 --- a/app/overrides/sidebar_taxons_show.rb +++ /dev/null @@ -1,7 +0,0 @@ -# In sidebar, always render both taxonomies and filters - -Deface::Override.new(:virtual_path => "spree/taxons/show", - :replace => "[data-hook='taxon_sidebar_navigation']", - :partial => 'spree/sidebar', - :name => 'sidebar_taxons_show', - :original => '697641363ffdb1fce91d8eea7cc883e983236ed2') \ No newline at end of file diff --git a/app/overrides/split_products_by_distributor_on_home.rb b/app/overrides/split_products_by_distributor_on_home.rb deleted file mode 100644 index 1481c17799..0000000000 --- a/app/overrides/split_products_by_distributor_on_home.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/home/index", - :replace => "[data-hook='homepage_products']", - :partial => "spree/shared/products_by_distribution", - :name => "split_products_by_distribution_on_home", - :original => '589053f6f3e534b0be729081bdfc0378beb29cca') diff --git a/app/overrides/split_products_by_distributor_on_products_home.rb b/app/overrides/split_products_by_distributor_on_products_home.rb deleted file mode 100644 index b8f9d90e2b..0000000000 --- a/app/overrides/split_products_by_distributor_on_products_home.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/products/index", - :replace => "[data-hook='homepage_products']", - :partial => "spree/shared/products_by_distribution", - :name => "split_products_by_distribution_on_products_home", - :original => '22097416de0a5851d43c572301779de06ed84d17') diff --git a/app/overrides/split_products_by_distributor_on_products_search.rb b/app/overrides/split_products_by_distributor_on_products_search.rb deleted file mode 100644 index 21937310da..0000000000 --- a/app/overrides/split_products_by_distributor_on_products_search.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/products/index", - :replace => "[data-hook='search_results']", - :partial => "spree/shared/products_by_distribution", - :name => "split_products_by_distribution_on_products_search", - :original => '5a764faee41bd3f2bb13b60bfeb61e63fede9fac') diff --git a/app/overrides/split_products_by_distributor_on_taxons_show.rb b/app/overrides/split_products_by_distributor_on_taxons_show.rb deleted file mode 100644 index c2c9419391..0000000000 --- a/app/overrides/split_products_by_distributor_on_taxons_show.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/taxons/show", - :replace => "[data-hook='taxon_products']", - :partial => "spree/shared/products_by_distribution", - :name => "split_products_by_distribution_on_taxons_show", - :original => '27b6ecd3954022246568b3ddf5e80462aa511ece') diff --git a/app/overrides/spree/products/index/change_product_render_logic.html.haml.deface b/app/overrides/spree/products/index/change_product_render_logic.html.haml.deface deleted file mode 100644 index 55f7f62d08..0000000000 --- a/app/overrides/spree/products/index/change_product_render_logic.html.haml.deface +++ /dev/null @@ -1,7 +0,0 @@ -/ replace_contents "[data-hook='homepage_products']" - -- if current_order_cycle - - if @products.empty? - %h6.search-results-title= t(:no_products_found) - - else - = render :partial => 'spree/shared/products', :locals => { :products => @products, :taxon => @taxon } diff --git a/app/views/open_food_network/cart/_show.html.haml b/app/views/open_food_network/cart/_show.html.haml deleted file mode 100644 index 5cebd3f40c..0000000000 --- a/app/views/open_food_network/cart/_show.html.haml +++ /dev/null @@ -1,34 +0,0 @@ -/ %script = Spree.api_key = raw(try_spree_current_user.try(:spree_api_key).to_s.inspect) - -= t :ofn_cart_headline -= spree_current_user.andand.email -%div{ 'ng-app' => 'store', 'ng-controller' => 'CartCtrl', 'ng-init' => "loadCart(#{spree_current_user.andand.cart.andand.id});" } - {{cart}} {{state}} - %br - %br - %ul - %li(ng-repeat="order in cart.orders") - %strong - = t :ofn_cart_distributor - {{order.distributor}} - %strong - = t :ofn_cart_oc - {{order.order_cycle.andand.name}} - %strong - = t :ofn_cart_from - {{order.order_cycle.andand.orders_open_at}} - %strong - = t :ofn_cart_to - {{order.order_cycle.andand.orders_close_at}} - %ul - %li(ng-repeat="line_item in order.line_items") - %strong - = t :ofn_cart_product - {{line_item.name}} - %strong - = t :ofn_cart_quatity - {{line_item.quantity}} - %button - = t :ofn_cart_send - %br - diff --git a/app/views/order_cycles/_choice.html.haml b/app/views/order_cycles/_choice.html.haml deleted file mode 100644 index 7b1cfeb444..0000000000 --- a/app/views/order_cycles/_choice.html.haml +++ /dev/null @@ -1,18 +0,0 @@ - -- if order_cycles_enabled? - #distribution-choice - - if current_distributor.present? - %p - %strong - = t :ocs_choice_distributor - = current_distributor.name - - - if current_order_cycle.present? - %p - %strong - = t :ocs_choice_oc - = current_order_cycle.name - - - if current_distributor.nil? && current_order_cycle.nil? - %p - = t :ocs_choice_text diff --git a/app/views/order_cycles/_orders_closed.html.haml b/app/views/order_cycles/_orders_closed.html.haml deleted file mode 100644 index 782c680add..0000000000 --- a/app/views/order_cycles/_orders_closed.html.haml +++ /dev/null @@ -1,17 +0,0 @@ -.columns.two= image_tag 'pickup.png' -.columns.nine - %h2 - = t :ocs_closed_headline - %p - - if most_recently_closed = OrderCycle.most_recently_closed_for(@enterprise) - = t :ocs_closed_time, time: distance_of_time_in_words_to_now(most_recently_closed.orders_close_at) - = t :ocs_closed_contact - - - if next_oc = OrderCycle.first_opening_for(@enterprise) - %h4 - = t :ocs_closed_opens, time: distance_of_time_in_words_to_now(next_oc.orders_open_at) - - %p - = t(:ocs_closed_email, email: current_distributor.email_address) if current_distributor.email_address - %br/ - = t(:ocs_closed_phone, phone: current_distributor.phone) if current_distributor.phone diff --git a/app/views/order_cycles/_orders_current.html.haml b/app/views/order_cycles/_orders_current.html.haml deleted file mode 100644 index 185011690d..0000000000 --- a/app/views/order_cycles/_orders_current.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -.columns.six - %h1 - = t :ocs_pickup_time, pickup_time: pickup_time - %i - = link_to t(:ocs_change_date), spree.clear_orders_path, :id => 'reset_order_cycle' - = t :ocs_change_date_notice -.columns.five - .row - %strong - = t :ocs_close_time - .countdown-panel - %h1= distance_of_time_in_words_to_now(current_order_cycle.orders_close_at) diff --git a/app/views/order_cycles/_orders_open.html.haml b/app/views/order_cycles/_orders_open.html.haml deleted file mode 100644 index 66ee9509e6..0000000000 --- a/app/views/order_cycles/_orders_open.html.haml +++ /dev/null @@ -1,12 +0,0 @@ -.columns.two= image_tag 'pickup.png' -.columns.six - %h2 - = t :ocs_when_headline - %p - = t :ocs_when_text -.columns.three - = form_for current_order(true), :html => {:id => 'order_cycle_select'} do |f| - = f.hidden_field :distributor_id, :value => @enterprise.id - .order-cycles - = f.select :order_cycle_id, order_cycle_options, {include_blank: t(:ocs_when_closing)} - = hidden_field_tag :commit, t(:ocs_when_choose) diff --git a/app/views/order_cycles/_selection.html.haml b/app/views/order_cycles/_selection.html.haml deleted file mode 100644 index 949766a162..0000000000 --- a/app/views/order_cycles/_selection.html.haml +++ /dev/null @@ -1,15 +0,0 @@ -- if order_cycles_enabled? - #distribution-selection.row - - - if current_order_cycle# && current_order_cycle.exchanges.to_enterprises(current_distributor).outgoing.any? - = render partial: "order_cycles/orders_current" - - - elsif order_cycle_options.empty? - = render partial: "order_cycles/orders_closed" - - - else - = render partial: "order_cycles/orders_open" - -%p - %strong= link_to t(:ocs_list), shop_path - diff --git a/app/views/spree/_sidebar.html.haml b/app/views/spree/_sidebar.html.haml deleted file mode 100644 index a7a11f5733..0000000000 --- a/app/views/spree/_sidebar.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -= render :partial => 'order_cycles/choice' -= render :partial => 'spree/shared/taxonomies' -= render :partial => 'spree/shared/filters' -= render :partial => 'spree/products/source_sidebar' diff --git a/app/views/spree/shared/_multi_cart.html.haml b/app/views/spree/shared/_multi_cart.html.haml deleted file mode 100644 index 6125d637b9..0000000000 --- a/app/views/spree/shared/_multi_cart.html.haml +++ /dev/null @@ -1,3 +0,0 @@ - -- if OpenFoodNetwork::FeatureToggle.enabled? :multi_cart - = render :partial => 'open_food_network/cart/show' \ No newline at end of file diff --git a/app/views/spree/shared/_products_by_distribution.html.haml b/app/views/spree/shared/_products_by_distribution.html.haml deleted file mode 100644 index 39a50f80ac..0000000000 --- a/app/views/spree/shared/_products_by_distribution.html.haml +++ /dev/null @@ -1,16 +0,0 @@ -%div(data-hook='homepage_products') - = home_page_cms_content - - - if @products - #products= render 'spree/shared/products', :products => @products, :taxon => @taxon - - else - #products-local - %h2 - = t :products - = t :products_in, oc: current_order_cycle.name if current_order_cycle - = t :products_at, distributor: current_distributor.name if current_distributor - = render 'spree/shared/products', :products => @products_local, :taxon => @taxon - #products-remote - %h2 - = t :products_elsewhere - = render 'spree/shared/products', :products => @products_remote, :taxon => @taxon diff --git a/config/locales/en.yml b/config/locales/en.yml index 9f1b6cfabc..d5ed777e17 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -571,25 +571,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using modal_producers: "Producers" modal_producers_explained: "Our producers make all the delicious food you can shop for on the Open Food Network." - ocs_choice_hub: "Hub:" - ocs_choice_oc: "Order Cycle:" - ocs_choice_text: "You have not yet picked where you will get your order from." - ocs_closed_headline: Orders are currently closed for this hub - ocs_closed_time: "The last cycle closed %{time} ago." - ocs_closed_contact: "Please contact your hub directly to see if they accept late orders, or wait until the next cycle opens." - ocs_closed_opens: "The next order cycle opens in %{time}" - ocs_closed_email: "Email: %{email}" - ocs_closed_phone: "Phone: %{phone}" - ocs_pickup_time: "Your order will be ready on %{pickup_time}" - ocs_change_date: "Change Collection Date" - ocs_change_date_notice: "(This will reset your cart)" - ocs_close_time: "ORDERS CLOSE" - ocs_when_headline: When do you want your order? - ocs_when_text: No products are displayed until you select a date. - ocs_when_closing: "Closing On" - ocs_when_choose: "Choose Order Cycle" - ocs_list: "List View" - producers_about: About us producers_buy: Shop for producers_contact: Contact diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index e95be176fc..024a17e068 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -10,7 +10,6 @@ module OpenFoodNetwork {eaterprises: true, local_organics: false, order_cycles: true, - multi_cart: false, enterprises_distributor_info_rich_text: true} end end From dee0fa6724464a29297451761ee6a09e5bfd4538 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 22 Jul 2016 14:10:16 +1000 Subject: [PATCH 31/77] Trigger checkout click more reliably in specs --- spec/features/consumer/shopping/variant_overrides_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index b59cb6a613..f600a0c269 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -199,7 +199,7 @@ feature "shopping with variant overrides defined", js: true do def click_checkout show_cart wait_until_enabled 'li.cart a.button' - click_link 'Checkout now', match: :first + first(:link, 'Checkout now').click end end From 9e03a130c2cf1822cad94640b151d89fe4368b85 Mon Sep 17 00:00:00 2001 From: Lynne Davis Date: Wed, 27 Jul 2016 18:40:28 +0100 Subject: [PATCH 32/77] Updating GB translation, from transifex --- config/locales/en-GB.yml | 346 +++++++++++++++++++++------------------ 1 file changed, 184 insertions(+), 162 deletions(-) diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index eb49b9a89b..035d74ea1c 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -1,22 +1,26 @@ -# Localization file for British English. Add more files in this directory for other locales. -# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. +# English language file +# --------------------- +# +# This is the source language file maintained by the Australian OFN team. +# 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 +# +# - uploading the file to Transifex or +# - opening a pull request at GitHub. +# +# +# See http://community.openfoodnetwork.org/t/localisation-ofn-in-your-language/397 - -en-GB: +en_GB: activerecord: - errors: - models: - spree/user: - attributes: - password: - confirmation: you have successfully registered - too_short: pick a longer name # Overridden here due to a bug in spree i18n (Issue #870) attributes: spree/order: payment_state: Payment State shipment_state: Shipment State - devise: failure: invalid: | @@ -28,13 +32,18 @@ en-GB: not_confirmed: Your email address could not be confirmed. Perhaps you have already completed this step? confirmation_sent: "Confirmation email sent!" confirmation_not_sent: "Could not send a confirmation email." + enterprise_mailer: + confirmation_instructions: + subject: "Please confirm the email address for %{enterprise}" + welcome: + subject: "%{enterprise} is now on %{sitename}" home: "OFN" title: Open Food Network welcome_to: 'Welcome to ' - site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can…" + site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world." search_by_name: Search by name... - producers: UK Producers - producers_join: UK producers are now welcome to join Open Food Network UK. + producers: 'UK Producers' + producers_join: UK producers are now welcome to join Open Food Network UK. #FIXME charges_sales_tax: Charges VAT? print_invoice: "Print Invoice" send_invoice: "Send Invoice" @@ -45,6 +54,7 @@ en-GB: cancel_order: "Cancel Order" confirm_send_invoice: "An invoice for this order will be sent to the customer. Are you sure you want to continue?" confirm_resend_order_confirmation: "Are you sure you want to resend the order confirmation email?" + must_have_valid_business_number: "Please enter your company number." invoice: "Invoice" percentage_of_sales: "%{percentage} of sales" percentage_of_turnover: "Percentage of turnover" @@ -53,31 +63,41 @@ en-GB: per_month: "per month" free: "free" free_trial: "free trial" - plus_tax: "plus GST" - total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)" + plus_tax: "plus VAT" + total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. VAT)" min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}" + business_model_configuration: "Business model configuration" say_no: "No" say_yes: "Yes" then: then sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By" - # To customise text in emails. - producer_mail_greeting: "Dear" - producer_mail_text_before: "We now have all the consumer orders for the next food drop." - producer_mail_order_text: "Here is a summary of the orders for your products:" - producer_mail_delivery_instructions: "Stock pickup/delivery instructions:" - producer_mail_text_after: "Please confirm that you have got this email. Please send me an invoice for this amount so that we can send you payment. If you need to phone me on the day, please use the number below." - producer_mail_signoff: "Thanks and best wishes" admin: + # Common properties / models + date: Date + email: Email + name: Name + on_hand: In Stock + on_demand: On Demand + on_demand?: On Demand? + order_cycle: Order Cycle + phone: Phone + price: Price + producer: Producer + product: Product + quantity: Quantity + shop: Shop + sku: SKU + tags: Tags + variant: Variant + # General form elements quick_search: Quick Search clear_all: Clear All - producer: Producer - shop: Shop - product: Product - variant: Variant + start_date: "Start Date" + end_date: "End Date" columns: Columns actions: Actions @@ -85,42 +105,86 @@ en-GB: whats_this: What's this? + tag_has_rules: "Existing rules for this tag: %{num}" + has_one_rule: "has one rule" + has_n_rules: "has %{num} rules" + customers: index: - add_customer: "Add customer" + add_customer: "Add Customer" + new_customer: "New Customer" customer_placeholder: "customer@example.org" - inventory: - title: Inventory - description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page - sku: SKU - price: Price - on_hand: On Hand - on_demand: On Demand? - enable_reset: Enable Stock Level Reset? - inherit: Inherit? - add: Add - hide: Hide - select_a_shop: Select A Shop - review_now: Review Now - new_products_alert_message: There are %{new_product_count} new products available to add to your inventory. - currently_empty: Your inventory is currently empty - no_matching_products: No matching products found in your inventory - no_hidden_products: No products have been hidden from this inventory - no_matching_hidden_products: No hidden products match your search criteria - no_new_products: No new products are available to add to this inventory - no_matching_new_products: No new products match your search criteria - inventory_powertip: This is your inventory of products. To add products to your inventory, select 'New Products' from the Viewing dropdown. - hidden_powertip: These products have been hidden from your inventory and will not be available to add to your shop. You can click 'Add' to add a product to you inventory. - new_powertip: These products are available to be added to your inventory. Click 'Add' to add a product to your inventory, or 'Hide' to hide it from view. You can always change your mind later! + valid_email_error: Please enter a valid email address + add_a_new_customer_for: Add a new customer for %{shop_name} + code: Code + duplicate_code: "This code is used already." + products: + bulk_edit: + unit: Unit + display_as: Display As + category: Category + tax_category: Tax Category + inherits_properties?: Inherits Properties? + available_on: Available On + av_on: "Av. On" - order_cycle: - choose_products_from: "Choose Products From:" + variant_overrides: + index: + title: Inventory + description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page + enable_reset?: Enable Stock Reset? + inherit?: Inherit? + add: Add + hide: Hide + select_a_shop: Select A Shop + review_now: Review Now + new_products_alert_message: '' + currently_empty: Your inventory is currently empty + no_matching_products: No matching products found in your inventory + no_hidden_products: No products have been hidden from this inventory + no_matching_hidden_products: No hidden products match your search criteria + no_new_products: No new products are available to add to this inventory + no_matching_new_products: No new products match your search criteria + inventory_powertip: This is your inventory of products. To add products to your inventory, select 'New Products' from the Viewing dropdown. + hidden_powertip: These products have been hidden from your inventory and will not be available to add to your shop. You can click 'Add' to add a product to you inventory. + new_powertip: These products are available to be added to your inventory. Click 'Add' to add a product to your inventory, or 'Hide' to hide it from view. You can always change your mind later! + + orders: + bulk_management: + tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required." + shared: "Shared Resource?" + order_no: "Order No." + order_date: "Order Date" + max: "Max" + product_unit: "Product: Unit" + weight_volume: "Weight/Volume" + ask: "Ask?" + page_title: "Bulk Order Management" + actions_delete: "Delete Selected" + loading: "Loading orders" + no_results: "No orders found." + group_buy_unit_size: "Group Buy Unit Size" + total_qtt_ordered: "Total Quantity Ordered" + max_qtt_ordered: "Max Quantity Ordered" + current_fulfilled_units: "Current Fulfilled Units" + 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" + + order_cycles: + edit: + choose_products_from: "Choose Products From:" enterprise: select_outgoing_oc_products_from: Select outgoing OC products from enterprises: + index: + producer?: '' + package: '' + status: '' + manage: '' form: primary_details: shopfront_requires_login: "Shopfront requires login?" @@ -135,7 +199,7 @@ en-GB: show_on_map: "Show all on the map" shared: register_call: - selling_on_ofn: "Interested in getting on the Open Food Network?" + selling_on_ofn: "Interested in selling through the Open Food Network?" register: "Register here" shop: messages: @@ -157,7 +221,7 @@ en-GB: logo_mobile_svg: "Mobile logo (SVG)" #FIXME home_hero: "Hero image" home_show_stats: "Show statistics" - footer_logo: "Logo (220x76)" + footer_logo: "Logo (220x76)" #FIXME footer_facebook_url: "Facebook URL" footer_twitter_url: "Twitter URL" footer_instagram_url: "Instagram URL" @@ -183,11 +247,9 @@ en-GB: country: Country unauthorized: Unauthorized terms_of_service: "Terms of service" - on_demand: On demand + on_demand: To Order none: None - alert_selling_on_ofn: "Interested in selling food on the Open Food Network?" - alert_start_here: "Start here" label_shops: "Shops" label_map: "Map" label_producers: "Producers" @@ -200,8 +262,9 @@ en-GB: label_administration: "Administration" label_admin: "Admin" label_account: "Account" - label_more: "More" + label_more: "Show more" label_less: "Show less" + label_notices: "Community Forum" items: "items" cart_headline: "Your shopping cart" @@ -308,7 +371,7 @@ en-GB: checkout_cart_total: Cart total checkout_shipping_price: Shipping checkout_total_price: Total - checkout_back_to_cart: "Back to Cart" + checkout_back_to_cart: "Back to cart" order_paid: PAID order_not_paid: NOT PAID @@ -319,28 +382,12 @@ en-GB: order_delivery_address: Delivery address order_special_instructions: "Your notes:" order_pickup_time: Ready for collection - order_pickup_instructions: Collection Instructions + order_pickup_instructions: Collection instructions order_produce: Produce order_total_price: Total order_includes_tax: (includes tax) order_payment_paypal_successful: Your payment via PayPal has been processed successfully. - order_hub_info: Hub Info - - bom_tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required." - bom_shared: "Shared Resource?" - bom_page_title: "Bulk Order Management" - bom_no: "Order no." - bom_date: "Order date" - bom_cycle: "Order cycle" - bom_max: "Max" - bom_hub: "Hub" - bom_variant: "Product: Unit" - bom_final_weigth_volume: "Weight/Volume" - bom_quantity: "Quantity" - bom_actions_delete: "Delete Selected" - bom_loading: "Loading orders" - bom_no_results: "No orders found." - bom_order_error: "Some errors must be resolved before you can update orders.\nAny fields with red borders contain errors." + order_hub_info: Hub info unsaved_changes_warning: "Unsaved changes exist and will be lost if you continue." unsaved_changes_error: "Fields with red borders contain errors." @@ -353,19 +400,15 @@ en-GB: email_welcome: "Welcome" email_confirmed: "Thank you for confirming your email address." email_registered: "is now part of" - email_userguide_html: "The User Guide with detailed support for setting up your Producer or Hub is here: -%{link}" + email_userguide_html: "The User Guide with detailed support for setting up your Producer or Hub is here: %{link}" 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}" + 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}" email_help: "If you have any difficulties, check out our FAQs, browse the forum or post a 'Support' topic and someone will help you out!" 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_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." 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_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_userguide: "User Guide" email_social: "Connect with Us:" email_contact: "Email us:" @@ -402,11 +445,16 @@ See the %{link} to find out more about %{sitename}'s features and to start using email_signup_login: Your login email_signup_email: Your login email is email_signup_shop_html: "You can start shopping online now 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_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" + producer_mail_greeting: "" + producer_mail_text_before: "" + producer_mail_order_text: "" + producer_mail_delivery_instructions: "" + producer_mail_text_after: "" + producer_mail_signoff: "" + shopping_oc_closed: Orders are closed shopping_oc_closed_description: "Please wait until the next cycle opens (or contact us directly to see if we can accept any late orders)" shopping_oc_last_closed: "The last cycle closed %{distance_of_time} ago" @@ -532,9 +580,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using ocs_close_time: "ORDERS CLOSE" ocs_when_headline: When do you want your order? ocs_when_text: No products are displayed until you select a date. - ocs_when_closing: "Closing On" + ocs_when_closing: "Closing on" ocs_when_choose: "Choose Order Cycle" - ocs_list: "List View" + ocs_list: "List view" producers_about: About us producers_buy: Shop for @@ -561,20 +609,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using products_description: Description products_variant: Variant products_quantity: Quantity - products_availabel: Available? + products_available: '' products_producer: "Producer" products_price: "Price" - products_sku: "SKU" - products_name: "name" - products_unit: "unit" - products_on_hand: "on hand" - products_on_demand: "On demand?" - products_category: "Category" - products_tax_category: "tax category" - products_available_on: "Available On" - products_inherit: "Inherit?" - products_inherits_properties: "Inherits Properties?" - products_stock_level_reset: "Enable Stock Level Reset?" register_title: Register @@ -592,7 +629,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using shops_signup_detail: Here's the detail. orders_fees: Fees... - orders_edit_title: Shopping Cart + orders_edit_title: Shopping cart orders_edit_headline: Your shopping cart orders_edit_time: Order ready for orders_edit_continue: Continue shopping @@ -620,14 +657,14 @@ See the %{link} to find out more about %{sitename}'s features and to start using products_oc_is: "Your order cycle for this order is %{name}." products_oc_error: "Please complete your order from %{link} before shopping in a different order cycle." products_oc_current: "your current order cycle" - products_quantity: Quantity products_max_quantity: Max quantity products_distributor: Distributor products_distributor_info: When you select a distributor for your order, their address and pickup times will be displayed here. - shop_trial_length: "Shop Trial Length (Days)" - shop_trial_expires_in: "Your shopfront trial expires in" - shop_trial_expired_notice: "Open Food Network UK is currently free while we prepare for our soft launch in April, 2016." + shop_trial_length: "" + shop_trial_expires_in: "" + shop_trial_expired_notice: "" + # keys used in javascript password: Password @@ -674,15 +711,15 @@ See the %{link} to find out more about %{sitename}'s features and to start using confirm_password: "Confirm password" action_signup: "Sign up now" welcome_to_ofn: "Welcome to the Open Food Network!" - signup_or_login: "Start By Signing Up (or logging in)" + signup_or_login: "Start By signing up (or logging in)" have_an_account: "Already have an account?" action_login: "Log in now." - forgot_password: "Forgot Password?" + forgot_password: "Forgot password?" password_reset_sent: "An email with instructions on resetting your password has been sent!" reset_password: "Reset password" registration_greeting: "Greetings!" who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?" - enterprise_contact: "Primary Contact" + enterprise_contact: "Primary contact" enterprise_contact_required: "You need to enter a primary contact." enterprise_email_address: "Email address" enterprise_phone: "Phone number" @@ -692,20 +729,20 @@ See the %{link} to find out more about %{sitename}'s features and to start using limit_reached_message: "You have reached the limit!" limit_reached_text: "You have reached the limit for the number of enterprises you are allowed to own on the" limit_reached_action: "Return to the homepage" - select_promo_image: "Step 3. Select Promo Image" + select_promo_image: "Step 3. Select promo image" promo_image_tip: "Tip: Shown as a banner, preferred size is 1200×260px" promo_image_label: "Choose a promo image" action_or: "OR" promo_image_drag: "Drag and drop your promo here" - review_promo_image: "Step 4. Review Your Promo Banner" + review_promo_image: "Step 4. Review your promo banner" review_promo_image_tip: "Tip: for best results, your promo image should fill the available space" promo_image_placeholder: "Your logo will appear here for review once uploaded" uploading: "Uploading..." - select_logo: "Step 1. Select Logo Image" + select_logo: "Step 1. Select logo image" logo_tip: "Tip: Square images will work best, preferably at least 300×300px" logo_label: "Choose a logo image" logo_drag: "Drag and drop your logo here" - review_logo: "Step 2. Review Your Logo" + review_logo: "Step 2. Review your logo" review_logo_tip: "Tip: for best results, your logo should fill the available space" logo_placeholder: "Your logo will appear here for review once uploaded" enterprise_about_headline: "Nice one!" @@ -752,8 +789,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using registration_finished_thanks: "Thanks for filling out the details for %{enterprise}." registration_finished_login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin." registration_finished_activate: "Activate %{enterprise}." - registration_finished_activate_instruction_html: "We've sent a confirmation email to %{email} if it hasn't been activated before.
-Please follow the instructions there to make your enterprise visible on the Open Food Network." + registration_finished_activate_instruction_html: "We've sent a confirmation email to %{email} if it hasn't been activated before.
Please follow the instructions there to make your enterprise visible on the Open Food Network." registration_finished_action: "Open Food Network home" registration_type_headline: "Last step to add %{enterprise}!" registration_type_question: "Are you a producer?" @@ -762,14 +798,14 @@ Please follow the instructions there to make your enterprise visible on the Open registration_type_error: "Please choose one. Are you are producer?" 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." - create_profile: "Create Profile" + create_profile: "Create profile" registration_images_headline: "Thanks!" registration_images_description: "Let's upload some pretty pictures so your profile looks great! :)" - registration_detail_headline: "Let's Get Started" + registration_detail_headline: "Let's get started" registration_detail_enterprise: "Woot! First we need to know a little bit about your enterprise:" registration_detail_producer: "Woot! First we need to know a little bit about your farm:" - registration_detail_name_enterprise: "Enterprise Name:" - registration_detail_name_producer: "Farm Name:" + registration_detail_name_enterprise: "Enterprise name:" + registration_detail_name_producer: "Farm name:" registration_detail_name_placeholder: "e.g. Charlie's Awesome Farm" registration_detail_name_error: "Please choose a unique name for your enterprise" registration_detail_address1: "Address line 1:" @@ -826,26 +862,23 @@ Please follow the instructions there to make your enterprise visible on the Open admin_entreprise_groups: "Enterprise Groups" admin_entreprise_groups_name: "Name" admin_entreprise_groups_owner: "Owner" - admin_entreprise_groups_on_front_page: "On front page ?" + admin_entreprise_groups_on_front_page: "On front page?" admin_entreprise_groups_entreprise: "Enterprises" - admin_entreprise_groups_primary_details: "Primary Details" admin_entreprise_groups_data_powertip: "The primary user responsible for this group." admin_entreprise_groups_data_powertip_logo: "This is the logo for the group" admin_entreprise_groups_data_powertip_promo_image: "This image is displayed at the top of the Group profile" - admin_entreprise_groups_about: "About" - admin_entreprise_groups_images: "Images" admin_entreprise_groups_contact: "Contact" admin_entreprise_groups_contact_phone_placeholder: "eg. 98 7654 3210" admin_entreprise_groups_contact_address1_placeholder: "eg. 123 High Street" admin_entreprise_groups_contact_city: "Suburb" - admin_entreprise_groups_contact_city_placeholder: "eg. Northcote" + admin_entreprise_groups_contact_city_placeholder: "eg. Camden" admin_entreprise_groups_contact_zipcode: "Postcode" - admin_entreprise_groups_contact_zipcode_placeholder: "eg. 3070" - admin_entreprise_groups_contact_state_id: "State" + admin_entreprise_groups_contact_zipcode_placeholder: "eg. NW1 0AA" + admin_entreprise_groups_contact_state_id: "County" admin_entreprise_groups_contact_country_id: "Country" admin_entreprise_groups_web: "Web Resources" - admin_entreprise_groups_web_twitter: "eg. @the_prof" - admin_entreprise_groups_web_website_placeholder: "eg. www.truffles.com" + admin_entreprise_groups_web_twitter: "eg. @openfoodnetuk" + admin_entreprise_groups_web_website_placeholder: "eg. www.truffles.co.uk" admin_order_cycles: "Admin Order Cycles" open: "Open" close: "Close" @@ -859,7 +892,7 @@ Please follow the instructions there to make your enterprise visible on the Open calculator: "Calculator" calculator_values: "Calculator values" new_order_cycles: "New Order Cycles" - select_a_coordinator_for_your_order_cycle: "select a coordinator for your order cycle" + select_a_coordinator_for_your_order_cycle: "" edit_order_cycle: "Edit Order Cycle" roles: "Roles" update: "Update" @@ -868,8 +901,8 @@ Please follow the instructions there to make your enterprise visible on the Open update_invoice: "Update Invoices" finalise_invoice: "Finalise Invoices" finalise_user_invoices: "Finalise User Invoices" - finalise_user_invoice_explained: "Use this button to finalize all invoices in the system for the previous calendar month. This task can be set up to run automatically once a month." - manually_run_task: "Manually Run Task " + finalise_user_invoice_explained: "Use this button to finalise all invoices in the system for the previous calendar month. This task can be set up to run automatically once a month." + manually_run_task: "Manually Run Task" update_user_invoices: "Update User Invoices" update_user_invoice_explained: "Use this button to immediately update invoices for the month to date for each enterprise user in the system. This task can be set up to run automatically every night." auto_finalise_invoices: "Auto-finalise invoices monthly on the 2nd at 1:30am" @@ -889,7 +922,7 @@ Please follow the instructions there to make your enterprise visible on the Open producer: "Producer" product: "Product" price: "Price" - on_hand: "On hand" + on_hand: "In stock" save_changes: "Save Changes" spree_admin_overview_enterprises_header: "My Enterprises" spree_admin_overview_enterprises_footer: "MANAGE MY ENTERPRISES" @@ -917,7 +950,7 @@ Please follow the instructions there to make your enterprise visible on the Open spree_admin_single_enterprise_alert_mail_confirmation: "Please confirm the email address for" spree_admin_single_enterprise_alert_mail_sent: "We've sent an email to" spree_admin_overview_action_required: "Action Required" - spree_admin_overview_check_your_inbox: "Please check you inbox for furher instructions. Thanks!" + spree_admin_overview_check_your_inbox: "Please check you inbox for further instructions. Thanks!" change_package: "Change Package" spree_admin_single_enterprise_hint: "Hint: To allow people to find you, turn on your visibility under" your_profil_live: "Your profile live" @@ -932,19 +965,7 @@ Please follow the instructions there to make your enterprise visible on the Open manage_products: "Manage products" edit_profile_details: "Edit profile details" edit_profile_details_etc: "Change your profile description, images, etc." - start_date: "Start Date" - end_date: "End Date" order_cycle: "Order Cycle" - group_buy_unit_size: "Group Buy Unit Size" - total_qtt_ordered: "Total Quantity Ordered" - max_qtt_ordered: "Max Quantity Ordered" - current_fulfilled_units: "Current Fulfilled Units" - max_fulfilled_units: "Max Fulfilled Units" - bulk_management_warning: "WARNING: Some variants do not have a unit value" - ask: "Ask?" - no_orders_found: "No orders found." - order_no: "Order No." - weight_volume: "Weight/Volume" remove_tax: "Remove tax" tax_settings: "Tax Settings" products_require_tax_category: "products require tax category" @@ -953,7 +974,7 @@ Please follow the instructions there to make your enterprise visible on the Open admin_share_city: "City" admin_share_zipcode: "Postcode" admin_share_country: "Country" - admin_share_state: "State" + admin_share_state: "County" hub_sidebar_hubs: "Hubs" hub_sidebar_none_available: "None Available" hub_sidebar_manage: "Manage" @@ -961,32 +982,32 @@ Please follow the instructions there to make your enterprise visible on the Open hub_sidebar_blue: "blue" hub_sidebar_red: "red" shop_trial_in_progress: "Your shopfront trial expires in %{days}." - shop_trial_expired: "Good news! We have decided to extend shopfront trials until further notice (probably around March 2015)." #FIXME + shop_trial_expired: "To view or change your current Open Food Network plan go to the Dashboard -> Change Package." #FIXME report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" report_customers_type: "Report Type" report_customers_csv: "Download as csv" - report_producers: "Producers: " - report_type: "Report Type: " - report_hubs: "Hubs: " - report_payment: "Payment Methods: " - report_distributor: "Distributor: " + report_producers: "Producers:" + report_type: "Report Type:" + report_hubs: "Hubs:" + report_payment: "Payment Methods:" + report_distributor: "Distributor:" report_payment_by: 'Payments By Type' report_itemised_payment: 'Itemised Payment Totals' report_payment_totals: 'Payment Totals' report_all: 'all' - report_order_cycle: "Order Cycle: " - report_entreprises: "Enterprises: " - report_users: "Users: " + report_order_cycle: "Order Cycle:" + report_entreprises: "Enterprises:" + report_users: "Users:" initial_invoice_number: "Initial invoice number:" invoice_date: "Invoice date:" - due_date: "Due date:" + due_date: "Invoice date:" account_code: "Account code:" equals: "Equals" contains: "contains" discount: "Discount" - filter_products: "Filter Products" + filter_products: " Filter Products" delete_product_variant: "The last variant cannot be deleted!" progress: "progress" saving: "Saving.." @@ -997,7 +1018,7 @@ Please follow the instructions there to make your enterprise visible on the Open products_unsaved: "Changes to %{n} products remain unsaved." add_manager: "Add a manager" is_already_manager: "is already a manager!" - no_change_to_save: " No change to save" + no_change_to_save: "No change to save" add_manager: "Add a manager" users: "Users" about: "About" @@ -1012,6 +1033,7 @@ Please follow the instructions there to make your enterprise visible on the Open properties: "Properties" shipping_methods: "Shipping Methods" payment_methods: "Payment Methods" + payment_method_fee: "" enterprise_fees: "Enterprise Fees" inventory_settings: "Inventory Settings" tag_rules: "Tag Rules" @@ -1039,7 +1061,7 @@ Please follow the instructions there to make your enterprise visible on the Open pending: pending processing: processing void: void - invalid: invalid + invalid: '' order_state: address: address adjustments: adjustments From ba854d12c86e0ef959957a7f3cedde834a5010c3 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:16:31 +1000 Subject: [PATCH 33/77] Remove CMS specs --- .../example.com/layouts/default/_default.yml | 1 - .../example.com/layouts/default/content.html | 5 -- .../example.com/layouts/default/css.css | 1 - .../example.com/layouts/default/js.js | 1 - .../layouts/default/nested/_nested.yml | 2 - .../layouts/default/nested/content.html | 2 - .../layouts/default/nested/css.css | 1 - .../example.com/layouts/default/nested/js.js | 1 - .../example.com/pages/index/_index.yml | 2 - .../example.com/pages/index/child/_child.yml | 3 - .../example.com/pages/index/child/left.html | 1 - .../example.com/pages/index/child/right.html | 1 - .../example.com/pages/index/content.html | 2 - .../example.com/snippets/default/_default.yml | 1 - .../example.com/snippets/default/content.html | 1 - spec/factories.rb | 36 ---------- spec/features/admin/cms_spec.rb | 34 ---------- spec/features/consumer/cms_spec.rb | 68 ------------------- 18 files changed, 163 deletions(-) delete mode 100644 db/cms_fixtures/example.com/layouts/default/_default.yml delete mode 100644 db/cms_fixtures/example.com/layouts/default/content.html delete mode 100644 db/cms_fixtures/example.com/layouts/default/css.css delete mode 100644 db/cms_fixtures/example.com/layouts/default/js.js delete mode 100644 db/cms_fixtures/example.com/layouts/default/nested/_nested.yml delete mode 100644 db/cms_fixtures/example.com/layouts/default/nested/content.html delete mode 100644 db/cms_fixtures/example.com/layouts/default/nested/css.css delete mode 100644 db/cms_fixtures/example.com/layouts/default/nested/js.js delete mode 100644 db/cms_fixtures/example.com/pages/index/_index.yml delete mode 100644 db/cms_fixtures/example.com/pages/index/child/_child.yml delete mode 100644 db/cms_fixtures/example.com/pages/index/child/left.html delete mode 100644 db/cms_fixtures/example.com/pages/index/child/right.html delete mode 100644 db/cms_fixtures/example.com/pages/index/content.html delete mode 100644 db/cms_fixtures/example.com/snippets/default/_default.yml delete mode 100644 db/cms_fixtures/example.com/snippets/default/content.html delete mode 100644 spec/features/admin/cms_spec.rb delete mode 100644 spec/features/consumer/cms_spec.rb diff --git a/db/cms_fixtures/example.com/layouts/default/_default.yml b/db/cms_fixtures/example.com/layouts/default/_default.yml deleted file mode 100644 index 6f1626b7c0..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/_default.yml +++ /dev/null @@ -1 +0,0 @@ -label: Default Fixture Layout \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/content.html b/db/cms_fixtures/example.com/layouts/default/content.html deleted file mode 100644 index f2707392b4..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/content.html +++ /dev/null @@ -1,5 +0,0 @@ - - - {{ cms:page:content }} - - \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/css.css b/db/cms_fixtures/example.com/layouts/default/css.css deleted file mode 100644 index cd8b4f19df..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/css.css +++ /dev/null @@ -1 +0,0 @@ -body{color: red} \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/js.js b/db/cms_fixtures/example.com/layouts/default/js.js deleted file mode 100644 index 6959d8bfc5..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/js.js +++ /dev/null @@ -1 +0,0 @@ -// default js \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/nested/_nested.yml b/db/cms_fixtures/example.com/layouts/default/nested/_nested.yml deleted file mode 100644 index 754f082c41..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/nested/_nested.yml +++ /dev/null @@ -1,2 +0,0 @@ -label: Default Fixture Nested Layout -position: 42 \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/nested/content.html b/db/cms_fixtures/example.com/layouts/default/nested/content.html deleted file mode 100644 index 350a3d016a..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/nested/content.html +++ /dev/null @@ -1,2 +0,0 @@ -
{{ cms:page:left }}
-
{{ cms:page:right }}
\ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/nested/css.css b/db/cms_fixtures/example.com/layouts/default/nested/css.css deleted file mode 100644 index 034f6fb9c2..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/nested/css.css +++ /dev/null @@ -1 +0,0 @@ -div{float:left} \ No newline at end of file diff --git a/db/cms_fixtures/example.com/layouts/default/nested/js.js b/db/cms_fixtures/example.com/layouts/default/nested/js.js deleted file mode 100644 index 2508c22ed6..0000000000 --- a/db/cms_fixtures/example.com/layouts/default/nested/js.js +++ /dev/null @@ -1 +0,0 @@ -// nested js \ No newline at end of file diff --git a/db/cms_fixtures/example.com/pages/index/_index.yml b/db/cms_fixtures/example.com/pages/index/_index.yml deleted file mode 100644 index 548e85356b..0000000000 --- a/db/cms_fixtures/example.com/pages/index/_index.yml +++ /dev/null @@ -1,2 +0,0 @@ -label: Home Fixture Page -layout: default \ No newline at end of file diff --git a/db/cms_fixtures/example.com/pages/index/child/_child.yml b/db/cms_fixtures/example.com/pages/index/child/_child.yml deleted file mode 100644 index d8602e1484..0000000000 --- a/db/cms_fixtures/example.com/pages/index/child/_child.yml +++ /dev/null @@ -1,3 +0,0 @@ -label: Child Fixture Page -layout: nested -position: 42 diff --git a/db/cms_fixtures/example.com/pages/index/child/left.html b/db/cms_fixtures/example.com/pages/index/child/left.html deleted file mode 100644 index 15beb8f985..0000000000 --- a/db/cms_fixtures/example.com/pages/index/child/left.html +++ /dev/null @@ -1 +0,0 @@ -Child Page Left Fixture Content \ No newline at end of file diff --git a/db/cms_fixtures/example.com/pages/index/child/right.html b/db/cms_fixtures/example.com/pages/index/child/right.html deleted file mode 100644 index 3ac08e9ab7..0000000000 --- a/db/cms_fixtures/example.com/pages/index/child/right.html +++ /dev/null @@ -1 +0,0 @@ -Child Page Right Fixture Content \ No newline at end of file diff --git a/db/cms_fixtures/example.com/pages/index/content.html b/db/cms_fixtures/example.com/pages/index/content.html deleted file mode 100644 index fb97a42a71..0000000000 --- a/db/cms_fixtures/example.com/pages/index/content.html +++ /dev/null @@ -1,2 +0,0 @@ -Home Page Fixture Contént -{{ cms:snippet:default }} \ No newline at end of file diff --git a/db/cms_fixtures/example.com/snippets/default/_default.yml b/db/cms_fixtures/example.com/snippets/default/_default.yml deleted file mode 100644 index 64cc262bd9..0000000000 --- a/db/cms_fixtures/example.com/snippets/default/_default.yml +++ /dev/null @@ -1 +0,0 @@ -label: Default Fixture Snippet \ No newline at end of file diff --git a/db/cms_fixtures/example.com/snippets/default/content.html b/db/cms_fixtures/example.com/snippets/default/content.html deleted file mode 100644 index 48a4995fa8..0000000000 --- a/db/cms_fixtures/example.com/snippets/default/content.html +++ /dev/null @@ -1 +0,0 @@ -Fixture Content for Default Snippet \ No newline at end of file diff --git a/spec/factories.rb b/spec/factories.rb index 06f5dbd879..3b0c548923 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -383,39 +383,3 @@ FactoryGirl.modify do end end end - - -# -- CMS -FactoryGirl.define do - factory :cms_site, :class => Cms::Site do - identifier 'open-food-network' - label 'Open Food Network' - hostname 'localhost' - end - - factory :cms_layout, :class => Cms::Layout do - site { Cms::Site.first || create(:cms_site) } - label 'layout' - identifier 'layout' - content '{{ cms:page:content:text }}' - end - - factory :cms_page, :class => Cms::Page do - site { Cms::Site.first || create(:cms_site) } - label 'page' - sequence(:slug) { |n| "page-#{n}" } - layout { Cms::Layout.first || create(:cms_layout) } - - # Pass content through to block, where it is stored - after(:create) do |cms_page, evaluator| - cms_page.blocks.first.update_attribute(:content, evaluator.content) - cms_page.save! # set_cached_content - end - end - - factory :cms_block, :class => Cms::Block do - page { Cms::Page.first || create(:cms_page) } - identifier 'block' - content 'hello, block' - end -end diff --git a/spec/features/admin/cms_spec.rb b/spec/features/admin/cms_spec.rb deleted file mode 100644 index c200bc57e4..0000000000 --- a/spec/features/admin/cms_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -feature %q{ - In order to provide content to users of the site - As an administrator - I want to access the CMS admin site -} do - include AuthenticationWorkflow - include WebHelper - - scenario "admin can access CMS admin and return to Spree admin" do - login_to_admin_section - click_link 'Configuration' - click_link 'CMS Admin' - page.should have_content "ComfortableMexicanSofa" - - click_link 'Spree Admin' - expect(page).to have_current_path /^\/admin/ - end - - scenario "anonymous user can't access CMS admin", js: true do - visit cms_admin_path - page.should_not have_content "ComfortableMexicanSofa" - page.should have_content "Login" - end - - scenario "non-admin user can't access CMS admin", js: true do - login_to_consumer_section - page.should_not have_content "Login" - visit cms_admin_path - page.should_not have_content "ComfortableMexicanSofa" - expect(page).to have_current_path root_path - end -end diff --git a/spec/features/consumer/cms_spec.rb b/spec/features/consumer/cms_spec.rb deleted file mode 100644 index 0f25bc549c..0000000000 --- a/spec/features/consumer/cms_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require 'spec_helper' - -feature %q{ - In order to learn about food - As a user of the site - I want to see static content pages -}, skip: true do - include AuthenticationWorkflow - include WebHelper - let(:d) { create(:distributor_enterprise, :name => 'Edible garden') } - - background do - create_enterprise_group_for d - end - - scenario "viewing shop front does not display home page content" do - # Given a CMS home page - create(:cms_page, content: 'Home page content') - - # When I visit the home page - visit spree.root_path - - # and proceed to the shop front - click_on 'Edible garden' - visit enterprise_path d - - # Then I should not see the home page content - page.should_not have_content 'Home page content' - end - - scenario "viewing the menu of CMS pages" do - # Given some CMS pages - home_page = create(:cms_page, content: 'Home') - create(:cms_page, parent: home_page, label: 'One') - create(:cms_page, parent: home_page, label: 'Two') - create(:cms_page, parent: home_page, label: 'Three') - - # When I visit the home page - visit spree.root_path - # and proceed to the shop front - click_on "Edible garden" - visit enterprise_path d - - - # Then I should see a menu with these pages - page.should have_selector 'ul#main-nav-bar li', :text => 'One' - page.should have_selector 'ul#main-nav-bar li', :text => 'Two' - page.should have_selector 'ul#main-nav-bar li', :text => 'Three' - end - - scenario "viewing a page from the CMS menu" do - # Given some CMS pages - home_page = create(:cms_page, content: 'Home') - create(:cms_page, parent: home_page, label: 'One') - create(:cms_page, parent: home_page, label: 'Two', content: 'This is the page') - create(:cms_page, parent: home_page, label: 'Three') - - # When I go to one of the pages - visit spree.root_path - click_on "Edible garden" - visit enterprise_path d - click_link 'Two' - - # Then I should see the page - page.should have_content 'This is the page' - end - -end From eb8cedc497c938d53d26e2ea6e3eebfbe45569ce Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:26:34 +1000 Subject: [PATCH 34/77] Remove CMS views and overrides --- app/overrides/add_cms_admin_tab.rb | 5 ----- .../add_cms_checkout_distribution.rb | 5 ----- app/overrides/add_cms_tabs_to_main_nav_bar.rb | 5 ----- app/overrides/add_cms_to_cart.rb | 5 ----- app/views/layouts/_cms_nav_spree.html.haml | 1 - app/views/shared/_cms_elrte_head.html.haml | 19 ------------------- app/views/spree/shared/_cms_tabs.html.haml | 3 --- 7 files changed, 43 deletions(-) delete mode 100644 app/overrides/add_cms_admin_tab.rb delete mode 100644 app/overrides/add_cms_checkout_distribution.rb delete mode 100644 app/overrides/add_cms_tabs_to_main_nav_bar.rb delete mode 100644 app/overrides/add_cms_to_cart.rb delete mode 100644 app/views/layouts/_cms_nav_spree.html.haml delete mode 100644 app/views/shared/_cms_elrte_head.html.haml delete mode 100644 app/views/spree/shared/_cms_tabs.html.haml diff --git a/app/overrides/add_cms_admin_tab.rb b/app/overrides/add_cms_admin_tab.rb deleted file mode 100644 index f13d100502..0000000000 --- a/app/overrides/add_cms_admin_tab.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/admin/shared/_configuration_menu", - :name => "add_cms_admin_to_admin_configurations_menu", - :insert_bottom => "[data-hook='admin_configurations_sidebar_menu']", - :text => "
  • <%= link_to 'CMS Admin', main_app.cms_admin_path %>
  • ", - :original => '29e0ab9c171ffab1988cb439b5d42300b78fe088' ) diff --git a/app/overrides/add_cms_checkout_distribution.rb b/app/overrides/add_cms_checkout_distribution.rb deleted file mode 100644 index bd4c3afbaa..0000000000 --- a/app/overrides/add_cms_checkout_distribution.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/checkout/_delivery", - :insert_before => "fieldset#shipping_method", - :text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('distribution')) %>", - :name => "add_cms_checkout_distribution", - :original => '3b417788fb9a63f464fdaeb8202f483f20518f80') \ No newline at end of file diff --git a/app/overrides/add_cms_tabs_to_main_nav_bar.rb b/app/overrides/add_cms_tabs_to_main_nav_bar.rb deleted file mode 100644 index 47d67141f7..0000000000 --- a/app/overrides/add_cms_tabs_to_main_nav_bar.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/shared/_main_nav_bar", - :name => "add_cms_tabs_to_main_nav_bar", - :insert_after => "li#home-link", - :partial => "spree/shared/cms_tabs", - :original => '05c6495f8760e58eb68e2cce67433cf7f5299fa4') \ No newline at end of file diff --git a/app/overrides/add_cms_to_cart.rb b/app/overrides/add_cms_to_cart.rb deleted file mode 100644 index 3ff7341a33..0000000000 --- a/app/overrides/add_cms_to_cart.rb +++ /dev/null @@ -1,5 +0,0 @@ -Deface::Override.new(:virtual_path => "spree/orders/edit", - :insert_after => "h1", - :text => "<%= cms_snippet_content(Cms::Snippet.find_by_identifier('cart')) %>", - :name => "add_cms_to_cart", - :original => '206a92e6f50966b057e877321b573bc293787894') \ No newline at end of file diff --git a/app/views/layouts/_cms_nav_spree.html.haml b/app/views/layouts/_cms_nav_spree.html.haml deleted file mode 100644 index d0ab75eeaa..0000000000 --- a/app/views/layouts/_cms_nav_spree.html.haml +++ /dev/null @@ -1 +0,0 @@ -%li= link_to 'Spree Admin', spree.admin_path diff --git a/app/views/shared/_cms_elrte_head.html.haml b/app/views/shared/_cms_elrte_head.html.haml deleted file mode 100644 index f070625f8a..0000000000 --- a/app/views/shared/_cms_elrte_head.html.haml +++ /dev/null @@ -1,19 +0,0 @@ --# Include all stylesheets except reset (which overrides Spree styles) --# Then restore styles which override Spree's --# See cms/app/views/layouts/cms_admin/_head.html.erb -= stylesheet_link_tag 'comfortable_mexican_sofa/structure', - 'comfortable_mexican_sofa/typography', - 'comfortable_mexican_sofa/form', - 'comfortable_mexican_sofa/content', - 'comfortable_mexican_sofa/files', - 'comfortable_mexican_sofa/elrte', - 'comfortable_mexican_sofa/codemirror', - 'comfortable_mexican_sofa/jquery_ui', - 'comfortable_mexican_sofa/dialogs', - 'comfortable_mexican_sofa/widgets', - 'admin/restore_spree_from_cms' - -= javascript_include_tag('comfortable_mexican_sofa/application') - -%meta{:name => "cms-admin-path", :content => ComfortableMexicanSofa.config.admin_route_prefix} -%meta{:name => "cms-locale", :content => I18n.locale} diff --git a/app/views/spree/shared/_cms_tabs.html.haml b/app/views/spree/shared/_cms_tabs.html.haml deleted file mode 100644 index 1921e8cfac..0000000000 --- a/app/views/spree/shared/_cms_tabs.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -- if @cms_site - - @cms_site.pages.root.children.published.each do |page| - %li= link_to page.label, page.full_path \ No newline at end of file From b637b5b75ab8bd757d0b0fb6f943eb368e358be3 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:28:27 +1000 Subject: [PATCH 35/77] Remove CMS helper: home_page_cms_content --- app/helpers/application_helper.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 15c20dfd55..f17a6dbbc9 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -2,13 +2,6 @@ module ApplicationHelper include FoundationRailsHelper::FlashHelper - def home_page_cms_content - if controller.controller_name == 'home' && controller.action_name == 'index' - cms_page_content(:content, Cms::Page.find_by_full_path('/')) - end - end - - def ng_form_for(name, *args, &block) options = args.extract_options! From d3ad823d97cc42b80d0f3411071f017969081638 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:34:12 +1000 Subject: [PATCH 36/77] Remove CMS configuration, gem. Fix permalink check dependent on CMS glob path. --- Gemfile | 1 - Gemfile.lock | 11 +- app/controllers/enterprises_controller.rb | 11 +- config/application.rb | 1 - .../initializers/comfortable_mexican_sofa.rb | 135 ------------------ 5 files changed, 10 insertions(+), 149 deletions(-) delete mode 100644 config/initializers/comfortable_mexican_sofa.rb diff --git a/Gemfile b/Gemfile index eb49f89c23..f28e8a8baa 100644 --- a/Gemfile +++ b/Gemfile @@ -21,7 +21,6 @@ gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_e gem 'delayed_job_active_record' gem 'daemons' -gem 'comfortable_mexican_sofa' # Fix bug in simple_form preventing collection_check_boxes usage within form_for block # When merged, revert to upstream gem diff --git a/Gemfile.lock b/Gemfile.lock index 07931312ab..397055e27f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -121,7 +121,6 @@ GEM rack-cache (~> 1.2) rack-test (~> 0.6.1) sprockets (~> 2.2.1) - active_link_to (1.0.0) active_model_serializers (0.8.3) activemodel (>= 3.0) activemerchant (1.57.0) @@ -202,10 +201,6 @@ GEM coffee-script-source (1.10.0) colorize (0.7.7) columnize (0.9.0) - comfortable_mexican_sofa (1.6.24) - active_link_to (~> 1.0.0) - paperclip (>= 2.3.0) - rails (>= 3.0.0) compass (1.0.3) chunky_png (~> 1.2) compass-core (~> 1.0.2) @@ -659,7 +654,6 @@ DEPENDENCIES bugsnag capybara coffee-rails (~> 3.2.1) - comfortable_mexican_sofa compass-rails css_splitter custom_error_message! @@ -734,5 +728,8 @@ DEPENDENCIES wicked_pdf wkhtmltopdf-binary +RUBY VERSION + ruby 2.1.5p273 + BUNDLED WITH - 1.11.2 + 1.12.5 diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 70d240abd1..6c38cfe83a 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -26,13 +26,14 @@ class EnterprisesController < BaseController end def check_permalink - return render text: params[:permalink], status: 409 if Enterprise.find_by_permalink params[:permalink] + render text: params[:permalink], status: 409 and return if Enterprise.find_by_permalink params[:permalink] - path = Rails.application.routes.recognize_path("/#{params[:permalink].to_s}") - if path && path[:controller] == "cms_content" - render text: params[:permalink], status: 200 - else + begin + Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" ) render text: params[:permalink], status: 409 + + rescue ActionController::RoutingError + render text: params[:permalink], status: 200 end end diff --git a/config/application.rb b/config/application.rb index a763f54718..4847d9bb52 100644 --- a/config/application.rb +++ b/config/application.rb @@ -103,7 +103,6 @@ module Openfoodnetwork config.assets.precompile += ['admin/all.css', 'admin/restore_spree_from_cms.css', 'admin/*.js', 'admin/**/*.js'] config.assets.precompile += ['darkswarm/all.css', 'darkswarm/all_split2.css', 'darkswarm/all.js'] config.assets.precompile += ['mail/all.css'] - config.assets.precompile += ['comfortable_mexican_sofa/*'] config.assets.precompile += ['search/all.css', 'search/*.js'] config.assets.precompile += ['shared/*'] diff --git a/config/initializers/comfortable_mexican_sofa.rb b/config/initializers/comfortable_mexican_sofa.rb deleted file mode 100644 index 279648a093..0000000000 --- a/config/initializers/comfortable_mexican_sofa.rb +++ /dev/null @@ -1,135 +0,0 @@ -# encoding: utf-8 - -ComfortableMexicanSofa.configure do |config| - # Title of the admin area - # config.cms_title = 'ComfortableMexicanSofa CMS Engine' - - # Module responsible for authentication. You can replace it with your own. - # It simply needs to have #authenticate method. See http_auth.rb for reference. - config.admin_auth = 'CmsSpreeAuth' - - # Module responsible for public authentication. Similar to the above. You also - # will have access to @cms_site, @cms_layout, @cms_page so you can use them in - # your logic. Default module doesn't do anything. - # config.public_auth = 'ComfortableMexicanSofa::DummyAuth' - - # Default url to access admin area is http://yourhost/cms-admin/ - # You can change 'cms-admin' to 'admin', for example. To disable admin area - # entirely set this to '' or nil - # config.admin_route_prefix = 'cms-admin' - - # When arriving at /cms-admin you may chose to redirect to arbirtary path, - # for example '/cms-admin/users' - # config.admin_route_redirect = '' - - # Normally we include default routes from https://github.com/comfy/comfortable-mexican-sofa/blob/master/config/routes.rb - # If you want to include the routes manually set this to false - # config.use_default_routes = true - - # /sitemap.xml that is used by search engines for indexing. It's enabled by - # default, but you may turn it off. - # config.enable_sitemap = true - - # File uploads use Paperclip and can support filesystem or s3 uploads. Override - # the upload method and appropriate settings based on Paperclip. For S3 see: - # http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/S3, and for - # filesystem see: http://rdoc.info/gems/paperclip/2.3.8/Paperclip/Storage/Filesystem - config.upload_file_options = { - :storage => 's3', - :s3_protocol => :https, - :s3_credentials => { - :bucket => Spree::Config[:s3_bucket], - :access_key_id => Spree::Config[:s3_access_key], - :secret_access_key => Spree::Config[:s3_secret] - } - } - - # Sofa allows you to setup entire site from files. Database is updated with each - # request (if necessary). Please note that database entries are destroyed if there's - # no corresponding file. Fixtures are disabled by default. - # config.enable_fixtures = false - - # Path where fixtures can be located. - # config.fixtures_path = File.expand_path('db/cms_fixtures', Rails.root) - - # Importing fixtures into Database - # To load fixtures into the database just run this rake task: - # local: $ rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=localhost - # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:import FROM=example.local TO=yourapp.herokuapp.com - # From indicates folder the fixtures are in and to is the Site hostname you have defined in the database. - - # Exporting fixtures into Files - # If you need to dump database contents into fixture files run: - # local: $ rake comfortable_mexican_sofa:fixtures:export FROM=localhost TO=example.local - # Heroku: $ heroku run rake comfortable_mexican_sofa:fixtures:export FROM=yourapp.herokuapp.com TO=example.local - # This will create example.local folder and dump all content from example.com Site. - - # Content for Layouts, Pages and Snippets has a revision history. You can revert - # a previous version using this system. You can control how many revisions per - # object you want to keep. Set it to 0 if you wish to turn this feature off. - # config.revisions_limit = 25 - - # Locale definitions. If you want to define your own locale merge - # {:locale => 'Locale Title'} with this. - # config.locales = {:en => 'English', :es => 'Español'} - - # Admin interface will respect the locale of the site being managed. However you can - # force it to English by setting this to `:en` - # config.admin_locale = nil - - # If you want to keep your CMS tables in a location other than the default database - # add a database_config. For example, setting it to 'cms' will look for a cms_#{Rails.env} - # definition in your database.yml file - # config.database_config = nil - - # A class that is included as a sweeper to admin base controller if it's set - # config.admin_cache_sweeper = nil - - # By default you cannot have irb code inside your layouts/pages/snippets. - # Generally this is to prevent putting something like this: - # <% User.delete_all %> but if you really want to allow it... - # config.allow_irb = false - - # Whitelist of all helper methods that can be used via {{cms:helper}} tag. By default - # all helpers are allowed except `eval`, `send`, `call` and few others. Empty array - # will prevent rendering of all helpers. - # config.allowed_helpers = nil - - # Whitelist of partials paths that can be used via {{cms:partial}} tag. All partials - # are accessible by default. Empty array will prevent rendering of all partials. - # config.allowed_partials = nil - - # Site aliases, if you want to have aliases for your site. Good for harmonizing - # production env with dev/testing envs. - # e.g. config.site_aliases = {'host.com' => 'host.inv', 'host_a.com' => ['host.lvh.me', 'host.dev']} - # Default is nil (not used) - # config.hostname_aliases = nil - -end - -module CmsSpreeAuth - def authenticate - unless spree_current_user && spree_current_user.has_spree_role?('admin') - redirect_to spree.login_path - end - end -end - -# Default credentials for ComfortableMexicanSofa::HttpAuth -# YOU REALLY WANT TO CHANGE THIS BEFORE PUTTING YOUR SITE LIVE -ComfortableMexicanSofa::HttpAuth.username = 'username' -ComfortableMexicanSofa::HttpAuth.password = 'password' - -# If you need to inject some html in cms admin views you can define what partial -# should be rendered into the following areas: -# ComfortableMexicanSofa::ViewHooks.add(:navigation, '/layouts/admin/navigation') -# ComfortableMexicanSofa::ViewHooks.add(:html_head, '/layouts/admin/html_head') -# ComfortableMexicanSofa::ViewHooks.add(:page_form, '/layouts/admin/page_form') -ComfortableMexicanSofa::ViewHooks.add(:navigation, 'layouts/cms_nav_spree') - -# Provide some Spree helpers to the CMS controller so it can render Spree's layout -ComfortableMexicanSofa::CmsContentController.class_eval do - helper 'spree/base' - include Spree::Core::ControllerHelpers - include Spree::Core::Engine.routes.url_helpers -end From 932edeb1c1ff7dff9e7a6b1eedbb504021be3a2f Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:36:33 +1000 Subject: [PATCH 37/77] Remove CMS style shim - Spree/CMS compatibility --- app/assets/stylesheets/admin/restore_spree_from_cms.css.scss | 4 ---- config/application.rb | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 app/assets/stylesheets/admin/restore_spree_from_cms.css.scss diff --git a/app/assets/stylesheets/admin/restore_spree_from_cms.css.scss b/app/assets/stylesheets/admin/restore_spree_from_cms.css.scss deleted file mode 100644 index a281031f02..0000000000 --- a/app/assets/stylesheets/admin/restore_spree_from_cms.css.scss +++ /dev/null @@ -1,4 +0,0 @@ -html { - height: auto; - background-color: transparent; -} diff --git a/config/application.rb b/config/application.rb index 4847d9bb52..9abd0a3b9b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -100,7 +100,7 @@ module Openfoodnetwork # http://stackoverflow.com/questions/8012434/what-is-the-purpose-of-config-assets-precompile config.assets.initialize_on_precompile = true config.assets.precompile += ['store/all.css', 'store/all.js', 'store/shop_front.js', 'iehack.js'] - config.assets.precompile += ['admin/all.css', 'admin/restore_spree_from_cms.css', 'admin/*.js', 'admin/**/*.js'] + config.assets.precompile += ['admin/all.css', 'admin/*.js', 'admin/**/*.js'] config.assets.precompile += ['darkswarm/all.css', 'darkswarm/all_split2.css', 'darkswarm/all.js'] config.assets.precompile += ['mail/all.css'] config.assets.precompile += ['search/all.css', 'search/*.js'] From 377074416e719a9b933285828881b96f483a25ad Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 12:45:48 +1000 Subject: [PATCH 38/77] Remove CMS tables. Adds migration helper: drop_table_cascade --- config/initializers/postgres.rb | 9 ++ db/migrate/20160707023818_drop_cms.rb | 154 ++++++++++++++++++++++++++ db/schema.rb | 140 +---------------------- 3 files changed, 165 insertions(+), 138 deletions(-) create mode 100644 config/initializers/postgres.rb create mode 100644 db/migrate/20160707023818_drop_cms.rb diff --git a/config/initializers/postgres.rb b/config/initializers/postgres.rb new file mode 100644 index 0000000000..f9f4ce3645 --- /dev/null +++ b/config/initializers/postgres.rb @@ -0,0 +1,9 @@ +module ActiveRecord + module ConnectionAdapters # :nodoc: + module SchemaStatements + def drop_table_cascade(table_name, options = {}) + execute "DROP TABLE #{quote_table_name(table_name)} CASCADE" + end + end + end +end diff --git a/db/migrate/20160707023818_drop_cms.rb b/db/migrate/20160707023818_drop_cms.rb new file mode 100644 index 0000000000..018b755466 --- /dev/null +++ b/db/migrate/20160707023818_drop_cms.rb @@ -0,0 +1,154 @@ +class DropCms < ActiveRecord::Migration + + # Reverse of CreateCms in 20121009232513_create_cms.rb, including foreign keys defined + # in 20140402033428_add_foreign_keys.rb + + def up + drop_table_cascade :cms_sites + drop_table_cascade :cms_layouts + drop_table_cascade :cms_pages + drop_table_cascade :cms_snippets + drop_table_cascade :cms_blocks + drop_table_cascade :cms_files + drop_table_cascade :cms_revisions + drop_table_cascade :cms_categories + drop_table_cascade :cms_categorizations + end + + def down + text_limit = case ActiveRecord::Base.connection.adapter_name + when 'PostgreSQL' + { } + else + { :limit => 16777215 } + end + + # -- Sites -------------------------------------------------------------- + create_table :cms_sites do |t| + t.string :label, :null => false + t.string :identifier, :null => false + t.string :hostname, :null => false + t.string :path + t.string :locale, :null => false, :default => 'en' + t.boolean :is_mirrored, :null => false, :default => false + end + add_index :cms_sites, :hostname + add_index :cms_sites, :is_mirrored + + # -- Layouts ------------------------------------------------------------ + create_table :cms_layouts do |t| + t.integer :site_id, :null => false + t.integer :parent_id + t.string :app_layout + t.string :label, :null => false + t.string :identifier, :null => false + t.text :content, text_limit + t.text :css, text_limit + t.text :js, text_limit + t.integer :position, :null => false, :default => 0 + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :cms_layouts, [:parent_id, :position] + add_index :cms_layouts, [:site_id, :identifier], :unique => true + + # -- Pages -------------------------------------------------------------- + create_table :cms_pages do |t| + t.integer :site_id, :null => false + t.integer :layout_id + t.integer :parent_id + t.integer :target_page_id + t.string :label, :null => false + t.string :slug + t.string :full_path, :null => false + t.text :content, text_limit + t.integer :position, :null => false, :default => 0 + t.integer :children_count, :null => false, :default => 0 + t.boolean :is_published, :null => false, :default => true + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :cms_pages, [:site_id, :full_path] + add_index :cms_pages, [:parent_id, :position] + + # -- Page Blocks -------------------------------------------------------- + create_table :cms_blocks do |t| + t.integer :page_id, :null => false + t.string :identifier, :null => false + t.text :content + t.timestamps + end + add_index :cms_blocks, [:page_id, :identifier] + + # -- Snippets ----------------------------------------------------------- + create_table :cms_snippets do |t| + t.integer :site_id, :null => false + t.string :label, :null => false + t.string :identifier, :null => false + t.text :content, text_limit + t.integer :position, :null => false, :default => 0 + t.boolean :is_shared, :null => false, :default => false + t.timestamps + end + add_index :cms_snippets, [:site_id, :identifier], :unique => true + add_index :cms_snippets, [:site_id, :position] + + # -- Files -------------------------------------------------------------- + create_table :cms_files do |t| + t.integer :site_id, :null => false + t.integer :block_id + t.string :label, :null => false + t.string :file_file_name, :null => false + t.string :file_content_type, :null => false + t.integer :file_file_size, :null => false + t.string :description, :limit => 2048 + t.integer :position, :null => false, :default => 0 + t.timestamps + end + add_index :cms_files, [:site_id, :label] + add_index :cms_files, [:site_id, :file_file_name] + add_index :cms_files, [:site_id, :position] + add_index :cms_files, [:site_id, :block_id] + + # -- Revisions ----------------------------------------------------------- + create_table :cms_revisions, :force => true do |t| + t.string :record_type, :null => false + t.integer :record_id, :null => false + t.text :data, text_limit + t.datetime :created_at + end + add_index :cms_revisions, [:record_type, :record_id, :created_at] + + # -- Categories --------------------------------------------------------- + create_table :cms_categories, :force => true do |t| + t.integer :site_id, :null => false + t.string :label, :null => false + t.string :categorized_type, :null => false + end + add_index :cms_categories, [:site_id, :categorized_type, :label], :unique => true + + create_table :cms_categorizations, :force => true do |t| + t.integer :category_id, :null => false + t.string :categorized_type, :null => false + t.integer :categorized_id, :null => false + end + add_index :cms_categorizations, [:category_id, :categorized_type, :categorized_id], :unique => true, + :name => 'index_cms_categorizations_on_cat_id_and_catd_type_and_catd_id' + + + # -- Foreign keys, from 20140402033428_add_foreign_keys.rb + add_foreign_key "cms_blocks", "cms_pages", name: "cms_blocks_page_id_fk", column: "page_id" + add_foreign_key "cms_categories", "cms_sites", name: "cms_categories_site_id_fk", column: "site_id", dependent: :delete + add_foreign_key "cms_categorizations", "cms_categories", name: "cms_categorizations_category_id_fk", column: "category_id" + add_foreign_key "cms_files", "cms_blocks", name: "cms_files_block_id_fk", column: "block_id" + add_foreign_key "cms_files", "cms_sites", name: "cms_files_site_id_fk", column: "site_id" + add_foreign_key "cms_layouts", "cms_layouts", name: "cms_layouts_parent_id_fk", column: "parent_id" + add_foreign_key "cms_layouts", "cms_sites", name: "cms_layouts_site_id_fk", column: "site_id", dependent: :delete + add_foreign_key "cms_pages", "cms_layouts", name: "cms_pages_layout_id_fk", column: "layout_id" + add_foreign_key "cms_pages", "cms_pages", name: "cms_pages_parent_id_fk", column: "parent_id" + add_foreign_key "cms_pages", "cms_sites", name: "cms_pages_site_id_fk", column: "site_id", dependent: :delete + add_foreign_key "cms_pages", "cms_pages", name: "cms_pages_target_page_id_fk", column: "target_page_id" + add_foreign_key "cms_snippets", "cms_sites", name: "cms_snippets_site_id_fk", column: "site_id", dependent: :delete + + end +end diff --git a/db/schema.rb b/db/schema.rb index 002e367dd6..d0403533fd 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 => 20160527012603) do +ActiveRecord::Schema.define(:version => 20160707023818) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -59,123 +59,6 @@ ActiveRecord::Schema.define(:version => 20160527012603) do add_index "carts", ["user_id"], :name => "index_carts_on_user_id" - create_table "cms_blocks", :force => true do |t| - t.integer "page_id", :null => false - t.string "identifier", :null => false - t.text "content" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "cms_blocks", ["page_id", "identifier"], :name => "index_cms_blocks_on_page_id_and_identifier" - - create_table "cms_categories", :force => true do |t| - t.integer "site_id", :null => false - t.string "label", :null => false - t.string "categorized_type", :null => false - end - - add_index "cms_categories", ["site_id", "categorized_type", "label"], :name => "index_cms_categories_on_site_id_and_categorized_type_and_label", :unique => true - - create_table "cms_categorizations", :force => true do |t| - t.integer "category_id", :null => false - t.string "categorized_type", :null => false - t.integer "categorized_id", :null => false - end - - add_index "cms_categorizations", ["category_id", "categorized_type", "categorized_id"], :name => "index_cms_categorizations_on_cat_id_and_catd_type_and_catd_id", :unique => true - - create_table "cms_files", :force => true do |t| - t.integer "site_id", :null => false - t.integer "block_id" - t.string "label", :null => false - t.string "file_file_name", :null => false - t.string "file_content_type", :null => false - t.integer "file_file_size", :null => false - t.string "description", :limit => 2048 - t.integer "position", :default => 0, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "cms_files", ["site_id", "block_id"], :name => "index_cms_files_on_site_id_and_block_id" - add_index "cms_files", ["site_id", "file_file_name"], :name => "index_cms_files_on_site_id_and_file_file_name" - add_index "cms_files", ["site_id", "label"], :name => "index_cms_files_on_site_id_and_label" - add_index "cms_files", ["site_id", "position"], :name => "index_cms_files_on_site_id_and_position" - - create_table "cms_layouts", :force => true do |t| - t.integer "site_id", :null => false - t.integer "parent_id" - t.string "app_layout" - t.string "label", :null => false - t.string "identifier", :null => false - t.text "content" - t.text "css" - t.text "js" - t.integer "position", :default => 0, :null => false - t.boolean "is_shared", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "cms_layouts", ["parent_id", "position"], :name => "index_cms_layouts_on_parent_id_and_position" - add_index "cms_layouts", ["site_id", "identifier"], :name => "index_cms_layouts_on_site_id_and_identifier", :unique => true - - create_table "cms_pages", :force => true do |t| - t.integer "site_id", :null => false - t.integer "layout_id" - t.integer "parent_id" - t.integer "target_page_id" - t.string "label", :null => false - t.string "slug" - t.string "full_path", :null => false - t.text "content" - t.integer "position", :default => 0, :null => false - t.integer "children_count", :default => 0, :null => false - t.boolean "is_published", :default => true, :null => false - t.boolean "is_shared", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "cms_pages", ["parent_id", "position"], :name => "index_cms_pages_on_parent_id_and_position" - add_index "cms_pages", ["site_id", "full_path"], :name => "index_cms_pages_on_site_id_and_full_path" - - create_table "cms_revisions", :force => true do |t| - t.string "record_type", :null => false - t.integer "record_id", :null => false - t.text "data" - t.datetime "created_at" - end - - add_index "cms_revisions", ["record_type", "record_id", "created_at"], :name => "index_cms_revisions_on_record_type_and_record_id_and_created_at" - - create_table "cms_sites", :force => true do |t| - t.string "label", :null => false - t.string "identifier", :null => false - t.string "hostname", :null => false - t.string "path" - t.string "locale", :default => "en", :null => false - t.boolean "is_mirrored", :default => false, :null => false - end - - add_index "cms_sites", ["hostname"], :name => "index_cms_sites_on_hostname" - add_index "cms_sites", ["is_mirrored"], :name => "index_cms_sites_on_is_mirrored" - - create_table "cms_snippets", :force => true do |t| - t.integer "site_id", :null => false - t.string "label", :null => false - t.string "identifier", :null => false - t.text "content" - t.integer "position", :default => 0, :null => false - t.boolean "is_shared", :default => false, :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "cms_snippets", ["site_id", "identifier"], :name => "index_cms_snippets_on_site_id_and_identifier", :unique => true - add_index "cms_snippets", ["site_id", "position"], :name => "index_cms_snippets_on_site_id_and_position" - create_table "column_preferences", :force => true do |t| t.integer "user_id", :null => false t.string "action_name", :null => false @@ -694,9 +577,9 @@ ActiveRecord::Schema.define(:version => 20160527012603) do t.string "email" t.text "special_instructions" t.integer "distributor_id" - t.integer "order_cycle_id" t.string "currency" t.string "last_ip_address" + t.integer "order_cycle_id" t.integer "cart_id" t.integer "customer_id" end @@ -1224,25 +1107,6 @@ ActiveRecord::Schema.define(:version => 20160527012603) do add_foreign_key "carts", "spree_users", name: "carts_user_id_fk", column: "user_id" - add_foreign_key "cms_blocks", "cms_pages", name: "cms_blocks_page_id_fk", column: "page_id" - - add_foreign_key "cms_categories", "cms_sites", name: "cms_categories_site_id_fk", column: "site_id", dependent: :delete - - add_foreign_key "cms_categorizations", "cms_categories", name: "cms_categorizations_category_id_fk", column: "category_id" - - add_foreign_key "cms_files", "cms_blocks", name: "cms_files_block_id_fk", column: "block_id" - add_foreign_key "cms_files", "cms_sites", name: "cms_files_site_id_fk", column: "site_id" - - add_foreign_key "cms_layouts", "cms_layouts", name: "cms_layouts_parent_id_fk", column: "parent_id" - add_foreign_key "cms_layouts", "cms_sites", name: "cms_layouts_site_id_fk", column: "site_id", dependent: :delete - - add_foreign_key "cms_pages", "cms_layouts", name: "cms_pages_layout_id_fk", column: "layout_id" - add_foreign_key "cms_pages", "cms_pages", name: "cms_pages_parent_id_fk", column: "parent_id" - add_foreign_key "cms_pages", "cms_pages", name: "cms_pages_target_page_id_fk", column: "target_page_id" - add_foreign_key "cms_pages", "cms_sites", name: "cms_pages_site_id_fk", column: "site_id", dependent: :delete - - add_foreign_key "cms_snippets", "cms_sites", name: "cms_snippets_site_id_fk", column: "site_id", dependent: :delete - add_foreign_key "coordinator_fees", "enterprise_fees", name: "coordinator_fees_enterprise_fee_id_fk" add_foreign_key "coordinator_fees", "order_cycles", name: "coordinator_fees_order_cycle_id_fk" From 160c535fd767afa38e12c2f54fedec627b882381 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 13:47:26 +1000 Subject: [PATCH 39/77] Update knapsack report --- knapsack_rspec_report.json | 384 ++++++++++++++++++++----------------- 1 file changed, 212 insertions(+), 172 deletions(-) diff --git a/knapsack_rspec_report.json b/knapsack_rspec_report.json index 9578580ffd..5d71fa12e2 100644 --- a/knapsack_rspec_report.json +++ b/knapsack_rspec_report.json @@ -1,173 +1,213 @@ { - "spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb": 5.547292709350586, - "spec/controllers/admin/business_model_configuration_controller_spec.rb": 0.3683593273162842, - "spec/controllers/admin/customers_controller_spec.rb": 0.8933048248291016, - "spec/controllers/admin/enterprises_controller_spec.rb": 5.984264850616455, - "spec/controllers/admin/order_cycles_controller_spec.rb": 2.839667558670044, - "spec/controllers/api/enterprises_controller_spec.rb": 0.2780017852783203, - "spec/controllers/api/order_cycles_controller_spec.rb": 1.8730568885803223, - "spec/controllers/base_controller_spec.rb": 0.02932429313659668, - "spec/controllers/cart_controller_spec.rb": 1.062530517578125, - "spec/controllers/checkout_controller_spec.rb": 1.6658811569213867, - "spec/controllers/enterprise_confirmations_controller_spec.rb": 1.1228001117706299, - "spec/controllers/enterprises_controller_spec.rb": 2.2625372409820557, - "spec/controllers/groups_controller_spec.rb": 0.40616846084594727, - "spec/controllers/registration_controller_spec.rb": 0.2145981788635254, - "spec/controllers/shop_controller_spec.rb": 5.298644304275513, - "spec/controllers/shops_controller_spec.rb": 0.2002561092376709, - "spec/controllers/spree/admin/adjustments_controller_spec.rb": 1.023233413696289, - "spec/controllers/spree/admin/base_controller_spec.rb": 0.28871917724609375, - "spec/controllers/spree/admin/line_items_controller_spec.rb": 14.042466402053833, - "spec/controllers/spree/admin/orders_controller_spec.rb": 12.639750480651855, - "spec/controllers/spree/admin/overview_controller_spec.rb": 0.691641092300415, - "spec/controllers/spree/admin/payment_methods_controller_spec.rb": 0.7098217010498047, - "spec/controllers/spree/admin/products_controller_spec.rb": 1.4383087158203125, - "spec/controllers/spree/admin/reports_controller_spec.rb": 47.79633665084839, - "spec/controllers/spree/admin/search_controller_spec.rb": 0.9386723041534424, - "spec/controllers/spree/admin/variants_controller_spec.rb": 2.0663084983825684, - "spec/controllers/spree/api/line_items_controller_spec.rb": 0.4743325710296631, - "spec/controllers/spree/api/products_controller_spec.rb": 8.339523792266846, - "spec/controllers/spree/api/variants_controller_spec.rb": 4.835069179534912, - "spec/controllers/spree/checkout_controller_spec.rb": 0.687798023223877, - "spec/controllers/spree/orders_controller_spec.rb": 1.7623963356018066, - "spec/controllers/spree/paypal_controller_spec.rb": 0.437147855758667, - "spec/controllers/spree/store_controller_spec.rb": 0.03699040412902832, - "spec/controllers/spree/user_sessions_controller_spec.rb": 0.09967947006225586, - "spec/controllers/user_passwords_controller_spec.rb": 0.31070899963378906, - "spec/controllers/user_registrations_controller_spec.rb": 0.36581993103027344, - "spec/features/admin/account_spec.rb": 0.32449865341186523, - "spec/features/admin/accounts_and_billing_settings_spec.rb": 15.864763259887695, - "spec/features/admin/adjustments_spec.rb": 6.825028896331787, - "spec/features/admin/authentication_spec.rb": 22.29801869392395, - "spec/features/admin/bulk_order_management_spec.rb": 112.38913011550903, - "spec/features/admin/bulk_product_update_spec.rb": 59.00568914413452, - "spec/features/admin/business_model_configuration_spec.rb": 2.5152199268341064, - "spec/features/admin/cms_spec.rb": 2.5085999965667725, - "spec/features/admin/content_spec.rb": 1.2907540798187256, - "spec/features/admin/customers_spec.rb": 33.99929761886597, - "spec/features/admin/enterprise_fees_spec.rb": 13.33712100982666, - "spec/features/admin/enterprise_groups_spec.rb": 8.689672231674194, - "spec/features/admin/enterprise_relationships_spec.rb": 7.257282733917236, - "spec/features/admin/enterprise_roles_spec.rb": 5.535412788391113, - "spec/features/admin/enterprise_user_spec.rb": 2.5493221282958984, - "spec/features/admin/enterprises/index_spec.rb": 5.77092719078064, - "spec/features/admin/enterprises_spec.rb": 34.78606820106506, - "spec/features/admin/image_settings_spec.rb": 0.4501008987426758, - "spec/features/admin/order_cycles_spec.rb": 64.186044216156, - "spec/features/admin/orders_spec.rb": 49.190918922424316, - "spec/features/admin/overview_spec.rb": 5.788672208786011, - "spec/features/admin/payment_method_spec.rb": 15.959310531616211, - "spec/features/admin/products_spec.rb": 21.46337914466858, - "spec/features/admin/reports_spec.rb": 150.51152086257935, - "spec/features/admin/shipping_methods_spec.rb": 8.671862363815308, - "spec/features/admin/tax_settings_spec.rb": 0.7941949367523193, - "spec/features/admin/variant_overrides_spec.rb": 29.70982050895691, - "spec/features/admin/variants_spec.rb": 5.565031290054321, - "spec/features/consumer/authentication_spec.rb": 12.449390649795532, - "spec/features/consumer/groups_spec.rb": 1.545715093612671, - "spec/features/consumer/producers_spec.rb": 3.3242862224578857, - "spec/features/consumer/registration_spec.rb": 2.421873092651367, - "spec/features/consumer/shopping/cart_spec.rb": 1.6924467086791992, - "spec/features/consumer/shopping/checkout_auth_spec.rb": 8.496914863586426, - "spec/features/consumer/shopping/checkout_spec.rb": 39.204933881759644, - "spec/features/consumer/shopping/shopping_spec.rb": 23.358332633972168, - "spec/features/consumer/shopping/variant_overrides_spec.rb": 58.16736888885498, - "spec/features/consumer/shops_spec.rb": 6.636866092681885, - "spec/helpers/admin/business_model_configuration_helper_spec.rb": 0.2595028877258301, - "spec/helpers/checkout_helper_spec.rb": 0.10617446899414062, - "spec/helpers/groups_helper_spec.rb": 0.007729053497314453, - "spec/helpers/html_helper_spec.rb": 0.05157279968261719, - "spec/helpers/injection_helper_spec.rb": 0.6142556667327881, - "spec/helpers/navigation_helper_spec.rb": 0.02951979637145996, - "spec/helpers/order_cycles_helper_spec.rb": 0.5953588485717773, - "spec/helpers/products_helper_spec.rb": 0.009511232376098633, - "spec/helpers/shared_helper_spec.rb": 0.017564058303833008, - "spec/helpers/shop_helper_spec.rb": 0.05760025978088379, - "spec/jobs/confirm_order_job_spec.rb": 0.0458524227142334, - "spec/jobs/confirm_signup_job_spec.rb": 0.021564006805419922, - "spec/jobs/finalize_account_invoices_spec.rb": 4.505181312561035, - "spec/jobs/order_cycle_notification_job_spec.rb": 2.0606272220611572, - "spec/jobs/update_account_invoices_spec.rb": 18.434475898742676, - "spec/jobs/update_billable_periods_spec.rb": 4.850176572799683, - "spec/jobs/welcome_enterprise_job_spec.rb": 0.07065534591674805, - "spec/lib/open_food_network/bulk_coop_report_spec.rb": 4.789663553237915, - "spec/lib/open_food_network/customers_report_spec.rb": 2.419727325439453, - "spec/lib/open_food_network/distribution_change_validator_spec.rb": 0.10607743263244629, - "spec/lib/open_food_network/enterprise_fee_applicator_spec.rb": 0.7333858013153076, - "spec/lib/open_food_network/enterprise_fee_calculator_spec.rb": 7.406745195388794, - "spec/lib/open_food_network/enterprise_injection_data_spec.rb": 0.291548490524292, - "spec/lib/open_food_network/enterprise_issue_validator_spec.rb": 0.09764814376831055, - "spec/lib/open_food_network/feature_toggle_spec.rb": 0.010193109512329102, - "spec/lib/open_food_network/group_buy_report_spec.rb": 3.708569049835205, - "spec/lib/open_food_network/last_used_address_spec.rb": 0.0254666805267334, - "spec/lib/open_food_network/lettuce_share_report_spec.rb": 2.3206725120544434, - "spec/lib/open_food_network/option_value_namer_spec.rb": 0.06185555458068848, - "spec/lib/open_food_network/order_and_distributor_report_spec.rb": 1.0406858921051025, - "spec/lib/open_food_network/order_cycle_form_applicator_spec.rb": 4.533008337020874, - "spec/lib/open_food_network/order_cycle_management_report_spec.rb": 2.036308526992798, - "spec/lib/open_food_network/order_cycle_permissions_spec.rb": 23.74185061454773, - "spec/lib/open_food_network/order_grouper_spec.rb": 0.029039621353149414, - "spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb": 5.135573148727417, - "spec/lib/open_food_network/packing_report_spec.rb": 5.088447093963623, - "spec/lib/open_food_network/permissions_spec.rb": 8.881855249404907, - "spec/lib/open_food_network/products_and_inventory_report_spec.rb": 3.55375337600708, - "spec/lib/open_food_network/referer_parser_spec.rb": 0.014271259307861328, - "spec/lib/open_food_network/reports/report_spec.rb": 0.02238297462463379, - "spec/lib/open_food_network/reports/row_spec.rb": 0.0031762123107910156, - "spec/lib/open_food_network/reports/rule_spec.rb": 0.013959169387817383, - "spec/lib/open_food_network/sales_tax_report_spec.rb": 0.10717129707336426, - "spec/lib/open_food_network/scope_variant_to_hub_spec.rb": 2.4846229553222656, - "spec/lib/open_food_network/user_balance_calculator_spec.rb": 3.4277901649475098, - "spec/lib/open_food_network/users_and_enterprises_report_spec.rb": 0.40532779693603516, - "spec/lib/open_food_network/xero_invoices_report_spec.rb": 1.1586685180664062, - "spec/lib/spree/product_filters_spec.rb": 0.13163042068481445, - "spec/mailers/enterprise_mailer_spec.rb": 0.4537942409515381, - "spec/mailers/order_mailer_spec.rb": 1.452355146408081, - "spec/mailers/producer_mailer_spec.rb": 8.775528192520142, - "spec/mailers/user_mailer_spec.rb": 0.057527780532836914, - "spec/models/adjustment_metadata_spec.rb": 0.22016620635986328, - "spec/models/billable_period_spec.rb": 2.06524658203125, - "spec/models/calculator/weight_spec.rb": 0.009344100952148438, - "spec/models/cart_spec.rb": 4.099429130554199, - "spec/models/customer_spec.rb": 0.07328605651855469, - "spec/models/enterprise_caching_spec.rb": 0.8475983142852783, - "spec/models/enterprise_fee_spec.rb": 3.1999905109405518, - "spec/models/enterprise_group_spec.rb": 0.30861926078796387, - "spec/models/enterprise_relationship_spec.rb": 2.1849746704101562, - "spec/models/enterprise_spec.rb": 17.679611682891846, - "spec/models/exchange_spec.rb": 13.899227857589722, - "spec/models/model_set_spec.rb": 0.22760748863220215, - "spec/models/order_cycle_spec.rb": 10.680967569351196, - "spec/models/product_distribution_spec.rb": 2.227938413619995, - "spec/models/spree/ability_spec.rb": 15.278357028961182, - "spec/models/spree/addresses_spec.rb": 0.055602312088012695, - "spec/models/spree/adjustment_spec.rb": 9.196375846862793, - "spec/models/spree/classification_spec.rb": 0.161299467086792, - "spec/models/spree/image_spec.rb": 0.007464408874511719, - "spec/models/spree/line_item_spec.rb": 13.545411586761475, - "spec/models/spree/order_populator_spec.rb": 1.635932207107544, - "spec/models/spree/order_spec.rb": 10.645411968231201, - "spec/models/spree/payment_method_spec.rb": 0.0733034610748291, - "spec/models/spree/payment_spec.rb": 1.691227912902832, - "spec/models/spree/preferences/file_configuration_spec.rb": 0.03429675102233887, - "spec/models/spree/product_spec.rb": 17.406191110610962, - "spec/models/spree/shipping_method_spec.rb": 3.0447566509246826, - "spec/models/spree/tax_rate_spec.rb": 0.44750261306762695, - "spec/models/spree/taxon_spec.rb": 0.553098201751709, - "spec/models/spree/user_spec.rb": 1.2693369388580322, - "spec/models/spree/variant_spec.rb": 13.75825023651123, - "spec/models/variant_override_spec.rb": 4.086935520172119, - "spec/performance/injection_helper_spec.rb": 6.890667676925659, - "spec/performance/orders_controller_spec.rb": 0.031180143356323242, - "spec/performance/shop_controller_spec.rb": 18.19426918029785, - "spec/requests/large_request_spec.rb": 0.02229022979736328, - "spec/requests/shop_spec.rb": 1.0012562274932861, - "spec/serializers/admin/enterprise_serializer_spec.rb": 0.10484433174133301, - "spec/serializers/admin/exchange_serializer_spec.rb": 0.7569985389709473, - "spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb": 0.4293792247772217, - "spec/serializers/admin/index_enterprise_serializer_spec.rb": 1.2506742477416992, - "spec/serializers/admin/variant_override_serializer_spec.rb": 0.38981151580810547, - "spec/serializers/enterprise_serializer_spec.rb": 0.3511006832122803, - "spec/serializers/spree/product_serializer_spec.rb": 0.26622653007507324, - "spec/serializers/spree/variant_serializer_spec.rb": 0.30304574966430664 -} + "spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb": 4.729289770126343, + "spec/controllers/admin/business_model_configuration_controller_spec.rb": 0.3204472064971924, + "spec/controllers/admin/column_preferences_controller_spec.rb": 0.21457862854003906, + "spec/controllers/admin/customers_controller_spec.rb": 1.2570579051971436, + "spec/controllers/admin/enterprises_controller_spec.rb": 6.453823804855347, + "spec/controllers/admin/inventory_items_controller_spec.rb": 3.3494999408721924, + "spec/controllers/admin/order_cycles_controller_spec.rb": 3.2418012619018555, + "spec/controllers/admin/tag_rules_controller_spec.rb": 0.278639554977417, + "spec/controllers/admin/variant_overrides_controller_spec.rb": 4.334253549575806, + "spec/controllers/api/enterprises_controller_spec.rb": 0.4233386516571045, + "spec/controllers/api/order_cycles_controller_spec.rb": 1.9799659252166748, + "spec/controllers/api/statuses_controller_spec.rb": 0.0580599308013916, + "spec/controllers/base_controller_spec.rb": 0.025392770767211914, + "spec/controllers/cart_controller_spec.rb": 1.188997507095337, + "spec/controllers/checkout_controller_spec.rb": 1.7111992835998535, + "spec/controllers/enterprise_confirmations_controller_spec.rb": 1.057147741317749, + "spec/controllers/enterprises_controller_spec.rb": 3.9115149974823, + "spec/controllers/groups_controller_spec.rb": 0.4256296157836914, + "spec/controllers/registration_controller_spec.rb": 0.1444110870361328, + "spec/controllers/shop_controller_spec.rb": 2.8928422927856445, + "spec/controllers/shops_controller_spec.rb": 0.23369908332824707, + "spec/controllers/spree/admin/adjustments_controller_spec.rb": 1.0890753269195557, + "spec/controllers/spree/admin/base_controller_spec.rb": 0.1624138355255127, + "spec/controllers/spree/admin/line_items_controller_spec.rb": 16.208045721054077, + "spec/controllers/spree/admin/orders_controller_spec.rb": 15.907819509506226, + "spec/controllers/spree/admin/overview_controller_spec.rb": 0.8662476539611816, + "spec/controllers/spree/admin/payment_methods_controller_spec.rb": 0.4896993637084961, + "spec/controllers/spree/admin/products_controller_spec.rb": 2.074070930480957, + "spec/controllers/spree/admin/reports_controller_spec.rb": 55.07741975784302, + "spec/controllers/spree/admin/search_controller_spec.rb": 0.5158224105834961, + "spec/controllers/spree/admin/variants_controller_spec.rb": 1.990790605545044, + "spec/controllers/spree/api/line_items_controller_spec.rb": 0.3319206237792969, + "spec/controllers/spree/api/products_controller_spec.rb": 6.679011106491089, + "spec/controllers/spree/api/variants_controller_spec.rb": 3.7782905101776123, + "spec/controllers/spree/checkout_controller_spec.rb": 0.9790353775024414, + "spec/controllers/spree/orders_controller_spec.rb": 4.158925294876099, + "spec/controllers/spree/paypal_controller_spec.rb": 0.020407676696777344, + "spec/controllers/spree/store_controller_spec.rb": 0.03319215774536133, + "spec/controllers/spree/user_sessions_controller_spec.rb": 0.07898402214050293, + "spec/controllers/user_passwords_controller_spec.rb": 0.717381477355957, + "spec/controllers/user_registrations_controller_spec.rb": 0.2160170078277588, + "spec/features/admin/account_spec.rb": 0.2934560775756836, + "spec/features/admin/accounts_and_billing_settings_spec.rb": 15.889720678329468, + "spec/features/admin/adjustments_spec.rb": 5.175323009490967, + "spec/features/admin/authentication_spec.rb": 18.345781087875366, + "spec/features/admin/bulk_order_management_spec.rb": 111.50722217559814, + "spec/features/admin/bulk_product_update_spec.rb": 63.564337730407715, + "spec/features/admin/business_model_configuration_spec.rb": 2.1073272228240967, + "spec/features/admin/caching_spec.rb": 0.8505651950836182, + "spec/features/admin/content_spec.rb": 1.1712932586669922, + "spec/features/admin/customers_spec.rb": 71.91736245155334, + "spec/features/admin/enterprise_fees_spec.rb": 15.482876300811768, + "spec/features/admin/enterprise_groups_spec.rb": 8.615704774856567, + "spec/features/admin/enterprise_relationships_spec.rb": 11.908889293670654, + "spec/features/admin/enterprise_roles_spec.rb": 5.027954578399658, + "spec/features/admin/enterprise_user_spec.rb": 2.158304214477539, + "spec/features/admin/enterprises/index_spec.rb": 5.7792346477508545, + "spec/features/admin/enterprises_spec.rb": 39.01360893249512, + "spec/features/admin/external_services_spec.rb": 0.41648149490356445, + "spec/features/admin/image_settings_spec.rb": 0.4291551113128662, + "spec/features/admin/order_cycles_spec.rb": 66.84531092643738, + "spec/features/admin/orders_spec.rb": 50.86089587211609, + "spec/features/admin/overview_spec.rb": 4.884965896606445, + "spec/features/admin/payment_method_spec.rb": 14.099174499511719, + "spec/features/admin/products_spec.rb": 17.05465793609619, + "spec/features/admin/reports_spec.rb": 142.85665917396545, + "spec/features/admin/shipping_methods_spec.rb": 6.785600900650024, + "spec/features/admin/tag_rules_spec.rb": 21.80374526977539, + "spec/features/admin/tax_settings_spec.rb": 0.5856199264526367, + "spec/features/admin/variant_overrides_spec.rb": 54.87969517707825, + "spec/features/admin/variants_spec.rb": 4.425906658172607, + "spec/features/consumer/account_spec.rb": 14.138294458389282, + "spec/features/consumer/authentication_spec.rb": 15.800535440444946, + "spec/features/consumer/external_services_spec.rb": 0.47263646125793457, + "spec/features/consumer/groups_spec.rb": 2.167065143585205, + "spec/features/consumer/producers_spec.rb": 8.219613790512085, + "spec/features/consumer/registration_spec.rb": 3.2899246215820312, + "spec/features/consumer/shopping/cart_spec.rb": 7.931907653808594, + "spec/features/consumer/shopping/checkout_auth_spec.rb": 10.027384042739868, + "spec/features/consumer/shopping/checkout_spec.rb": 60.93560552597046, + "spec/features/consumer/shopping/shopping_spec.rb": 64.26991128921509, + "spec/features/consumer/shopping/variant_overrides_spec.rb": 71.18549585342407, + "spec/features/consumer/shops_spec.rb": 12.581299543380737, + "spec/helpers/admin/business_model_configuration_helper_spec.rb": 0.4121088981628418, + "spec/helpers/checkout_helper_spec.rb": 0.017447471618652344, + "spec/helpers/enterprises_helper_spec.rb": 3.16050124168396, + "spec/helpers/groups_helper_spec.rb": 0.008687734603881836, + "spec/helpers/html_helper_spec.rb": 0.12075495719909668, + "spec/helpers/injection_helper_spec.rb": 13.099636316299438, + "spec/helpers/navigation_helper_spec.rb": 0.037546634674072266, + "spec/helpers/order_cycles_helper_spec.rb": 0.5602025985717773, + "spec/helpers/products_helper_spec.rb": 0.009445667266845703, + "spec/helpers/shared_helper_spec.rb": 0.021656036376953125, + "spec/helpers/shop_helper_spec.rb": 0.06465697288513184, + "spec/jobs/confirm_order_job_spec.rb": 0.04894542694091797, + "spec/jobs/confirm_signup_job_spec.rb": 0.15027284622192383, + "spec/jobs/finalize_account_invoices_spec.rb": 4.740641832351685, + "spec/jobs/heartbeat_job_spec.rb": 0.020777225494384766, + "spec/jobs/order_cycle_notification_job_spec.rb": 2.3326029777526855, + "spec/jobs/products_cache_integrity_checker_job_spec.rb": 2.176734685897827, + "spec/jobs/refresh_products_cache_job_spec.rb": 0.14060688018798828, + "spec/jobs/update_account_invoices_spec.rb": 18.77696418762207, + "spec/jobs/update_billable_periods_spec.rb": 5.19831395149231, + "spec/jobs/welcome_enterprise_job_spec.rb": 0.05716228485107422, + "spec/lib/open_food_network/bulk_coop_report_spec.rb": 5.522400140762329, + "spec/lib/open_food_network/cached_products_renderer_spec.rb": 0.0779104232788086, + "spec/lib/open_food_network/customers_report_spec.rb": 2.789498805999756, + "spec/lib/open_food_network/distribution_change_validator_spec.rb": 0.12454366683959961, + "spec/lib/open_food_network/enterprise_fee_applicator_spec.rb": 1.0582823753356934, + "spec/lib/open_food_network/enterprise_fee_calculator_spec.rb": 9.390950918197632, + "spec/lib/open_food_network/enterprise_injection_data_spec.rb": 0.30153727531433105, + "spec/lib/open_food_network/enterprise_issue_validator_spec.rb": 0.09757637977600098, + "spec/lib/open_food_network/feature_toggle_spec.rb": 0.011552810668945312, + "spec/lib/open_food_network/group_buy_report_spec.rb": 4.40512228012085, + "spec/lib/open_food_network/last_used_address_spec.rb": 0.4271695613861084, + "spec/lib/open_food_network/lettuce_share_report_spec.rb": 2.5144362449645996, + "spec/lib/open_food_network/option_value_namer_spec.rb": 0.47345566749572754, + "spec/lib/open_food_network/order_and_distributor_report_spec.rb": 1.1131298542022705, + "spec/lib/open_food_network/order_cycle_form_applicator_spec.rb": 7.482408761978149, + "spec/lib/open_food_network/order_cycle_management_report_spec.rb": 2.9279346466064453, + "spec/lib/open_food_network/order_cycle_permissions_spec.rb": 27.034855365753174, + "spec/lib/open_food_network/order_grouper_spec.rb": 0.0347137451171875, + "spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb": 6.190460443496704, + "spec/lib/open_food_network/packing_report_spec.rb": 5.795913934707642, + "spec/lib/open_food_network/permissions_spec.rb": 9.981389284133911, + "spec/lib/open_food_network/products_and_inventory_report_spec.rb": 4.536849737167358, + "spec/lib/open_food_network/products_cache_refreshment_spec.rb": 0.3400561809539795, + "spec/lib/open_food_network/products_cache_spec.rb": 13.676804304122925, + "spec/lib/open_food_network/products_renderer_spec.rb": 5.883910894393921, + "spec/lib/open_food_network/property_merge_spec.rb": 0.28261804580688477, + "spec/lib/open_food_network/referer_parser_spec.rb": 0.016553640365600586, + "spec/lib/open_food_network/reports/report_spec.rb": 0.027279138565063477, + "spec/lib/open_food_network/reports/row_spec.rb": 0.004057884216308594, + "spec/lib/open_food_network/reports/rule_spec.rb": 0.018927812576293945, + "spec/lib/open_food_network/sales_tax_report_spec.rb": 0.1267712116241455, + "spec/lib/open_food_network/scope_variant_to_hub_spec.rb": 5.346986532211304, + "spec/lib/open_food_network/tag_rule_applicator_spec.rb": 2.972744941711426, + "spec/lib/open_food_network/user_balance_calculator_spec.rb": 6.290127754211426, + "spec/lib/open_food_network/users_and_enterprises_report_spec.rb": 0.435042142868042, + "spec/lib/open_food_network/xero_invoices_report_spec.rb": 1.327892780303955, + "spec/lib/spree/product_filters_spec.rb": 0.14480209350585938, + "spec/mailers/enterprise_mailer_spec.rb": 1.2255680561065674, + "spec/mailers/order_mailer_spec.rb": 1.9922146797180176, + "spec/mailers/producer_mailer_spec.rb": 28.504019021987915, + "spec/mailers/user_mailer_spec.rb": 0.06116366386413574, + "spec/models/adjustment_metadata_spec.rb": 0.22940421104431152, + "spec/models/billable_period_spec.rb": 5.919523477554321, + "spec/models/calculator/weight_spec.rb": 0.011056900024414062, + "spec/models/cart_spec.rb": 4.7867491245269775, + "spec/models/column_preference_spec.rb": 0.12476158142089844, + "spec/models/content_configuration_spec.rb": 0.0069255828857421875, + "spec/models/coordinator_fee_spec.rb": 0.1413099765777588, + "spec/models/customer_spec.rb": 0.9213364124298096, + "spec/models/enterprise_caching_spec.rb": 0.8015868663787842, + "spec/models/enterprise_fee_spec.rb": 3.8326468467712402, + "spec/models/enterprise_group_spec.rb": 0.35931992530822754, + "spec/models/enterprise_relationship_spec.rb": 7.324019908905029, + "spec/models/enterprise_spec.rb": 20.723163843154907, + "spec/models/exchange_fee_spec.rb": 0.24502134323120117, + "spec/models/exchange_spec.rb": 15.133025646209717, + "spec/models/inventory_item_spec.rb": 0.2637319564819336, + "spec/models/model_set_spec.rb": 0.2381300926208496, + "spec/models/order_cycle_spec.rb": 19.834176540374756, + "spec/models/producer_property_spec.rb": 0.12196111679077148, + "spec/models/product_distribution_spec.rb": 2.8120880126953125, + "spec/models/spree/ability_spec.rb": 16.657139778137207, + "spec/models/spree/addresses_spec.rb": 0.06702327728271484, + "spec/models/spree/adjustment_spec.rb": 13.998104333877563, + "spec/models/spree/classification_spec.rb": 0.7607810497283936, + "spec/models/spree/image_spec.rb": 2.1546812057495117, + "spec/models/spree/line_item_spec.rb": 18.319732189178467, + "spec/models/spree/option_type_spec.rb": 0.38923072814941406, + "spec/models/spree/option_value_spec.rb": 0.4280354976654053, + "spec/models/spree/order_populator_spec.rb": 1.4095511436462402, + "spec/models/spree/order_spec.rb": 9.809221029281616, + "spec/models/spree/payment_method_spec.rb": 0.5280671119689941, + "spec/models/spree/payment_spec.rb": 2.4764130115509033, + "spec/models/spree/preference_spec.rb": 0.059625864028930664, + "spec/models/spree/preferences/file_configuration_spec.rb": 0.038376808166503906, + "spec/models/spree/price_spec.rb": 0.5022625923156738, + "spec/models/spree/product_property_spec.rb": 0.3601999282836914, + "spec/models/spree/product_spec.rb": 16.564993381500244, + "spec/models/spree/property_spec.rb": 1.6884117126464844, + "spec/models/spree/shipping_method_spec.rb": 2.2080821990966797, + "spec/models/spree/tax_rate_spec.rb": 0.37114739418029785, + "spec/models/spree/taxon_spec.rb": 1.0655884742736816, + "spec/models/spree/user_spec.rb": 16.094335317611694, + "spec/models/spree/variant_spec.rb": 14.885905027389526, + "spec/models/tag_rule/filter_order_cycles_spec.rb": 0.21634840965270996, + "spec/models/tag_rule/filter_payment_methods_spec.rb": 0.4332749843597412, + "spec/models/tag_rule/filter_products_spec.rb": 0.21471834182739258, + "spec/models/tag_rule/filter_shipping_methods_spec.rb": 0.3680458068847656, + "spec/models/tag_rule_spec.rb": 0.05348682403564453, + "spec/models/variant_override_spec.rb": 5.598196029663086, + "spec/performance/injection_helper_spec.rb": 4.83400297164917, + "spec/performance/orders_controller_spec.rb": 0.028135061264038086, + "spec/performance/shop_controller_spec.rb": 14.35703420639038, + "spec/requests/large_request_spec.rb": 0.024456262588500977, + "spec/requests/shop_spec.rb": 1.0987565517425537, + "spec/serializers/admin/customer_serializer_spec.rb": 0.0909874439239502, + "spec/serializers/admin/enterprise_serializer_spec.rb": 0.06178736686706543, + "spec/serializers/admin/exchange_serializer_spec.rb": 2.586963653564453, + "spec/serializers/admin/for_order_cycle/enterprise_serializer_spec.rb": 0.8507771492004395, + "spec/serializers/admin/for_order_cycle/supplied_product_serializer_spec.rb": 0.6380510330200195, + "spec/serializers/admin/index_enterprise_serializer_spec.rb": 0.19609999656677246, + "spec/serializers/admin/variant_override_serializer_spec.rb": 0.27136850357055664, + "spec/serializers/enterprise_serializer_spec.rb": 0.22696876525878906, + "spec/serializers/order_serializer_spec.rb": 1.3858006000518799, + "spec/serializers/orders_by_distributor_serializer_spec.rb": 3.6581554412841797, + "spec/serializers/spree/product_serializer_spec.rb": 0.17654776573181152, + "spec/serializers/spree/variant_serializer_spec.rb": 0.2116224765777588 +} \ No newline at end of file From 6f947380cbdcbc53258743ed943f3d69ae29f6b5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 13:58:54 +1000 Subject: [PATCH 40/77] Remove unused overrides and views --- .../spree/products/_source_sidebar.html.haml | 28 ------------------- 1 file changed, 28 deletions(-) delete mode 100644 app/views/spree/products/_source_sidebar.html.haml diff --git a/app/views/spree/products/_source_sidebar.html.haml b/app/views/spree/products/_source_sidebar.html.haml deleted file mode 100644 index 8a58a65ea1..0000000000 --- a/app/views/spree/products/_source_sidebar.html.haml +++ /dev/null @@ -1,28 +0,0 @@ -%nav#filters - %div#distributor_filter - %h6.filter_name Shop by Distributor - %ul.filter_choices - - order = current_order(false) - - validator = DistributionChangeValidator.new(order) - - @sidebar_distributors.each do |distributor| - %li.nowrap - - if order.nil? || order.distributor == distributor || validator.can_change_to_distributor?(distributor) - = link_to distributor.name, [main_app, distributor] - - else - %abbr(title="One or more of the products in your cart is not available from this distributor")= distributor.name - - if @total_distributors > @sidebar_distributors.length - - distributors_more = @total_distributors - @sidebar_distributors.length - %span.filter_more - = "#{distributors_more} more..." - = button_to 'Browse All Distributors', main_app.distributors_enterprises_path, :method => :get - - %div#supplier_filter - %h6.filter_name Shop by Supplier - %ul.filter_choices - - @sidebar_suppliers.each do |supplier| - %li.nowrap= link_to supplier.name, [main_app, supplier] - - if @total_suppliers > @sidebar_suppliers.length - - suppliers_more = @total_suppliers - @sidebar_suppliers.length - %span.filter_more - = "#{suppliers_more} more..." - = button_to 'Browse All Suppliers', main_app.suppliers_enterprises_path, :method => :get From 0b84afd67a800b48887fe5f3b1a551606dc2ebe6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 24 Jun 2016 12:13:29 +1000 Subject: [PATCH 41/77] Display property filters for producers --- .../controllers/enterprises_controller.js.coffee | 2 +- .../darkswarm/directives/single_line_selectors.coffee | 2 +- app/views/producers/_filters.html.haml | 8 ++++++++ app/views/producers/index.html.haml | 2 +- config/locales/en.yml | 1 + 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index fa11c0e92f..b60914bbd8 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -30,7 +30,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris # When filter settings change, this could change which name match is at the top, or even # result in no matches. This affects the reference point that the distance matches are # calculated from, so we need to recalculate distances. - $scope.$watch '[activeTaxons, shippingTypes, show_profiles]', -> + $scope.$watch '[activeTaxons, activeProperties, shippingTypes, show_profiles]', -> $timeout -> Enterprises.calculateDistance $scope.query, $scope.firstNameMatch() $rootScope.$broadcast 'enterprisesChanged' diff --git a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee index ea5d8568d2..fca5366547 100644 --- a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee +++ b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee @@ -20,7 +20,7 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> scope.emit = -> scope.activeSelectors = scope.allSelectors.filter (selector)-> selector.active - .map (selector)-> + .map (selector) -> selector.object.id # From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index 97cc204cab..a7c8ccd134 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -12,4 +12,12 @@ = t :producers_filter = t :producers_filter_type %filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-6{"selector-set" => "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons"} + + %h5.tdhead + .light + = t :producers_filter + = t :producers_filter_property + .filter-shopfront.property-selectors + %single-line-selectors{ selectors: "filterSelectors", objects: "producers_to_filter | searchEnterprises:query | propertiesOf", "active-selectors" => "activeProperties"} + = render partial: 'shared/components/filter_box' diff --git a/app/views/producers/index.html.haml b/app/views/producers/index.html.haml index 8b7fd5695e..04048ef77e 100644 --- a/app/views/producers/index.html.haml +++ b/app/views/producers/index.html.haml @@ -16,7 +16,7 @@ .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons)", + "ng-repeat" => "producer in filteredEnterprises = (Enterprises.producers | visible | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", "ng-controller" => "ProducerNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/config/locales/en.yml b/config/locales/en.yml index d5ed777e17..2d2e4bc3df 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -579,6 +579,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using producers_buy_at_html: "Shop for %{enterprise} products at:" producers_filter: Filter by producers_filter_type: Type + producers_filter_property: Property producers_title: Producers producers_headline: Find local producers producers_signup_title: Sign up as a producer From 69382c4c13e17c17f6b27d61e7259590b27d54b5 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 24 Jun 2016 12:35:35 +1000 Subject: [PATCH 42/77] Move properties filter dropdown in front of search results --- app/assets/stylesheets/darkswarm/_shop-filters.css.sass | 6 ++++++ app/views/producers/_filters.html.haml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass index cf80c63035..3c4f9a514d 100644 --- a/app/assets/stylesheets/darkswarm/_shop-filters.css.sass +++ b/app/assets/stylesheets/darkswarm/_shop-filters.css.sass @@ -92,6 +92,12 @@ span.filter-label opacity: 0.75 +// singleLineSelectors directive provides a drop-down that can overlap +// content. Ensure that the dropdown appears above the content. +.filter-row + position: relative + z-index: 100 + .filter-shopfront &.taxon-selectors, &.property-selectors background: transparent diff --git a/app/views/producers/_filters.html.haml b/app/views/producers/_filters.html.haml index a7c8ccd134..771ed932c9 100644 --- a/app/views/producers/_filters.html.haml +++ b/app/views/producers/_filters.html.haml @@ -3,7 +3,7 @@ .small-12.medium-6.columns.text-right   -.row.animate-show{"ng-show" => "filtersActive"} +.row.animate-show.filter-row{"ng-show" => "filtersActive"} .small-12.columns .row.filter-box .small-12.columns From e3173c955d0c234f9ac847694251e1413dfc4f9e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 24 Jun 2016 12:47:52 +1000 Subject: [PATCH 43/77] Refit filters when box opens --- .../enterprises_controller.js.coffee | 2 ++ .../directives/single_line_selectors.coffee | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index b60914bbd8..bc4365b56a 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -21,6 +21,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris Enterprises.calculateDistance query, $scope.firstNameMatch() $rootScope.$broadcast 'enterprisesChanged' + $scope.$watch "filtersActive", (value) -> + $scope.$broadcast 'filtersToggled' $rootScope.$on "enterprisesChanged", -> $scope.filterEnterprises() diff --git a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee index fca5366547..4613041f47 100644 --- a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee +++ b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee @@ -6,7 +6,7 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> objects: "&" activeSelectors: "=" selectorName: "@activeSelectors" - link: (scope,element,attrs) -> + link: (scope, element, attrs) -> scope.fitting = false scope.overFlowSelectors = -> @@ -23,6 +23,13 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> .map (selector) -> selector.object.id + scope.refit = -> + if scope.allSelectors? + scope.fitting = true + selector.fits = true for selector in scope.allSelectors + $timeout(loadWidths, 0, true).then -> + $timeout fit, 0, true + # From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing debouncer = (func, timeout) -> timeoutID = undefined @@ -62,11 +69,10 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> scope.fitting = false scope.$watchCollection "allSelectors", -> - if scope.allSelectors? - scope.fitting = true - selector.fits = true for selector in scope.allSelectors - $timeout(loadWidths, 0, true).then -> - $timeout fit, 0, true + scope.refit() + + scope.$on "filtersToggled", -> + scope.refit() $(window).resize debouncer (e) -> scope.fitting = true From 1257ee09f2a618fd745e67bba57fcfd84abc0fec Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 24 Jun 2016 12:56:16 +1000 Subject: [PATCH 44/77] Reorder methods for clarity --- .../directives/single_line_selectors.coffee | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee index 4613041f47..04fa639bf4 100644 --- a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee +++ b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee @@ -9,20 +9,6 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> link: (scope, element, attrs) -> scope.fitting = false - scope.overFlowSelectors = -> - return [] unless scope.allSelectors? - $filter('filter')(scope.allSelectors, { fits: false }) - - scope.selectedOverFlowSelectors = -> - $filter('filter')(scope.overFlowSelectors(), { active: true }) - - # had to duplicate this to make overflow selectors work - scope.emit = -> - scope.activeSelectors = scope.allSelectors.filter (selector)-> - selector.active - .map (selector) -> - selector.object.id - scope.refit = -> if scope.allSelectors? scope.fitting = true @@ -30,24 +16,6 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> $timeout(loadWidths, 0, true).then -> $timeout fit, 0, true - # From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing - debouncer = (func, timeout) -> - timeoutID = undefined - timeout = timeout or 50 - -> - subject = this - args = arguments - clearTimeout timeoutID - timeoutID = setTimeout(-> - func.apply subject, Array::slice.call(args) - , timeout) - - loadWidths = -> - $(element).find("li").not(".more").each (i) -> - scope.allSelectors[i].width = $(this).outerWidth(true) - return null # So we don't exit the loop weirdly - - fit = -> used = $(element).find("li.more").outerWidth(true) used += selector.width for selector in scope.allSelectors when selector.fits @@ -68,6 +36,39 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> available += selector.width scope.fitting = false + loadWidths = -> + $(element).find("li").not(".more").each (i) -> + scope.allSelectors[i].width = $(this).outerWidth(true) + return null # So we don't exit the loop weirdly + + scope.overFlowSelectors = -> + return [] unless scope.allSelectors? + $filter('filter')(scope.allSelectors, { fits: false }) + + scope.selectedOverFlowSelectors = -> + $filter('filter')(scope.overFlowSelectors(), { active: true }) + + # had to duplicate this to make overflow selectors work + scope.emit = -> + scope.activeSelectors = scope.allSelectors.filter (selector)-> + selector.active + .map (selector) -> + selector.object.id + + # From: http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing + debouncer = (func, timeout) -> + timeoutID = undefined + timeout = timeout or 50 + -> + subject = this + args = arguments + clearTimeout timeoutID + timeoutID = setTimeout(-> + func.apply subject, Array::slice.call(args) + , timeout) + + + # -- Event management scope.$watchCollection "allSelectors", -> scope.refit() From 13cf5d29de78633ca7409e9d76ab467a705a88cb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 10:04:11 +1000 Subject: [PATCH 45/77] Add guard for selector overflow (only seen in phantom, not selenium/firefox or dev server/chrome) --- .../directives/single_line_selectors.coffee | 3 ++- spec/features/consumer/producers_spec.rb | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee index 04fa639bf4..9cc125a537 100644 --- a/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee +++ b/app/assets/javascripts/darkswarm/directives/single_line_selectors.coffee @@ -38,7 +38,8 @@ Darkswarm.directive 'singleLineSelectors', ($timeout, $filter) -> loadWidths = -> $(element).find("li").not(".more").each (i) -> - scope.allSelectors[i].width = $(this).outerWidth(true) + if i < scope.allSelectors.length + scope.allSelectors[i].width = $(this).outerWidth(true) return null # So we don't exit the loop weirdly scope.overFlowSelectors = -> diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 5c89a23529..4bb8d2d97e 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -55,6 +55,23 @@ feature %q{ page.should_not have_content producer2.name end + describe "filtering by product property" do + it "filters" do + toggle_filters + + toggle_filter 'Organic' + + page.should have_content producer1.name + page.should_not have_content producer2.name + + toggle_filter 'Organic' + toggle_filter 'Biodynamic' + + page.should_not have_content producer1.name + page.should have_content producer2.name + end + end + it "shows all producers with expandable details" do page.should have_content producer1.name expand_active_table_node producer1.name From b13360d2d0deccc22a36cb98ca9b839c34c8c336 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 10:39:35 +1000 Subject: [PATCH 46/77] Extract filter helpers from individual spec to spec helper --- spec/features/consumer/producers_spec.rb | 12 ------------ spec/spec_helper.rb | 1 + spec/support/filters_helper.rb | 14 ++++++++++++++ 3 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 spec/support/filters_helper.rb diff --git a/spec/features/consumer/producers_spec.rb b/spec/features/consumer/producers_spec.rb index 4bb8d2d97e..514c71d7c4 100644 --- a/spec/features/consumer/producers_spec.rb +++ b/spec/features/consumer/producers_spec.rb @@ -93,16 +93,4 @@ feature %q{ page.should have_link shop.name end end - - - private - - def toggle_filters - find('a.filterbtn').click - end - - def toggle_filter(name) - page.find('span', text: name).click - end - end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index c7a7f8e790..f1150cc485 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -103,6 +103,7 @@ RSpec.configure do |config| config.include Spree::Api::TestingSupport::Helpers, :type => :controller config.include OpenFoodNetwork::ControllerHelper, :type => :controller config.include OpenFoodNetwork::FeatureToggleHelper + config.include OpenFoodNetwork::FiltersHelper config.include OpenFoodNetwork::EnterpriseGroupsHelper config.include OpenFoodNetwork::ProductsHelper config.include OpenFoodNetwork::DistributionHelper diff --git a/spec/support/filters_helper.rb b/spec/support/filters_helper.rb new file mode 100644 index 0000000000..5e509568f7 --- /dev/null +++ b/spec/support/filters_helper.rb @@ -0,0 +1,14 @@ +module OpenFoodNetwork + # Helper for customer-facing filters (eg. producers, shops, groups, etc.) + module FiltersHelper + # Expand/collapse the filters dialog + def toggle_filters + find('a.filterbtn').click + end + + # Toggle one particular filter + def toggle_filter(name) + page.find('span', text: name).click + end + end +end From d9d3a4a645a4d627af279cc8ccc6d8972793bc87 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 10:40:31 +1000 Subject: [PATCH 47/77] Set up producer filters on group producers page --- .../group_enterprises_controller.js.coffee | 3 ++ app/views/groups/show.html.haml | 2 +- spec/features/consumer/groups_spec.rb | 40 ++++++++++++++++++- 3 files changed, 43 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/group_enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/group_enterprises_controller.js.coffee index 13c1017386..567767be7b 100644 --- a/app/assets/javascripts/darkswarm/controllers/group_enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/group_enterprises_controller.js.coffee @@ -8,3 +8,6 @@ Darkswarm.controller "GroupEnterprisesCtrl", ($scope, Search, FilterSelectorsSer $scope.$watch "query", (query)-> Search.search query + + $scope.$watch "filtersActive", (value) -> + $scope.$broadcast 'filtersToggled' diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a21bdb7460..ef9e281155 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -67,7 +67,7 @@ .small-12.columns .active_table %producer.active_table_node.row.animate-repeat{id: "{{producer.path}}", - "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons)", + "ng-repeat" => "producer in filteredEnterprises = (group_producers | searchEnterprises:query | taxons:activeTaxons | properties:activeProperties)", "ng-controller" => "GroupEnterpriseNodeCtrl", "ng-class" => "{'closed' : !open(), 'open' : open(), 'inactive' : !producer.active}", id: "{{producer.hash}}"} diff --git a/spec/features/consumer/groups_spec.rb b/spec/features/consumer/groups_spec.rb index 5ea96ac17e..039322b379 100644 --- a/spec/features/consumer/groups_spec.rb +++ b/spec/features/consumer/groups_spec.rb @@ -9,11 +9,49 @@ feature 'Groups', js: true do it "renders groups" do visit groups_path - page.should have_content group.name + expect(page).to have_content group.name end it "searches by URL" do visit groups_path(anchor: "/?query=xyzzy") expect(page).to have_content "No groups found" end + + describe "producers" do + describe "filtering by product property" do + let!(:producer1) { create(:supplier_enterprise) } + let!(:producer2) { create(:supplier_enterprise) } + + let!(:product1) { create(:simple_product, supplier: producer1) } + let!(:product2) { create(:simple_product, supplier: producer2) } + + before do + product1.set_property 'Organic', 'NASAA 12345' + product2.set_property 'Biodynamic', 'ABC123' + + producer1.set_producer_property 'Local', 'Victoria' + producer2.set_producer_property 'Fair Trade', 'FT123' + + group.enterprises << producer1 + group.enterprises << producer2 + + visit group_path(group, anchor: "/producers") + end + + it "filters" do + toggle_filters + + toggle_filter 'Organic' + + expect(page).to have_content producer1.name + expect(page).not_to have_content producer2.name + + toggle_filter 'Organic' + toggle_filter 'Fair Trade' + + expect(page).not_to have_content producer1.name + expect(page).to have_content producer2.name + end + end + end end From 243dfa7a934a93554562fa33375ae6ce3b10ac90 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 8 Jul 2016 14:52:25 +1000 Subject: [PATCH 48/77] Add retry for intermittently failing spec in variant overrides --- spec/features/consumer/shopping/variant_overrides_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index f600a0c269..ecb0c4efe8 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature "shopping with variant overrides defined", js: true do +feature "shopping with variant overrides defined", js: true, retry: 3 do include AuthenticationWorkflow include WebHelper include ShopWorkflow @@ -191,7 +191,7 @@ feature "shopping with variant overrides defined", js: true do within "#payment" do choose pm.name end - + place_order expect(page).to have_content "Your order has been processed successfully" end From 4db29ce32276fe6e5acc9c9787db2e646a81e006 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 29 Jul 2016 11:53:45 +1000 Subject: [PATCH 49/77] Update css_splitter, fixes problem with keyframes spanning limit https://github.com/zweilove/css_splitter/issues/53 --- Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 397055e27f..2a10493f3e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -221,7 +221,7 @@ GEM safe_yaml (~> 0.9.0) css_parser (1.3.5) addressable - css_splitter (0.4.1) + css_splitter (0.4.5) sprockets (>= 2.0.0) daemons (1.2.2) dalli (2.7.2) @@ -451,7 +451,7 @@ GEM railties (>= 3.1) money (5.1.1) i18n (~> 0.6.0) - multi_json (1.12.0) + multi_json (1.12.1) multi_xml (0.5.5) newrelic_rpm (3.12.0.288) nokogiri (1.6.7.2) From 1586cd399296f3aec3b185a80b320e9cc5320816 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 29 Jul 2016 15:39:08 +1000 Subject: [PATCH 50/77] Uncache enterprise producer properties - we have no cache invalidation for this --- app/serializers/api/enterprise_serializer.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/serializers/api/enterprise_serializer.rb b/app/serializers/api/enterprise_serializer.rb index 127aee1a08..d30c2d8677 100644 --- a/app/serializers/api/enterprise_serializer.rb +++ b/app/serializers/api/enterprise_serializer.rb @@ -21,6 +21,7 @@ end class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer attributes :orders_close_at, :active + has_many :properties, serializer: Api::PropertySerializer def orders_close_at options[:data].earliest_closing_times[object.id] @@ -29,6 +30,14 @@ class Api::UncachedEnterpriseSerializer < ActiveModel::Serializer def active options[:data].active_distributors.andand.include? object end + + def properties + # This results in 3 queries per enterprise + product_properties = Spree::Property.applied_by(object) + producer_properties = object.properties + + OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties + end end class Api::CachedEnterpriseSerializer < ActiveModel::Serializer @@ -49,8 +58,6 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer attributes :taxons, :supplied_taxons has_one :address, serializer: Api::AddressSerializer - has_many :properties, serializer: Api::PropertySerializer - def taxons ids_to_objs options[:data].distributed_taxons[object.id] end @@ -59,14 +66,6 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer ids_to_objs options[:data].supplied_taxons[object.id] end - def properties - # This results in 3 queries per enterprise - product_properties = Spree::Property.applied_by(object) - producer_properties = object.properties - - OpenFoodNetwork::PropertyMerge.merge product_properties, producer_properties - end - def pickup services = options[:data].shipping_method_services[object.id] services ? services[:pickup] : false From 4d1a5c6ffc098cef1c76d762d013961cc2765a26 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Mon, 1 Aug 2016 21:47:34 +1000 Subject: [PATCH 51/77] Updating translations for config/locales/en_GB.yml [skip ci] --- config/locales/en_GB.yml | 979 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 979 insertions(+) create mode 100644 config/locales/en_GB.yml diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml new file mode 100644 index 0000000000..41e3643699 --- /dev/null +++ b/config/locales/en_GB.yml @@ -0,0 +1,979 @@ +en_GB: + activerecord: + attributes: + spree/order: + payment_state: Payment State + shipment_state: Shipment State + devise: + failure: + invalid: | + Invalid email or password. + Were you a guest last time? Perhaps you need to create an account or reset your password. + enterprise_confirmations: + enterprise: + confirmed: Thankyou, your email address has been confirmed. + not_confirmed: Your email address could not be confirmed. Perhaps you have already completed this step? + confirmation_sent: "Confirmation email sent!" + confirmation_not_sent: "Could not send a confirmation email." + enterprise_mailer: + confirmation_instructions: + subject: "Please confirm the email address for %{enterprise}" + welcome: + subject: "%{enterprise} is now on %{sitename}" + title: Open Food Network + welcome_to: 'Welcome to ' + site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world." + search_by_name: Search by name... + producers: 'UK Producers' + producers_join: UK producers are now welcome to join Open Food Network UK. + charges_sales_tax: Charges VAT? + print_invoice: "Print Invoice" + send_invoice: "Send Invoice" + resend_confirmation: "Resend Confirmation" + view_order: "View Order" + edit_order: "Edit Order" + ship_order: "Ship Order" + cancel_order: "Cancel Order" + confirm_send_invoice: "An invoice for this order will be sent to the customer. Are you sure you want to continue?" + confirm_resend_order_confirmation: "Are you sure you want to resend the order confirmation email?" + must_have_valid_business_number: "Please enter your company number." + invoice: "Invoice" + percentage_of_sales: "%{percentage} of sales" + percentage_of_turnover: "Percentage of turnover" + monthly_cap_excl_tax: "monthly cap (excl. VAT)" + capped_at_cap: "capped at %{cap}" + per_month: "per month" + free: "free" + free_trial: "free trial" + plus_tax: "plus VAT" + total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. VAT)" + min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}" + business_model_configuration: "Business model configuration" + say_no: "No" + say_yes: "Yes" + then: then + sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By" + admin: + date: Date + email: Email + name: Name + on_hand: In Stock + on_demand: On Demand + on_demand?: On Demand? + order_cycle: Order Cycle + phone: Phone + price: Price + producer: Producer + product: Product + quantity: Quantity + shop: Shop + sku: SKU + tags: Tags + variant: Variant + quick_search: Quick Search + clear_all: Clear All + start_date: "Start Date" + end_date: "End Date" + columns: Columns + actions: Actions + viewing: "Viewing: %{current_view_name}" + whats_this: What's this? + tag_has_rules: "Existing rules for this tag: %{num}" + has_one_rule: "has one rule" + has_n_rules: "has %{num} rules" + customers: + index: + add_customer: "Add Customer" + new_customer: "New Customer" + customer_placeholder: "customer@example.org" + valid_email_error: Please enter a valid email address + add_a_new_customer_for: Add a new customer for %{shop_name} + code: Code + duplicate_code: "This code is used already." + products: + bulk_edit: + unit: Unit + display_as: Display As + category: Category + tax_category: Tax Category + inherits_properties?: Inherits Properties? + available_on: Available On + av_on: "Av. On" + variant_overrides: + index: + title: Inventory + description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page + enable_reset?: Enable Stock Reset? + inherit?: Inherit? + add: Add + hide: Hide + select_a_shop: Select A Shop + review_now: Review Now + new_products_alert_message: There are %{new_product_count} new products available to add to your inventory. + currently_empty: Your inventory is currently empty + no_matching_products: No matching products found in your inventory + no_hidden_products: No products have been hidden from this inventory + no_matching_hidden_products: No hidden products match your search criteria + no_new_products: No new products are available to add to this inventory + no_matching_new_products: No new products match your search criteria + inventory_powertip: This is your inventory of products. To add products to your inventory, select 'New Products' from the Viewing dropdown. + hidden_powertip: These products have been hidden from your inventory and will not be available to add to your shop. You can click 'Add' to add a product to you inventory. + new_powertip: These products are available to be added to your inventory. Click 'Add' to add a product to your inventory, or 'Hide' to hide it from view. You can always change your mind later! + orders: + bulk_management: + tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required." + shared: "Shared Resource?" + order_no: "Order No." + order_date: "Order Date" + max: "Max" + product_unit: "Product: Unit" + weight_volume: "Weight/Volume" + ask: "Ask?" + page_title: "Bulk Order Management" + actions_delete: "Delete Selected" + loading: "Loading orders" + no_results: "No orders found." + group_buy_unit_size: "Group Buy Unit Size" + total_qtt_ordered: "Total Quantity Ordered" + max_qtt_ordered: "Max Quantity Ordered" + current_fulfilled_units: "Current Fulfilled Units" + 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" + order_cycles: + edit: + choose_products_from: "Choose Products From:" + enterprise: + select_outgoing_oc_products_from: Select outgoing OC products from + enterprises: + index: + producer?: Producer? + package: Package + status: Status + manage: Manage + form: + primary_details: + shopfront_requires_login: "Shopfront requires login?" + shopfront_requires_login_tip: "Choose whether customers must login to view the shopfront." + shopfront_requires_login_false: "Public" + shopfront_requires_login_true: "Require customers to login" + home: + hubs: + show_closed_shops: "Show closed shops" + hide_closed_shops: "Hide closed shops" + show_on_map: "Show all on the map" + shared: + register_call: + selling_on_ofn: "Interested in selling through the Open Food Network?" + register: "Register here" + shop: + messages: + login: "login" + register: "register" + contact: "contact" + 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." + invoice_column_item: "Item" + invoice_column_qty: "Qty" + invoice_column_tax: "VAT" + invoice_column_price: "Price" + logo: "Logo (640x130)" + logo_mobile: "Mobile logo (75x26)" + logo_mobile_svg: "Mobile logo (SVG)" + home_hero: "Hero image" + home_show_stats: "Show statistics" + footer_logo: "Logo (220x76)" + footer_facebook_url: "Facebook URL" + footer_twitter_url: "Twitter URL" + footer_instagram_url: "Instagram URL" + footer_linkedin_url: "LinkedIn URL" + footer_googleplus_url: "Google Plus URL" + footer_pinterest_url: "Pinterest URL" + footer_email: "Email" + footer_links_md: "Links" + footer_about_url: "About URL" + footer_tos_url: "Terms of Service URL" + name: Name + first_name: First Name + last_name: Last Name + email: Email + phone: Phone + next: Next + address: Address + address2: Address (contd.) + city: City + state: County + postcode: Postcode + country: Country + unauthorized: Unauthorized + terms_of_service: "Terms of service" + on_demand: To Order + none: None + label_shops: "Shops" + label_map: "Map" + label_producers: "Producers" + label_groups: "Groups" + label_about: "About" + label_shopping: "Shopping" + label_login: "Login" + label_logout: "Logout" + label_signup: "Sign up" + label_administration: "Administration" + label_admin: "Admin" + label_account: "Account" + label_more: "Show more" + label_less: "Show less" + label_notices: "Community Forum" + items: "items" + cart_headline: "Your shopping cart" + total: "Total" + checkout: "Checkout now" + cart_updating: "Updating cart..." + cart_empty: "Cart empty" + cart_edit: "Edit your cart" + card_number: Card Number + card_securitycode: "Security Code" + card_expiry_date: Expiry Date + ofn_cart_headline: "Current cart for:" + ofn_cart_distributor: "Distributor:" + ofn_cart_oc: "Order cycle:" + ofn_cart_from: "From:" + ofn_cart_to: "To:" + ofn_cart_product: "Product:" + ofn_cart_quantitiy: "Quantity:" + ofn_cart_send: "Buy me" + ie_warning_headline: "Your browser is out of date :-(" + ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:" + ie_warning_chrome: Download Chrome + ie_warning_firefox: Download Firefox + ie_warning_ie: Upgrade Internet Explorer + ie_warning_other: "Can't upgrade your browser? Try Open Food Network on your smartphone :-)" + footer_global_headline: "OFN Global" + footer_global_home: "Home" + footer_global_news: "News" + footer_global_about: "About" + footer_global_contact: "Contact" + footer_sites_headline: "OFN Sites" + footer_sites_developer: "Developer" + footer_sites_community: "Community" + footer_sites_userguide: "User Guide" + footer_secure: "Secure and trusted." + footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services." + footer_contact_headline: "Keep in touch" + footer_contact_email: "Email us" + footer_nav_headline: "Navigate" + footer_join_headline: "Join us" + footer_join_producers: "Producers sign-up" + footer_join_hubs: "Hubs sign-up" + footer_join_groups: "Groups sign-up" + footer_join_partners: "Food systems partners" + footer_legal_call: "Read our" + 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}." + home_shop: Shop Now + brandstory_headline: "Food, unincorporated." + brandstory_intro: "Sometimes the best way to fix the system is to start a new one…" + brandstory_part1: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world." + brandstory_part2: "Then we need a way to make it real. A way to empower everyone who grows, sells and buys food. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day." + brandstory_part3: "So we build an online marketplace that levels the playing field. It’s transparent, so it creates real relationships. It’s open source, so it’s owned by everyone. It scales to regions and nations, so people start versions across the world." + brandstory_part4: "It works everywhere. It changes everything." + brandstory_part5_strong: "We call it Open Food Network." + brandstory_part6: "We all love food. Now we can love our food system too." + system_headline: "Here's how it works." + system_step1: "1. Search" + system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup." + system_step2: "2. Shop" + system_step2_text: "Transform your transactions with affordable local food from diverse producers and hubs. Know the stories behind your food and the people who make it!" + system_step3: "3. Pick-up / Delivery" + system_step3_text: "Hang on for your delivery, or visit your producer or hub for a more personal connection with your food. Food shopping as diverse as nature intended it." + cta_headline: "Shopping that makes the world a better place." + cta_label: "I'm Ready" + stats_headline: "We're creating a new food system." + stats_producers: "food producers" + stats_shops: "food shops" + stats_shoppers: "food shoppers" + stats_orders: "food orders" + checkout_title: Checkout + checkout_now: Checkout now + checkout_order_ready: Order ready for + checkout_hide: Hide + checkout_expand: Expand + checkout_headline: "Ok, ready to checkout?" + checkout_as_guest: "Checkout as guest" + checkout_details: "Your details" + checkout_billing: "Billing info" + checkout_shipping: Shipping info + checkout_method_free: Free + checkout_address_same: Shipping address same as billing address? + checkout_ready_for: "Ready for:" + checkout_instructions: "Any comments or special instructions?" + checkout_payment: Payment + checkout_send: Place order now + checkout_your_order: Your order + checkout_cart_total: Cart total + checkout_shipping_price: Shipping + checkout_total_price: Total + checkout_back_to_cart: "Back to cart" + order_paid: PAID + order_not_paid: NOT PAID + order_total: Total order + order_payment: "Paying via:" + order_billing_address: Billing address + order_delivery_on: Delivery on + order_delivery_address: Delivery address + order_special_instructions: "Your notes:" + order_pickup_time: Ready for collection + order_pickup_instructions: Collection instructions + order_produce: Produce + order_total_price: Total + order_includes_tax: (includes tax) + order_payment_paypal_successful: Your payment via PayPal has been processed successfully. + order_hub_info: Hub info + unsaved_changes_warning: "Unsaved changes exist and will be lost if you continue." + unsaved_changes_error: "Fields with red borders contain errors." + products: "Products" + products_in: "in %{oc}" + products_at: "at %{distributor}" + products_elsewhere: "Products found elsewhere" + email_welcome: "Welcome" + email_confirmed: "Thank you for confirming your email address." + email_registered: "is now part of" + email_userguide_html: "The User Guide with detailed support for setting up your Producer or Hub is here: %{link}" + 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}" + email_help: "If you have any difficulties, check out our FAQs, browse the forum or post a 'Support' topic and someone will help you out!" + 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." + 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_userguide: "User Guide" + email_social: "Connect with Us:" + email_contact: "Email us:" + email_signoff: "Cheers," + email_signature: "%{sitename} Team" + email_confirm_customer_greeting: "Hi %{name}," + email_confirm_customer_intro_html: "Thanks for shopping at %{distributor}!" + email_confirm_customer_number_html: "Order confirmation #%{number}" + email_confirm_customer_details_html: "Here are your order details from %{distributor}:" + email_confirm_customer_signoff: "Kind regards," + email_confirm_shop_greeting: "Hi %{name}," + email_confirm_shop_order_html: "Well done! You have a new order for %{distributor}!" + email_confirm_shop_number_html: "Order confirmation #%{number}" + email_order_summary_item: "Item" + email_order_summary_quantity: "Qty" + email_order_summary_price: "Price" + email_order_summary_subtotal: "Subtotal:" + email_order_summary_total: "Total:" + email_payment_paid: PAID + email_payment_not_paid: NOT PAID + email_payment_summary: Payment summary + email_payment_method: "Paying via:" + email_shipping_delivery_details: Delivery details + email_shipping_delivery_time: "Delivery on:" + email_shipping_delivery_address: "Delivery address:" + email_shipping_collection_details: Collection details + email_shipping_collection_time: "Ready for collection:" + email_shipping_collection_instructions: "Collection instructions:" + email_special_instructions: "Your notes:" + email_signup_greeting: Hello! + email_signup_welcome: "Welcome to %{sitename}!" + email_signup_login: Your login + email_signup_email: Your login email is + email_signup_shop_html: "You can start shopping online now 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" + 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:" + producer_mail_delivery_instructions: "Stock pickup/delivery instructions:" + producer_mail_signoff: "Thanks and best wishes" + shopping_oc_closed: Orders are closed + shopping_oc_closed_description: "Please wait until the next cycle opens (or contact us directly to see if we can accept any late orders)" + shopping_oc_last_closed: "The last cycle closed %{distance_of_time} ago" + shopping_oc_next_open: "The next cycle opens in %{distance_of_time}" + shopping_tabs_about: "About %{distributor}" + shopping_tabs_contact: "Contact" + shopping_contact_address: "Address" + shopping_contact_web: "Contact" + shopping_contact_social: "Follow" + shopping_groups_part_of: "is part of:" + shopping_producers_of_hub: "%{hub}'s producers:" + enterprises_next_closing: "Next order closing" + enterprises_ready_for: "Ready for" + enterprises_choose: "Choose when you want your order:" + hubs_buy: "Shop for:" + hubs_shopping_here: "Shopping here" + hubs_orders_closed: "Orders closed" + hubs_profile_only: "Profile only" + hubs_delivery_options: "Delivery options" + hubs_pickup: "Pickup" + hubs_delivery: "Delivery" + hubs_producers: "Our producers" + hubs_filter_by: "Filter by" + hubs_filter_type: "Type" + hubs_filter_delivery: "Delivery" + hubs_matches: "Did you mean?" + hubs_intro: Shop in your local area + hubs_distance: Closest to + hubs_distance_filter: "Show me shops near %{location}" + products_clear_all: Clear all + products_showing: "Showing:" + products_with: with + products_search: "Search by product or producer" + products_loading: "Loading products..." + products_updating_cart: "Updating cart..." + products_cart_empty: "Cart empty" + products_edit_cart: "Edit your cart" + products_from: from + products_change: "No changes to save." + products_update_error: "Saving failed with the following error(s):" + products_update_error_msg: "Saving failed." + products_update_error_data: "Save failed due to invalid data:" + products_changes_saved: "Changes saved." + search_no_results_html: "Sorry, no results found for %{query}. Try another search?" + components_profiles_popover: "Profiles do not have a shopfront on the Open Food Network, but may have their own physical or online shop elsewhere" + components_profiles_show: "Show profiles" + components_filters_nofilters: "No filters" + components_filters_clearfilters: "Clear all filters" + groups_title: Groups + groups_headline: Groups / regions + groups_text: "Every producer is unique. Every business has something different to offer. Our groups are collectives of producers, hubs and distributors who share something in common like location, farmers market or philosophy. This makes your shopping experience easier. So explore our groups and have the curating done for you." + groups_search: "Search name or keyword" + groups_no_groups: "No groups found" + groups_about: "About Us" + groups_producers: "Our producers" + groups_hubs: "Our hubs" + groups_contact_web: Contact + groups_contact_social: Follow + groups_contact_address: Address + groups_contact_email: Email us + groups_contact_website: Visit our website + groups_contact_facebook: Follow us on Facebook + groups_signup_title: Sign up as a group + groups_signup_headline: Groups sign up + groups_signup_intro: "We're an amazing platform for collaborative marketing, the easiest way for your members and stakeholders to reach new markets. We're non-profit, affordable, and simple." + groups_signup_email: Email us + groups_signup_motivation1: We transform food systems fairly. + groups_signup_motivation2: It's why we get out of bed every day. We're a global non-profit, based on open source code. We play fair. You can always trust us. + groups_signup_motivation3: We know you have big ideas, and we want to help. We'll share our knowledge, networks and resources. We know that isolation doesn't create change, so we'll partner with you. + groups_signup_motivation4: We meet you where you are. + groups_signup_motivation5: You might be an alliance of food hubs, producers, or distributors, and an industry body, or a local government. + groups_signup_motivation6: Whatever your role in your local food movement, we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation. + groups_signup_motivation7: We make food movements make more sense. + groups_signup_motivation8: You need to activate and enable your networks, we offer a platform for conversation and action. You need real engagement. We’ll help reach all the players, all the stakeholders, all the sectors. + groups_signup_motivation9: You need resourcing. We’ll bring all our experience to bear. You need cooperation. We’ll better connect you to a global network of peers. + groups_signup_pricing: Group Account + groups_signup_studies: Case Studies + groups_signup_contact: Ready to discuss? + groups_signup_contact_text: "Get in touch to discover what OFN can do for you:" + groups_signup_detail: "Here's the detail." + login_invalid: "Invalid email or password" + modal_hubs: "Food Hubs" + modal_hubs_abstract: Our food hubs are the point of contact between you and the people who make your food! + modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each food hub is a sales point with independent business operations and logistics - so variations between hubs are to be expected. + modal_hubs_content2: You can only shop at one food hub at a time. + modal_groups: "Groups / Regions" + modal_groups_content1: These are the organisations and relationships between hubs which make up the Open Food Network. + modal_groups_content2: Some groups are clustered by location or council, others by non-geographic similarities. + modal_how: "How it works" + modal_how_shop: Shop the Open Food Network + modal_how_shop_explained: Search for a food hub near you to start shopping! You can expand each food hub to see what kinds of goodies are available, and click through to start shopping. (You can only shop one food hub at a time.) + modal_how_pickup: Pick-ups, delivery and shipping costs + modal_how_pickup_explained: Some food hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each food hub is a sales point with independent business operations and logisitics - so variations between hubs are to be expected. + modal_how_more: Learn more + modal_how_more_explained: "If you want to learn more about the Open Food Network, how it works, and get involved, check out:" + modal_producers: "Producers" + modal_producers_explained: "Our producers make all the delicious food you can shop for on the Open Food Network." + ocs_choice_hub: "Hub:" + ocs_choice_oc: "Order Cycle:" + ocs_choice_text: "You have not yet picked where you will get your order from." + ocs_closed_headline: Orders are currently closed for this hub + ocs_closed_time: "The last cycle closed %{time} ago." + ocs_closed_contact: "Please contact your hub directly to see if they accept late orders, or wait until the next cycle opens." + ocs_closed_opens: "The next order cycle opens in %{time}" + ocs_closed_email: "Email: %{email}" + ocs_closed_phone: "Phone: %{phone}" + ocs_pickup_time: "Your order will be ready on %{pickup_time}" + ocs_change_date: "Change Collection Date" + ocs_change_date_notice: "(This will reset your cart)" + ocs_close_time: "ORDERS CLOSE" + ocs_when_headline: When do you want your order? + ocs_when_text: No products are displayed until you select a date. + ocs_when_closing: "Closing on" + ocs_when_choose: "Choose Order Cycle" + ocs_list: "List view" + producers_about: About us + producers_buy: Shop for + producers_contact: Contact + producers_contact_phone: Call + producers_contact_social: Follow + producers_buy_at_html: "Shop for %{enterprise} products at:" + producers_filter: Filter by + producers_filter_type: Type + producers_title: Producers + producers_headline: Find local producers + producers_signup_title: Sign up as a producer + producers_signup_headline: Food producers, empowered. + producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field. + producers_signup_send: Join now + producers_signup_enterprise: Enterprise Accounts + producers_signup_studies: Stories from our producers. + producers_signup_cta_headline: Join now! + producers_signup_cta_action: Join now + producers_signup_detail: Here's the detail. + products_item: Item + products_description: Description + products_variant: Variant + products_quantity: Quantity + products_available: Available? + products_producer: "Producer" + products_price: "Price" + register_title: Register + shops_title: Shops + shops_headline: Shopping, transformed. + shops_text: Food grows in cycles, farmers harvest in cycles, and we order food in cycles. If you find an order cycle closed, check back soon. + shops_signup_title: Sign up as a hub + shops_signup_headline: Food hubs, unlimited. + shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of. + shops_signup_action: Join now + shops_signup_pricing: Enterprise Accounts + shops_signup_stories: Stories from our hubs. + 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_fees: Fees... + orders_edit_title: Shopping cart + orders_edit_headline: Your shopping cart + orders_edit_time: Order ready for + orders_edit_continue: Continue shopping + orders_edit_checkout: Checkout + orders_form_empty_cart: "Empty cart" + orders_form_subtotal: Produce subtotal + orders_form_admin: Admin and handling + orders_form_total: Total + orders_oc_expired_headline: Orders have closed for this order cycle + orders_oc_expired_text: "Sorry, orders for this order cycle closed %{time} ago! Please contact your hub directly to see if they can accept late orders." + orders_oc_expired_text_others_html: "Sorry, orders for this order cycle closed %{time} ago! Please contact your hub directly to see if they can accept late orders %{link}." + orders_oc_expired_text_link: "or see the other order cycles available at this hub" + orders_oc_expired_email: "Email:" + orders_oc_expired_phone: "Phone:" + orders_show_title: Order Confirmation + orders_show_time: Order ready on + orders_show_number: Order confirmation + products_cart_distributor_choice: "Distributor for your order:" + products_cart_distributor_change: "Your distributor for this order will be changed to %{name} if you add this product to your cart." + products_cart_distributor_is: "Your distributor for this order is %{name}." + products_distributor_error: "Please complete your order at %{link} before shopping with another distributor." + products_oc: "Order cycle for your order:" + products_oc_change: "Your order cycle for this order will be changed to %{name} if you add this product to your cart." + products_oc_is: "Your order cycle for this order is %{name}." + products_oc_error: "Please complete your order from %{link} before shopping in a different order cycle." + products_oc_current: "your current order cycle" + products_max_quantity: Max quantity + products_distributor: Distributor + products_distributor_info: When you select a distributor for your order, their address and pickup times will be displayed here. + shop_trial_length: "Shop Trial Length (Days)" + shop_trial_expires_in: "Your shopfront trial expires in" + shop_trial_expired_notice: "OFN UK is a non-profit social enterprise making software affordable through open source collaboration. Thanks for being part of it!" + password: Password + remember_me: Remember Me + are_you_sure: "Are you sure?" + orders_open: Orders open + closing: "Closing " + going_back_to_home_page: "Taking you back to the home page" + creating: Creating + updating: Updating + failed_to_create_enterprise: "Failed to create your enterprise." + failed_to_create_enterprise_unknown: "Failed to create your enterprise.\nPlease ensure all fields are completely filled out." + failed_to_update_enterprise_unknown: "Failed to update your enterprise.\nPlease ensure all fields are completely filled out." + order_not_saved_yet: "Your order hasn't been saved yet. Give us a few seconds to finish!" + filter_by: "Filter by" + hide_filters: "Hide filters" + one_filter_applied: "1 filter applied" + x_filters_applied: " filters applied" + submitting_order: "Submitting your order: please wait" + confirm_hub_change: "Are you sure? This will change your selected hub and remove any items in your shopping cart." + confirm_oc_change: "Are you sure? This will change your selected order cycle and remove any items in your shopping cart." + location_placeholder: "Type in a location..." + error_required: "can't be blank" + error_number: "must be number" + error_email: "must be email address" + item_handling_fees: "Item Handling Fees (included in item totals)" + january: "January" + february: "February" + march: "March" + april: "April" + may: "May" + june: "June" + july: "July" + august: "August" + september: "September" + october: "October" + november: "November" + december: "December" + email_not_found: "Email address not found" + email_required: "You must provide an email address" + logging_in: "Hold on a moment, we're logging you in" + signup_email: "Your email" + choose_password: "Choose a password" + confirm_password: "Confirm password" + action_signup: "Sign up now" + welcome_to_ofn: "Welcome to the Open Food Network!" + signup_or_login: "Start By signing up (or logging in)" + have_an_account: "Already have an account?" + action_login: "Log in now." + forgot_password: "Forgot password?" + 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}?" + enterprise_contact: "Primary contact" + enterprise_contact_required: "You need to enter a primary contact." + enterprise_email_address: "Email address" + enterprise_phone: "Phone number" + back: "Back" + continue: "Continue" + limit_reached_headline: "Oh no!" + limit_reached_message: "You have reached the limit!" + limit_reached_text: "You have reached the limit for the number of enterprises you are allowed to own on the" + limit_reached_action: "Return to the homepage" + select_promo_image: "Step 3. Select promo image" + promo_image_tip: "Tip: Shown as a banner, preferred size is 1200×260px" + promo_image_label: "Choose a promo image" + action_or: "OR" + promo_image_drag: "Drag and drop your promo here" + review_promo_image: "Step 4. Review your promo banner" + review_promo_image_tip: "Tip: for best results, your promo image should fill the available space" + promo_image_placeholder: "Your logo will appear here for review once uploaded" + uploading: "Uploading..." + select_logo: "Step 1. Select logo image" + logo_tip: "Tip: Square images will work best, preferably at least 300×300px" + logo_label: "Choose a logo image" + logo_drag: "Drag and drop your logo here" + review_logo: "Step 2. Review your logo" + review_logo_tip: "Tip: for best results, your logo should fill the available space" + logo_placeholder: "Your logo will appear here for review once uploaded" + 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 need to click the confirmation link in the email you have received. This will take you to your admin interface where you can continue setting up your profile." + enterprise_description: "Short Description" + enterprise_description_placeholder: "A short sentence describing your enterprise" + enterprise_long_desc: "Long Description" + enterprise_long_desc_placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words." + enterprise_long_desc_length: "%{num} characters / up to 600 recommended" + enterprise_abn: "ABN" + enterprise_abn_placeholder: "eg. 99 123 456 789" + enterprise_acn: "ACN" + enterprise_acn_placeholder: "eg. 123 456 789" + enterprise_tax_required: "You need to make a selection." + enterprise_final_step: "Final step!" + enterprise_social_text: "How can people find %{enterprise} online?" + website: "Website" + website_placeholder: "eg. openfoodnetwork.org.au" + facebook: "Facebook" + facebook_placeholder: "eg. www.facebook.com/PageNameHere" + linkedin: "LinkedIn" + linkedin_placeholder: "eg. www.linkedin.com/YourNameHere" + twitter: "Twitter" + twitter_placeholder: "eg. @twitter_handle" + instagram: "Instagram" + instagram_placeholder: "eg. @instagram_handle" + registration_greeting: "Hi there!" + registration_intro: "You can now create a profile for your Producer or Hub" + registration_action: "Let's get started!" + registration_checklist: "You'll need" + registration_time: "5-10 minutes" + registration_enterprise_address: "Enterprise address" + registration_contact_details: "Primary contact details" + registration_logo: "Your logo image" + registration_promo_image: "Landscape image for your profile" + registration_about_us: "'About Us' text" + registration_outcome_headline: "What do I get?" + registration_outcome1_html: "Your profile helps people find and contact you on the Open Food Network." + registration_outcome2: "Use this space to tell the story of your enterprise, to help drive connections to your social and online presence. " + registration_outcome3: "It's also the first step towards trading on the Open Food Network, or opening an online store." + registration_finished_headline: "Finished!" + registration_finished_thanks: "Thanks for filling out the details for %{enterprise}." + registration_finished_login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin." + registration_finished_activate: "Activate %{enterprise}." + registration_finished_activate_instruction_html: "We've sent a confirmation email to %{email} if it hasn't been activated before.
    Please follow the instructions there to make your enterprise visible on the Open Food Network." + registration_finished_action: "Open Food Network home" + registration_type_headline: "Last step to add %{enterprise}!" + registration_type_question: "Are you a producer?" + registration_type_producer: "Yes, I'm a producer" + registration_type_no_producer: "No, I'm not a producer" + registration_type_error: "Please choose one. Are you are producer?" + 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." + create_profile: "Create profile" + registration_images_headline: "Thanks!" + registration_images_description: "Let's upload some pretty pictures so your profile looks great! :)" + registration_detail_headline: "Let's get started" + registration_detail_enterprise: "Woot! First we need to know a little bit about your enterprise:" + registration_detail_producer: "Woot! First we need to know a little bit about your farm:" + registration_detail_name_enterprise: "Enterprise name:" + registration_detail_name_producer: "Farm name:" + registration_detail_name_placeholder: "e.g. Charlie's Awesome Farm" + registration_detail_name_error: "Please choose a unique name for your enterprise" + registration_detail_address1: "Address line 1:" + registration_detail_address1_placeholder: "e.g. 123 Cranberry Drive" + registration_detail_address1_error: "Please enter an address" + registration_detail_address2: "Address line 2:" + registration_detail_suburb: "Suburb:" + registration_detail_suburb_placeholder: "e.g. Northcote" + registration_detail_suburb_error: "Please enter a suburb" + registration_detail_postcode: "Postcode:" + registration_detail_postcode_placeholder: "e.g. 3070" + registration_detail_postcode_error: "Postcode required" + registration_detail_state: "State:" + registration_detail_state_error: "State required" + registration_detail_country: "Country:" + registration_detail_country_error: "Please select a country" + fees: "Fees" + item_cost: "Item cost" + bulk: "Bulk" + shop_variant_quantity_min: "min" + shop_variant_quantity_max: "max" + follow: "Follow" + shop_for_products_html: "Shop for %{enterprise} products at:" + change_shop: "Change shop to:" + shop_at: "Shop now at:" + price_breakdown: "Full price breakdown" + admin_fee: "Admin fee" + sales_fee: "Sales fee" + packing_fee: "Packing fee" + transport_fee: "Transport fee" + fundraising_fee: "Fundraising fee" + price_graph: "Price graph" + included_tax: "Included tax" + balance: "Balance" + transaction: "Transaction" + transaction_date: "Date" + payment_state: "Payment status" + shipping_state: "Shipping status" + value: "Value" + balance_due: "Balance due" + credit: "Credit" + Paid: "Paid" + Ready: "Ready" + 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_everything: "Everything" + admin_entreprise_relationships_permits: "permits" + admin_entreprise_relationships_seach_placeholder: "Search" + admin_entreprise_relationships_button_create: "Create" + admin_entreprise_groups: "Enterprise Groups" + admin_entreprise_groups_name: "Name" + admin_entreprise_groups_owner: "Owner" + admin_entreprise_groups_on_front_page: "On front page?" + admin_entreprise_groups_entreprise: "Enterprises" + admin_entreprise_groups_data_powertip: "The primary user responsible for this group." + admin_entreprise_groups_data_powertip_logo: "This is the logo for the group" + admin_entreprise_groups_data_powertip_promo_image: "This image is displayed at the top of the Group profile" + admin_entreprise_groups_contact: "Contact" + admin_entreprise_groups_contact_phone_placeholder: "eg. 98 7654 3210" + admin_entreprise_groups_contact_address1_placeholder: "eg. 123 High Street" + admin_entreprise_groups_contact_city: "Suburb" + admin_entreprise_groups_contact_city_placeholder: "eg. Camden" + admin_entreprise_groups_contact_zipcode: "Postcode" + admin_entreprise_groups_contact_zipcode_placeholder: "eg. NW1 0AA" + admin_entreprise_groups_contact_state_id: "County" + admin_entreprise_groups_contact_country_id: "Country" + admin_entreprise_groups_web: "Web Resources" + admin_entreprise_groups_web_twitter: "eg. @openfoodnetuk" + admin_entreprise_groups_web_website_placeholder: "eg. www.truffles.co.uk" + admin_order_cycles: "Admin Order Cycles" + open: "Open" + close: "Close" + supplier: "Supplier" + coordinator: "Coordinator" + distributor: "Distributor" + fee_type: "Fee Type" + tax_category: "Tax Category" + calculator: "Calculator" + calculator_values: "Calculator values" + new_order_cycles: "New Order Cycles" + select_a_coordinator_for_your_order_cycle: "Select a coordinator for your order cycle" + edit_order_cycle: "Edit Order Cycle" + roles: "Roles" + update: "Update" + add_producer_property: "Add producer property" + admin_settings: "Settings" + update_invoice: "Update Invoices" + finalise_invoice: "Finalise Invoices" + finalise_user_invoices: "Finalise User Invoices" + finalise_user_invoice_explained: "Use this button to finalise all invoices in the system for the previous calendar month. This task can be set up to run automatically once a month." + manually_run_task: "Manually Run Task" + update_user_invoices: "Update User Invoices" + update_user_invoice_explained: "Use this button to immediately update invoices for the month to date for each enterprise user in the system. This task can be set up to run automatically every night." + auto_finalise_invoices: "Auto-finalise invoices monthly on the 2nd at 1:30am" + auto_update_invoices: "Auto-update invoices nightly at 1:00am" + in_progress: "In Progress" + started_at: "Started at" + queued: "Queued" + scheduled_for: "Scheduled for" + customers: "Customers" + please_select_hub: "Please select a Hub" + loading_customers: "Loading Customers" + no_customers_found: "No customers found" + go: "Go" + hub: "Hub" + accounts_administration_distributor: "accounts administration distributor" + accounts_and_billing: "Accounts & Billing" + producer: "Producer" + product: "Product" + price: "Price" + on_hand: "In stock" + save_changes: "Save Changes" + spree_admin_overview_enterprises_header: "My Enterprises" + spree_admin_overview_enterprises_footer: "MANAGE MY ENTERPRISES" + spree_admin_enterprises_hubs_name: "Name" + spree_admin_enterprises_create_new: "CREATE NEW" + spree_admin_enterprises_shipping_methods: "Shipping Methods" + 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_order_cycles: "MANAGE ORDER CYCLES" + spree_admin_enterprises_producers_manage_products: "MANAGE PRODUCTS" + spree_admin_enterprises_producers_orders_cycle_text: "You don't have any active order cycles." + spree_admin_enterprises_any_active_products_text: "You don't have any active products." + spree_admin_enterprises_create_new_product: "CREATE A NEW PRODUCT" + spree_admin_order_cycles: "Order Cycles" + spree_admin_order_cycles_tip: "Order cycles determine when and where your products are available to customers." + dashbord: "Dashboard" + spree_admin_single_enterprise_alert_mail_confirmation: "Please confirm the email address for" + spree_admin_single_enterprise_alert_mail_sent: "We've sent an email to" + spree_admin_overview_action_required: "Action Required" + spree_admin_overview_check_your_inbox: "Please check you inbox for further instructions. Thanks!" + change_package: "Change Package" + spree_admin_single_enterprise_hint: "Hint: To allow people to find you, turn on your visibility under" + your_profil_live: "Your profile live" + on_ofn_map: "on the Open Food Network map" + see: "See" + live: "live" + manage: "Manage" + resend: "Resend" + add_and_manage_products: "Add & manage products" + add_and_manage_order_cycles: "Add & manage order cycles" + manage_order_cycles: "Manage order cycles" + manage_products: "Manage products" + edit_profile_details: "Edit profile details" + edit_profile_details_etc: "Change your profile description, images, etc." + order_cycle: "Order Cycle" + remove_tax: "Remove tax" + tax_settings: "Tax Settings" + products_require_tax_category: "products require tax category" + admin_shared_address_1: "Address" + admin_shared_address_2: "Address (cont.)" + admin_share_city: "City" + admin_share_zipcode: "Postcode" + admin_share_country: "Country" + admin_share_state: "County" + hub_sidebar_hubs: "Hubs" + hub_sidebar_none_available: "None Available" + hub_sidebar_manage: "Manage" + hub_sidebar_at_least: "At least one hub must be selected" + hub_sidebar_blue: "blue" + hub_sidebar_red: "red" + shop_trial_in_progress: "Your shopfront trial expires in %{days}." + shop_trial_expired: "To view or change your current Open Food Network plan go to the Dashboard -> Change Package." + report_customers_distributor: "Distributor" + report_customers_supplier: "Supplier" + report_customers_cycle: "Order Cycle" + report_customers_type: "Report Type" + report_customers_csv: "Download as csv" + report_producers: "Producers:" + report_type: "Report Type:" + report_hubs: "Hubs:" + report_payment: "Payment Methods:" + report_distributor: "Distributor:" + report_payment_by: 'Payments By Type' + report_itemised_payment: 'Itemised Payment Totals' + report_payment_totals: 'Payment Totals' + report_all: 'all' + report_order_cycle: "Order Cycle:" + report_entreprises: "Enterprises:" + report_users: "Users:" + initial_invoice_number: "Initial invoice number:" + invoice_date: "Invoice date:" + due_date: "Invoice date:" + account_code: "Account code:" + equals: "Equals" + contains: "contains" + discount: "Discount" + filter_products: " Filter Products" + delete_product_variant: "The last variant cannot be deleted!" + progress: "progress" + saving: "Saving.." + success: "success" + failure: "failure" + unsaved_changes_confirmation: "Unsaved changes will be lost. Continue anyway?" + one_product_unsaved: "Changes to one product remain unsaved." + products_unsaved: "Changes to %{n} products remain unsaved." + is_already_manager: "is already a manager!" + no_change_to_save: "No change to save" + add_manager: "Add a manager" + users: "Users" + about: "About" + images: "Images" + web: "Web" + primary_details: "Primary Details" + adrdress: "Address" + contact: "Contact" + social: "Social" + business_details: "Business Details" + properties: "Properties" + shipping_methods: "Shipping Methods" + payment_methods: "Payment Methods" + payment_method_fee: "Transaction fee" + enterprise_fees: "Enterprise Fees" + inventory_settings: "Inventory Settings" + tag_rules: "Tag Rules" + shop_preferences: "Shop Preferences" + validation_msg_relationship_already_established: "^That relationship is already established." + validation_msg_at_least_one_hub: "^At least one hub must be selected" + validation_msg_product_category_cant_be_blank: "^Product Category cant be blank" + validation_msg_tax_category_cant_be_blank: "^Tax Category can't be blank" + validation_msg_is_associated_with_an_exising_customer: "is associated with an existing customer" + spree: + shipment_states: + backorder: backorder + partial: partial + pending: pending + ready: ready + shipped: shipped + payment_states: + balance_due: balance due + completed: completed + checkout: checkout + credit_owed: credit owed + failed: failed + paid: paid + pending: pending + processing: processing + void: void + invalid: invalid + order_state: + address: address + adjustments: adjustments + awaiting_return: awaiting return + canceled: canceled + cart: cart + complete: complete + confirm: confirm + delivery: delivery + payment: payment + resumed: resumed + returned: returned + skrill: skrill From 1388c077ea3918f18fdaec528680d6421054c960 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 12:08:51 +1000 Subject: [PATCH 52/77] Remove unused feature toggles --- lib/open_food_network/feature_toggle.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index 024a17e068..10d49a3d1a 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -7,10 +7,7 @@ module OpenFoodNetwork private def self.features - {eaterprises: true, - local_organics: false, - order_cycles: true, - enterprises_distributor_info_rich_text: true} + {order_cycles: true} end end end From e966b474b4ab34810a5e20c288a9e701c02f653e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 12:11:52 +1000 Subject: [PATCH 53/77] Remove order cycles feature toggle --- app/helpers/order_cycles_helper.rb | 4 ---- app/models/spree/order_decorator.rb | 6 +----- app/views/spree/products/_add_to_cart.html.haml | 2 +- lib/open_food_network/feature_toggle.rb | 2 +- spec/models/spree/order_spec.rb | 2 +- 5 files changed, 4 insertions(+), 12 deletions(-) diff --git a/app/helpers/order_cycles_helper.rb b/app/helpers/order_cycles_helper.rb index 18222ee1f0..031fdf4736 100644 --- a/app/helpers/order_cycles_helper.rb +++ b/app/helpers/order_cycles_helper.rb @@ -67,10 +67,6 @@ module OrderCyclesHelper @order_cycles_simple_form ||= @order_cycle.coordinator.sells == 'own' end - def order_cycles_enabled? - OpenFoodNetwork::FeatureToggle.enabled? :order_cycles - end - def pickup_time(order_cycle = current_order_cycle) order_cycle.exchanges.to_enterprises(current_distributor).outgoing.first.pickup_time end diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index a4995274b3..fccbc639b2 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -74,11 +74,7 @@ Spree::Order.class_eval do # -- Methods def products_available_from_new_distribution # Check that the line_items in the current order are available from a newly selected distribution - if OpenFoodNetwork::FeatureToggle.enabled? :order_cycles - errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle) - else - errors.add(:distributor_id, "cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distributor?(distributor) - end + errors.add(:base, "Distributor or order cycle cannot supply the products in your cart") unless DistributionChangeValidator.new(self).can_change_to_distribution?(distributor, order_cycle) end def empty_with_clear_shipping_and_payments! diff --git a/app/views/spree/products/_add_to_cart.html.haml b/app/views/spree/products/_add_to_cart.html.haml index 621b999ddc..dd406ff50b 100644 --- a/app/views/spree/products/_add_to_cart.html.haml +++ b/app/views/spree/products/_add_to_cart.html.haml @@ -7,7 +7,7 @@ - elsif !distributor_available_for?(order, @product) = render 'add_to_cart_distributor_unavailable' - - elsif !order_cycle_available_for?(order, @product) and order_cycles_enabled? + - elsif !order_cycle_available_for?(order, @product) = render 'add_to_cart_order_cycle_unavailable' - else diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index 10d49a3d1a..0721e01c44 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -7,7 +7,7 @@ module OpenFoodNetwork private def self.features - {order_cycles: true} + {} end end end diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index 114c7d5fac..2140163f98 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -437,7 +437,7 @@ describe Spree::Order do subject.distributor = test_enterprise subject.should_not be_valid - subject.errors.messages.should == {:distributor_id => ["cannot supply the products in your cart"]} + subject.errors.messages.should == {:base => ["Distributor or order cycle cannot supply the products in your cart"]} end end From 23827d6c5799c07d7cb1422c20d91b19954e2bc6 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 12:14:52 +1000 Subject: [PATCH 54/77] Add feature toggle for Connect+Learn homepage --- lib/open_food_network/feature_toggle.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index 0721e01c44..7e0866933a 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -7,7 +7,7 @@ module OpenFoodNetwork private def self.features - {} + {connect_learn_homepage: false} end end end From 87e063593a550ae63f41ef1bd01e5ffa77434590 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 12:50:26 +1000 Subject: [PATCH 55/77] Add feature toggle helper, allow hash or string queries --- app/helpers/application_helper.rb | 3 +++ lib/open_food_network/feature_toggle.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index f17a6dbbc9..af68240432 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,9 @@ module ApplicationHelper include FoundationRailsHelper::FlashHelper + def feature?(feature) + OpenFoodNetwork::FeatureToggle.enabled? feature + end def ng_form_for(name, *args, &block) options = args.extract_options! diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index 7e0866933a..be1a9b0065 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -1,7 +1,7 @@ module OpenFoodNetwork class FeatureToggle def self.enabled? feature - features[feature] + features.with_indifferent_access[feature] end private From 5b43d7a87a04e431eeb4df0b2402189e0f40af30 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 12:52:05 +1000 Subject: [PATCH 56/77] Add connect and learn links to page alert --- .../stylesheets/darkswarm/page_alert.css.sass | 4 +-- app/views/shared/_register_call.html.haml | 29 ++++++++++++++----- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/page_alert.css.sass b/app/assets/stylesheets/darkswarm/page_alert.css.sass index b7d6ea643e..7e66d35518 100644 --- a/app/assets/stylesheets/darkswarm/page_alert.css.sass +++ b/app/assets/stylesheets/darkswarm/page_alert.css.sass @@ -21,13 +21,13 @@ font-size: 10px line-height: 24px - a.alert-cta + .alert-cta &, & * @include csstrans color: #333 strong letter-spacing: 0.5px - &:hover, &:active, &:focus + a:hover, a:active, a:focus &, & * text-decoration: none color: white diff --git a/app/views/shared/_register_call.html.haml b/app/views/shared/_register_call.html.haml index 8c2d95ed2e..c5bf5b7830 100644 --- a/app/views/shared/_register_call.html.haml +++ b/app/views/shared/_register_call.html.haml @@ -1,7 +1,22 @@ -%a.alert-cta{href: registration_path, target: "_blank"} - %h6 - = t '.selling_on_ofn' -   - %strong - = t '.register' - %i.ofn-i_054-point-right +- if feature? :connect_learn_homepage + :css + .page-alert .alert-box { background-color: #f27052; } + + .alert-cta + %h6 + %strong + = link_to "Connect", "https://openfoodnetwork.org/au/connect/", target: '_blank' + and + %strong + = link_to "Learn", "https://openfoodnetwork.org/au/learn/", target: '_blank' + + +- else + .alert-cta + %h6 + %a{href: registration_path, target: "_blank"} + = t '.selling_on_ofn' +   + %strong + = t '.register' + %i.ofn-i_054-point-right From 1216da38d1fe36839d878aef672bcd501453741a Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 14:38:29 +1000 Subject: [PATCH 57/77] Update menu: [Groups, About] -> [Connect, Learn] --- app/views/shared/menu/_large_menu.html.haml | 27 ++++++++++++++------ app/views/shared/menu/_mobile_menu.html.haml | 8 +++--- config/locales/en.yml | 2 ++ 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/app/views/shared/menu/_large_menu.html.haml b/app/views/shared/menu/_large_menu.html.haml index 05209dff75..6a5be15a67 100644 --- a/app/views/shared/menu/_large_menu.html.haml +++ b/app/views/shared/menu/_large_menu.html.haml @@ -17,14 +17,25 @@ %a{href: main_app.producers_path} %span.nav-primary = t 'label_producers' - %li - %a{href: main_app.groups_path} - %span.nav-primary - = t 'label_groups' - %li - %a{href: ContentConfig.footer_about_url} - %span.nav-primary - = t 'label_about' + - if feature? :connect_learn_homepage + %li + %a{href: "https://openfoodnetwork.org/au/connect/"} + %span.nav-primary + = t 'label_connect' + %li + %a{href: "https://openfoodnetwork.org/au/learn/"} + %span.nav-primary + = t 'label_learn' + - else + %li + %a{href: main_app.groups_path} + %span.nav-primary + = t 'label_groups' + %li + %a{href: ContentConfig.footer_about_url} + %span.nav-primary + = t 'label_about' + %ul.right - if spree_current_user.nil? = render 'shared/signed_out' diff --git a/app/views/shared/menu/_mobile_menu.html.haml b/app/views/shared/menu/_mobile_menu.html.haml index 71fd8ea86f..1ae4439cd9 100644 --- a/app/views/shared/menu/_mobile_menu.html.haml +++ b/app/views/shared/menu/_mobile_menu.html.haml @@ -41,15 +41,15 @@ %i.ofn-i_036-producers = t 'label_producers' %li.li-menu - %a{href: main_app.groups_path} + %a{href: "https://openfoodnetwork.org/au/connect/"} %span.nav-primary %i.ofn-i_035-groups - = t 'label_groups' + = t 'label_connect' %li.li-menu - %a{href: ContentConfig.footer_about_url} + %a{href: "https://openfoodnetwork.org/au/learn/"} %span.nav-primary %i.ofn-i_013-help - = t 'label_about' + = t 'label_learn' %li - if spree_current_user.nil? diff --git a/config/locales/en.yml b/config/locales/en.yml index 2d2e4bc3df..e56cd90622 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -255,6 +255,8 @@ en: label_producers: "Producers" label_groups: "Groups" label_about: "About" + label_connect: "Connect" + label_learn: "Learn" label_shopping: "Shopping" label_login: "Login" label_logout: "Logout" From 140589fc2da4f66170e30de18b6b610524776980 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 29 Jul 2016 10:11:04 +1000 Subject: [PATCH 58/77] Extract classical backgrounds to mixins --- .../stylesheets/darkswarm/groups.css.sass | 25 ++++++++----------- app/assets/stylesheets/darkswarm/mixins.sass | 20 +++++++++++++++ .../stylesheets/darkswarm/producers.css.sass | 6 +---- .../stylesheets/darkswarm/signup.css.sass | 4 +-- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/groups.css.sass b/app/assets/stylesheets/darkswarm/groups.css.sass index 765689049d..7243112b67 100644 --- a/app/assets/stylesheets/darkswarm/groups.css.sass +++ b/app/assets/stylesheets/darkswarm/groups.css.sass @@ -4,11 +4,7 @@ // Search page #groups - background-color: lighten($clr-brick, 56%) - background-image: url("/assets/groups.svg") - background-position: center 50px - background-repeat: no-repeat - background-size: 922px 922px + @include groupsbg @include sidepaddingSm @include panepadding h1, p.text @@ -23,13 +19,13 @@ text-align: right a font-size: 1.5em - + .groups-header border: 2px solid $clr-brick-light-bright @include border-radius-mixed(0.5em, 0.5em, 0, 0) margin: -1rem 0 1rem padding: 1rem 0.9375rem - @media screen and (min-width: 640px) + @media screen and (min-width: 640px) border: 0 none @include border-radius(0) margin: 0 @@ -44,12 +40,12 @@ .ofn-i_035-groups font-size: 120% vertical-align: middle - + // Individual Page #group-page .group-logo, .group-header - text-align: center - .group-logo + text-align: center + .group-logo padding-bottom: 1em max-height: 200px .group-name @@ -57,7 +53,7 @@ @media screen and (min-width: 768px) .group-logo, .group-header text-align: left - .group-logo + .group-logo max-height: 120px float: left padding-right: 1em @@ -72,18 +68,18 @@ margin-right: 2px text-transform: capitalize @include headingFont - @include border-radius(1em 0.25em 0 0) + @include border-radius(1em 0.25em 0 0) @include gradient($disabled-light, $disabled-bright) @media screen and (min-width: 768px) .tabs dd a padding: 0.5rem 1rem 0.25em font-size: 0.875rem - @include border-radius(1.5em 0.25em 0 0) + @include border-radius(1.5em 0.25em 0 0) @media screen and (min-width: 1024px) .tabs dd a padding: 0.75rem 1.5rem 0.5em font-size: 1rem - @include border-radius(2em 0.25em 0 0) + @include border-radius(2em 0.25em 0 0) .tabs dd.active a @include gradient(white, white) margin-bottom: -1px @@ -110,4 +106,3 @@ background-image: none padding-top: 0 padding-bottom: 0 - diff --git a/app/assets/stylesheets/darkswarm/mixins.sass b/app/assets/stylesheets/darkswarm/mixins.sass index 4e779bd2a5..d35c5aa1a7 100644 --- a/app/assets/stylesheets/darkswarm/mixins.sass +++ b/app/assets/stylesheets/darkswarm/mixins.sass @@ -170,3 +170,23 @@ // W3C filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='$gradient-clr1', endColorstr='$gradient-clr2',GradientType=0 ) // IE6-8 + + +@mixin producersbg + background-color: lighten($clr-turquoise, 68%) + background-image: url("/assets/producers.svg") + background-position: center 50px + background-repeat: no-repeat + background-size: 922px 763px + +@mixin hubsbg + background-color: $brand-colour + background-image: url("/assets/hubs-bg.jpg") + background-position: center center + +@mixin groupsbg + background-color: lighten($clr-brick, 56%) + background-image: url("/assets/groups.svg") + background-position: center 50px + background-repeat: no-repeat + background-size: 922px 922px diff --git a/app/assets/stylesheets/darkswarm/producers.css.sass b/app/assets/stylesheets/darkswarm/producers.css.sass index dce972629b..caa31f224d 100644 --- a/app/assets/stylesheets/darkswarm/producers.css.sass +++ b/app/assets/stylesheets/darkswarm/producers.css.sass @@ -2,11 +2,7 @@ @import mixins .producers - background-color: lighten($clr-turquoise, 68%) - background-image: url("/assets/producers.svg") - background-position: center 50px - background-repeat: no-repeat - background-size: 922px 763px + @include producersbg @include sidepaddingSm @include panepadding a diff --git a/app/assets/stylesheets/darkswarm/signup.css.sass b/app/assets/stylesheets/darkswarm/signup.css.sass index cd6ebf458a..12c01d0325 100644 --- a/app/assets/stylesheets/darkswarm/signup.css.sass +++ b/app/assets/stylesheets/darkswarm/signup.css.sass @@ -18,11 +18,9 @@ #producer-case-studies, #shops-case-studies + @include hubsbg padding-top: 100px padding-bottom: 100px - background-color: $brand-colour - background-image: url("/assets/hubs-bg.jpg") - background-position: center center -webkit-filter: brightness(1.1) filter: brightness(1.1) h2 From d93d1653db8dd86e2028775ae40caba84d1d20a9 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 29 Jul 2016 10:11:37 +1000 Subject: [PATCH 59/77] Add directive for smooth scrolling to anchor --- .../directives/smooth_scroll_to.js.coffee | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee diff --git a/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee b/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee new file mode 100644 index 0000000000..c3bcc9590d --- /dev/null +++ b/app/assets/javascripts/darkswarm/directives/smooth_scroll_to.js.coffee @@ -0,0 +1,15 @@ +Darkswarm.directive "ofnSmoothScrollTo", ($location, $document)-> + # Onclick sets $location.hash to attrs.ofnScrollTo + # Then triggers $document.scrollTo + restrict: 'A' + link: (scope, element, attrs)-> + element.bind 'click', (ev)-> + ev.stopPropagation() + $location.hash attrs.ofnScrollTo + target = $("a[name='#{attrs.ofnSmoothScrollTo}']") + # Scrolling is confused by our position:fixed top bar and page alert bar + # - add an offset to scroll to the correct location, plus 5px buffer + offset = $("nav.top-bar").height() + offset += $(".page-alert.move-down").height() + offset += 5 + $document.scrollTo target, offset, 1000 From 57a2f1b3396a08ad975033a4f200583ec67dd060 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 14:42:09 +1000 Subject: [PATCH 60/77] Simplify, simplify --- app/views/home/index.html.haml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index cfb3015179..3d31282901 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -3,7 +3,7 @@ %div{"ng-controller" => "HomeCtrl"} - = render partial: "shared/menu/alert" + = render "shared/menu/alert" #tagline .row @@ -17,9 +17,9 @@ #panes - = render partial: "home/brandstory" - = render partial: "home/system" - = render partial: "home/cta" - = render partial: "home/stats" + = render "home/brandstory" + = render "home/system" + = render "home/cta" + = render "home/stats" - = render partial: "shared/footer" + = render "shared/footer" From ee2c1ef1951687e958a07172376da323bbe330bb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 14:59:28 +1000 Subject: [PATCH 61/77] Extract home page tagline to partial --- app/views/home/_tagline.html.haml | 9 +++++++++ app/views/home/index.html.haml | 12 +----------- 2 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 app/views/home/_tagline.html.haml diff --git a/app/views/home/_tagline.html.haml b/app/views/home/_tagline.html.haml new file mode 100644 index 0000000000..817afdd051 --- /dev/null +++ b/app/views/home/_tagline.html.haml @@ -0,0 +1,9 @@ +#tagline + .row + .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} + %br/ + %a.button.transparent{href: "/shops"} + = t :home_shop diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 3d31282901..564b8b7e25 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -4,17 +4,7 @@ %div{"ng-controller" => "HomeCtrl"} = render "shared/menu/alert" - - #tagline - .row - .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} - %br/ - %a.button.transparent{href: "/shops"} - = t :home_shop - + = render "home/tagline" #panes = render "home/brandstory" From d3ab9faede950e406ff73369cee3aa7f051947a7 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 15:03:14 +1000 Subject: [PATCH 62/77] Show registration CTA in footer rather than connect and learn CTA --- app/assets/stylesheets/darkswarm/footer.sass | 4 +-- .../shared/_connect_learn_call.html.haml | 10 +++++++ app/views/shared/_page_alert.html.haml | 5 ++++ app/views/shared/_register_call.html.haml | 28 +++++-------------- app/views/shared/menu/_alert.html.haml | 2 +- 5 files changed, 25 insertions(+), 24 deletions(-) create mode 100644 app/views/shared/_connect_learn_call.html.haml create mode 100644 app/views/shared/_page_alert.html.haml diff --git a/app/assets/stylesheets/darkswarm/footer.sass b/app/assets/stylesheets/darkswarm/footer.sass index a0d2244c0e..80681cedfb 100644 --- a/app/assets/stylesheets/darkswarm/footer.sass +++ b/app/assets/stylesheets/darkswarm/footer.sass @@ -30,7 +30,7 @@ footer background-color: transparent border: none padding: 0 - a.alert-cta + .alert-cta @include csstrans width: 100% border: 1px solid rgba($dark-grey, 0.35) @@ -44,7 +44,7 @@ footer color: #333 strong letter-spacing: 0.5px - &:hover, &:active, &:focus + a:hover, a:active, a:focus text-decoration: none border-color: white &, & * diff --git a/app/views/shared/_connect_learn_call.html.haml b/app/views/shared/_connect_learn_call.html.haml new file mode 100644 index 0000000000..99f2990990 --- /dev/null +++ b/app/views/shared/_connect_learn_call.html.haml @@ -0,0 +1,10 @@ +:css + .page-alert .alert-box { background-color: #f27052; } + +.alert-cta + %h6 + %strong + = link_to "Connect", "https://openfoodnetwork.org/au/connect/", target: '_blank' + and + %strong + = link_to "Learn", "https://openfoodnetwork.org/au/learn/", target: '_blank' diff --git a/app/views/shared/_page_alert.html.haml b/app/views/shared/_page_alert.html.haml new file mode 100644 index 0000000000..92def240e7 --- /dev/null +++ b/app/views/shared/_page_alert.html.haml @@ -0,0 +1,5 @@ +- if feature? :connect_learn_homepage + = render "shared/connect_learn_call" + +- else + = render "shared/register_call" diff --git a/app/views/shared/_register_call.html.haml b/app/views/shared/_register_call.html.haml index c5bf5b7830..f4c03b7b92 100644 --- a/app/views/shared/_register_call.html.haml +++ b/app/views/shared/_register_call.html.haml @@ -1,22 +1,8 @@ -- if feature? :connect_learn_homepage - :css - .page-alert .alert-box { background-color: #f27052; } - - .alert-cta - %h6 +.alert-cta + %h6 + %a{href: registration_path, target: "_blank"} + = t '.selling_on_ofn' +   %strong - = link_to "Connect", "https://openfoodnetwork.org/au/connect/", target: '_blank' - and - %strong - = link_to "Learn", "https://openfoodnetwork.org/au/learn/", target: '_blank' - - -- else - .alert-cta - %h6 - %a{href: registration_path, target: "_blank"} - = t '.selling_on_ofn' -   - %strong - = t '.register' - %i.ofn-i_054-point-right + = t '.register' + %i.ofn-i_054-point-right diff --git a/app/views/shared/menu/_alert.html.haml b/app/views/shared/menu/_alert.html.haml index 6512358cc3..e3eb53fe74 100644 --- a/app/views/shared/menu/_alert.html.haml +++ b/app/views/shared/menu/_alert.html.haml @@ -1,4 +1,4 @@ .text-center.page-alert.fixed{ "ofn-page-alert" => true } .alert-box - = render 'shared/register_call' + = render 'shared/page_alert' %a.close{ ng: { click: "close()" } } × From 0076b1b9a0d468615b932791a95db1c879a77f6c Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 15:09:01 +1000 Subject: [PATCH 63/77] Add connect and learn panes to home page --- app/assets/stylesheets/darkswarm/home_panes.css.sass | 11 ++++++----- app/views/home/_connect.html.haml | 5 +++++ app/views/home/_learn.html.haml | 5 +++++ app/views/home/index.html.haml | 12 ++++++++++-- 4 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 app/views/home/_connect.html.haml create mode 100644 app/views/home/_learn.html.haml diff --git a/app/assets/stylesheets/darkswarm/home_panes.css.sass b/app/assets/stylesheets/darkswarm/home_panes.css.sass index ed74450317..631d43e07b 100644 --- a/app/assets/stylesheets/darkswarm/home_panes.css.sass +++ b/app/assets/stylesheets/darkswarm/home_panes.css.sass @@ -4,7 +4,6 @@ @import animations @import variables - // Styling for big panes on homepage \\ #panes .pane @@ -25,6 +24,12 @@ #brand-story.pane, #cta.pane, #shops.pane @include tiledPane +#connect.pane + @include groupsbg + +#learn.pane + @include hubsbg + #stats.pane background-image: url("/assets/home/background-blurred-oranges.jpg") background-position: center center @@ -94,10 +99,6 @@ @media all and (max-width: 640px) font-size: 45px - - a - color: $brand-colour - .home-icon-box-bottom margin-top: 1rem width: 100% diff --git a/app/views/home/_connect.html.haml b/app/views/home/_connect.html.haml new file mode 100644 index 0000000000..f101139e31 --- /dev/null +++ b/app/views/home/_connect.html.haml @@ -0,0 +1,5 @@ +#connect.pane + .row + .small-12.columns.text-center + %a{name: "connect"} + %h2 TODO: Connect diff --git a/app/views/home/_learn.html.haml b/app/views/home/_learn.html.haml new file mode 100644 index 0000000000..f9a8a52e01 --- /dev/null +++ b/app/views/home/_learn.html.haml @@ -0,0 +1,5 @@ +#learn.pane + .row + .small-12.columns.text-center + %a{name: "learn"} + %h2 TODO: Learn diff --git a/app/views/home/index.html.haml b/app/views/home/index.html.haml index 564b8b7e25..2dcaf58bd5 100644 --- a/app/views/home/index.html.haml +++ b/app/views/home/index.html.haml @@ -8,8 +8,16 @@ #panes = render "home/brandstory" - = render "home/system" - = render "home/cta" + + - if feature? :connect_learn_homepage + = render "home/learn" + = render "home/connect" + = render "home/system" + - else + = render "home/system" + = render "home/cta" + = render "home/stats" + = render "shared/footer" From f03839b70c70a931bd886dac765eaac74efeb81e Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 15:11:36 +1000 Subject: [PATCH 64/77] Update shopping header --- config/locales/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index e56cd90622..d9b438e04d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -336,7 +336,7 @@ en: brandstory_part5_strong: "We call it Open Food Network." brandstory_part6: "We all love food. Now we can love our food system too." - system_headline: "Here's how it works." + system_headline: "Shopping - here's how it works." system_step1: "1. Search" system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup." system_step2: "2. Shop" From 1054fd2d05addca5f4dc8900cc348b76a54e33cd Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Wed, 3 Aug 2016 15:41:31 +1000 Subject: [PATCH 65/77] View closed shops by URL --- .../controllers/enterprises_controller.js.coffee | 8 +++++++- spec/features/consumer/shops_spec.rb | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee index bc4365b56a..f0a174a47c 100644 --- a/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/enterprises_controller.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> +Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, $location, Enterprises, Search, $document, HashNavigation, FilterSelectorsService, EnterpriseModal, enterpriseMatchesNameQueryFilter, distanceWithinKmFilter) -> $scope.Enterprises = Enterprises $scope.producers_to_filter = Enterprises.producers $scope.filterSelectors = FilterSelectorsService.createSelectors() @@ -21,6 +21,10 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris Enterprises.calculateDistance query, $scope.firstNameMatch() $rootScope.$broadcast 'enterprisesChanged' + $timeout -> + if $location.search()['show_closed']? + $scope.showClosedShops() + $scope.$watch "filtersActive", (value) -> $scope.$broadcast 'filtersToggled' @@ -71,6 +75,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris $scope.showClosedShops = -> delete $scope.filterExpression['active'] + $location.search('show_closed', '1') $scope.hideClosedShops = -> $scope.filterExpression['active'] = true + $location.search('show_closed', null) diff --git a/spec/features/consumer/shops_spec.rb b/spec/features/consumer/shops_spec.rb index 0c5d3d7e09..adbbf05f9a 100644 --- a/spec/features/consumer/shops_spec.rb +++ b/spec/features/consumer/shops_spec.rb @@ -75,6 +75,19 @@ feature 'Shops', js: true do end end + describe "viewing closed shops by URL" do + before do + d1 + d2 + visit shops_path(anchor: "/?show_closed=1") + end + + it "shows closed shops" do + #click_link_and_ensure("Show closed shops", -> { page.has_selector? 'hub.inactive' }) + page.should have_selector 'hub.inactive', text: d2.name + end + end + private From 0830a5bd85fc5fb1c28f59a5a2cf948b68e762cb Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Thu, 7 Jul 2016 14:58:07 +1000 Subject: [PATCH 66/77] Add basic sell page Conflicts: config/routes.rb --- .../stylesheets/darkswarm/home_panes.css.sass | 2 +- app/controllers/home_controller.rb | 4 +++ app/views/home/sell.html.haml | 32 +++++++++++++++++++ config/locales/en.yml | 7 ++++ config/routes.rb | 1 + 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 app/views/home/sell.html.haml diff --git a/app/assets/stylesheets/darkswarm/home_panes.css.sass b/app/assets/stylesheets/darkswarm/home_panes.css.sass index 631d43e07b..2173284b6e 100644 --- a/app/assets/stylesheets/darkswarm/home_panes.css.sass +++ b/app/assets/stylesheets/darkswarm/home_panes.css.sass @@ -21,7 +21,7 @@ #system.pane background-color: white -#brand-story.pane, #cta.pane, #shops.pane +#brand-story.pane, #cta.pane, #shops.pane, #sell.pane @include tiledPane #connect.pane diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 07ba097f85..fbf1819277 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -9,4 +9,8 @@ class HomeController < BaseController @num_orders = Spree::Order.complete.count end end + + def sell + end + end diff --git a/app/views/home/sell.html.haml b/app/views/home/sell.html.haml new file mode 100644 index 0000000000..40fd87e028 --- /dev/null +++ b/app/views/home/sell.html.haml @@ -0,0 +1,32 @@ +- content_for(:title) do + = t :sell_title + +#panes + #sell.pane + .row.header + .small-12.medium-12.columns.text-center + %h2 + = t :sell_headline + .row.content + .small-12.medium-6.medium-offset-3.columns.text-center + %p.text-big + = t :sell_motivation + + .pane + .row + .small-12.medium-4.columns.text-center + %h3= t :sell_producers + %a.button.transparent{href: signup_producers_path} + = t :register_title + + .small-12.medium-4.columns.text-center + %h3= t :sell_shops + %a.button.transparent{href: signup_shops_path} + = t :register_title + + .small-12.medium-4.columns.text-center + %h3= t :sell_groups + %a.button.transparent{href: signup_groups_path} + = t :register_title + += render "shared/footer" diff --git a/config/locales/en.yml b/config/locales/en.yml index d9b438e04d..5788987462 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -605,6 +605,13 @@ See the %{link} to find out more about %{sitename}'s features and to start using register_title: Register + sell_title: "Sell" + sell_headline: "Sell food" + sell_motivation: "Here's why" + sell_producers: "Producers" + sell_shops: "Shops" + sell_groups: "Groups" + shops_title: Shops shops_headline: Shopping, transformed. shops_text: Food grows in cycles, farmers harvest in cycles, and we order food in cycles. If you find an order cycle closed, check back soon. diff --git a/config/routes.rb b/config/routes.rb index cd7c7780c4..e625cca37b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,6 +15,7 @@ Openfoodnetwork::Application.routes.draw do get "/discourse/sso", to: "discourse_sso#sso" get "/map", to: "map#index", as: :map + get "/sell", to: "home#sell", as: :sell get "/register", to: "registration#index", as: :registration get "/register/auth", to: "registration#authenticate", as: :registration_auth From 61c9355ffb16d7f091916e8ed92df74115988589 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 14:40:42 +1000 Subject: [PATCH 67/77] Fill in sell page copy --- .../stylesheets/darkswarm/home_panes.css.sass | 6 +++++ app/views/home/sell.html.haml | 22 +++++++++++++++++-- config/locales/en.yml | 15 +++++++++---- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/home_panes.css.sass b/app/assets/stylesheets/darkswarm/home_panes.css.sass index 2173284b6e..4bb9c19aa6 100644 --- a/app/assets/stylesheets/darkswarm/home_panes.css.sass +++ b/app/assets/stylesheets/darkswarm/home_panes.css.sass @@ -148,3 +148,9 @@ #shops-signup.pane background-color: $brand-colour + +#sell-detail.pane + margin: 50px 0 + .row + padding-top: 25px + padding-bottom: 25px diff --git a/app/views/home/sell.html.haml b/app/views/home/sell.html.haml index 40fd87e028..64c71f01c1 100644 --- a/app/views/home/sell.html.haml +++ b/app/views/home/sell.html.haml @@ -12,21 +12,39 @@ %p.text-big = t :sell_motivation - .pane + #sell-detail.pane .row .small-12.medium-4.columns.text-center %h3= t :sell_producers + %p + = t :sell_producers_detail + %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) %a.button.transparent{href: signup_producers_path} = t :register_title .small-12.medium-4.columns.text-center - %h3= t :sell_shops + %h3= t :sell_hubs + %p + = t :sell_hubs_detail + %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) %a.button.transparent{href: signup_shops_path} = t :register_title .small-12.medium-4.columns.text-center %h3= t :sell_groups + %p + = t :sell_groups_detail + %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) %a.button.transparent{href: signup_groups_path} = t :register_title + .row + .small-12.medium-12.columns.text-center + %p= t :sell_listing_price + + %p + = t :sell_embed + %a{href: "hello@openfoodnetwork.org".reverse, target: '_blank', mailto: true} + = t :sell_ask_services + = render "shared/footer" diff --git a/config/locales/en.yml b/config/locales/en.yml index 5788987462..3006806546 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -605,12 +605,19 @@ See the %{link} to find out more about %{sitename}'s features and to start using register_title: Register - sell_title: "Sell" - sell_headline: "Sell food" - sell_motivation: "Here's why" + sell_title: "Register" + sell_headline: "Get on the Open Food Network!" + sell_motivation: "Showcase your beautiful food." sell_producers: "Producers" - sell_shops: "Shops" + sell_hubs: "Hubs" sell_groups: "Groups" + sell_producers_detail: "Set up a profile for your business on the OFN in just minutes. At any time you can upgrade your profile to an online store and sell your products direct to customers." + sell_hubs_detail: "Set up a profile for your food enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop." + sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation." + sell_user_guide: "Find out more in our user guide." + sell_listing_price: "Listing on the OFN is free. Opening and running a shop on OFN is free. Setting up a group directory on OFN for your organisation or regional network is free." + sell_embed: "We can also embed an OFN shop in your own customised website or build a customised local food network website for your region." + sell_ask_services: "Ask us about OFN services." shops_title: Shops shops_headline: Shopping, transformed. From 0dba54a4b8824a82b0d4218f3ce9f72fb64223d7 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 14:43:44 +1000 Subject: [PATCH 68/77] Update page alert text --- app/views/shared/_connect_learn_call.html.haml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/views/shared/_connect_learn_call.html.haml b/app/views/shared/_connect_learn_call.html.haml index 99f2990990..32db588ffe 100644 --- a/app/views/shared/_connect_learn_call.html.haml +++ b/app/views/shared/_connect_learn_call.html.haml @@ -3,8 +3,10 @@ .alert-cta %h6 + NEW Open Food Network %strong = link_to "Connect", "https://openfoodnetwork.org/au/connect/", target: '_blank' and %strong = link_to "Learn", "https://openfoodnetwork.org/au/learn/", target: '_blank' + \- Go exploring and get inspired! From 8f4cbf1d9f40ec962800cd4fa76060a8dead0d05 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 15:02:10 +1000 Subject: [PATCH 69/77] Update page alert label and background colour --- app/views/shared/_connect_learn_call.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/shared/_connect_learn_call.html.haml b/app/views/shared/_connect_learn_call.html.haml index 32db588ffe..68152b2b8f 100644 --- a/app/views/shared/_connect_learn_call.html.haml +++ b/app/views/shared/_connect_learn_call.html.haml @@ -1,12 +1,12 @@ :css - .page-alert .alert-box { background-color: #f27052; } + .page-alert .alert-box { background-color: #fdddac; } .alert-cta %h6 - NEW Open Food Network + Open Food Network %strong - = link_to "Connect", "https://openfoodnetwork.org/au/connect/", target: '_blank' + = link_to t(:label_connect), "https://openfoodnetwork.org/au/connect/", target: '_blank' and %strong - = link_to "Learn", "https://openfoodnetwork.org/au/learn/", target: '_blank' + = link_to t(:label_learn), "https://openfoodnetwork.org/au/learn/", target: '_blank' \- Go exploring and get inspired! From 3b0084025a944dc942ba2fa2f47301558b9f48e1 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 15:02:44 +1000 Subject: [PATCH 70/77] Add copy for home page learn and connect panes --- app/views/home/_connect.html.haml | 8 +++++--- app/views/home/_learn.html.haml | 8 +++++--- config/locales/en.yml | 6 ++++++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/views/home/_connect.html.haml b/app/views/home/_connect.html.haml index f101139e31..6afcb1ae96 100644 --- a/app/views/home/_connect.html.haml +++ b/app/views/home/_connect.html.haml @@ -1,5 +1,7 @@ #connect.pane .row - .small-12.columns.text-center - %a{name: "connect"} - %h2 TODO: Connect + .small-12.medium-6.medium-offset-3.columns.text-center + %h2= t :label_connect + %p.text-normal= t :connect_body + %a.button.transparent{href: "https://openfoodnetwork.org/au/connect/"} + = t :connect_cta diff --git a/app/views/home/_learn.html.haml b/app/views/home/_learn.html.haml index f9a8a52e01..f6d3061e20 100644 --- a/app/views/home/_learn.html.haml +++ b/app/views/home/_learn.html.haml @@ -1,5 +1,7 @@ #learn.pane .row - .small-12.columns.text-center - %a{name: "learn"} - %h2 TODO: Learn + .small-12.medium-6.medium-offset-3.columns.text-center + %h2= t :label_learn + %p.text-normal= t :learn_body + %a.button.transparent{href: "https://openfoodnetwork.org/au/learn/"} + = t :learn_cta diff --git a/config/locales/en.yml b/config/locales/en.yml index 3006806546..7f1dee7b38 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -336,6 +336,12 @@ en: brandstory_part5_strong: "We call it Open Food Network." brandstory_part6: "We all love food. Now we can love our food system too." + learn_body: "Explore models, stories and resources to support you to develop your fair food business or organisation. Find training, events and other opportunities to learn from peers." + learn_cta: "Get Inspired" + + connect_body: "Search our full directories of producers, hubs and groups to find fair food traders near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together." + connect_cta: "Go Exploring" + system_headline: "Shopping - here's how it works." system_step1: "1. Search" system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup." From 5eecdb8c9c7af554f398ffafc0259fd1b23f64c1 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 15:03:07 +1000 Subject: [PATCH 71/77] Update footer: Link to sell instead of individual register links --- app/views/shared/_footer.html.haml | 14 +++----------- config/locales/en.yml | 6 ++---- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index e3e1f44174..21a97e7eb5 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -113,17 +113,9 @@ %h4 = t :footer_join_headline %p - %a{href: "/producers/signup"} - = t :footer_join_producers - %p - %a{href: "/shops/signup"} - = t :footer_join_hubs - %p - %a{href: "/groups/signup"} - = t :footer_join_groups - %p - %a{href: "http://www.openfoodnetwork.org/platform/food-system-partners/", target: "_blank"} - = t :footer_join_partners + = t :footer_join_body + %a{href: sell_path} + = t :footer_join_cta .medium-2.columns.text-center / Placeholder diff --git a/config/locales/en.yml b/config/locales/en.yml index 7f1dee7b38..386f44ae8b 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -315,10 +315,8 @@ en: footer_nav_headline: "Navigate" footer_join_headline: "Join us" - footer_join_producers: "Producers sign-up" - footer_join_hubs: "Hubs sign-up" - footer_join_groups: "Groups sign-up" - footer_join_partners: "Food systems partners" + footer_join_body: "Create a listing, shop or group directory on the Open Food Network." + footer_join_cta: "Tell me more!" footer_legal_call: "Read our" footer_legal_tos: "Terms and conditions" From fcd422c6cebad5d6de8c6ecf4c84caef491b4af0 Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 15:18:29 +1000 Subject: [PATCH 72/77] Fix path helper fail in footer --- app/views/shared/_footer.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 21a97e7eb5..c7fc79b888 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -114,7 +114,7 @@ = t :footer_join_headline %p = t :footer_join_body - %a{href: sell_path} + %a{href: "/sell"} = t :footer_join_cta .medium-2.columns.text-center From 1f5da8699d75a734f97c518d63e3eeed30a3db6d Mon Sep 17 00:00:00 2001 From: Rohan Mitchell Date: Fri, 5 Aug 2016 15:58:00 +1000 Subject: [PATCH 73/77] Build plz --- app/views/shared/_footer.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index c7fc79b888..de352b444a 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -114,7 +114,7 @@ = t :footer_join_headline %p = t :footer_join_body - %a{href: "/sell"} + %a{href: "/sell"} = t :footer_join_cta .medium-2.columns.text-center From d40733d447e1840336114b98d74e7edafabf55df Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Sun, 7 Aug 2016 10:24:07 +1000 Subject: [PATCH 74/77] Add redirects to global site for /connect, /learn --- Gemfile.lock | 3 --- config/routes.rb | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2a10493f3e..a645196fc5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -728,8 +728,5 @@ DEPENDENCIES wicked_pdf wkhtmltopdf-binary -RUBY VERSION - ruby 2.1.5p273 - BUNDLED WITH 1.12.5 diff --git a/config/routes.rb b/config/routes.rb index e625cca37b..5f37bbe831 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -20,6 +20,10 @@ Openfoodnetwork::Application.routes.draw do get "/register", to: "registration#index", as: :registration get "/register/auth", to: "registration#authenticate", as: :registration_auth + # Redirects to global website + get "/connect", to: redirect("https://openfoodnetwork.org/#{ENV['DEFAULT_COUNTRY_CODE'].andand.downcase}/connect/") + get "/learn", to: redirect("https://openfoodnetwork.org/#{ENV['DEFAULT_COUNTRY_CODE'].andand.downcase}/learn/") + resource :shop, controller: "shop" do get :products post :order_cycle From b957555c824de49d096115da0d44945a01d7b70a Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 3 Aug 2016 12:45:45 +1000 Subject: [PATCH 75/77] Adding infinite-scroll to the shopfront For performance improvement with large data sets --- .../controllers/products_controller.js.coffee | 11 +++++++---- .../darkswarm/filters/filter_products.js.coffee | 1 + .../javascripts/shared/ng-infinite-scroll.min.js | 4 ++-- .../partials/shop_variant_no_group_buy.html.haml | 2 +- .../partials/shop_variant_with_group_buy.html.haml | 11 ++++++----- .../javascripts/templates/shop_variant.html.haml | 8 ++++---- app/views/shop/products/_form.html.haml | 9 ++++----- app/views/shop/products/_summary.html.haml | 2 +- .../controllers/products_controller_spec.js.coffee | 4 ++-- 9 files changed, 28 insertions(+), 24 deletions(-) diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index 4f149db1e5..f431714571 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -1,18 +1,21 @@ -Darkswarm.controller "ProductsCtrl", ($scope, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) -> +Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, OrderCycle, FilterSelectorsService, Cart, Taxons, Properties) -> $scope.Products = Products $scope.Cart = Cart + $scope.query = "" $scope.taxonSelectors = FilterSelectorsService.createSelectors() $scope.propertySelectors = FilterSelectorsService.createSelectors() $scope.filtersActive = true - $scope.limit = 3 + $scope.limit = 10 $scope.order_cycle = OrderCycle.order_cycle $scope.$watch "Products.loading", (newValue, oldValue) -> $scope.$broadcast("loadFilterSelectors") if !newValue $scope.incrementLimit = -> - if $scope.limit < Products.products.length - $scope.limit = $scope.limit + 1 + $scope.limit += 10 if $scope.limit < Products.products.length + + $scope.$watchGroup ['query','taxonSelectors','propertySelectors'], -> + $scope.limit = 10 $scope.searchKeypress = (e)-> code = e.keyCode || e.which diff --git a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee index f65c8854dc..4cc325e483 100644 --- a/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/filter_products.js.coffee @@ -2,6 +2,7 @@ Darkswarm.filter 'products', (Matcher) -> (products, text) -> products ||= [] text ?= "" + return products if text == "" products.filter (product) => propertiesToMatch = [product.name, product.supplier.name, product.primary_taxon.name] Matcher.match propertiesToMatch, text diff --git a/app/assets/javascripts/shared/ng-infinite-scroll.min.js b/app/assets/javascripts/shared/ng-infinite-scroll.min.js index d4410b93c0..3e69b49588 100644 --- a/app/assets/javascripts/shared/ng-infinite-scroll.min.js +++ b/app/assets/javascripts/shared/ng-infinite-scroll.min.js @@ -1,2 +1,2 @@ -/* ng-infinite-scroll - v1.0.0 - 2013-02-23 */ -var mod;mod=angular.module("infinite-scroll",[]),mod.directive("infiniteScroll",["$rootScope","$window","$timeout",function(i,n,e){return{link:function(t,l,o){var r,c,f,a;return n=angular.element(n),f=0,null!=o.infiniteScrollDistance&&t.$watch(o.infiniteScrollDistance,function(i){return f=parseInt(i,10)}),a=!0,r=!1,null!=o.infiniteScrollDisabled&&t.$watch(o.infiniteScrollDisabled,function(i){return a=!i,a&&r?(r=!1,c()):void 0}),c=function(){var e,c,u,d;return d=n.height()+n.scrollTop(),e=l.offset().top+l.height(),c=e-d,u=n.height()*f>=c,u&&a?i.$$phase?t.$eval(o.infiniteScroll):t.$apply(o.infiniteScroll):u?r=!0:void 0},n.on("scroll",c),t.$on("$destroy",function(){return n.off("scroll",c)}),e(function(){return o.infiniteScrollImmediateCheck?t.$eval(o.infiniteScrollImmediateCheck)?c():void 0:c()},0)}}}]); \ No newline at end of file +/* ng-infinite-scroll - v1.3.0 - 2016-06-30 */ +angular.module("infinite-scroll",[]).value("THROTTLE_MILLISECONDS",null).directive("infiniteScroll",["$rootScope","$window","$interval","THROTTLE_MILLISECONDS",function(a,b,c,d){return{scope:{infiniteScroll:"&",infiniteScrollContainer:"=",infiniteScrollDistance:"=",infiniteScrollDisabled:"=",infiniteScrollUseDocumentBottom:"=",infiniteScrollListenForEvent:"@"},link:function(e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z;return z=angular.element(b),u=null,v=null,j=null,k=null,r=!0,y=!1,x=null,i=!1,q=function(a){return a=a[0]||a,isNaN(a.offsetHeight)?a.document.documentElement.clientHeight:a.offsetHeight},s=function(a){if(a[0].getBoundingClientRect&&!a.css("none"))return a[0].getBoundingClientRect().top+t(a)},t=function(a){return a=a[0]||a,isNaN(window.pageYOffset)?a.document.documentElement.scrollTop:a.ownerDocument.defaultView.pageYOffset},p=function(){var b,d,g,h,l;return k===z?(b=q(k)+t(k[0].document.documentElement),g=s(f)+q(f)):(b=q(k),d=0,void 0!==s(k)&&(d=s(k)),g=s(f)-d+q(f)),y&&(g=q((f[0].ownerDocument||f[0].document).documentElement)),h=g-b,l=h<=q(k)*u+1,l?(j=!0,v?e.$$phase||a.$$phase?e.infiniteScroll():e.$apply(e.infiniteScroll):void 0):(i&&c.cancel(i),j=!1)},w=function(a,b){var d,e,f;return f=null,e=0,d=function(){return e=(new Date).getTime(),c.cancel(f),f=null,a.call()},function(){var g,h;return g=(new Date).getTime(),h=b-(g-e),h<=0?(c.cancel(f),f=null,e=g,a.call()):f?void 0:f=c(d,h,1)}},null!=d&&(p=w(p,d)),e.$on("$destroy",function(){if(k.unbind("scroll",p),null!=x&&(x(),x=null),i)return c.cancel(i)}),n=function(a){return u=parseFloat(a)||0},e.$watch("infiniteScrollDistance",n),n(e.infiniteScrollDistance),m=function(a){if(v=!a,v&&j)return j=!1,p()},e.$watch("infiniteScrollDisabled",m),m(e.infiniteScrollDisabled),o=function(a){return y=a},e.$watch("infiniteScrollUseDocumentBottom",o),o(e.infiniteScrollUseDocumentBottom),h=function(a){if(null!=k&&k.unbind("scroll",p),k=a,null!=a)return k.bind("scroll",p)},h(z),e.infiniteScrollListenForEvent&&(x=a.$on(e.infiniteScrollListenForEvent,p)),l=function(a){if(null!=a&&0!==a.length){if(a.nodeType&&1===a.nodeType?a=angular.element(a):"function"==typeof a.append?a=angular.element(a[a.length-1]):"string"==typeof a&&(a=angular.element(document.querySelector(a))),null!=a)return h(a);throw new Error("invalid infinite-scroll-container attribute.")}},e.$watch("infiniteScrollContainer",l),l(e.infiniteScrollContainer||[]),null!=g.infiniteScrollParent&&h(angular.element(f.parent())),null!=g.infiniteScrollImmediateCheck&&(r=e.$eval(g.infiniteScrollImmediateCheck)),i=c(function(){return r&&p(),c.cancel(i)})}}}]),"undefined"!=typeof module&&"undefined"!=typeof exports&&module.exports===exports&&(module.exports="infinite-scroll"); diff --git a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml index 3a52ba9d07..0441156c2c 100644 --- a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml +++ b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml @@ -9,4 +9,4 @@ "ng-model" => "variant.line_item.quantity", "ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}", "ng-disabled" => "!variant.on_demand && variant.count_on_hand == 0", - name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"} + name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"} diff --git a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml index d4c88092b6..05bdf468b4 100644 --- a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml +++ b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml @@ -1,4 +1,5 @@ .small-5.medium-3.large-3.columns.text-right{"ng-if" => "::variant.product.group_buy"} + %span.bulk-input-container %span.bulk-input %input.bulk.first{type: :number, @@ -6,18 +7,18 @@ integer: true, min: 0, "ng-model" => "variant.line_item.quantity", - placeholder: "{{'shop_variant_quantity_min' | t}}", + placeholder: "{{::'shop_variant_quantity_min' | t}}", "ofn-disable-scroll" => true, "ofn-on-hand" => "{{variant.on_demand && 9999 || variant.count_on_hand }}", - name: "variants[{{variant.id}}]", id: "variants_{{variant.id}}"} + name: "variants[{{::variant.id}}]", id: "variants_{{::variant.id}}"} %span.bulk-input %input.bulk.second{type: :number, "ng-disabled" => "!variant.line_item.quantity", integer: true, min: 0, "ng-model" => "variant.line_item.max_quantity", - placeholder: "{{'shop_variant_quantity_max' | t}}", + placeholder: "{{::'shop_variant_quantity_max' | t}}", "ofn-disable-scroll" => true, min: "{{variant.line_item.quantity}}", - name: "variant_attributes[{{variant.id}}][max_quantity]", - id: "variants_{{variant.id}}_max"} + name: "variant_attributes[{{::variant.id}}][max_quantity]", + id: "variants_{{::variant.id}}_max"} diff --git a/app/assets/javascripts/templates/shop_variant.html.haml b/app/assets/javascripts/templates/shop_variant.html.haml index 1d06ffbb39..978ec2e7c0 100644 --- a/app/assets/javascripts/templates/shop_variant.html.haml +++ b/app/assets/javascripts/templates/shop_variant.html.haml @@ -1,23 +1,23 @@ .variants.row .small-12.medium-4.large-4.columns.variant-name .table-cell - .inline {{ variant.name_to_display }} + .inline {{ ::variant.name_to_display }} .bulk-buy.inline{"ng-if" => "::variant.product.group_buy"} %i.ofn-i_056-bulk>< %em>< - \ {{'bulk' | t}} + \ {{::'bulk' | t}} %ng-include{src: "'partials/shop_variant_no_group_buy.html'"} %ng-include{src: "'partials/shop_variant_with_group_buy.html'"} .small-3.medium-1.large-1.columns.variant-unit .table-cell - %em {{ variant.unit_to_display }} + %em {{ ::variant.unit_to_display }} .small-4.medium-2.large-2.columns.variant-price .table-cell.price %i.ofn-i_009-close - {{ variant.price_with_fees | localizeCurrency }} + {{ ::variant.price_with_fees | localizeCurrency }} -# Now in a template in app/assets/javascripts/templates ! %price-breakdown{"price-breakdown" => "_", variant: "variant", diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 1decc0a43c..18e299a8ec 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -1,6 +1,5 @@ .footer-pad.small-12.columns - %products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true, - "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1"} + %products{"ng-controller" => "ProductsCtrl", "ng-show" => "order_cycle.order_cycle_id != null", "ng-cloak" => true } // TODO: Needs an ng-show to slide content down .row.animate-slide{ "ng-show" => "query || appliedPropertiesList() || appliedTaxonsList()" } @@ -29,10 +28,10 @@ .small-12.medium-6.large-6.large-offset-1.columns = render partial: "shop/products/filters" - %div.pad-top - %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) track by product.id ", "id" => "product-{{ product.id }}"} + %div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "inifinite-scroll-disabled" => '{{filteredProducts.length <= limit}}' } + %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) | limitTo:limit track by product.id ", "id" => "product-{{ product.id }}"} = render "shop/products/summary" - %shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"} + -# %shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"} %shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.count_on_hand == 0}"} %product{"ng-show" => "Products.loading"} diff --git a/app/views/shop/products/_summary.html.haml b/app/views/shop/products/_summary.html.haml index 4dd5b3f224..09f9aa15d5 100644 --- a/app/views/shop/products/_summary.html.haml +++ b/app/views/shop/products/_summary.html.haml @@ -18,4 +18,4 @@ %span{"ng-bind" => "::enterprise.name"} .small-2.medium-2.large-1.columns.text-center .taxon-flag - %render-svg{path: "{{product.primary_taxon.icon}}"} + %render-svg{path: "{{::product.primary_taxon.icon}}"} diff --git a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee index 9e4237d1e7..1e188f4f16 100644 --- a/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/products_controller_spec.js.coffee @@ -30,9 +30,9 @@ describe 'ProductsCtrl', -> it "increments the limit up to the number of products", -> scope.limit = 0 scope.incrementLimit() - expect(scope.limit).toEqual 1 + expect(scope.limit).toEqual 10 scope.incrementLimit() - expect(scope.limit).toEqual 1 + expect(scope.limit).toEqual 10 it "blocks keypresses on code 13", -> event = From f9b58b7b90f7c8b280b22bac7caefb0169087b0d Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 3 Aug 2016 16:08:31 +1000 Subject: [PATCH 76/77] Ensure bill is > 0 for spec --- spec/jobs/finalize_account_invoices_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/jobs/finalize_account_invoices_spec.rb b/spec/jobs/finalize_account_invoices_spec.rb index d4b250d42f..5a51972d67 100644 --- a/spec/jobs/finalize_account_invoices_spec.rb +++ b/spec/jobs/finalize_account_invoices_spec.rb @@ -189,6 +189,7 @@ describe FinalizeAccountInvoices do Spree::Config.set(:account_invoices_monthly_fixed, 5) Spree::Config.set(:account_invoices_monthly_rate, 0.02) Spree::Config.set(:account_invoices_monthly_cap, 50) + Spree::Config.set(:minimum_billable_turnover, 0) end context "finalizing an invoice" do From 47df8d6d8ee924d94a24c33931bf1ade33e5dbde Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 5 Aug 2016 16:13:46 +1000 Subject: [PATCH 77/77] Refactoring AngularJS Shop Variant filtering logic for improved speed --- .../controllers/cart_controller.js.coffee | 8 --- .../line_item_controller.js.coffee | 5 -- .../controllers/products_controller.js.coffee | 24 +++++++- .../directives/shop_variant.js.coffee | 5 +- .../darkswarm/services/cart.js.coffee | 46 +++++---------- .../darkswarm/services/products.js.coffee | 17 ++---- .../darkswarm/services/variants.js.coffee | 21 +++++-- .../templates/price_breakdown.html.haml | 16 ++--- .../templates/price_percentage.html.haml | 5 +- .../templates/shop_variant.html.haml | 4 +- app/views/shared/menu/_cart.html.haml | 7 +-- app/views/shop/products/_form.html.haml | 12 +++- .../darkswarm/services/cart_spec.js.coffee | 59 +++++++------------ .../services/products_spec.js.coffee | 6 -- .../services/variants_spec.js.coffee | 38 +++++++++++- 15 files changed, 142 insertions(+), 131 deletions(-) delete mode 100644 app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee diff --git a/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee index 1b8703899a..ebad820ebd 100644 --- a/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/cart_controller.js.coffee @@ -1,10 +1,2 @@ Darkswarm.controller "CartCtrl", ($scope, Cart, $timeout) -> $scope.Cart = Cart - initializing = true - - $scope.$watchCollection "Cart.line_items_present()", -> - if initializing - $timeout -> - initializing = false - else - $scope.Cart.orderChanged() diff --git a/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee deleted file mode 100644 index 864f25177a..0000000000 --- a/app/assets/javascripts/darkswarm/controllers/line_item_controller.js.coffee +++ /dev/null @@ -1,5 +0,0 @@ -Darkswarm.controller "LineItemCtrl", ($scope)-> - $scope.$watch '[line_item.quantity, line_item.max_quantity]', (newValue, oldValue)-> - if newValue != oldValue - $scope.Cart.orderChanged() - , true \ No newline at end of file diff --git a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee index f431714571..34b65aa405 100644 --- a/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/products_controller.js.coffee @@ -7,15 +7,35 @@ Darkswarm.controller "ProductsCtrl", ($scope, $filter, $rootScope, Products, Ord $scope.filtersActive = true $scope.limit = 10 $scope.order_cycle = OrderCycle.order_cycle + # $scope.infiniteDisabled = true + + # All of this logic basically just replicates the functionality filtering an ng-repeat + # except that it allows us to filter a separate list before rendering, meaning that + # we can get much better performance when applying filters by resetting the limit on the + # number of products being rendered each time a filter is changed. $scope.$watch "Products.loading", (newValue, oldValue) -> + $scope.updateFilteredProducts() $scope.$broadcast("loadFilterSelectors") if !newValue $scope.incrementLimit = -> - $scope.limit += 10 if $scope.limit < Products.products.length + if $scope.limit < Products.products.length + $scope.limit += 10 + $scope.updateVisibleProducts() - $scope.$watchGroup ['query','taxonSelectors','propertySelectors'], -> + $scope.$watch 'query', -> $scope.updateFilteredProducts() + $scope.$watchCollection 'activeTaxons', -> $scope.updateFilteredProducts() + $scope.$watchCollection 'activeProperties', -> $scope.updateFilteredProducts() + + $scope.updateFilteredProducts = -> $scope.limit = 10 + f1 = $filter('products')(Products.products, $scope.query) + f2 = $filter('taxons')(f1, $scope.activeTaxons) + $scope.filteredProducts = $filter('properties')(f2, $scope.activeProperties) + $scope.updateVisibleProducts() + + $scope.updateVisibleProducts = -> + $scope.visibleProducts = $filter('limitTo')($scope.filteredProducts, $scope.limit) $scope.searchKeypress = (e)-> code = e.keyCode || e.which diff --git a/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee index e4cbed11c5..d679e6c3f0 100644 --- a/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/shop_variant.js.coffee @@ -1,6 +1,9 @@ -Darkswarm.directive "shopVariant", -> +Darkswarm.directive "shopVariant", -> restrict: 'E' replace: true templateUrl: 'shop_variant.html' scope: variant: '=' + controller: ($scope, Cart) -> + $scope.$watchGroup ['variant.line_item.quantity', 'variant.line_item.max_quantity'], -> + Cart.adjust($scope.variant.line_item) diff --git a/app/assets/javascripts/darkswarm/services/cart.js.coffee b/app/assets/javascripts/darkswarm/services/cart.js.coffee index 9ee03e26b3..456d567bb7 100644 --- a/app/assets/javascripts/darkswarm/services/cart.js.coffee +++ b/app/assets/javascripts/darkswarm/services/cart.js.coffee @@ -11,7 +11,15 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo for line_item in @line_items line_item.variant.line_item = line_item Variants.register line_item.variant - line_item.variant.extended_name = @extendedVariantName(line_item.variant) + + adjust: (line_item) => + line_item.total_price = line_item.variant.price_with_fees * line_item.quantity + if line_item.quantity > 0 + @line_items.push line_item unless line_item in @line_items + else + index = @line_items.indexOf(line_item) + @line_items.splice(index, 1) if index >= 0 + @orderChanged() orderChanged: => @unsaved() @@ -48,7 +56,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo # TODO: These changes to quantity/max_quantity trigger another cart update, which # is unnecessary. - for li in @line_items_present() + for li in @line_items when li.quantity > 0 if stockLevels[li.variant.id]? li.variant.count_on_hand = stockLevels[li.variant.id].on_hand if li.quantity > li.variant.count_on_hand @@ -67,7 +75,7 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo data: => variants = {} - for li in @line_items_present() + for li in @line_items when li.quantity > 0 variants[li.variant.id] = quantity: li.quantity max_quantity: li.max_quantity @@ -89,45 +97,21 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo $(window).bind "beforeunload", -> t 'order_not_saved_yet' - line_items_present: => - @line_items.filter (li)-> - li.quantity > 0 - total_item_count: => - @line_items_present().reduce (sum,li) -> + @line_items.reduce (sum,li) -> sum = sum + li.quantity , 0 empty: => - @line_items_present().length == 0 + @line_items.length == 0 total: => - @line_items_present().map (li)-> - li.variant.totalPrice() + @line_items.map (li)-> + li.total_price .reduce (t, price)-> t + price , 0 - register_variant: (variant)=> - exists = @line_items.some (li)-> li.variant == variant - @create_line_item(variant) unless exists - clear: -> @line_items = [] storage.clearAll() # One day this will have to be moar GRANULAR - - create_line_item: (variant)-> - variant.extended_name = @extendedVariantName(variant) - variant.line_item = - variant: variant - quantity: null - max_quantity: null - @line_items.push variant.line_item - - extendedVariantName: (variant) => - if variant.product_name == variant.name_to_display - variant.product_name - else - name = "#{variant.product_name} - #{variant.name_to_display}" - name += " (#{variant.options_text})" if variant.options_text - name diff --git a/app/assets/javascripts/darkswarm/services/products.js.coffee b/app/assets/javascripts/darkswarm/services/products.js.coffee index 475ed5be0b..b120cab737 100644 --- a/app/assets/javascripts/darkswarm/services/products.js.coffee +++ b/app/assets/javascripts/darkswarm/services/products.js.coffee @@ -17,7 +17,6 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro @extend() @dereference() @registerVariants() - @registerVariantsWithCart() @loading = false extend: -> @@ -44,15 +43,7 @@ Darkswarm.factory 'Products', ($resource, Enterprises, Dereferencer, Taxons, Pro registerVariants: -> for product in @products if product.variants - product.variants = (Variants.register variant for variant in product.variants) - variant.product = product for variant in product.variants - if product.master - product.master.product = product - product.master = Variants.register product.master - - registerVariantsWithCart: -> - for product in @products - if product.variants - for variant in product.variants - Cart.register_variant variant - Cart.register_variant product.master if product.master + product.variants = for variant in product.variants + variant = Variants.register variant + variant.product = product + variant diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee index 3048049ad5..441258dc1a 100644 --- a/app/assets/javascripts/darkswarm/services/variants.js.coffee +++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee @@ -9,8 +9,21 @@ Darkswarm.factory 'Variants', -> @variants[variant.id] ||= @extend variant extend: (variant)-> - # Add totalPrice method to calculate line item total. This should be on a line item! - variant.totalPrice = -> - variant.price_with_fees * variant.line_item.quantity - variant.basePricePercentage = Math.round(variant.price / variant.price_with_fees * 100) + variant.extended_name = @extendedVariantName(variant) + variant.base_price_percentage = Math.round(variant.price / variant.price_with_fees * 100) + variant.line_item ||= @lineItemFor(variant) # line_item may have been initialised in Cart#constructor + variant.line_item.total_price = variant.price_with_fees * variant.line_item.quantity variant + + extendedVariantName: (variant) => + if variant.product_name == variant.name_to_display + variant.product_name + else + name = "#{variant.product_name} - #{variant.name_to_display}" + name += " (#{variant.options_text})" if variant.options_text + name + + lineItemFor: (variant) -> + variant: variant + quantity: null + max_quantity: null diff --git a/app/assets/javascripts/templates/price_breakdown.html.haml b/app/assets/javascripts/templates/price_breakdown.html.haml index fa884cd4f0..48e0a8d5e0 100644 --- a/app/assets/javascripts/templates/price_breakdown.html.haml +++ b/app/assets/javascripts/templates/price_breakdown.html.haml @@ -2,7 +2,7 @@ %span.joyride-nub.right .joyride-content-wrapper .collapsed{"ng-show" => "!expanded"} - %price-percentage{percentage: 'variant.basePricePercentage'} + %price-percentage{percentage: 'variant.base_price_percentage'} %a{"ng-click" => "expanded = !expanded"} %span{"ng-bind" => "::'price_breakdown' | t"} %i.ofn-i_005-caret-down @@ -10,26 +10,26 @@ .expanded{"ng-show" => "expanded"} %ul %li.cost - .right {{ variant.price | localizeCurrency }} + .right {{ ::variant.price | localizeCurrency }} %span{"ng-bind" => "::'item_cost' | t"} %li.admin-fee{"ng-if" => "::variant.fees.admin"} - .right {{ variant.fees.admin | localizeCurrency }} + .right {{ ::variant.fees.admin | localizeCurrency }} %span{"ng-bind" => "::'admin_fee' | t"} %li.sales-fee{"ng-if" => "::variant.fees.sales"} - .right {{ variant.fees.sales | localizeCurrency }} + .right {{ ::variant.fees.sales | localizeCurrency }} %span{"ng-bind" => "::'sales_fee' | t"} %li.packing-fee{"ng-if" => "::variant.fees.packing"} - .right {{ variant.fees.packing | localizeCurrency }} + .right {{ ::variant.fees.packing | localizeCurrency }} %span{"ng-bind" => "::'packing_fee' | t"} %li.transport-fee{"ng-if" => "::variant.fees.transport"} - .right {{ variant.fees.transport | localizeCurrency }} + .right {{ ::variant.fees.transport | localizeCurrency }} %span{"ng-bind" => "::'transport_fee' | t"} %li.fundraising-fee{"ng-if" => "::variant.fees.fundraising"} - .right {{ variant.fees.fundraising | localizeCurrency }} + .right {{ ::variant.fees.fundraising | localizeCurrency }} %span{"ng-bind" => "::'fundraising_fee' | t"} %li.total %strong - .right = {{ variant.price_with_fees | localizeCurrency }} + .right = {{ ::variant.price_with_fees | localizeCurrency }}   %a{"ng-click" => "expanded = !expanded"} diff --git a/app/assets/javascripts/templates/price_percentage.html.haml b/app/assets/javascripts/templates/price_percentage.html.haml index 7892ebc0ab..f524103643 100644 --- a/app/assets/javascripts/templates/price_percentage.html.haml +++ b/app/assets/javascripts/templates/price_percentage.html.haml @@ -1,5 +1,4 @@ .progress - .right {{'fees' | t}} + .right {{::'fees' | t}} .meter - {{'item_cost' | t}} - + {{::'item_cost' | t}} diff --git a/app/assets/javascripts/templates/shop_variant.html.haml b/app/assets/javascripts/templates/shop_variant.html.haml index 978ec2e7c0..3214612e88 100644 --- a/app/assets/javascripts/templates/shop_variant.html.haml +++ b/app/assets/javascripts/templates/shop_variant.html.haml @@ -27,5 +27,5 @@ .small-12.medium-2.large-2.columns.total-price.text-right .table-cell - %strong{"ng-class" => "{filled: variant.totalPrice()}"} - {{ variant.totalPrice() | localizeCurrency }} + %strong{"ng-class" => "{filled: variant.line_item.total_price}"} + {{ variant.line_item.total_price | localizeCurrency }} diff --git a/app/views/shared/menu/_cart.html.haml b/app/views/shared/menu/_cart.html.haml index f67ff2ffe1..73e9fe14be 100644 --- a/app/views/shared/menu/_cart.html.haml +++ b/app/views/shared/menu/_cart.html.haml @@ -17,8 +17,7 @@ %a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"} = t 'checkout' %table - %tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_present()", - "ng-controller" => "LineItemCtrl", "id" => "cart-variant-{{ line_item.variant.id }}"} + %tr.product-cart{"ng-repeat" => "line_item in Cart.line_items", "id" => "cart-variant-{{ line_item.variant.id }}"} %td %small %strong @@ -33,9 +32,9 @@ %small \= %strong - .total-price.right {{ line_item.variant.totalPrice() | localizeCurrency }} + .total-price.right {{ line_item.total_price | localizeCurrency }} - %table{"ng-show" => "Cart.line_items_present().length > 0"} + %table{"ng-show" => "Cart.line_items.length > 0"} %tr.total-cart %td %em diff --git a/app/views/shop/products/_form.html.haml b/app/views/shop/products/_form.html.haml index 18e299a8ec..2d5481b5f5 100644 --- a/app/views/shop/products/_form.html.haml +++ b/app/views/shop/products/_form.html.haml @@ -28,12 +28,18 @@ .small-12.medium-6.large-6.large-offset-1.columns = render partial: "shop/products/filters" - %div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "inifinite-scroll-disabled" => '{{filteredProducts.length <= limit}}' } - %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons | properties: activeProperties) | limitTo:limit track by product.id ", "id" => "product-{{ product.id }}"} + %div.pad-top{ "infinite-scroll" => "incrementLimit()", "infinite-scroll-distance" => "1", "infinite-scroll-disabled" => 'filteredProducts.length <= limit' } + %product.animate-repeat{"ng-controller" => "ProductNodeCtrl", "ng-repeat" => "product in visibleProducts track by product.id", "id" => "product-{{ product.id }}"} = render "shop/products/summary" - -# %shop-variant{variant: 'product.master', "ng-if" => "::!product.hasVariants", "id" => "variant-{{ product.master.id }}"} %shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id", "id" => "variant-{{ variant.id }}", "ng-class" => "{'out-of-stock': !variant.on_demand && variant.count_on_hand == 0}"} + -# Load more button, which can be used to initiate infinite scrolling. + -# %product{ "ng-hide" => "Products.loading || !infiniteDisabled || limit >= filteredProducts.length" } + -# .row.summary + -# .small-12.columns.text-center + -# %a.button{ ng: { click: 'infiniteDisabled = false; incrementLimit();' } } + -# Load More Products + %product{"ng-show" => "Products.loading"} .row.summary .small-12.columns.text-center diff --git a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee index ce3fe7eec3..53ae64f437 100644 --- a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee @@ -33,18 +33,19 @@ describe 'Cart service', -> it "generates extended variant names", -> expect(Cart.line_items[0].variant.extended_name).toEqual "name" - it "creates and backreferences new line items if necessary", -> - Cart.register_variant(v2 = {id: 2}) - expect(Cart.line_items[1].variant).toBe v2 - expect(Cart.line_items[1].variant.line_item).toBe Cart.line_items[1] - - it "returns a list of items actually in the cart", -> - expect(Cart.line_items_present()).toEqual [] + it "adds item to and removes items from the cart", -> + Cart.line_items = [] + expect(Cart.line_items.length).toEqual 0 order.line_items[0].quantity = 1 - expect(Cart.line_items_present().length).toEqual + expect(Cart.line_items.length).toEqual 0 + Cart.adjust(order.line_items[0]) + expect(Cart.line_items.length).toEqual 1 + order.line_items[0].quantity = 0 + expect(Cart.line_items.length).toEqual 1 + Cart.adjust(order.line_items[0]) + expect(Cart.line_items.length).toEqual 0 it "sums the quantity of each line item for cart total", -> - expect(Cart.line_items_present()).toEqual [] order.line_items[0].quantity = 2 expect(Cart.total_item_count()).toEqual 2 @@ -130,62 +131,62 @@ describe 'Cart service', -> describe "when an item is out of stock", -> it "reduces the quantity in the cart", -> li = {variant: {id: 1}, quantity: 5} + Cart.line_items = [li] stockLevels = {1: {quantity: 0, max_quantity: 0, on_hand: 0}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.quantity).toEqual 0 expect(li.max_quantity).toBeUndefined() it "reduces the max_quantity in the cart", -> li = {variant: {id: 1}, quantity: 5, max_quantity: 6} + Cart.line_items = [li] stockLevels = {1: {quantity: 0, max_quantity: 0, on_hand: 0}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.max_quantity).toEqual 0 it "resets the count on hand available", -> li = {variant: {id: 1, count_on_hand: 10}, quantity: 5} + Cart.line_items = [li] stockLevels = {1: {quantity: 0, max_quantity: 0, on_hand: 0}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.variant.count_on_hand).toEqual 0 describe "when the quantity available is less than that requested", -> it "reduces the quantity in the cart", -> li = {variant: {id: 1}, quantity: 6} + Cart.line_items = [li] stockLevels = {1: {quantity: 5, on_hand: 5}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.quantity).toEqual 5 expect(li.max_quantity).toBeUndefined() it "does not reduce the max_quantity in the cart", -> li = {variant: {id: 1}, quantity: 6, max_quantity: 7} + Cart.line_items = [li] stockLevels = {1: {quantity: 5, max_quantity: 5, on_hand: 5}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.max_quantity).toEqual 7 it "resets the count on hand available", -> li = {variant: {id: 1}, quantity: 6} + Cart.line_items = [li] stockLevels = {1: {quantity: 5, on_hand: 6}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.variant.count_on_hand).toEqual 6 describe "when the client-side quantity has been increased during the request", -> it "does not reset the quantity", -> li = {variant: {id: 1}, quantity: 6} + Cart.line_items = [li] stockLevels = {1: {quantity: 5, on_hand: 6}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.quantity).toEqual 6 expect(li.max_quantity).toBeUndefined() it "does not reset the max_quantity", -> li = {variant: {id: 1}, quantity: 5, max_quantity: 7} + Cart.line_items = [li] stockLevels = {1: {quantity: 5, max_quantity: 6, on_hand: 7}} - spyOn(Cart, 'line_items_present').and.returnValue [li] Cart.compareAndNotifyStockLevels stockLevels expect(li.quantity).toEqual 5 expect(li.max_quantity).toEqual 7 @@ -193,14 +194,14 @@ describe 'Cart service', -> describe "when the client-side quantity has been changed from 0 to 1 during the request", -> it "does not reset the quantity", -> li = {variant: {id: 1}, quantity: 1} - spyOn(Cart, 'line_items_present').and.returnValue [li] + Cart.line_items = [li] Cart.compareAndNotifyStockLevels {} expect(li.quantity).toEqual 1 expect(li.max_quantity).toBeUndefined() it "does not reset the max_quantity", -> li = {variant: {id: 1}, quantity: 1, max_quantity: 1} - spyOn(Cart, 'line_items_present').and.returnValue [li] + Cart.line_items = [li] Cart.compareAndNotifyStockLevels {} expect(li.quantity).toEqual 1 expect(li.max_quantity).toEqual 1 @@ -222,23 +223,3 @@ describe 'Cart service', -> expect(Cart.line_items).not.toEqual [] Cart.clear() expect(Cart.line_items).toEqual [] - - describe "generating an extended variant name", -> - it "returns the product name when it is the same as the variant name", -> - variant = {product_name: 'product_name', name_to_display: 'product_name'} - expect(Cart.extendedVariantName(variant)).toEqual "product_name" - - describe "when the product name and the variant name differ", -> - it "returns a combined name when there is no options text", -> - variant = - product_name: 'product_name' - name_to_display: 'name_to_display' - expect(Cart.extendedVariantName(variant)).toEqual "product_name - name_to_display" - - it "returns a combined name when there is some options text", -> - variant = - product_name: 'product_name' - name_to_display: 'name_to_display' - options_text: 'options_text' - - expect(Cart.extendedVariantName(variant)).toEqual "product_name - name_to_display (options_text)" diff --git a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee index 778e701c7d..c5f9d64f12 100644 --- a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee @@ -82,12 +82,6 @@ describe 'Products service', -> $httpBackend.flush() expect(Products.products[0].variants[0]).toBe Variants.variants[1] - it "registers variants with the Cart", -> - product.variants = [{id: 8}] - $httpBackend.expectGET("/shop/products").respond([product]) - $httpBackend.flush() - expect(Cart.line_items[0].variant).toBe Products.products[0].variants[0] - it "sets primaryImageOrMissing when no images are provided", -> $httpBackend.expectGET("/shop/products").respond([product]) $httpBackend.flush() diff --git a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee index a235bafaee..7d8047ecc9 100644 --- a/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/variants_spec.js.coffee @@ -21,11 +21,45 @@ describe 'Variants service', -> it "will return the same object as passed", -> expect(Variants.register(variant)).toBe variant + describe "initialising the line_item", -> + describe "when variant.line_item does not exist", -> + it "creates it", -> + line_item = Variants.register(variant).line_item + expect(line_item).toBeDefined() + expect(line_item.total_price).toEqual 0 + + describe "when variant.line_item already exists", -> + beforeEach -> + variant.line_item = { quantity: 4 } + + it "initialises the total_price", -> + expect(Variants.register(variant).line_item.total_price).toEqual 400 + it "initialises base price percentage", -> - expect(Variants.register(variant).basePricePercentage).toEqual 81 + expect(Variants.register(variant).base_price_percentage).toEqual 81 it "clears registered variants", -> Variants.register(variant) expect(Variants.variants[variant.id]).toBe variant Variants.clear() - expect(Variants.variants[variant.id]).toBeUndefined() \ No newline at end of file + expect(Variants.variants[variant.id]).toBeUndefined() + + describe "generating an extended variant name", -> + it "returns the product name when it is the same as the variant name", -> + variant = {product_name: 'product_name', name_to_display: 'product_name'} + expect(Variants.extendedVariantName(variant)).toEqual "product_name" + + describe "when the product name and the variant name differ", -> + it "returns a combined name when there is no options text", -> + variant = + product_name: 'product_name' + name_to_display: 'name_to_display' + expect(Variants.extendedVariantName(variant)).toEqual "product_name - name_to_display" + + it "returns a combined name when there is some options text", -> + variant = + product_name: 'product_name' + name_to_display: 'name_to_display' + options_text: 'options_text' + + expect(Variants.extendedVariantName(variant)).toEqual "product_name - name_to_display (options_text)"