From 8ecc786b99863ec8e3c7bf10306ded0805fb9f46 Mon Sep 17 00:00:00 2001 From: Maikel Date: Mon, 30 Jul 2018 14:28:01 +1000 Subject: [PATCH 001/122] Include bug severity in issue template And formatted for easier reading and writing. --- .github/ISSUE_TEMPLATE.md | 52 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 633ea4d0abe..2848902d5f5 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,21 +1,28 @@ - + +If your issue is not a bug, please use the Feature template instead: +https://github.com/openfoodfoundation/openfoodnetwork/wiki/Feature-template +--> ## Description - + + + ## Expected Behavior - + + + ## Actual Behavior - + + + ## Steps to Reproduce - - + + + 1. 2. 3. @@ -25,18 +32,35 @@ instead --> + + ## Context - + + + ## Severity - + + + ## Your Environment - + + * Version used: * Browser name and version: * Operating System and version (desktop or mobile): ## Possible Fix - + + + From 915531acc44edca76ff1f4f0061e8c4af5c60b59 Mon Sep 17 00:00:00 2001 From: Maikel Date: Mon, 30 Jul 2018 14:44:07 +1000 Subject: [PATCH 002/122] Add section about documentation updates This should prevent issues like https://github.com/openfoodfoundation/openfoodnetwork/issues/2427. Also converted comments into HTML syntax so that you don't have to delete them when creating a PR. --- .github/PULL_REQUEST_TEMPLATE.md | 38 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a0c8f5638b4..86e47255188 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,36 +2,46 @@ Closes #[the issue number this PR is related to] -[Explain why is this change needed and the solution you propose. Provide -context for others to understand it] + + + #### What should we test? + -[List which features should be tested and how] -[Should we test on mobile?] #### Release notes + -[In case this should be present in the release notes, please write them or -remove this section otherwise] -[To streamline the release process, please designate your PR with ONE of the following -categories, based on the specification from keepachangelog.com (and delete the others):] + + Changelog Category: Added | Changed | Deprecated | Removed | Fixed | Security #### How is this related to the Spree upgrade? + + -[Any known conflicts with the Spree Upgrade? explain them or remove this section -otherwise] #### Discourse thread + + -[Is there a discussion about this in Discourse? add the link if so or remove -this section otherwise] #### Dependencies + + + + +#### Documentation updates + -[Does this PR depend on another one? add the link of so or remove this section -otherwise] From c4b23b62d0088c62ec8d61e97f17dc217b34bac5 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 27 Jul 2018 15:18:37 +0200 Subject: [PATCH 003/122] Update Spree's fork revision in Gemfile --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 6c6ebf43fea..57a17495e7a 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ gem 'i18n-js', '~> 3.0.0' gem 'nokogiri', '>= 1.6.7.1' gem 'pg' -gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '86bf87f1b1e1b299edc8cd10a2486e44ba0a3987' +gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '69db1c090f3711088d84b524f1b94d25e6d21616' gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable' gem 'spree_auth_devise', github: 'openfoodfoundation/spree_auth_devise', branch: 'spree-upgrade-intermediate' diff --git a/Gemfile.lock b/Gemfile.lock index dac1b3d220b..3418c41250b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -31,8 +31,8 @@ GIT GIT remote: https://github.com/openfoodfoundation/spree.git - revision: 86bf87f1b1e1b299edc8cd10a2486e44ba0a3987 - ref: 86bf87f1b1e1b299edc8cd10a2486e44ba0a3987 + revision: 69db1c090f3711088d84b524f1b94d25e6d21616 + ref: 69db1c090f3711088d84b524f1b94d25e6d21616 branch: step-6a specs: spree (1.3.99) From fb93351386383facc1a13cfdfad5e0bc75d461cf Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 30 May 2018 12:48:25 +1000 Subject: [PATCH 004/122] Show fee breakdown in line items panel if present --- .../_subscription_line_items.html.haml | 11 ++++++++++- spec/features/admin/subscriptions_spec.rb | 19 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/views/admin/subscriptions/_subscription_line_items.html.haml b/app/views/admin/subscriptions/_subscription_line_items.html.haml index dcfd0c5fe09..0ef917dd3da 100644 --- a/app/views/admin/subscriptions/_subscription_line_items.html.haml +++ b/app/views/admin/subscriptions/_subscription_line_items.html.haml @@ -29,7 +29,16 @@ = t(:subtotal) \: %td.total.align-center - %span {{ subscription.estimatedSubtotal() | currency }} + %span#order_subtotal {{ subscription.estimatedSubtotal() | currency }} + %td.actions + %tbody#fees.no-border-top{ ng: { show: "subscription.estimatedFees() > 0" } } + %tr#fees-row + %td{:colspan => "3"} + %b + = t(:fees) + \: + %td.total.align-center + %span#order_fees {{ subscription.estimatedFees() | currency }} %td.actions %tbody#order-total.grand-total.no-border-top{"data-hook" => "admin_order_form_total"} %tr diff --git a/spec/features/admin/subscriptions_spec.rb b/spec/features/admin/subscriptions_spec.rb index 556164386a0..ccdac62aef6 100644 --- a/spec/features/admin/subscriptions_spec.rb +++ b/spec/features/admin/subscriptions_spec.rb @@ -17,6 +17,13 @@ let!(:subscription2) { create(:subscription, shop: shop2, with_items: true, with_proxy_orders: true) } let!(:subscription_unmanaged) { create(:subscription, shop: shop_unmanaged, with_items: true, with_proxy_orders: true) } + before do + subscription.update_attributes(shipping_fee_estimate: 3.5) + subscription.subscription_line_items.each do |sli| + sli.update_attributes(price_estimate: 5) + end + end + it "passes the smoke test" do visit spree.admin_path click_link 'Orders' @@ -60,6 +67,18 @@ expect(page).to_not have_selector "th.customer" expect(page).to_not have_content subscription.customer.email + # Viewing Products + within "tr#so_#{subscription.id}" do + expect(page).to have_selector "td.items.panel-toggle", text: 3 + page.find("td.items.panel-toggle").trigger('click') + end + + within "#subscription-line-items" do + expect(page).to have_selector "span#order_subtotal", text: "$15.00" # 3 x $5 items + expect(page).to have_selector "span#order_fees", text: "$3.50" # $3.5 shipping + expect(page).to have_selector "span#order_form_total", text: "$18.50" # 3 x $5 items + $3.5 shipping + end + # Viewing Orders within "tr#so_#{subscription.id}" do expect(page).to have_selector "td.orders.panel-toggle", text: 1 From cead905d0553aaff1ab60479e5d67067db4513b4 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 30 May 2018 12:49:11 +1000 Subject: [PATCH 005/122] Use estimated subscription total for proxy orders if order has not been initialized --- app/serializers/api/admin/proxy_order_serializer.rb | 7 ++----- app/views/admin/subscriptions/_orders_panel.html.haml | 2 +- spec/features/admin/subscriptions_spec.rb | 1 + 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/app/serializers/api/admin/proxy_order_serializer.rb b/app/serializers/api/admin/proxy_order_serializer.rb index f5f24522bde..e496c339575 100644 --- a/app/serializers/api/admin/proxy_order_serializer.rb +++ b/app/serializers/api/admin/proxy_order_serializer.rb @@ -5,11 +5,8 @@ class ProxyOrderSerializer < ActiveModel::Serializer attributes :update_issues def total - if object.total.present? - object.total.to_money.to_s - else - object.subscription.subscription_line_items.sum(&:total_estimate) - end + return unless object.total.present? + object.total.to_money.to_s end def update_issues diff --git a/app/views/admin/subscriptions/_orders_panel.html.haml b/app/views/admin/subscriptions/_orders_panel.html.haml index 7bbf1b20b0b..7314ee244db 100644 --- a/app/views/admin/subscriptions/_orders_panel.html.haml +++ b/app/views/admin/subscriptions/_orders_panel.html.haml @@ -19,7 +19,7 @@ %div{ ng: { bind: "::orderCycleCloses(proxyOrder.order_cycle_id)" } } %td.text-center %span.state{ ng: { class: "proxyOrder.state", bind: 'stateText(proxyOrder.state)' } } - %td.text-center{ ng: { bind: 'proxyOrder.total | currency' } } + %td.text-center{ ng: { bind: '(proxyOrder.total || subscription.estimatedTotal()) | currency' } } %td.actions %a.edit-order.icon-edit.no-text{ href: '{{::proxyOrder.edit_path}}', target: '_blank', 'ofn-with-tip' => t(:edit_order), confirm_order_edit: true } %a.cancel-order.icon-remove.no-text{ href: 'javascript:void(0)', ng: { hide: "proxyOrder.state == 'canceled'", click: "cancelOrder(proxyOrder)" }, 'ofn-with-tip' => t(:cancel_order) } diff --git a/spec/features/admin/subscriptions_spec.rb b/spec/features/admin/subscriptions_spec.rb index ccdac62aef6..3ca4e0efe25 100644 --- a/spec/features/admin/subscriptions_spec.rb +++ b/spec/features/admin/subscriptions_spec.rb @@ -87,6 +87,7 @@ within ".subscription-orders" do expect(page).to have_selector "tr.proxy_order", count: 1 + expect(page).to have_content "$18.50" # 3 x $5 items + $3.5 shipping proxy_order = subscription.proxy_orders.first within "tr#po_#{proxy_order.id}" do From c48889f368cea5a281c890f8acdc5d6afa219bb4 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 3 Aug 2018 11:52:39 +1000 Subject: [PATCH 006/122] Remove duplicate translation key --- config/locales/en.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 9ffd7894f15..bbd76162a0d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2048,7 +2048,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using edit_profile_details_etc: "Change your profile description, images, etc." order_cycle: "Order Cycle" order_cycles: "Order Cycles" - enterprises: "Enterprises" enterprise_relationships: "Enterprise permissions" remove_tax: "Remove tax" enterprise_terms_of_service: "Enterprise Terms of Service" From d5fdda1c46e9742b0ddfa9b35eab11ba85201322 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 3 Aug 2018 11:56:09 +1000 Subject: [PATCH 007/122] Fix typo translating Enterprises --- app/views/admin/subscriptions/setup_explanation.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/subscriptions/setup_explanation.html.haml b/app/views/admin/subscriptions/setup_explanation.html.haml index f771b6af1d9..676483a55ed 100644 --- a/app/views/admin/subscriptions/setup_explanation.html.haml +++ b/app/views/admin/subscriptions/setup_explanation.html.haml @@ -14,7 +14,7 @@ .steps %div = t('.enable_subscriptions_step_1_html', - enterprises_link: link_to(t('admin.enterprises.title'), main_app.admin_enterprises_path, target: '_blank')) + enterprises_link: link_to(t('admin.enterprises.index.title'), main_app.admin_enterprises_path, target: '_blank')) %div= t('.enable_subscriptions_step_2') .row.margin-bottom-20.todo{ class: shipping_and_payment_methods_ok?(@shop) ? 'done' : '' } From c8397024e4a7f6e626983dc45d7f336441fd2f66 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 26 Jul 2018 15:55:42 +0100 Subject: [PATCH 008/122] Streamline Product Import UX flow --- .../import_form_controller.js.coffee | 54 +++++++++--------- .../stylesheets/admin/product_import.css.scss | 36 +++++++----- .../admin/product_import_controller.rb | 16 +++++- app/models/product_import/product_importer.rb | 2 +- .../admin/product_import/_ams_data.html.haml | 1 + .../admin/product_import/import.html.haml | 29 ++++------ config/locales/en.yml | 2 +- spec/features/admin/product_import_spec.rb | 56 ++----------------- 8 files changed, 78 insertions(+), 118 deletions(-) create mode 100644 app/views/admin/product_import/_ams_data.html.haml diff --git a/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee b/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee index 8f031cf4abb..75b506fc664 100644 --- a/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee +++ b/app/assets/javascripts/admin/product_import/controllers/import_form_controller.js.coffee @@ -1,20 +1,22 @@ -angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $http, $filter, ProductImportService, $timeout) -> +angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $http, $filter, ProductImportService, ams_data, $timeout) -> $scope.entries = {} $scope.update_counts = {} $scope.reset_counts = {} - $scope.importSettings = null + $scope.supplier_product_counts = ams_data.supplier_product_counts $scope.updates = {} $scope.updated_total = 0 $scope.updated_ids = [] $scope.update_errors = [] + $scope.step = 'settings' $scope.chunks = 0 $scope.completed = 0 - $scope.percentage = "0%" - $scope.started = false - $scope.finished = false + $scope.percentage = { + import: "0%", + save: "0%" + } $scope.countResettable = () -> angular.forEach $scope.supplier_product_counts, (value, key) -> @@ -25,7 +27,6 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.resetProgress = () -> $scope.chunks = 0 $scope.completed = 0 - $scope.percentage = "0%" $scope.started = false $scope.finished = false @@ -33,22 +34,23 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.confirmSettings = () -> $scope.step = 'import' + $scope.start() $scope.viewResults = () -> $scope.countResettable() $scope.step = 'results' - $scope.resetProgress() $scope.acceptResults = () -> + $scope.resetProgress() $scope.step = 'save' + $scope.start() $scope.finalResults = () -> $scope.step = 'complete' $scope.start = () -> $scope.started = true - $scope.percentage = "1%" - total = $scope.item_count + total = ams_data.item_count size = 100 $scope.chunks = Math.ceil(total / size) @@ -64,15 +66,14 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt i++ $scope.processImport = (start, end) -> - $scope.getSettings() if $scope.importSettings == null $http( - url: $scope.import_url + url: ams_data.import_url method: 'POST' data: 'start': start 'end': end - 'filepath': $scope.filepath - 'settings': $scope.importSettings + 'filepath': ams_data.filepath + 'settings': ams_data.importSettings ).success((data, status) -> angular.merge($scope.entries, angular.fromJson(data['entries'])) $scope.sortUpdates(data['reset_counts']) @@ -83,12 +84,6 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt console.error(data) ) - $scope.getSettings = () -> - $scope.importSettings = { - reset_all_absent: document.getElementsByName('settings[reset_all_absent]')[0].value, - import_into: document.getElementsByName('settings[import_into]')[0].value - } - $scope.sortUpdates = (data) -> angular.forEach data, (value, key) -> if (key in $scope.update_counts) @@ -97,15 +92,14 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.update_counts[key] = value['updates_count'] $scope.processSave = (start, end) -> - $scope.getSettings() if $scope.importSettings == null $http( - url: $scope.save_url + url: ams_data.save_url method: 'POST' data: 'start': start 'end': end - 'filepath': $scope.filepath - 'settings': $scope.importSettings + 'filepath': ams_data.filepath + 'settings': ams_data.importSettings ).success((data, status) -> $scope.sortResults(data['results']) @@ -131,7 +125,7 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.updated_total += value $scope.resetAbsent = () -> - return unless $scope.importSettings['reset_all_absent'] + return unless ams_data.importSettings['reset_all_absent'] enterprises_to_reset = [] angular.forEach $scope.reset_counts, (count, enterprise_id) -> @@ -139,11 +133,11 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt if enterprises_to_reset.length && $scope.updated_ids.length $http( - url: $scope.reset_url + url: ams_data.reset_url method: 'POST' data: - 'filepath': $scope.filepath - 'settings': $scope.importSettings + 'filepath': ams_data.filepath + 'settings': ams_data.importSettings 'reset_absent': true, 'updated_ids': $scope.updated_ids, 'enterprises_to_reset': enterprises_to_reset @@ -155,8 +149,10 @@ angular.module("admin.productImport").controller "ImportFormCtrl", ($scope, $htt $scope.updateProgress = () -> $scope.completed++ - $scope.percentage = String(Math.round(($scope.completed / $scope.chunks) * 100)) + '%' + $scope.percentage[$scope.step] = String(Math.round(($scope.completed / $scope.chunks) * 100)) + '%' if $scope.completed == $scope.chunks - $scope.finished = true + $timeout($scope.viewResults, 1000) if $scope.step == 'import' + $timeout($scope.finalResults, 1000) if $scope.step == 'save' + $scope.resetAbsent() if $scope.step == 'save' diff --git a/app/assets/stylesheets/admin/product_import.css.scss b/app/assets/stylesheets/admin/product_import.css.scss index 91d7e702972..d8ad019af9a 100644 --- a/app/assets/stylesheets/admin/product_import.css.scss +++ b/app/assets/stylesheets/admin/product_import.css.scss @@ -232,29 +232,35 @@ form.product-import, div.post-save-results, div.import-wrapper { } } -form.product-import, div.save-results { - transition: all linear 0.25s; -} +div.import-wrapper { -form.product-import.ng-hide, div.save-results.ng-hide { - opacity: 0; -} + .ng-hide:not(.ng-hide-animate) { + // We have to use !important here to override angular's display properties + // scss-lint:disable ImportantRule + display: block !important; + position: absolute; + opacity: 0; + top: -9999px; + left: -9999px; + } + + .ng-hide-add, .ng-hide-remove, .ng-hide-animate { + transition: all .4s ease-in-out; + } + + form.product-import, div.save-results { + transition: all .4s ease-in-out; + } -div.import-wrapper { div.progress-interface { text-align: center; - transition: all linear 0.25s; + transition: all .4s ease-in-out; button:disabled { background: #ccc !important; } - - } - div.progress-interface.ng-hide { - position: absolute; - width: 100%; - opacity: 0; } + .post-save-results { a.button{ float: left; @@ -279,7 +285,7 @@ div.progress-bar { height: 100%; border-radius: 0.3em; box-shadow: inset 0 0 3px rgba(0,0,0,0.3); - transition: width 0.5s ease-in-out; + transition: width .3s ease-in-out; } } diff --git a/app/controllers/admin/product_import_controller.rb b/app/controllers/admin/product_import_controller.rb index 88d9623b3a4..38ea79a97db 100644 --- a/app/controllers/admin/product_import_controller.rb +++ b/app/controllers/admin/product_import_controller.rb @@ -11,7 +11,6 @@ def index end def import - # Save uploaded file to tmp directory @filepath = save_uploaded_file(params[:file]) @importer = ProductImport::ProductImporter.new(File.new(@filepath), spree_current_user, params[:settings]) @original_filename = params[:file].try(:original_filename) @@ -19,8 +18,7 @@ def import check_file_errors @importer check_spreadsheet_has_data @importer - @tax_categories = Spree::TaxCategory.order('is_default DESC, name ASC') - @shipping_categories = Spree::ShippingCategory.order('name ASC') + @ams_data = ams_data end def validate_data @@ -87,6 +85,18 @@ def save_uploaded_file(upload) end end + def ams_data + { + filepath: @filepath, + item_count: @importer.item_count, + supplier_product_counts: @importer.supplier_products, + import_url: main_app.admin_product_import_process_async_path, + save_url: main_app.admin_product_import_save_async_path, + reset_url: main_app.admin_product_import_reset_async_path, + importSettings: @importer.import_settings, + } + end + # Define custom model class for Cancan permissions def model_class ProductImport::ProductImporter diff --git a/app/models/product_import/product_importer.rb b/app/models/product_import/product_importer.rb index 2dc12a9e74c..6ec06957682 100644 --- a/app/models/product_import/product_importer.rb +++ b/app/models/product_import/product_importer.rb @@ -68,7 +68,7 @@ def suppliers_index end def supplier_products - @processor.supplier_products + @processor.andand.supplier_products end def total_supplier_products diff --git a/app/views/admin/product_import/_ams_data.html.haml b/app/views/admin/product_import/_ams_data.html.haml new file mode 100644 index 00000000000..868538dd9a8 --- /dev/null +++ b/app/views/admin/product_import/_ams_data.html.haml @@ -0,0 +1 @@ += admin_inject_json "admin.productImport", "ams_data", @ams_data \ No newline at end of file diff --git a/app/views/admin/product_import/import.html.haml b/app/views/admin/product_import/import.html.haml index 7a4326e3d85..a760635f6c2 100644 --- a/app/views/admin/product_import/import.html.haml +++ b/app/views/admin/product_import/import.html.haml @@ -1,14 +1,12 @@ - content_for :page_title do #{t('admin.product_import.title')} += render partial: 'ams_data' = render partial: 'spree/admin/shared/product_sub_menu' -.import-wrapper{ng: {app: 'admin.productImport', controller: 'ImportFormCtrl', init: "supplier_product_counts = #{@importer.supplier_products.to_json}"}} +.import-wrapper{ng: {app: 'admin.productImport', controller: 'ImportFormCtrl'}} - = hidden_field_tag "settings[reset_all_absent]", @importer.import_settings['reset_all_absent'], 'ng-model' => "importSettings[reset_all_absent]" - = hidden_field_tag "settings[import_into]", @importer.import_settings['import_into'], 'ng-model' => "importSettings[import_into]" - - - if @importer.item_count == 0 #and @importer.invalid_count + - if @importer.item_count == 0 %h5 = t('.no_valid_entries') %p @@ -19,20 +17,16 @@ = render 'import_options' if @importer.table_headings %br %a.button.proceed{href: '', ng: {click: 'confirmSettings()'}} - = t('.proceed') + = t('.import') %a.button{href: main_app.admin_product_import_path} #{t('admin.cancel')} .progress-interface{ng: {show: 'step == "import"'}} %span.filename = @original_filename %span.percentage - ({{ percentage }}) + ({{ percentage.import }}) .progress-bar - %span.progress-track{class: 'ng-binding', style: "width:{{percentage}}"} - %button.start_import{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; import_url = '#{main_app.admin_product_import_process_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}} - = t('.import') - %button.review{ng: {click: 'viewResults()', disabled: '!finished'}} - = t('.review') + %span.progress-track{class: 'ng-binding', style: "width:{{ percentage.import }}"} %p.red {{ exception }} @@ -53,7 +47,8 @@ = hidden_field_tag :filepath, @filepath = hidden_field_tag "settings[import_into]", @import_into - %a.button.proceed{href: '', ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0', click: 'acceptResults()'}}= t('.proceed') + %a.button.proceed{href: '', ng: {show: 'count((entries | entriesFilterValid:"invalid")) == 0', click: 'acceptResults()'}} + = t('.save') %a.button{href: main_app.admin_product_import_path}= t('admin.cancel') @@ -63,13 +58,9 @@ .progress-interface{ng: {show: 'step == "save"'}} %span.filename - #{t('.save_imported')} ({{ percentage }}) + #{t('.save_imported')} ({{ percentage.save }}) .progress-bar{} - %span.progress-track{ng: {style: "{'width':percentage}"}} - %button.start_save{ng: {click: 'start()', disabled: 'started', init: "item_count = #{@importer.item_count}; save_url = '#{main_app.admin_product_import_save_async_path}'; reset_url = '#{main_app.admin_product_import_reset_async_path}'; filepath = '#{@filepath}'; import_into = '#{@import_into}'"}} - = t('.save') - %button.view_results{ng: {click: 'finalResults()', disabled: '!finished'}} - = t('.results') + %span.progress-track{ng: {style: "{'width': percentage.save }"}} %p.red {{ exception }} diff --git a/config/locales/en.yml b/config/locales/en.yml index 9ffd7894f15..7f85aff2070 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -481,7 +481,7 @@ en: shipping_categories: Shipping Categories import: review: Review - proceed: Proceed + import: Import save: Save results: Results save_imported: Save imported products diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb index 25a44311870..af23ddf9bfa 100644 --- a/spec/features/admin/product_import_spec.rb +++ b/spec/features/admin/product_import_spec.rb @@ -45,9 +45,6 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data expect(page).to have_selector '.item-count', text: "2" @@ -55,9 +52,6 @@ expect(page).to have_selector '.create-count', text: "2" expect(page).to_not have_selector '.update-count' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - save_data expect(page).to have_selector '.created-count', text: '2' @@ -94,9 +88,6 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data expect(page).to have_selector '.item-count', text: "2" @@ -120,18 +111,12 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data expect(page).to have_selector '.item-count', text: "1" expect(page).to have_selector '.create-count', text: "1" expect(page).to_not have_selector '.update-count' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - save_data expect(page).to have_selector '.created-count', text: '1' @@ -156,14 +141,8 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - save_data carrots = Spree::Product.find_by_name('Carrots') @@ -210,14 +189,8 @@ click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - save_data expect(page).to have_selector '.created-count', text: '1' @@ -242,9 +215,6 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data expect(page).to have_selector '.item-count', text: "3" @@ -254,9 +224,6 @@ expect(page).to have_selector '.inv-create-count', text: "2" expect(page).to have_selector '.inv-update-count', text: "1" - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - save_data expect(page).to_not have_selector '.created-count' @@ -345,9 +312,6 @@ attach_file 'file', '/tmp/test.csv' click_button 'Upload' - expect(page).to have_selector 'a.button.proceed', visible: true - click_link 'Proceed' - import_data expect(page).to have_content I18n.t('admin.product_import.import.validation_overview') @@ -363,24 +327,16 @@ private def import_data - expect(page).to have_selector 'button.start_import', visible: true - expect(page).to have_selector "button.review[disabled='disabled']" - - find('button.start_import').trigger 'click' - wait_until { page.find("button.review:not([disabled='disabled'])").present? } - - find('button.review').trigger 'click' + expect(page).to have_selector 'a.button.proceed', visible: true + click_link I18n.t('admin.product_import.import.import') + expect(page).to have_selector 'form.product-import', visible: true expect(page).to have_content I18n.t('admin.product_import.import.validation_overview') end def save_data - expect(page).to have_selector 'button.start_save', visible: true - expect(page).to have_selector "button.view_results[disabled='disabled']" - - find('button.start_save').trigger 'click' - wait_until { page.find("button.view_results:not([disabled='disabled'])").present? } - - find('button.view_results').trigger 'click' + expect(page).to have_selector 'a.button.proceed', visible: true + click_link I18n.t('admin.product_import.import.save') + expect(page).to have_selector 'div.save-results', visible: true expect(page).to have_content I18n.t('admin.product_import.save_results.final_results') end end From b736560d630cfabe7abeacb7de1f5728b615d768 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 3 Aug 2018 14:59:27 +1000 Subject: [PATCH 009/122] Inform about inaccurate subscription totals https://github.com/openfoodfoundation/openfoodnetwork/pull/2346#issuecomment-409822038 --- app/assets/stylesheets/admin/index_panel_buttons.css.scss | 1 + app/views/admin/subscriptions/_review.html.haml | 2 ++ .../admin/subscriptions/_subscription_line_items.html.haml | 2 ++ config/locales/en.yml | 4 ++++ 4 files changed, 9 insertions(+) diff --git a/app/assets/stylesheets/admin/index_panel_buttons.css.scss b/app/assets/stylesheets/admin/index_panel_buttons.css.scss index 50e174eb373..4ff84bac899 100644 --- a/app/assets/stylesheets/admin/index_panel_buttons.css.scss +++ b/app/assets/stylesheets/admin/index_panel_buttons.css.scss @@ -5,6 +5,7 @@ tbody.panel-ctrl { > td { a.update { cursor: pointer; + margin-top: 10px; margin-bottom: 10px; font-size: 1.3rem; background-color: $warning-red; diff --git a/app/views/admin/subscriptions/_review.html.haml b/app/views/admin/subscriptions/_review.html.haml index 38f597a36bc..e1591e6210a 100644 --- a/app/views/admin/subscriptions/_review.html.haml +++ b/app/views/admin/subscriptions/_review.html.haml @@ -91,3 +91,5 @@ \: %td.total.align-center %span#order_form_total {{ subscription.estimatedTotal() | currency }} + %p.notice + = t "this_is_an_estimate", scope: 'admin.subscriptions.subscription_line_items' diff --git a/app/views/admin/subscriptions/_subscription_line_items.html.haml b/app/views/admin/subscriptions/_subscription_line_items.html.haml index 0ef917dd3da..0be91f2c934 100644 --- a/app/views/admin/subscriptions/_subscription_line_items.html.haml +++ b/app/views/admin/subscriptions/_subscription_line_items.html.haml @@ -49,3 +49,5 @@ %td.total.align-center %span#order_form_total {{ subscription.estimatedTotal() | currency }} %td.actions +%p.notice + = t ".this_is_an_estimate" diff --git a/config/locales/en.yml b/config/locales/en.yml index bbd76162a0d..7eee25742ea 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -999,6 +999,10 @@ en: address: 2. Address products: 3. Add Products review: 4. Review & Save + subscription_line_items: + this_is_an_estimate: | + The displayed prices are only an estimate and calculated at the time the subscription is changed. + If you change prices or fees, orders will be updated, but the subscription will still display the old values. details: details: Details invalid_error: Oops! Please fill in all of the required fields... From f0be8ff290022a07b4a413a696b4cacb0b83e101 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 3 Aug 2018 15:07:22 +1000 Subject: [PATCH 010/122] Style proxy order serializer --- app/serializers/api/admin/proxy_order_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/api/admin/proxy_order_serializer.rb b/app/serializers/api/admin/proxy_order_serializer.rb index e496c339575..00f87e3f5dc 100644 --- a/app/serializers/api/admin/proxy_order_serializer.rb +++ b/app/serializers/api/admin/proxy_order_serializer.rb @@ -5,7 +5,7 @@ class ProxyOrderSerializer < ActiveModel::Serializer attributes :update_issues def total - return unless object.total.present? + return if object.total.blank? object.total.to_money.to_s end From 72036a499374f5c512a5d12d66fdfce1cbd99de6 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 6 Aug 2018 09:54:54 +0800 Subject: [PATCH 011/122] Move admin routes from main file --- config/routes.rb | 118 +---------------------------------------- config/routes/admin.rb | 116 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 117 deletions(-) create mode 100644 config/routes/admin.rb diff --git a/config/routes.rb b/config/routes.rb index 229b26e331b..ca058842345 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -58,10 +58,6 @@ resources :webhooks, only: [:create] end - namespace :admin do - resources :bulk_line_items - end - get '/checkout', :to => 'checkout#edit' , :as => :checkout put '/checkout', :to => 'checkout#update' , :as => :update_checkout get '/checkout/paypal_payment/:order_id', to: 'checkout#paypal_payment', as: :paypal_payment @@ -84,119 +80,6 @@ get '/:id/shop', to: 'enterprises#shop', as: 'enterprise_shop' get "/enterprises/:permalink", to: redirect("/") # Legacy enterprise URL - namespace :admin do - resources :order_cycles do - post :bulk_update, on: :collection, as: :bulk_update - - member do - get :clone - post :notify_producers - end - end - - resources :enterprises do - collection do - get :for_order_cycle - get :visible - post :bulk_update, as: :bulk_update - end - - member do - get :welcome - put :register - end - - resources :producer_properties do - post :update_positions, on: :collection - end - - resources :tag_rules, only: [:destroy] - end - - resources :manager_invitations, only: [:create] - - resources :enterprise_relationships - resources :enterprise_roles - - resources :enterprise_fees do - collection do - get :for_order_cycle - post :bulk_update, :as => :bulk_update - end - end - - resources :enterprise_groups do - get :move_up - get :move_down - end - - get '/inventory', to: 'variant_overrides#index' - - get '/product_import', to: 'product_import#index' - post '/product_import', to: 'product_import#import' - post '/product_import/validate_data', to: 'product_import#validate_data', as: 'product_import_process_async' - post '/product_import/save_data', to: 'product_import#save_data', as: 'product_import_save_async' - post '/product_import/reset_absent', to: 'product_import#reset_absent_products', as: 'product_import_reset_async' - - resources :variant_overrides do - post :bulk_update, on: :collection - post :bulk_reset, on: :collection - end - - resources :inventory_items, only: [:create, :update] - - resources :customers, only: [:index, :create, :update, :destroy, :show] - - resources :tag_rules, only: [], format: :json do - get :map_by_tag, on: :collection - end - - resource :content - - resource :accounts_and_billing_settings, only: [:edit, :update] do - collection do - get :show_methods - get :start_job - end - end - - resource :business_model_configuration, only: [:edit, :update], controller: 'business_model_configuration' - - resource :cache_settings - - resource :account, only: [:show], controller: 'account' - - resources :column_preferences, only: [], format: :json do - put :bulk_update, on: :collection - end - - resource :invoice_settings, only: [:edit, :update] - - resource :stripe_connect_settings, only: [:edit, :update] - - resources :stripe_accounts, only: [:destroy] do - get :connect, on: :collection - get :status, on: :collection - end - - resources :schedules, only: [:index, :create, :update, :destroy], format: :json - - resources :subscriptions, only: [:index, :new, :create, :edit, :update] do - put :cancel, on: :member - put :pause, on: :member - put :unpause, on: :member - end - - resources :subscription_line_items, only: [], format: :json do - post :build, on: :collection - end - - resources :proxy_orders, only: [:edit] do - put :cancel, on: :member, format: :json - put :resume, on: :member, format: :json - end - end - namespace :api do resources :enterprises do post :update_image, on: :member @@ -230,6 +113,7 @@ end +require Rails.root.join("config/routes/admin.rb") # Overriding Devise routes to use our own controller Spree::Core::Engine.routes.draw do diff --git a/config/routes/admin.rb b/config/routes/admin.rb new file mode 100644 index 00000000000..ce58bc480bb --- /dev/null +++ b/config/routes/admin.rb @@ -0,0 +1,116 @@ +Openfoodnetwork::Application.routes.draw do + namespace :admin do + resources :bulk_line_items + + resources :order_cycles do + post :bulk_update, on: :collection, as: :bulk_update + + member do + get :clone + post :notify_producers + end + end + + resources :enterprises do + collection do + get :for_order_cycle + get :visible + post :bulk_update, as: :bulk_update + end + + member do + get :welcome + put :register + end + + resources :producer_properties do + post :update_positions, on: :collection + end + + resources :tag_rules, only: [:destroy] + end + + resources :manager_invitations, only: [:create] + + resources :enterprise_relationships + resources :enterprise_roles + + resources :enterprise_fees do + collection do + get :for_order_cycle + post :bulk_update, :as => :bulk_update + end + end + + resources :enterprise_groups do + get :move_up + get :move_down + end + + get '/inventory', to: 'variant_overrides#index' + + get '/product_import', to: 'product_import#index' + post '/product_import', to: 'product_import#import' + post '/product_import/validate_data', to: 'product_import#validate_data', as: 'product_import_process_async' + post '/product_import/save_data', to: 'product_import#save_data', as: 'product_import_save_async' + post '/product_import/reset_absent', to: 'product_import#reset_absent_products', as: 'product_import_reset_async' + + resources :variant_overrides do + post :bulk_update, on: :collection + post :bulk_reset, on: :collection + end + + resources :inventory_items, only: [:create, :update] + + resources :customers, only: [:index, :create, :update, :destroy, :show] + + resources :tag_rules, only: [], format: :json do + get :map_by_tag, on: :collection + end + + resource :content + + resource :accounts_and_billing_settings, only: [:edit, :update] do + collection do + get :show_methods + get :start_job + end + end + + resource :business_model_configuration, only: [:edit, :update], controller: 'business_model_configuration' + + resource :cache_settings + + resource :account, only: [:show], controller: 'account' + + resources :column_preferences, only: [], format: :json do + put :bulk_update, on: :collection + end + + resource :invoice_settings, only: [:edit, :update] + + resource :stripe_connect_settings, only: [:edit, :update] + + resources :stripe_accounts, only: [:destroy] do + get :connect, on: :collection + get :status, on: :collection + end + + resources :schedules, only: [:index, :create, :update, :destroy], format: :json + + resources :subscriptions, only: [:index, :new, :create, :edit, :update] do + put :cancel, on: :member + put :pause, on: :member + put :unpause, on: :member + end + + resources :subscription_line_items, only: [], format: :json do + post :build, on: :collection + end + + resources :proxy_orders, only: [:edit] do + put :cancel, on: :member, format: :json + put :resume, on: :member, format: :json + end + end +end From 4d34693c0524093a1cba8aa452904d2acf387c29 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 6 Aug 2018 09:55:52 +0800 Subject: [PATCH 012/122] Move Spree route customizations from main file --- config/routes.rb | 90 +----------------------------------------- config/routes/spree.rb | 85 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 89 deletions(-) create mode 100644 config/routes/spree.rb diff --git a/config/routes.rb b/config/routes.rb index ca058842345..ad0d3dcc32e 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -114,92 +114,4 @@ end require Rails.root.join("config/routes/admin.rb") - -# Overriding Devise routes to use our own controller -Spree::Core::Engine.routes.draw do - devise_for :spree_user, - :class_name => 'Spree::User', - :controllers => { :sessions => 'spree/user_sessions', - :registrations => 'user_registrations', - :passwords => 'user_passwords', - :confirmations => 'user_confirmations'}, - :skip => [:unlocks, :omniauth_callbacks], - :path_names => { :sign_out => 'logout' }, - :path_prefix => :user -end - - - -Spree::Core::Engine.routes.prepend do - match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post] - match '/admin/reports/order_cycle_management' => 'admin/reports#order_cycle_management', :as => "order_cycle_management_admin_reports", :via => [:get, :post] - match '/admin/reports/packing' => 'admin/reports#packing', :as => "packing_admin_reports", :via => [:get, :post] - match '/admin/reports/group_buys' => 'admin/reports#group_buys', :as => "group_buys_admin_reports", :via => [:get, :post] - match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post] - match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post] - match '/admin/reports/orders_and_fulfillment' => 'admin/reports#orders_and_fulfillment', :as => "orders_and_fulfillment_admin_reports", :via => [:get, :post] - match '/admin/reports/users_and_enterprises' => 'admin/reports#users_and_enterprises', :as => "users_and_enterprises_admin_reports", :via => [:get, :post] - match '/admin/reports/sales_tax' => 'admin/reports#sales_tax', :as => "sales_tax_admin_reports", :via => [:get, :post] - match '/admin/orders/bulk_management' => 'admin/orders#bulk_management', :as => "admin_bulk_order_management" - match '/admin/reports/products_and_inventory' => 'admin/reports#products_and_inventory', :as => "products_and_inventory_admin_reports", :via => [:get, :post] - match '/admin/reports/customers' => 'admin/reports#customers', :as => "customers_admin_reports", :via => [:get, :post] - match '/admin/reports/xero_invoices' => 'admin/reports#xero_invoices', :as => "xero_invoices_admin_reports", :via => [:get, :post] - match '/admin', :to => 'admin/overview#index', :as => :admin - match '/admin/payment_methods/show_provider_preferences' => 'admin/payment_methods#show_provider_preferences', :via => :get - put 'credit_cards/new_from_token', to: 'credit_cards#new_from_token' - - resources :credit_cards - - - namespace :api, :defaults => { :format => 'json' } do - resources :users do - get :authorise_api, on: :collection - end - - resources :products do - collection do - get :managed - get :bulk_products - get :overridable - end - delete :soft_delete - post :clone - - resources :variants do - delete :soft_delete - end - end - - resources :orders do - get :managed, on: :collection - end - end - - namespace :admin do - get '/search/known_users' => "search#known_users", :as => :search_known_users - get '/search/customers' => 'search#customers', :as => :search_customers - get '/search/customer_addresses' => 'search#customer_addresses', :as => :search_customer_addresses - - resources :products do - get :product_distributions, on: :member - get :group_buy_options, on: :member - get :seo, on: :member - - post :bulk_update, :on => :collection, :as => :bulk_update - end - - resources :orders do - get :invoice, on: :member - get :print, on: :member - get :print_ticket, on: :member - get :managed, on: :collection - end - end - - resources :orders do - get :clear, :on => :collection - get :order_cycle_expired, :on => :collection - put :cancel, on: :member - end - -end +require Rails.root.join("config/routes/spree.rb") diff --git a/config/routes/spree.rb b/config/routes/spree.rb new file mode 100644 index 00000000000..a203ab0fb04 --- /dev/null +++ b/config/routes/spree.rb @@ -0,0 +1,85 @@ +# Overriding Devise routes to use our own controller +Spree::Core::Engine.routes.draw do + devise_for :spree_user, + :class_name => 'Spree::User', + :controllers => { :sessions => 'spree/user_sessions', + :registrations => 'user_registrations', + :passwords => 'user_passwords', + :confirmations => 'user_confirmations'}, + :skip => [:unlocks, :omniauth_callbacks], + :path_names => { :sign_out => 'logout' }, + :path_prefix => :user +end + +Spree::Core::Engine.routes.prepend do + match '/admin/reports/orders_and_distributors' => 'admin/reports#orders_and_distributors', :as => "orders_and_distributors_admin_reports", :via => [:get, :post] + match '/admin/reports/order_cycle_management' => 'admin/reports#order_cycle_management', :as => "order_cycle_management_admin_reports", :via => [:get, :post] + match '/admin/reports/packing' => 'admin/reports#packing', :as => "packing_admin_reports", :via => [:get, :post] + match '/admin/reports/group_buys' => 'admin/reports#group_buys', :as => "group_buys_admin_reports", :via => [:get, :post] + match '/admin/reports/bulk_coop' => 'admin/reports#bulk_coop', :as => "bulk_coop_admin_reports", :via => [:get, :post] + match '/admin/reports/payments' => 'admin/reports#payments', :as => "payments_admin_reports", :via => [:get, :post] + match '/admin/reports/orders_and_fulfillment' => 'admin/reports#orders_and_fulfillment', :as => "orders_and_fulfillment_admin_reports", :via => [:get, :post] + match '/admin/reports/users_and_enterprises' => 'admin/reports#users_and_enterprises', :as => "users_and_enterprises_admin_reports", :via => [:get, :post] + match '/admin/reports/sales_tax' => 'admin/reports#sales_tax', :as => "sales_tax_admin_reports", :via => [:get, :post] + match '/admin/orders/bulk_management' => 'admin/orders#bulk_management', :as => "admin_bulk_order_management" + match '/admin/reports/products_and_inventory' => 'admin/reports#products_and_inventory', :as => "products_and_inventory_admin_reports", :via => [:get, :post] + match '/admin/reports/customers' => 'admin/reports#customers', :as => "customers_admin_reports", :via => [:get, :post] + match '/admin/reports/xero_invoices' => 'admin/reports#xero_invoices', :as => "xero_invoices_admin_reports", :via => [:get, :post] + match '/admin', :to => 'admin/overview#index', :as => :admin + match '/admin/payment_methods/show_provider_preferences' => 'admin/payment_methods#show_provider_preferences', :via => :get + put 'credit_cards/new_from_token', to: 'credit_cards#new_from_token' + + resources :credit_cards + + + namespace :api, :defaults => { :format => 'json' } do + resources :users do + get :authorise_api, on: :collection + end + + resources :products do + collection do + get :managed + get :bulk_products + get :overridable + end + delete :soft_delete + post :clone + + resources :variants do + delete :soft_delete + end + end + + resources :orders do + get :managed, on: :collection + end + end + + namespace :admin do + get '/search/known_users' => "search#known_users", :as => :search_known_users + get '/search/customers' => 'search#customers', :as => :search_customers + get '/search/customer_addresses' => 'search#customer_addresses', :as => :search_customer_addresses + + resources :products do + get :product_distributions, on: :member + get :group_buy_options, on: :member + get :seo, on: :member + + post :bulk_update, :on => :collection, :as => :bulk_update + end + + resources :orders do + get :invoice, on: :member + get :print, on: :member + get :print_ticket, on: :member + get :managed, on: :collection + end + end + + resources :orders do + get :clear, :on => :collection + get :order_cycle_expired, :on => :collection + put :cancel, on: :member + end +end From b67c8cc9f1dc01291cdac78cee010aac26206b53 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 6 Aug 2018 09:58:40 +0800 Subject: [PATCH 013/122] Improve requiring of additional routes This is more appropriate, and allows changes the separate route files to be loaded automatically in the development environment. --- config/application.rb | 6 ++++++ config/routes.rb | 3 --- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/config/application.rb b/config/application.rb index f93d224129f..ea3539556b2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -92,6 +92,12 @@ class Application < Rails::Application #{config.root}/app/jobs ) + config.paths["config/routes"] = %w( + config/routes.rb + config/routes/admin.rb + config/routes/spree.rb + ).map { |relative_path| Rails.root.join(relative_path) } + # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. # config.plugins = [ :exception_notification, :ssl_requirement, :all ] diff --git a/config/routes.rb b/config/routes.rb index ad0d3dcc32e..42488bf3367 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -112,6 +112,3 @@ mount Spree::Core::Engine, :at => '/' end - -require Rails.root.join("config/routes/admin.rb") -require Rails.root.join("config/routes/spree.rb") From a494fb274ea5fdf2d2002eae6ee5fe2a2ebe545b Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 6 Aug 2018 18:12:35 +0800 Subject: [PATCH 014/122] Disable rubocop cop Rails/ActiveRecordAliases The methods :update! and :update (to replace :update_attributes! and :update_attributes) were not added until Rails 4. See this for more information: https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Rails/ActiveRecordAliases --- .rubocop.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.rubocop.yml b/.rubocop.yml index 25acf35f577..80d4c1bf7e6 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -63,6 +63,10 @@ Rails/DynamicFindBy: Rails/FindBy: Enabled: false +# Same as above, #update! is not available until Rails 4 +Rails/ActiveRecordAliases: + Enabled: false + # This should be the programmer's discretion, perhaps we should review all of # the uses of it an make specific exceptions though. Rails/SkipsModelValidations: From d77a94335bfcd4cbd5ed929d4297c22147c3c5ac Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Mon, 6 Aug 2018 18:23:44 +0800 Subject: [PATCH 015/122] Update .rubocop_todo.yml --- .rubocop_todo.yml | 96 +++++------------------------------------------ 1 file changed, 9 insertions(+), 87 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b9bd3d09087..65e05628caf 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,12 +1,12 @@ # This configuration was generated by # `rubocop --auto-gen-config --exclude-limit 1400` -# on 2018-07-20 18:57:26 +0200 using RuboCop version 0.55.0. +# on 2018-08-06 18:22:59 +0800 using RuboCop version 0.55.0. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 36 +# Offense count: 35 # Cop supports --auto-correct. # Configuration parameters: Include, TreatCommentsAsGroupSeparators. # Include: **/*.gemfile, **/Gemfile, **/gems.rb @@ -263,7 +263,7 @@ Layout/EmptyLinesAroundArguments: Exclude: - 'spec/archive/features/consumer/checkout_spec.rb' -# Offense count: 65 +# Offense count: 64 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle. # SupportedStyles: empty_lines, no_empty_lines @@ -364,7 +364,7 @@ Layout/EndAlignment: - 'app/serializers/api/admin/for_order_cycle/supplied_product_serializer.rb' - 'app/serializers/api/admin/order_cycle_serializer.rb' -# Offense count: 49 +# Offense count: 48 # Cop supports --auto-correct. # Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. Layout/ExtraSpacing: @@ -387,7 +387,6 @@ Layout/ExtraSpacing: - 'spec/features/admin/bulk_order_management_spec.rb' - 'spec/features/admin/bulk_product_update_spec.rb' - 'spec/features/admin/orders_spec.rb' - - 'spec/features/admin/product_import_spec.rb' - 'spec/features/admin/reports_spec.rb' - 'spec/features/consumer/groups_spec.rb' - 'spec/features/consumer/shopping/shopping_spec.rb' @@ -794,7 +793,7 @@ Layout/SpaceInsideBlockBraces: - 'spec/spec_helper.rb' - 'spec/support/cancan_helper.rb' -# Offense count: 798 +# Offense count: 772 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces. # SupportedStyles: space, no_space, compact @@ -976,11 +975,6 @@ Lint/AmbiguousOperator: Exclude: - 'spec/controllers/spree/admin/payments_controller_spec.rb' -# Offense count: 2 -Lint/BooleanSymbol: - Exclude: - - 'spec/features/consumer/shopping/embedded_groups_spec.rb' - # Offense count: 4 Lint/DuplicateMethods: Exclude: @@ -1030,7 +1024,7 @@ Lint/ShadowingOuterLocalVariable: - 'app/models/spree/product_set.rb' - 'spec/models/model_set_spec.rb' -# Offense count: 7 +# Offense count: 6 # Cop supports --auto-correct. Lint/StringConversionInInterpolation: Exclude: @@ -1040,7 +1034,6 @@ Lint/StringConversionInInterpolation: - 'app/helpers/injection_helper.rb' - 'app/helpers/spree/products_helper_decorator.rb' - 'app/serializers/api/admin/tag_rule_serializer.rb' - - 'spec/features/admin/product_import_spec.rb' # Offense count: 2 Lint/UnderscorePrefixedVariableName: @@ -1171,7 +1164,7 @@ Lint/Void: - 'spec/serializers/enterprise_serializer_spec.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 998 +# Offense count: 993 # Configuration parameters: CountComments, ExcludedMethods. Metrics/BlockLength: Max: 776 @@ -1326,76 +1319,6 @@ Performance/UnneededSort: - 'app/models/spree/product_decorator.rb' - 'spec/features/admin/order_cycles_spec.rb' -# Offense count: 206 -# Cop supports --auto-correct. -Rails/ActiveRecordAliases: - Exclude: - - 'app/controllers/admin/bulk_line_items_controller.rb' - - 'app/controllers/admin/enterprises_controller.rb' - - 'app/controllers/admin/subscriptions_controller.rb' - - 'app/controllers/api/customers_controller.rb' - - 'app/controllers/api/enterprises_controller.rb' - - 'app/controllers/api/product_images_controller.rb' - - 'app/controllers/checkout_controller.rb' - - 'app/controllers/spree/admin/line_items_controller_decorator.rb' - - 'app/controllers/spree/credit_cards_controller.rb' - - 'app/controllers/spree/orders_controller_decorator.rb' - - 'app/helpers/i18n_helper.rb' - - 'app/jobs/subscription_placement_job.rb' - - 'app/jobs/update_account_invoices.rb' - - 'app/jobs/update_billable_periods.rb' - - 'app/models/billable_period.rb' - - 'app/models/spree/adjustment_decorator.rb' - - 'app/models/spree/line_item_decorator.rb' - - 'app/models/spree/order_decorator.rb' - - 'app/models/spree/product_set.rb' - - 'app/services/create_mail_method.rb' - - 'app/services/line_item_syncer.rb' - - 'app/services/order_factory.rb' - - 'app/services/order_syncer.rb' - - 'lib/open_food_network/order_cycle_form_applicator.rb' - - 'lib/open_food_network/subscription_payment_updater.rb' - - 'lib/stripe/profile_storer.rb' - - 'spec/controllers/admin/proxy_orders_controller_spec.rb' - - 'spec/controllers/admin/subscriptions_controller_spec.rb' - - 'spec/controllers/line_items_controller_spec.rb' - - 'spec/controllers/spree/admin/payment_methods_controller_spec.rb' - - 'spec/controllers/spree/orders_controller_spec.rb' - - 'spec/features/admin/bulk_order_management_spec.rb' - - 'spec/features/admin/order_cycles_spec.rb' - - 'spec/features/admin/orders_spec.rb' - - 'spec/features/admin/subscriptions_spec.rb' - - 'spec/features/admin/variants_spec.rb' - - 'spec/features/consumer/account_spec.rb' - - 'spec/features/consumer/registration_spec.rb' - - 'spec/features/consumer/shopping/cart_spec.rb' - - 'spec/features/consumer/shopping/orders_spec.rb' - - 'spec/features/consumer/shopping/shopping_spec.rb' - - 'spec/jobs/subscription_confirm_job_spec.rb' - - 'spec/jobs/subscription_placement_job_spec.rb' - - 'spec/jobs/update_account_invoices_spec.rb' - - 'spec/jobs/update_billable_periods_spec.rb' - - 'spec/lib/open_food_network/products_cache_refreshment_spec.rb' - - 'spec/lib/open_food_network/products_cache_spec.rb' - - 'spec/lib/open_food_network/proxy_order_syncer_spec.rb' - - 'spec/models/customer_spec.rb' - - 'spec/models/enterprise_caching_spec.rb' - - 'spec/models/exchange_spec.rb' - - 'spec/models/order_cycle_spec.rb' - - 'spec/models/producer_property_spec.rb' - - 'spec/models/proxy_order_spec.rb' - - 'spec/models/spree/adjustment_spec.rb' - - 'spec/models/spree/credit_card_spec.rb' - - 'spec/models/spree/line_item_spec.rb' - - 'spec/models/spree/order_spec.rb' - - 'spec/models/spree/product_spec.rb' - - 'spec/models/spree/user_spec.rb' - - 'spec/models/spree/variant_spec.rb' - - 'spec/models/variant_override_spec.rb' - - 'spec/requests/checkout/stripe_connect_spec.rb' - - 'spec/services/order_syncer_spec.rb' - - 'spec/services/subscription_estimator_spec.rb' - # Offense count: 11 # Cop supports --auto-correct. # Configuration parameters: NilOrEmpty, NotPresent, UnlessPresent. @@ -1951,7 +1874,7 @@ Style/GuardClause: - 'spec/support/request/distribution_helper.rb' - 'spec/support/request/shop_workflow.rb' -# Offense count: 970 +# Offense count: 968 # Cop supports --auto-correct. # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys @@ -2080,7 +2003,6 @@ Style/HashSyntax: - 'spec/features/admin/subscriptions_spec.rb' - 'spec/features/admin/variant_overrides_spec.rb' - 'spec/features/consumer/account/cards_spec.rb' - - 'spec/features/consumer/shopping/embedded_groups_spec.rb' - 'spec/features/consumer/shopping/products_spec.rb' - 'spec/features/consumer/shopping/shopping_spec.rb' - 'spec/jobs/subscription_placement_job_spec.rb' @@ -2538,7 +2460,7 @@ Style/UnneededPercentQ: - 'spec/features/consumer/producers_spec.rb' - 'spec/support/request/web_helper.rb' -# Offense count: 6631 +# Offense count: 6607 # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # URISchemes: http, https Metrics/LineLength: From 30fad228c5f3e692d88bb0dc29dbf63ba9162688 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 09:24:31 +1000 Subject: [PATCH 016/122] Remove code duplication in spec helper --- spec/support/request/authentication_workflow.rb | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/spec/support/request/authentication_workflow.rb b/spec/support/request/authentication_workflow.rb index 61ba32e1b05..5d3181ea4f5 100644 --- a/spec/support/request/authentication_workflow.rb +++ b/spec/support/request/authentication_workflow.rb @@ -20,16 +20,7 @@ def quick_login_as_admin end def login_to_admin_section - admin_role = Spree::Role.find_or_create_by_name!('admin') - admin_user = create(:user, - :password => 'passw0rd', - :password_confirmation => 'passw0rd', - :remember_me => false, - :persistence_token => 'pass', - :login => 'admin@ofn.org') - - admin_user.spree_roles << admin_role - quick_login_as admin_user + quick_login_as_admin visit spree.admin_path end From 0edf393c12ddef70c36f83fee10848c861d06997 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 10:56:42 +1000 Subject: [PATCH 017/122] Use quick login to speed up spec We don't need to visit the admin dashboard before each spec. On my machine: 54 seconds before 47 seconds after speed up by 13% --- .../admin/bulk_product_update_spec.rb | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index 26090d4330d..66e06e094b8 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -8,8 +8,8 @@ include WebHelper describe "listing products" do - before :each do - login_to_admin_section + before do + quick_login_as_admin end it "displays a list of products" do @@ -102,8 +102,8 @@ end describe "listing variants" do - before :each do - login_to_admin_section + before do + quick_login_as_admin end it "displays a list of variants for each product" do @@ -171,8 +171,7 @@ d = FactoryBot.create(:distributor_enterprise) taxon = create(:taxon) - login_to_admin_section - + quick_login_as_admin visit spree.admin_products_path find("a", text: "NEW PRODUCT").click @@ -195,7 +194,7 @@ scenario "creating new variants" do # Given a product without variants or a unit p = FactoryBot.create(:product, variant_unit: 'weight', variant_unit_scale: 1000) - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path # I should see an add variant button @@ -244,8 +243,7 @@ t2 = FactoryBot.create(:taxon) p = FactoryBot.create(:product, supplier: s1, available_on: Date.current, variant_unit: 'volume', variant_unit_scale: 1, primary_taxon: t2, sku: "OLD SKU") - login_to_admin_section - + quick_login_as_admin visit spree.admin_products_path find("div#columns-dropdown", :text => "COLUMNS").click @@ -290,8 +288,7 @@ scenario "updating a product with a variant unit of 'items'" do p = FactoryBot.create(:product, variant_unit: 'weight', variant_unit_scale: 1000) - login_to_admin_section - + quick_login_as_admin visit spree.admin_products_path expect(page).to have_select "variant_unit_with_scale", selected: "Weight (kg)" @@ -316,8 +313,7 @@ v = p.variants.first v.update_column(:sku, "VARIANTSKU") - login_to_admin_section - + quick_login_as_admin visit spree.admin_products_path expect(page).to have_selector "a.view-variants", count: 1 find("a.view-variants").trigger('click') @@ -355,8 +351,7 @@ p = FactoryBot.create(:product) v = FactoryBot.create(:variant, product: p, price: 3.0) - login_to_admin_section - + quick_login_as_admin visit spree.admin_products_path expect(page).to have_selector "a.view-variants", count: 1 find("a.view-variants").trigger('click') @@ -379,7 +374,7 @@ scenario "updating a product mutiple times without refresh" do p = FactoryBot.create(:product, name: 'original name') - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path @@ -412,7 +407,7 @@ scenario "updating a product after cloning a product" do p = FactoryBot.create(:product, :name => "product 1") - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path @@ -435,7 +430,7 @@ s2 = create(:supplier_enterprise) p1 = FactoryBot.create(:simple_product, :name => "product1", supplier: s1) p2 = FactoryBot.create(:simple_product, :name => "product2", supplier: s2) - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path @@ -541,7 +536,7 @@ p1 = FactoryBot.create(:product, :name => "P1") p2 = FactoryBot.create(:product, :name => "P2") p3 = FactoryBot.create(:product, :name => "P3") - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path @@ -567,7 +562,7 @@ describe "using column display dropdown" do it "shows a column display dropdown, which shows a list of columns when clicked" do FactoryBot.create(:simple_product) - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path @@ -599,7 +594,7 @@ s2 = create(:supplier_enterprise) p1 = FactoryBot.create(:simple_product, :name => "product1", supplier: s1) p2 = FactoryBot.create(:simple_product, :name => "product2", supplier: s2) - login_to_admin_section + quick_login_as_admin visit spree.admin_products_path From edb32218b0de1cda68a84875dc6b15ab59cb916e Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 12:11:15 +1000 Subject: [PATCH 018/122] Use quick login to speed up product edit spec From 48s to 44s: 8% speed up --- spec/features/admin/enterprise_fees_spec.rb | 22 ++++++++------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/spec/features/admin/enterprise_fees_spec.rb b/spec/features/admin/enterprise_fees_spec.rb index 9307574bc4d..50d84121160 100644 --- a/spec/features/admin/enterprise_fees_spec.rb +++ b/spec/features/admin/enterprise_fees_spec.rb @@ -30,9 +30,8 @@ e = create(:supplier_enterprise, name: 'Feedme') # When I go to the enterprise fees page - login_to_admin_section - click_link 'Configuration' - click_link 'Enterprise Fees' + quick_login_as_admin + visit admin_enterprise_fees_path # And I fill in the fields for a new enterprise fee and click update select 'Feedme', from: 'enterprise_fee_set_collection_attributes_0_enterprise_id' @@ -60,9 +59,8 @@ enterprise = create(:enterprise, name: 'Foo') # When I go to the enterprise fees page - login_to_admin_section - click_link 'Configuration' - click_link 'Enterprise Fees' + quick_login_as_admin + visit admin_enterprise_fees_path # And I update the fields for the enterprise fee and click update select 'Foo', from: 'enterprise_fee_set_collection_attributes_0_enterprise_id' @@ -95,11 +93,8 @@ fee = create(:enterprise_fee) # When I go to the enterprise fees page - login_to_admin_section - click_link 'Configuration' - expect(page).to have_link 'Enterprise Fees' - click_link 'Enterprise Fees' - expect(page).to have_content 'Enterprise Fees' + quick_login_as_admin + visit admin_enterprise_fees_path # And I click delete find("a.delete-resource").click @@ -117,9 +112,8 @@ create(:product_distribution, product: p, distributor: d, enterprise_fee: fee) # When I go to the enterprise fees page - login_to_admin_section - click_link 'Configuration' - click_link 'Enterprise Fees' + quick_login_as_admin + visit admin_enterprise_fees_path # And I click delete find("a.delete-resource").click From 126f312c6b124b036baeb06b69a4dff4ab20497c Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 12:30:59 +1000 Subject: [PATCH 019/122] Make spec more robust not relying on order Enterprises can be in different order. Using `with_options` doesn't care about the order. --- spec/features/admin/enterprise_relationships_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb index c40b8e8f3b9..82c92850d4c 100644 --- a/spec/features/admin/enterprise_relationships_spec.rb +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -111,7 +111,7 @@ scenario "enterprise user can only add their own enterprises as parent" do visit admin_enterprise_relationships_path page.should have_select2 'enterprise_relationship_parent_id', options: ['', d1.name] - page.should have_select2 'enterprise_relationship_child_id', options: ['', d1.name, d2.name, d3.name] + page.should have_select2 'enterprise_relationship_child_id', with_options: ['', d1.name, d2.name, d3.name] end end From 0b390549546b778f2b5333453f8a3e737ea14504 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 12:33:26 +1000 Subject: [PATCH 020/122] Speed up relationships spec From 18s to 12s: 33% speed up --- spec/features/admin/enterprise_relationships_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/features/admin/enterprise_relationships_spec.rb b/spec/features/admin/enterprise_relationships_spec.rb index 82c92850d4c..45d26a9e876 100644 --- a/spec/features/admin/enterprise_relationships_spec.rb +++ b/spec/features/admin/enterprise_relationships_spec.rb @@ -9,7 +9,7 @@ context "as a site administrator" do - before { login_to_admin_section } + before { quick_login_as_admin } scenario "listing relationships" do # Given some enterprises with relationships @@ -19,6 +19,7 @@ create(:enterprise_relationship, parent: e3, child: e4, permissions_list: [:add_to_order_cycle, :manage_products]) # When I go to the relationships page + visit spree.admin_path click_link 'Enterprises' click_link 'Permissions' @@ -97,7 +98,7 @@ let!(:er2) { create(:enterprise_relationship, parent: d2, child: d1) } let!(:er3) { create(:enterprise_relationship, parent: d2, child: d3) } - before { login_to_admin_as enterprise_user } + before { quick_login_as enterprise_user } scenario "enterprise user can only see relationships involving their enterprises" do visit admin_enterprise_relationships_path @@ -107,7 +108,6 @@ page.should_not have_relationship d2, d3 end - scenario "enterprise user can only add their own enterprises as parent" do visit admin_enterprise_relationships_path page.should have_select2 'enterprise_relationship_parent_id', options: ['', d1.name] From e4ebeb8a29b167822568cbfabe0ae785881051d3 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 12:37:49 +1000 Subject: [PATCH 021/122] Remove dead spec code The code has been inactive since 2015 and was probably obsolete anyway. --- spec/features/admin/enterprise_user_spec.rb | 65 --------------------- 1 file changed, 65 deletions(-) diff --git a/spec/features/admin/enterprise_user_spec.rb b/spec/features/admin/enterprise_user_spec.rb index 0a070a80ea1..5b3f1412a04 100644 --- a/spec/features/admin/enterprise_user_spec.rb +++ b/spec/features/admin/enterprise_user_spec.rb @@ -33,71 +33,6 @@ end end - # This case no longer exists as anyone with an enterprise can supply into the system. - # Or can they?? There is no producer profile anyway. - # TODO discuss what parts of this are still necessary in which cases. - pending "with only a profile-level enterprise" do - before do - user.enterprise_roles.create! enterprise: supplier_profile - user.enterprise_roles.create! enterprise: distributor_profile - login_to_admin_as user - end - - it "shows me only menu items for enterprise management" do - page.should have_admin_menu_item 'Dashboard' - page.should have_admin_menu_item 'Enterprises' - - ['Orders', 'Reports', 'Configuration', 'Promotions', 'Users', 'Order Cycles'].each do |menu_item_name| - page.should_not have_admin_menu_item menu_item_name - end - end - - describe "dashboard" do - it "shows me enterprise management controls" do - within('#enterprises') do - page.should have_selector 'h3', text: 'My Enterprises' - page.should have_link 'CREATE NEW' - page.should have_link supplier_profile.name - page.should have_link 'MANAGE MY ENTERPRISES' - end - end - - it "shows me product management controls, but not order_cycle controls" do - page.should have_selector '#products' - page.should_not have_selector '#order_cycles' - end - - it "shows me enterprise product info but not payment methods, shipping methods or enterprise fees" do - # Payment methods, shipping methods, enterprise fees - page.should_not have_selector '.hubs_tab span', text: 'Payment Methods' - page.should_not have_selector '.hubs_tab span', text: 'Shipping Methods' - page.should_not have_selector '.hubs_tab span', text: 'Enterprise Fees' - end - end - - it "shows me only profile options on the enterprise listing page" do - click_link 'Enterprises' - - within "tr.enterprise-#{supplier_profile.id}" do - page.should_not have_link 'Enterprise Fees' - end - - within "tr.enterprise-#{distributor_profile.id}" do - page.should_not have_link 'Payment Methods' - page.should_not have_link 'Shipping Methods' - page.should_not have_link 'Enterprise Fees' - end - end - - it "shows me only profile fields on the hub edit page" do - click_link distributor_profile.name - - page.should_not have_selector '#payment_methods' - page.should_not have_selector '#shipping_methods' - page.should_not have_selector '#enterprise_fees' - end - end - describe "system management lockdown" do before do user.enterprise_roles.create!(enterprise: supplier1) From f0da823445a138e016dde623ee16c25f4cc7a334 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 12:41:07 +1000 Subject: [PATCH 022/122] Speed up enterprise user spec From 1.9s to 1.7s. --- spec/features/admin/enterprise_user_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/enterprise_user_spec.rb b/spec/features/admin/enterprise_user_spec.rb index 5b3f1412a04..8ef52ee6b4a 100644 --- a/spec/features/admin/enterprise_user_spec.rb +++ b/spec/features/admin/enterprise_user_spec.rb @@ -36,7 +36,7 @@ describe "system management lockdown" do before do user.enterprise_roles.create!(enterprise: supplier1) - login_to_admin_as user + quick_login_as user end scenario "should not be able to see system configuration" do From 121bc51feb1f61d82e42377e67f12825f32bf97d Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 13:54:29 +1000 Subject: [PATCH 023/122] Speed up admin enterprises spec From 6.5s to 5.3s. --- spec/features/admin/enterprises/index_spec.rb | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/features/admin/enterprises/index_spec.rb b/spec/features/admin/enterprises/index_spec.rb index 5786e7a75b1..f8f1a5f263c 100644 --- a/spec/features/admin/enterprises/index_spec.rb +++ b/spec/features/admin/enterprises/index_spec.rb @@ -45,8 +45,8 @@ context "without violating rules" do before do - login_to_admin_section - click_link 'Enterprises' + quick_login_as_admin + visit admin_enterprises_path end it "updates the enterprises" do @@ -72,8 +72,8 @@ d_manager.enterprise_roles.build(enterprise: second_distributor).save expect(d.owner).to_not eq d_manager - login_to_admin_section - click_link 'Enterprises' + quick_login_as_admin + visit admin_enterprises_path end it "does not update the enterprises and displays errors" do @@ -106,12 +106,12 @@ enterprise_manager.enterprise_roles.build(enterprise: supplier1).save enterprise_manager.enterprise_roles.build(enterprise: distributor1).save - login_to_admin_as enterprise_manager + quick_login_as enterprise_manager end context "listing enterprises", js: true do it "displays enterprises I have permission to manage" do - click_link "Enterprises" + visit admin_enterprises_path within("tbody#e_#{distributor1.id}") do expect(page).to have_content distributor1.name @@ -139,7 +139,7 @@ it "does not give me an option to change or update the package and producer properties of enterprises I manage" do - click_link "Enterprises" + visit admin_enterprises_path within("tbody#e_#{distributor1.id}") do find("td.producer").click @@ -162,12 +162,12 @@ let!(:owned_distributor) { create(:distributor_enterprise, name: 'Owned Distributor', owner: user) } before do - login_to_admin_as user + quick_login_as user end context "listing enterprises", js: true do it "allows me to change or update the package and producer properties of enterprises I manage" do - click_link "Enterprises" + visit admin_enterprises_path within("tbody#e_#{owned_distributor.id}") do # Open the producer panel From f4cd5a7e4b9e524d57c24004a750f8c9fc4593d2 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 14:11:03 +1000 Subject: [PATCH 024/122] Speed up admin enterprise spec From 40s to 36s. --- spec/features/admin/enterprises_spec.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index 1a35aebffed..c7df54a6ac3 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -205,8 +205,8 @@ s = create(:supplier_enterprise) # When I go to its properties page - login_to_admin_section - click_link 'Enterprises' + quick_login_as_admin + visit admin_enterprises_path within(".enterprise-#{s.id}") { click_link 'Properties' } # And I create a property @@ -229,7 +229,7 @@ s.producer_properties.create! property_name: 'Certified Organic', value: 'NASAA 12345' # When I go to its properties page - login_to_admin_section + quick_login_as_admin visit main_app.admin_enterprise_producer_properties_path(s) # And I update the property @@ -252,7 +252,7 @@ pp = s.producer_properties.create! property_name: 'Certified Organic', value: 'NASAA 12345' # When I go to its properties page - login_to_admin_section + quick_login_as_admin visit main_app.admin_enterprise_producer_properties_path(s) # And I remove the property @@ -310,7 +310,7 @@ enterprise_user.enterprise_roles.build(enterprise: supplier1).save enterprise_user.enterprise_roles.build(enterprise: distributor1).save - login_to_admin_as enterprise_user + quick_login_as enterprise_user end context "when I have reached my enterprise ownership limit" do @@ -318,7 +318,7 @@ supplier1.reload enterprise_user.owned_enterprises.push [supplier1] - click_link "Enterprises" + visit admin_enterprises_path page.should have_content supplier1.name page.should have_content distributor1.name @@ -335,7 +335,7 @@ context "creating an enterprise" do before do # When I create an enterprise - click_link 'Enterprises' + visit admin_enterprises_path click_link 'New Enterprise' fill_in 'enterprise_name', with: 'zzz' fill_in 'enterprise_email_address', with: 'bob@example.com' @@ -375,7 +375,7 @@ end scenario "editing enterprises I manage" do - click_link 'Enterprises' + visit admin_enterprises_path within("tbody#e_#{distributor1.id}") { click_link 'Manage' } fill_in 'enterprise_name', :with => 'Eaterprises' @@ -391,7 +391,7 @@ describe "enterprises I have edit permission for, but do not manage" do it "allows me to edit them" do - click_link 'Enterprises' + visit admin_enterprises_path within("tbody#e_#{distributor3.id}") { click_link 'Manage' } fill_in 'enterprise_name', :with => 'Eaterprises' @@ -406,7 +406,7 @@ end it "does not show links to manage shipping methods, payment methods or enterprise fees on the edit page" do - click_link 'Enterprises' + visit admin_enterprises_path within("tbody#e_#{distributor3.id}") { click_link 'Manage' } within(".side_menu") do @@ -418,7 +418,7 @@ end scenario "editing images for an enterprise" do - click_link 'Enterprises' + visit admin_enterprises_path within("tbody#e_#{distributor1.id}") { click_link 'Manage' } within(".side_menu") do @@ -431,7 +431,7 @@ scenario "managing producer properties" do create(:property, name: "Certified Organic") - click_link 'Enterprises' + visit admin_enterprises_path within("#e_#{supplier1.id}") { click_link 'Manage' } within(".side_menu") do click_link "Properties" From 71a381e48e56f0d9f00dcb3d030d333a7632e590 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 14:32:52 +1000 Subject: [PATCH 025/122] Speed up order cycles spec From 68 to 63 seconds. --- spec/features/admin/order_cycles_spec.rb | 49 ++++++++++++------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index 30d49fd39f3..bfb6d4d30e9 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -129,7 +129,7 @@ context 'using datepickers' do it "correctly opens the datepicker and changes the date field" do - login_to_admin_section + quick_login_as_admin visit admin_order_cycles_path within("tr.order-cycle-#{oc_de.id}") do @@ -177,8 +177,8 @@ distributor_fee = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee') # When I go to the new order cycle page - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path click_link 'New Order Cycle' # Select a coordinator since there are two available @@ -304,8 +304,8 @@ distributor_fee2 = create(:enterprise_fee, enterprise: distributor, name: 'Distributor fee 2') # When I go to its edit page - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path click_link oc.name wait_until { page.find('#order_cycle_name').value.present? } @@ -429,9 +429,8 @@ oc.distributors.last.update_attribute :name, 'ZZZZ' # When I edit it - login_to_admin_section - click_link 'Order Cycles' - click_link oc.name + quick_login_as_admin + visit edit_admin_order_cycle_path(oc) wait_until { page.find('#order_cycle_name').value.present? } # Then I should see the basic settings @@ -498,7 +497,6 @@ scenario "editing an order cycle with an exchange between the same enterprise" do c = create(:distributor_enterprise, is_primary_producer: true) - login_to_admin_section # Given two order cycles, one with a mono-enterprise incoming exchange... oc_incoming = create(:simple_order_cycle, suppliers: [c], coordinator: c) @@ -507,6 +505,7 @@ oc_outgoing = create(:simple_order_cycle, coordinator: c, distributors: [c]) # When I edit the first order cycle, the exchange should appear as incoming + quick_login_as_admin visit edit_admin_order_cycle_path(oc_incoming) page.should have_selector 'table.exchanges tr.supplier' page.should_not have_selector 'table.exchanges tr.distributor' @@ -528,8 +527,8 @@ # When I go to the order cycles page - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path # And I fill in some new opening/closing times and save them within("tr.order-cycle-#{oc1.id}") do @@ -581,8 +580,8 @@ oc = create(:simple_order_cycle) # When I clone it - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path within "tr.order-cycle-#{oc.id}" do find('a.clone-order-cycle').click end @@ -607,9 +606,8 @@ ExchangeVariant.where(exchange_id: exchange_ids, variant_id: p.master.id).should_not be_empty # When I go to the order cycle page and remove the obsolete master - login_to_admin_section - click_link 'Order Cycles' - click_link oc.name + quick_login_as_admin + visit edit_admin_order_cycle_path(oc) within("table.exchanges tbody tr.supplier") { page.find('td.products').click } page.find("#order_cycle_incoming_exchange_0_variants_#{p.master.id}", visible: true).trigger('click') # uncheck click_button "Update" @@ -631,7 +629,7 @@ end it "displays a warning on the order cycles screen" do - login_to_admin_section + quick_login_as_admin visit admin_order_cycles_path page.should have_content "The hub #{hub.name} is listed in an active order cycle, but does not have valid shipping and payment methods. Until you set these up, customers will not be able to shop at this hub." end @@ -684,13 +682,14 @@ @new_user.enterprise_roles.build(enterprise: supplier_managed).save @new_user.enterprise_roles.build(enterprise: distributor_managed).save - login_to_admin_as @new_user + quick_login_as @new_user end scenario "viewing a list of order cycles I am coordinating" do oc_user_coordinating = create(:simple_order_cycle, { suppliers: [supplier_managed, supplier_unmanaged], coordinator: distributor_managed, distributors: [distributor_managed, distributor_unmanaged], name: 'Order Cycle 1' } ) oc_for_other_user = create(:simple_order_cycle, { coordinator: supplier_unmanaged, name: 'Order Cycle 2' } ) + visit spree.admin_path click_link "Order Cycles" # I should see only the order cycle I am coordinating @@ -715,7 +714,7 @@ # Make the page long enough to avoid the save bar overlaying the form page.driver.resize(1280, 2000) - click_link "Order Cycles" + visit admin_order_cycles_path click_link 'New Order Cycle' fill_in 'order_cycle_name', with: 'My order cycle' @@ -832,7 +831,7 @@ scenario "cloning an order cycle" do oc = create(:simple_order_cycle, coordinator: distributor_managed) - click_link "Order Cycles" + visit admin_order_cycles_path within "tr.order-cycle-#{oc.id}" do find('a.clone-order-cycle').click end @@ -1063,8 +1062,8 @@ ex.update_attributes! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' # When I edit it - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path click_link oc.name wait_until { page.find('#order_cycle_name').value.present? } @@ -1093,7 +1092,7 @@ ex.update_attributes! pickup_time: 'pickup time', pickup_instructions: 'pickup instructions' # When I edit it - login_to_admin_section + quick_login_as_admin visit edit_admin_order_cycle_path oc wait_until { page.find('#order_cycle_name').value.present? } @@ -1147,8 +1146,8 @@ scenario "deleting an order cycle" do create(:simple_order_cycle, name: "Translusent Berries") - login_to_admin_section - click_link 'Order Cycles' + quick_login_as_admin + visit admin_order_cycles_path page.should have_content("Translusent Berries") first('a.delete-order-cycle').click page.should_not have_content("Translusent Berries") From 9023b163955d2de2f8012ce2ac06b1f2a8ee546d Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 14:45:57 +1000 Subject: [PATCH 026/122] Speed up admin orders spec From 80s to 74s. --- spec/features/admin/orders_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/features/admin/orders_spec.rb b/spec/features/admin/orders_spec.rb index 6f034451356..0b9a6cb6027 100644 --- a/spec/features/admin/orders_spec.rb +++ b/spec/features/admin/orders_spec.rb @@ -37,7 +37,7 @@ def new_order_with_distribution(distributor, order_cycle) create(:simple_order_cycle, name: 'Four', orders_close_at: 4.weeks.from_now) create(:simple_order_cycle, name: 'Three', orders_close_at: 3.weeks.from_now) - login_to_admin_section + quick_login_as_admin visit 'admin/orders' open_select2('#s2id_q_order_cycle_id_in') @@ -49,7 +49,7 @@ def new_order_with_distribution(distributor, order_cycle) distributor_disabled = create(:distributor_enterprise) create(:simple_order_cycle, name: 'Two') - login_to_admin_section + quick_login_as_admin visit '/admin/orders' click_link 'New Order' @@ -85,7 +85,7 @@ def new_order_with_distribution(distributor, order_cycle) end scenario "can add a product to an existing order", retry: 3 do - login_to_admin_section + quick_login_as_admin visit '/admin/orders' click_edit @@ -106,7 +106,7 @@ def new_order_with_distribution(distributor, order_cycle) @order.state = 'cart'; @order.completed_at = nil; @order.save - login_to_admin_section + quick_login_as_admin visit '/admin/orders' uncheck 'Only show complete orders' click_button 'Filter Results' @@ -124,7 +124,7 @@ def new_order_with_distribution(distributor, order_cycle) scenario "can't add products to an order outside the order's hub and order cycle" do product = create(:simple_product) - login_to_admin_section + quick_login_as_admin visit '/admin/orders' page.find('td.actions a.icon-edit').click @@ -134,7 +134,7 @@ def new_order_with_distribution(distributor, order_cycle) scenario "can't change distributor or order cycle once order has been finalized" do @order.update_attributes order_cycle_id: nil - login_to_admin_section + quick_login_as_admin visit '/admin/orders' page.find('td.actions a.icon-edit').click @@ -173,7 +173,7 @@ def new_order_with_distribution(distributor, order_cycle) end scenario "capture payment from the orders index page" do - login_to_admin_section + quick_login_as_admin visit spree.admin_orders_path expect(page).to have_current_path spree.admin_orders_path @@ -207,7 +207,7 @@ def new_order_with_distribution(distributor, order_cycle) @enterprise_user.enterprise_roles.build(enterprise: coordinator1).save @enterprise_user.enterprise_roles.build(enterprise: distributor1).save - login_to_admin_as @enterprise_user + quick_login_as @enterprise_user end feature "viewing the edit page" do From eb550505ae5d0c3626ae4cbd7976c2a533b3a0ba Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 14:50:38 +1000 Subject: [PATCH 027/122] Speed up admin payment method spec --- spec/features/admin/payment_method_spec.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/features/admin/payment_method_spec.rb b/spec/features/admin/payment_method_spec.rb index 9df6ef0114c..fd101d5045a 100644 --- a/spec/features/admin/payment_method_spec.rb +++ b/spec/features/admin/payment_method_spec.rb @@ -47,7 +47,7 @@ end it "communicates the status of the stripe connection to the user" do - login_as user + quick_login_as user visit spree.new_admin_payment_method_path select2_select "Stripe", from: "payment_method_type" @@ -71,7 +71,7 @@ scenario "updating a payment method", js: true do pm = create(:payment_method, distributors: [@distributors[0]]) - login_to_admin_section + quick_login_as_admin visit spree.edit_admin_payment_method_path pm @@ -127,11 +127,11 @@ before(:each) do enterprise_user.enterprise_roles.build(enterprise: distributor1).save enterprise_user.enterprise_roles.build(enterprise: distributor2).save - login_to_admin_as enterprise_user + quick_login_as enterprise_user end it "I can get to the new enterprise page" do - click_link 'Enterprises' + visit admin_enterprises_path within("#e_#{distributor1.id}") { click_link 'Manage' } within(".side_menu") do click_link "Payment Methods" @@ -181,7 +181,7 @@ pm1 pm2 - click_link 'Enterprises' + visit admin_enterprises_path within("#e_#{distributor1.id}") { click_link 'Manage' } within(".side_menu") do click_link "Payment Methods" From aa677a117ba464e513c6fa575b34daa66926ce22 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 14:58:23 +1000 Subject: [PATCH 028/122] Speed up admin products spec --- spec/features/admin/products_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/admin/products_spec.rb b/spec/features/admin/products_spec.rb index bccc223953a..3894e46e93e 100644 --- a/spec/features/admin/products_spec.rb +++ b/spec/features/admin/products_spec.rb @@ -60,9 +60,9 @@ end scenario "creating an on-demand product", js: true do - login_to_admin_section + quick_login_as_admin + visit spree.admin_products_path - click_link 'Products' click_link 'New Product' fill_in 'product_name', with: 'Hot Cakes' @@ -100,13 +100,13 @@ create(:enterprise_relationship, parent: @supplier_permitted, child: @supplier2, permissions_list: [:manage_products]) - login_to_admin_as @new_user + quick_login_as @new_user end context "products do not require a tax category" do scenario "creating a new product", js: true do with_products_require_tax_category(false) do - click_link 'Products' + visit spree.admin_products_path click_link 'New Product' fill_in 'product_name', :with => 'A new product !!!' From 819a17316770126c3de7dc449b2fb7fb3c654106 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 15:04:00 +1000 Subject: [PATCH 029/122] Speed up reports spec --- spec/features/admin/reports_spec.rb | 53 +++++++++++++++-------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 3435d487e6e..6e2f3101759 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -33,9 +33,10 @@ describe "Customers report" do before do - login_to_admin_section - click_link "Reports" + quick_login_as_admin + visit spree.admin_reports_path end + scenario "customers report" do click_link "Mailing List" expect(page).to have_select('report_type', selected: 'Mailing List') @@ -64,8 +65,8 @@ describe "Order cycle management report" do before do - login_to_admin_section - click_link "Reports" + quick_login_as_admin + visit spree.admin_reports_path end scenario "payment method report" do @@ -91,8 +92,8 @@ describe "Packing reports" do before do - login_to_admin_section - click_link "Reports" + quick_login_as_admin + visit spree.admin_reports_path end let(:bill_address1) { create(:address, lastname: "Aman") } @@ -150,8 +151,8 @@ scenario "orders and distributors report" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Orders And Distributors' click_button 'Search' @@ -159,8 +160,8 @@ end scenario "bulk co-op report" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Bulk Co-Op' click_button 'Search' @@ -168,8 +169,8 @@ end scenario "payments reports" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Payment Reports' click_button 'Search' @@ -204,8 +205,8 @@ order1.finalize! - login_to_admin_as user1 - click_link "Reports" + quick_login_as user1 + visit spree.admin_reports_path click_link "Sales Tax" select("Tax types", from: "report_type") end @@ -239,8 +240,8 @@ describe "orders & fulfilment reports" do it "loads the report page" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Orders & Fulfillment Reports' expect(page).to have_content 'Supplier' @@ -266,7 +267,7 @@ it "is precise to time of day, not just date" do # When I generate a customer report with a timeframe that includes one order but not the other - login_to_admin_section + quick_login_as_admin visit spree.orders_and_fulfillment_admin_reports_path fill_in 'q_completed_at_gt', with: '2013-04-25 13:00:00' @@ -284,7 +285,7 @@ oc = create(:simple_order_cycle, name: "My Order Cycle", distributors: [distributor], orders_open_at: Time.zone.now, orders_close_at: nil) o = create(:order, order_cycle: oc, distributor: distributor) - login_to_admin_section + quick_login_as_admin visit spree.orders_and_fulfillment_admin_reports_path expect(page).to have_content "My Order Cycle" @@ -316,8 +317,8 @@ end it "shows products and inventory report" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path expect(page).to have_content "All products" expect(page).to have_content "Inventory (on hand)" @@ -331,8 +332,8 @@ end it "shows the LettuceShare report" do - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'LettuceShare' click_button "Search" @@ -349,8 +350,8 @@ before do enterprise3.enterprise_roles.build( user: enterprise1.owner ).save - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Users & Enterprises' end @@ -420,8 +421,8 @@ order1.update_attribute :email, 'customer@email.com' Timecop.travel(Time.zone.local(2015, 4, 25, 14, 0, 0)) { order1.finalize! } - login_to_admin_section - click_link 'Reports' + quick_login_as_admin + visit spree.admin_reports_path click_link 'Xero Invoices' end From 54552f2be7de458b37797759dd1c4bcec1b411f5 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 15:10:57 +1000 Subject: [PATCH 030/122] Speed up admin schedules spec --- spec/features/admin/schedules_spec.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/features/admin/schedules_spec.rb b/spec/features/admin/schedules_spec.rb index c569475a9dd..33eace602dc 100644 --- a/spec/features/admin/schedules_spec.rb +++ b/spec/features/admin/schedules_spec.rb @@ -16,10 +16,11 @@ let!(:oc5) { create(:simple_order_cycle, coordinator: managed_enterprise2, name: 'oc5') } let!(:weekly_schedule) { create(:schedule, name: 'Weekly', order_cycles: [oc1, oc2, oc3, oc4]) } - before { login_to_admin_as user } + before { quick_login_as user } describe "Adding a new Schedule" do it "immediately shows the schedule in the order cycle list once created" do + visit spree.admin_path click_link 'Order Cycles' expect(page).to have_selector ".order-cycle-#{oc1.id}" find('a', text: 'NEW SCHEDULE').click @@ -65,7 +66,7 @@ let!(:fortnightly_schedule) { create(:schedule, name: 'Fortnightly', order_cycles: [oc1, oc3]) } it "immediately shows updated schedule lists for order cycles" do - click_link 'Order Cycles' + visit admin_order_cycles_path within ".order-cycle-#{oc1.id} td.schedules" do find('a', text: "Weekly").click @@ -100,7 +101,7 @@ describe "deleting a schedule" do it "immediately removes deleted schedules from order cycles" do - click_link 'Order Cycles' + visit admin_order_cycles_path within ".order-cycle-#{oc1.id} td.schedules" do find('a', text: "Weekly").click From b628ead525310d53770f0c5b9951beb33e06d97b Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 15:31:46 +1000 Subject: [PATCH 031/122] Speed up shipping methods spec --- spec/features/admin/shipping_methods_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/admin/shipping_methods_spec.rb b/spec/features/admin/shipping_methods_spec.rb index 46816f5737a..2a83f2531fa 100644 --- a/spec/features/admin/shipping_methods_spec.rb +++ b/spec/features/admin/shipping_methods_spec.rb @@ -10,7 +10,7 @@ context "as a site admin" do before(:each) do - login_to_admin_section + quick_login_as_admin end scenario "creating a shipping method owned by some distributors" do @@ -73,11 +73,11 @@ before(:each) do enterprise_user.enterprise_roles.build(enterprise: distributor1).save enterprise_user.enterprise_roles.build(enterprise: distributor2).save - login_to_admin_as enterprise_user + quick_login_as enterprise_user end it "creating a shipping method" do - click_link 'Enterprises' + visit admin_enterprises_path within("#e_#{distributor1.id}") { click_link 'Manage' } within(".side_menu") do click_link "Shipping Methods" @@ -130,7 +130,7 @@ sm1 sm2 - click_link 'Enterprises' + visit admin_enterprises_path within("#e_#{distributor1.id}") { click_link 'Manage' } within(".side_menu") do click_link "Shipping Methods" From 9aff9fbce28ae29a3035ac9f1e103b4119a30e7b Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 7 Aug 2018 15:37:03 +1000 Subject: [PATCH 032/122] Remove empty spec --- spec/features/admin/stripe_connect_spec.rb | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 spec/features/admin/stripe_connect_spec.rb diff --git a/spec/features/admin/stripe_connect_spec.rb b/spec/features/admin/stripe_connect_spec.rb deleted file mode 100644 index 1c56f703e90..00000000000 --- a/spec/features/admin/stripe_connect_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'spec_helper' - -feature "Connecting a Stripe Account" do - include AuthenticationWorkflow - include WebHelper - - let!(:enterprise_user) { create :enterprise_user } - before(:each) do - login_to_admin_as enterprise_user - end -end From 27ddb712c1a9ab92059cce00ab3b9758d0db89a5 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 27 Jun 2018 17:04:01 +1000 Subject: [PATCH 033/122] Remove unused scope `Spree::Variant.in_stock` Our added scope is not used anywhere and conflicts with the Spree upgrade. https://github.com/openfoodfoundation/openfoodnetwork/issues/2014 --- app/models/spree/variant_decorator.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/spree/variant_decorator.rb b/app/models/spree/variant_decorator.rb index 2947efc2826..4c7e6ed5ab2 100644 --- a/app/models/spree/variant_decorator.rb +++ b/app/models/spree/variant_decorator.rb @@ -33,7 +33,6 @@ scope :not_deleted, where(deleted_at: nil) scope :not_master, where(is_master: false) - scope :in_stock, where('spree_variants.count_on_hand > 0 OR spree_variants.on_demand=?', true) scope :in_order_cycle, lambda { |order_cycle| with_order_cycles_inner. merge(Exchange.outgoing). From 289d0b937fdcb2c0e6aed563d5de3fe9e9967a9a Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 28 Jun 2018 13:57:45 +1000 Subject: [PATCH 034/122] Style ScopeVariantToHub --- .rubocop_todo.yml | 2 -- lib/open_food_network/scope_variant_to_hub.rb | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 65e05628caf..eaff617a863 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -191,7 +191,6 @@ Layout/EmptyLines: - 'lib/open_food_network/reports/bulk_coop_report.rb' - 'lib/open_food_network/sales_tax_report.rb' - 'lib/open_food_network/scope_product_to_hub.rb' - - 'lib/open_food_network/scope_variant_to_hub.rb' - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/core/controller_helpers/order_decorator.rb' - 'lib/tasks/cache.rake' @@ -648,7 +647,6 @@ Layout/SpaceAroundEqualsInParameterDefault: - 'lib/open_food_network/enterprise_issue_validator.rb' - 'lib/open_food_network/order_cycle_form_applicator.rb' - 'lib/open_food_network/permissions.rb' - - 'lib/open_food_network/scope_variant_to_hub.rb' - 'lib/open_food_network/tag_rule_applicator.rb' - 'lib/open_food_network/xero_invoices_report.rb' - 'lib/spree/money_decorator.rb' diff --git a/lib/open_food_network/scope_variant_to_hub.rb b/lib/open_food_network/scope_variant_to_hub.rb index e70e7966e1d..94e430c53da 100644 --- a/lib/open_food_network/scope_variant_to_hub.rb +++ b/lib/open_food_network/scope_variant_to_hub.rb @@ -1,6 +1,6 @@ module OpenFoodNetwork class ScopeVariantToHub - def initialize(hub, variant_overrides=nil) + def initialize(hub, variant_overrides = nil) @hub = hub @variant_overrides = variant_overrides || VariantOverride.indexed(@hub) end @@ -11,7 +11,6 @@ def scope(variant) variant.instance_variable_set :@variant_override, @variant_overrides[variant] end - module ScopeVariantToHub def price @variant_override.andand.price || super @@ -39,7 +38,7 @@ def on_demand end end - def decrement!(attribute, by=1) + def decrement!(attribute, by = 1) if attribute == :count_on_hand && @variant_override.andand.stock_overridden? @variant_override.decrement_stock! by else @@ -47,7 +46,7 @@ def decrement!(attribute, by=1) end end - def increment!(attribute, by=1) + def increment!(attribute, by = 1) if attribute == :count_on_hand && @variant_override.andand.stock_overridden? @variant_override.increment_stock! by else From b84e524f2d30b7357857fa349007ef1b281b7034 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 28 Jun 2018 14:55:24 +1000 Subject: [PATCH 035/122] Prepare inventory report for Spree upgrade This change could impact the performance of the report. But therefore it takes VariantOverrides into consideration. The old code ignored the distributor for this filter. It also ignored the `on_demand` flag. --- lib/open_food_network/products_and_inventory_report_base.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/open_food_network/products_and_inventory_report_base.rb b/lib/open_food_network/products_and_inventory_report_base.rb index dff53fdb9a0..121df3221ec 100644 --- a/lib/open_food_network/products_and_inventory_report_base.rb +++ b/lib/open_food_network/products_and_inventory_report_base.rb @@ -29,16 +29,18 @@ def child_variants end def filter(variants) - filter_to_distributor filter_to_order_cycle filter_on_hand filter_to_supplier filter_not_deleted variants + filter_on_hand filter_to_distributor filter_to_order_cycle filter_to_supplier filter_not_deleted variants end def filter_not_deleted(variants) variants.not_deleted end + # Using the `in_stock?` method allows overrides by distributors. + # It also allows the upgrade to Spree 2.0. def filter_on_hand(variants) if params[:report_type] == 'inventory' - variants.where('spree_variants.count_on_hand > 0') + variants.select(&:in_stock?) else variants end From 9dcbd9076ef4085d73842e1945ec2a50e8fac541 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 28 Jun 2018 15:39:15 +1000 Subject: [PATCH 036/122] Override `in_stock?` to prepare for Spree 2.0 --- lib/open_food_network/scope_variant_to_hub.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/open_food_network/scope_variant_to_hub.rb b/lib/open_food_network/scope_variant_to_hub.rb index 94e430c53da..feb99ae7c33 100644 --- a/lib/open_food_network/scope_variant_to_hub.rb +++ b/lib/open_food_network/scope_variant_to_hub.rb @@ -20,6 +20,14 @@ def price_in(currency) Spree::Price.new(amount: price, currency: currency) end + # Old Spree has the same logic as here and doesn't need this override. + # But we need this to use VariantOverrides with Spree 2.0. + def in_stock? + return true unless Spree::Config[:track_inventory_levels] + + on_demand || (count_on_hand > 0) + end + def count_on_hand @variant_override.andand.count_on_hand || super end From b91019ad6428e2b17ea9779147d1b37121ccf3d6 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 12:53:41 +0800 Subject: [PATCH 037/122] Split translation key for enterprise manage button The ".manage" key is still used by the column header for the "Manage" buttons. --- app/views/admin/enterprises/_enterprise_user_index.html.haml | 2 +- config/locales/en.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/admin/enterprises/_enterprise_user_index.html.haml b/app/views/admin/enterprises/_enterprise_user_index.html.haml index 4129da6b936..0afa9317e9b 100644 --- a/app/views/admin/enterprises/_enterprise_user_index.html.haml +++ b/app/views/admin/enterprises/_enterprise_user_index.html.haml @@ -40,7 +40,7 @@ %i.icon-status{ ng: { class: "enterprise.status" } } %td.manage{ ng: { show: 'columns.manage.visible' } } %a.button.fullwidth{ ng: { href: '{{::enterprise.edit_path}}' } } - = t('.manage') + = t('.manage_link') %i.icon-arrow-right %tr.panel-row{ object: "enterprise", panels: "{producer: 'enterprise_producer', package: 'enterprise_package', status: 'enterprise_status'}" } diff --git a/config/locales/en.yml b/config/locales/en.yml index d1f17bfa5a0..67a53ef6405 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -788,6 +788,7 @@ en: no_enterprises_found: No enterprises found. search_placeholder: Search By Name manage: Manage + manage_link: Manage new_form: owner: Owner owner_tip: The primary user responsible for this enterprise. From 0b4fcf8a14bf7ad564bca7047153daec3db83c50 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 12:56:33 +0800 Subject: [PATCH 038/122] Change enterprise "Manage" button to "Settings" --- config/locales/en.yml | 2 +- spec/features/admin/enterprise_fees_spec.rb | 12 ++++++------ spec/features/admin/enterprises_spec.rb | 10 +++++----- spec/features/admin/payment_method_spec.rb | 6 +++--- spec/features/admin/shipping_methods_spec.rb | 6 +++--- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 67a53ef6405..c000aa3453e 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -788,7 +788,7 @@ en: no_enterprises_found: No enterprises found. search_placeholder: Search By Name manage: Manage - manage_link: Manage + manage_link: Settings new_form: owner: Owner owner_tip: The primary user responsible for this enterprise. diff --git a/spec/features/admin/enterprise_fees_spec.rb b/spec/features/admin/enterprise_fees_spec.rb index 50d84121160..52b532e70cb 100644 --- a/spec/features/admin/enterprise_fees_spec.rb +++ b/spec/features/admin/enterprise_fees_spec.rb @@ -145,7 +145,7 @@ ef2 click_link 'Enterprises' - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") { click_link 'Enterprise Fees' } click_link "Create One Now" @@ -169,16 +169,16 @@ ef2 click_link 'Enterprises' - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") { click_link 'Enterprise Fees' } - click_link "Manage Enterprise Fees" + click_link "Settings Enterprise Fees" page.should have_field 'enterprise_fee_set_collection_attributes_0_name', with: 'One' page.should_not have_field 'enterprise_fee_set_collection_attributes_1_name', with: 'Two' click_link 'Enterprises' - within("#e_#{distributor2.id}") { click_link 'Manage' } + within("#e_#{distributor2.id}") { click_link 'Settings' } within(".side_menu") { click_link 'Enterprise Fees' } - click_link "Manage Enterprise Fees" + click_link "Settings Enterprise Fees" page.should_not have_field 'enterprise_fee_set_collection_attributes_0_name', with: 'One' page.should have_field 'enterprise_fee_set_collection_attributes_0_name', with: 'Two' end @@ -189,7 +189,7 @@ distributor3 click_link 'Enterprises' - within("#e_#{distributor2.id}") { click_link 'Manage' } + within("#e_#{distributor2.id}") { click_link 'Settings' } within(".side_menu") { click_link 'Enterprise Fees' } click_link "Manage Enterprise Fees" page.should have_select('enterprise_fee_set_collection_attributes_1_enterprise_id', diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index c7df54a6ac3..c3d559b57fd 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -376,7 +376,7 @@ scenario "editing enterprises I manage" do visit admin_enterprises_path - within("tbody#e_#{distributor1.id}") { click_link 'Manage' } + within("tbody#e_#{distributor1.id}") { click_link 'Settings' } fill_in 'enterprise_name', :with => 'Eaterprises' @@ -392,7 +392,7 @@ describe "enterprises I have edit permission for, but do not manage" do it "allows me to edit them" do visit admin_enterprises_path - within("tbody#e_#{distributor3.id}") { click_link 'Manage' } + within("tbody#e_#{distributor3.id}") { click_link 'Settings' } fill_in 'enterprise_name', :with => 'Eaterprises' @@ -407,7 +407,7 @@ it "does not show links to manage shipping methods, payment methods or enterprise fees on the edit page" do visit admin_enterprises_path - within("tbody#e_#{distributor3.id}") { click_link 'Manage' } + within("tbody#e_#{distributor3.id}") { click_link 'Settings' } within(".side_menu") do page.should_not have_link 'Shipping Methods' @@ -419,7 +419,7 @@ scenario "editing images for an enterprise" do visit admin_enterprises_path - within("tbody#e_#{distributor1.id}") { click_link 'Manage' } + within("tbody#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Images" @@ -432,7 +432,7 @@ scenario "managing producer properties" do create(:property, name: "Certified Organic") visit admin_enterprises_path - within("#e_#{supplier1.id}") { click_link 'Manage' } + within("#e_#{supplier1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Properties" end diff --git a/spec/features/admin/payment_method_spec.rb b/spec/features/admin/payment_method_spec.rb index fd101d5045a..9ce7f76a837 100644 --- a/spec/features/admin/payment_method_spec.rb +++ b/spec/features/admin/payment_method_spec.rb @@ -132,7 +132,7 @@ it "I can get to the new enterprise page" do visit admin_enterprises_path - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Payment Methods" end @@ -182,7 +182,7 @@ pm2 visit admin_enterprises_path - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Payment Methods" end @@ -191,7 +191,7 @@ page.should have_content pm2.name click_link 'Enterprises' - within("#e_#{distributor2.id}") { click_link 'Manage' } + within("#e_#{distributor2.id}") { click_link 'Settings' } within(".side_menu") do click_link "Payment Methods" end diff --git a/spec/features/admin/shipping_methods_spec.rb b/spec/features/admin/shipping_methods_spec.rb index 2a83f2531fa..4a06ea139af 100644 --- a/spec/features/admin/shipping_methods_spec.rb +++ b/spec/features/admin/shipping_methods_spec.rb @@ -78,7 +78,7 @@ it "creating a shipping method" do visit admin_enterprises_path - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Shipping Methods" end @@ -131,7 +131,7 @@ sm2 visit admin_enterprises_path - within("#e_#{distributor1.id}") { click_link 'Manage' } + within("#e_#{distributor1.id}") { click_link 'Settings' } within(".side_menu") do click_link "Shipping Methods" end @@ -139,7 +139,7 @@ page.should have_content sm2.name click_link 'Enterprises' - within("#e_#{distributor2.id}") { click_link 'Manage' } + within("#e_#{distributor2.id}") { click_link 'Settings' } within(".side_menu") do click_link "Shipping Methods" end From 295604b6893f74cddfb9041990048b17efd59f5e Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 20 Jul 2018 13:00:18 +0800 Subject: [PATCH 039/122] Change heading for edit enterprise page Change the start of the heading from "Editing:" to "Settings:". --- 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 c000aa3453e..005df217cdd 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -795,7 +795,7 @@ en: i_am_producer: I am a Producer contact_name: Contact Name edit: - editing: 'Editing:' + editing: 'Settings:' back_link: Back to enterprises list new: title: New Enterprise From 17978f58c7772ed78cdd384bb5c837c0435b4b80 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 3 Aug 2018 19:17:59 +0800 Subject: [PATCH 040/122] Rename edit link in admin enterprise index Change "Edit Profile" link to "Settings". --- config/locales/en.yml | 2 +- spec/features/admin/enterprises/index_spec.rb | 4 ++-- spec/features/admin/enterprises_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 005df217cdd..fb0a50dba17 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -748,7 +748,7 @@ en: email_confirmed: "Email confirmed" email_not_confirmed: "Email not confirmed" actions: - edit_profile: Edit Profile + edit_profile: Settings properties: Properties payment_methods: Payment Methods payment_methods_tip: This enterprise has no payment methods diff --git a/spec/features/admin/enterprises/index_spec.rb b/spec/features/admin/enterprises/index_spec.rb index f8f1a5f263c..83ddaaa1020 100644 --- a/spec/features/admin/enterprises/index_spec.rb +++ b/spec/features/admin/enterprises/index_spec.rb @@ -15,7 +15,7 @@ within("tr.enterprise-#{s.id}") do expect(page).to have_content s.name expect(page).to have_select "enterprise_set_collection_attributes_1_sells" - expect(page).to have_content "Edit Profile" + expect(page).to have_content "Settings" expect(page).to have_content "Delete" expect(page).to_not have_content "Payment Methods" expect(page).to_not have_content "Shipping Methods" @@ -25,7 +25,7 @@ within("tr.enterprise-#{d.id}") do expect(page).to have_content d.name expect(page).to have_select "enterprise_set_collection_attributes_0_sells" - expect(page).to have_content "Edit Profile" + expect(page).to have_content "Settings" expect(page).to have_content "Delete" expect(page).to have_content "Payment Methods" expect(page).to have_content "Shipping Methods" diff --git a/spec/features/admin/enterprises_spec.rb b/spec/features/admin/enterprises_spec.rb index c3d559b57fd..bdbb7cde16a 100644 --- a/spec/features/admin/enterprises_spec.rb +++ b/spec/features/admin/enterprises_spec.rb @@ -77,7 +77,7 @@ visit '/admin/enterprises' within "tr.enterprise-#{@enterprise.id}" do - first("a", text: 'Edit Profile').trigger 'click' + first("a", text: 'Settings').trigger 'click' end fill_in 'enterprise_name', :with => 'Eaterprises' From 6251c729219630a1d496aaa8224ecdb592485dde Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 3 Aug 2018 19:38:40 +0800 Subject: [PATCH 041/122] Add divider between admin enterprise index actions --- app/assets/stylesheets/admin/enterprises.css.scss | 8 ++++++++ app/assets/stylesheets/admin/variables.css.scss | 2 ++ app/views/admin/enterprises/_actions.html.haml | 2 ++ 3 files changed, 12 insertions(+) diff --git a/app/assets/stylesheets/admin/enterprises.css.scss b/app/assets/stylesheets/admin/enterprises.css.scss index c12c8bb53f0..2c74a30508c 100644 --- a/app/assets/stylesheets/admin/enterprises.css.scss +++ b/app/assets/stylesheets/admin/enterprises.css.scss @@ -29,3 +29,11 @@ form[name="enterprise_form"] { } } } + +.admin-enterprises-index-admin-actions-divider { + background-color: $admin-table-border; + border-width: 0; + height: 1px; + margin-bottom: 1em; + margin-top: 1em; +} diff --git a/app/assets/stylesheets/admin/variables.css.scss b/app/assets/stylesheets/admin/variables.css.scss index d4c6bf522ef..c7f904a38a3 100644 --- a/app/assets/stylesheets/admin/variables.css.scss +++ b/app/assets/stylesheets/admin/variables.css.scss @@ -8,3 +8,5 @@ $warning-red: #da5354; $warning-orange: #da7f52; $medium-grey: #919191; $pale-blue: #cee1f4; + +$admin-table-border: $pale-blue; diff --git a/app/views/admin/enterprises/_actions.html.haml b/app/views/admin/enterprises/_actions.html.haml index d5b3ae14a97..250f508bf72 100644 --- a/app/views/admin/enterprises/_actions.html.haml +++ b/app/views/admin/enterprises/_actions.html.haml @@ -5,6 +5,8 @@ = link_to_delete_enterprise enterprise %br/ +%hr.admin-enterprises-index-admin-actions-divider + - if enterprise.is_primary_producer = link_to_with_icon 'icon-dashboard', t('.properties'), main_app.admin_enterprise_producer_properties_path(enterprise_id: enterprise) (#{enterprise.producer_properties.count}) From 3b1bd53d3a2e58f5dce1a1f4e30389a1071e62a4 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sat, 21 Jul 2018 16:05:58 +0100 Subject: [PATCH 042/122] Added basic integration with Matomo Added matomo script and added a new matomo settings menu entry under configuration. Improved organization of en.yml by grouping configuration screens. --- .../admin/invoice_settings_controller.rb | 18 ++--- .../admin/matomo_settings_controller.rb | 13 ++++ .../spree/app_configuration_decorator.rb | 2 + .../add_invoice_settings.html.haml.deface | 2 +- .../add_matomo_settings.html.haml.deface | 4 + ...d_stripe_connect_settings.html.haml.deface | 2 +- .../admin/matomo_settings/edit.html.haml | 23 ++++++ app/views/layouts/_matomo_tag.html.haml | 15 ++++ app/views/layouts/darkswarm.html.haml | 1 + config/locales/en.yml | 75 ++++++++++--------- config/routes/admin.rb | 2 + 11 files changed, 111 insertions(+), 46 deletions(-) create mode 100644 app/controllers/admin/matomo_settings_controller.rb create mode 100644 app/overrides/spree/admin/shared/_configuration_menu/add_matomo_settings.html.haml.deface create mode 100644 app/views/admin/matomo_settings/edit.html.haml create mode 100644 app/views/layouts/_matomo_tag.html.haml diff --git a/app/controllers/admin/invoice_settings_controller.rb b/app/controllers/admin/invoice_settings_controller.rb index ac65c9860e4..bfa22205ece 100644 --- a/app/controllers/admin/invoice_settings_controller.rb +++ b/app/controllers/admin/invoice_settings_controller.rb @@ -1,13 +1,13 @@ -class Admin::InvoiceSettingsController < Spree::Admin::BaseController +module Admin + class InvoiceSettingsController < Spree::Admin::BaseController + def update + Spree::Config.set(params[:preferences]) - def update - Spree::Config.set(params[:preferences]) - - respond_to do |format| - format.html { - redirect_to main_app.edit_admin_invoice_settings_path - } + respond_to do |format| + format.html { + redirect_to main_app.edit_admin_invoice_settings_path + } + end end end - end diff --git a/app/controllers/admin/matomo_settings_controller.rb b/app/controllers/admin/matomo_settings_controller.rb new file mode 100644 index 00000000000..102f5b0ed5e --- /dev/null +++ b/app/controllers/admin/matomo_settings_controller.rb @@ -0,0 +1,13 @@ +module Admin + class MatomoSettingsController < Spree::Admin::BaseController + def update + Spree::Config.set(params[:preferences]) + + respond_to do |format| + format.html { + redirect_to main_app.edit_admin_matomo_settings_path + } + end + end + end +end diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index 53cf81b3b7b..b083edebc53 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -35,6 +35,8 @@ # External services preference :bugherd_api_key, :string, default: nil + preference :matomo_url, :string, default: nil + preference :matomo_site_id, :string, default: nil # Invoices & Receipts preference :invoice_style2?, :boolean, default: false diff --git a/app/overrides/spree/admin/shared/_configuration_menu/add_invoice_settings.html.haml.deface b/app/overrides/spree/admin/shared/_configuration_menu/add_invoice_settings.html.haml.deface index f65ed9eeea2..d814050cea3 100644 --- a/app/overrides/spree/admin/shared/_configuration_menu/add_invoice_settings.html.haml.deface +++ b/app/overrides/spree/admin/shared/_configuration_menu/add_invoice_settings.html.haml.deface @@ -1,4 +1,4 @@ // insert_bottom "[data-hook='admin_configurations_sidebar_menu']" %li - = link_to t('admin.invoice_settings.edit.invoice_settings'), main_app.edit_admin_invoice_settings_path + = link_to t('admin.invoice_settings.edit.title'), main_app.edit_admin_invoice_settings_path diff --git a/app/overrides/spree/admin/shared/_configuration_menu/add_matomo_settings.html.haml.deface b/app/overrides/spree/admin/shared/_configuration_menu/add_matomo_settings.html.haml.deface new file mode 100644 index 00000000000..b8aeabf3ae1 --- /dev/null +++ b/app/overrides/spree/admin/shared/_configuration_menu/add_matomo_settings.html.haml.deface @@ -0,0 +1,4 @@ +// insert_bottom "[data-hook='admin_configurations_sidebar_menu']" + +%li + = link_to t('admin.matomo_settings.edit.title'), main_app.edit_admin_matomo_settings_path diff --git a/app/overrides/spree/admin/shared/_configuration_menu/add_stripe_connect_settings.html.haml.deface b/app/overrides/spree/admin/shared/_configuration_menu/add_stripe_connect_settings.html.haml.deface index c7b3f4789a9..90b76643ee8 100644 --- a/app/overrides/spree/admin/shared/_configuration_menu/add_stripe_connect_settings.html.haml.deface +++ b/app/overrides/spree/admin/shared/_configuration_menu/add_stripe_connect_settings.html.haml.deface @@ -1,4 +1,4 @@ // insert_bottom "[data-hook='admin_configurations_sidebar_menu']" %li - = link_to t('.stripe_connect'), main_app.edit_admin_stripe_connect_settings_path + = link_to t('admin.stripe_connect_settings.edit.title'), main_app.edit_admin_stripe_connect_settings_path diff --git a/app/views/admin/matomo_settings/edit.html.haml b/app/views/admin/matomo_settings/edit.html.haml new file mode 100644 index 00000000000..51f553bcff3 --- /dev/null +++ b/app/views/admin/matomo_settings/edit.html.haml @@ -0,0 +1,23 @@ += render :partial => 'spree/admin/shared/configuration_menu' + +- content_for :page_title do + = t('.title') + += form_tag main_app.admin_matomo_settings_path, :method => :put do + + .div + %legend= t('.info_html') + = tag(:br) + = t('.config_instructions_html') + + .field + = label_tag(:matomo_url, t('.matomo_url')) + tag(:br) + = preference_field_tag("preferences[#{:matomo_url}]", Spree::Config[:matomo_url], type: Spree::Config.preference_type(:matomo_url)) + + .field + = label_tag(:matomo_site_id, t('.matomo_site_id')) + tag(:br) + = preference_field_tag("preferences[#{:matomo_site_id}]", Spree::Config[:matomo_site_id], type: Spree::Config.preference_type(:matomo_site_id)) + + + .form-buttons{"data-hook" => "buttons"} + = button t(:update), 'icon-refresh' diff --git a/app/views/layouts/_matomo_tag.html.haml b/app/views/layouts/_matomo_tag.html.haml new file mode 100644 index 00000000000..aba1b195281 --- /dev/null +++ b/app/views/layouts/_matomo_tag.html.haml @@ -0,0 +1,15 @@ +- if Spree::Config.matomo_url.present? + :javascript + var _paq = _paq || []; + _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); + _paq.push(["setCookieDomain", "*.#{Spree::Config.site_url}"]); + _paq.push(["setDomains", ["*.#{Spree::Config.site_url}"]]); + _paq.push(['trackPageView']); + _paq.push(['enableLinkTracking']); + (function() { + var u="#{Spree::Config.matomo_url}"; + _paq.push(['setTrackerUrl', u+'piwik.php']); + _paq.push(['setSiteId', '#{Spree::Config.matomo_site_id}']); + var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); + })(); diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index c6123880711..2b796ad0cc9 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -22,6 +22,7 @@ = render "layouts/i18n_script" = render "layouts/bugherd_script" + = render "layouts/matomo_tag" = csrf_meta_tags %body{class: body_classes, ng: {app: "Darkswarm"}} diff --git a/config/locales/en.yml b/config/locales/en.yml index fb0a50dba17..db41bf15b92 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -354,6 +354,46 @@ en: total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)" total_monthly_bill_incl_tax_tip: "The example total monthly bill with tax included, given the settings and the turnover provided." + cache_settings: + show: + title: Caching + distributor: Distributor + order_cycle: Order Cycle + status: Status + diff: Diff + error: Error + + invoice_settings: + edit: + title: Invoice Settings + invoice_style2?: Use the alternative invoice model that includes total tax breakdown per rate and tax rate info per item (not yet suitable for countries displaying prices excluding tax) + enable_receipt_printing?: Show options for printing receipts using thermal printers in order dropdown? + + stripe_connect_settings: + edit: + title: "Stripe Connect" + settings: "Settings" + stripe_connect_enabled: Enable shops to accept payments using Stripe Connect? + no_api_key_msg: No Stripe account exists for this enterprise. + configuration_explanation_html: For detailed instructions on configuring the Stripe Connect integration, please consult this guide. + status: Status + ok: Ok + instance_secret_key: Instance Secret Key + account_id: Account ID + business_name: Business Name + charges_enabled: Charges Enabled + charges_enabled_warning: "Warning: Charges are not enabled for your account" + auth_fail_error: The API key you provided is invalid + empty_api_key_error_html: No Stripe API key has been provided. To set your API key, please follow these instructions + + matomo_settings: + edit: + title: "Matomo Settings" + matomo_url: "Matomo URL" + matomo_site_id: "Matomo Site ID" + info_html: "Matomo is a Web and Mobile Analytics. You can either host Matomo on-premises or use a cloud-hosted service. See matomo.org for more information." + config_instructions_html: "Here you can configure the OFN Matomo integration. The Matomo URL below should point to the Matomo instance where the user tracking information will be sent to; if it is left empty, Matomo user tracking will be disabled. The Site ID field is not mandatory but useful if you are tracking more than one website on a single Matomo instance; it can be found on the Matomo instance console." + customers: index: add_customer: "Add Customer" @@ -380,15 +420,6 @@ en: destroy: has_associated_orders: 'Delete failed: customer has associated orders with his shop' - cache_settings: - show: - title: Caching - distributor: Distributor - order_cycle: Order Cycle - status: Status - diff: Diff - error: Error - contents: edit: title: Content @@ -899,12 +930,6 @@ en: shared: user_guide_link: user_guide: User Guide - - invoice_settings: - edit: - title: Invoice Settings - invoice_style2?: Use the alternative invoice model that includes total tax breakdown per rate and tax rate info per item (not yet suitable for countries displaying prices excluding tax) - enable_receipt_printing?: Show options for printing receipts using thermal printers in order dropdown? overview: enterprises_header: ofn_with_tip: Enterprises are Producers and/or Hubs and are the basic unit of organisation within the Open Food Network. @@ -1043,23 +1068,6 @@ en: destroy: associated_subscriptions_error: This schedule cannot be deleted because it has associated subscriptions - stripe_connect_settings: - edit: - title: "Stripe Connect" - settings: "Settings" - stripe_connect_enabled: Enable shops to accept payments using Stripe Connect? - no_api_key_msg: No Stripe account exists for this enterprise. - configuration_explanation_html: For detailed instructions on configuring the Stripe Connect integration, please consult this guide. - status: Status - ok: Ok - instance_secret_key: Instance Secret Key - account_id: Account ID - business_name: Business Name - charges_enabled: Charges Enabled - charges_enabled_warning: "Warning: Charges are not enabled for your account" - auth_fail_error: The API key you provided is invalid - empty_api_key_error_html: No Stripe API key has been provided. To set your API key, please follow these instructions - # Admin controllers controllers: enterprises: @@ -2604,9 +2612,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using bulk_coop_allocation: 'Bulk Co-op - Allocation' bulk_coop_packing_sheets: 'Bulk Co-op - Packing Sheets' bulk_coop_customer_payments: 'Bulk Co-op - Customer Payments' - shared: - configuration_menu: - stripe_connect: Stripe Connect users: email_confirmation: confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}." diff --git a/config/routes/admin.rb b/config/routes/admin.rb index ce58bc480bb..c191322d74e 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -91,6 +91,8 @@ resource :stripe_connect_settings, only: [:edit, :update] + resource :matomo_settings, only: [:edit, :update] + resources :stripe_accounts, only: [:destroy] do get :connect, on: :collection get :status, on: :collection From 6c306aa1ddfbc3cf9455e1bd4ca1315baf297b71 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 10 Aug 2018 21:09:21 +1000 Subject: [PATCH 043/122] Updating translations for config/locales/fr.yml --- config/locales/fr.yml | 83 ++++++++++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 24 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 3f9b4d75483..e41fabacfbd 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -19,7 +19,7 @@ fr: email: taken: "Un compte existe déjà pour cet e-mail. Connectez-vous ou demandez un nouveau mot de passe." spree/order: - no_card: Aucune carte de crédit valide trouvée + no_card: Aucune carte de paiement autorisée disponible order_cycle: attributes: orders_close_at: @@ -41,11 +41,10 @@ fr: payment_method: not_available_to_shop: "n'est pas disponible pour %{shop}" invalid_type: "doit être une méthode de paiement de type \"cash\" ou \"Stripe\"" + charges_not_allowed: "Le débit automatique sur carte de paiement n'a pas été autorisé par l'acheteur" + no_default_card: "Pas de carte de paiement par défaut pour cet acheteur" shipping_method: not_available_to_shop: "n'est pas disponible pour %{shop}" - credit_card: - not_available: "n'est pas disponible" - blank: "est requis" devise: confirmations: send_instructions: "Un email a été envoyé avec des instructions pour confirmer votre adresse email. Vérifiez votre boite mail!" @@ -160,6 +159,7 @@ fr: distributors: Distributeurs distribution: Distribution bulk_order_management: Gestion des commandes par lot + enterprises: Entreprises enterprise_groups: Groupes reports: Rapports variant_overrides: Catalogue boutique @@ -332,6 +332,7 @@ fr: update_address: 'Mettre à jour l''adresse' confirm_delete: 'Confirmer suppression?' search_by_email: "Recherche par email/code..." + guest_label: 'Commande en mode invité' destroy: has_associated_orders: 'Suppression impossible: des commandes sont associées à cet acheteur pour cette boutique' cache_settings: @@ -414,20 +415,29 @@ fr: index: select_file: Sélectionner le fichier (tableur sous format csv) à importer spreadsheet: Tableur csv - import_into: "Importer dans:" + choose_import_type: Choisir le type d'import + import_into: Type d'import product_list: Catalogues produits des producteurs inventories: Catalogues boutiques des hubs distributeurs import: Importer upload: Télécharger + csv_templates: Modèles de fichiers csv + product_list_template: Télécharger le modèle pour import dans catalogue producteur + inventory_template: Télécharger le modèle pour import dans catalogue boutique + category_values: Valeurs disponibles pour les catégories + product_categories: Catégorie Produit + tax_categories: TVA applicable + shipping_categories: Condition de transport import: review: Vérifier - proceed: Continuer + import: Importer save: Sauvergarder results: Résultats save_imported: Sauvegarder les produits importés no_valid_entries: Aucune entrée valide trouvée none_to_save: Il n'y a pas aucune information pouvant être sauvegardée - some_invalid_entries: 'Le fichier importé contient des données non-conformes ' + some_invalid_entries: Les fichiers importés contiennent des valeurs invalides + fix_before_import: Veuillez corriger ces erreurs et recommencer l'import save_valid?: Sauvegarder les informations valides et détruire les autres? no_errors: Aucune erreur détectée! save_all_imported?: Sauvegarder tous les produits importés? @@ -436,7 +446,8 @@ fr: not_found: l'entreprise n'a pas été trouvée dans la base de données no_name: Pas de nom blank_supplier: certains produits ne sont associés à aucun fournisseur - reset_absent?: Mettre à zéro le produits absents du fichier? + reset_absent?: Mettre à zéro le produits absents du fichier + reset_absent_tip: Remettre le sock à zero pour les produits non présents dans le fichier. overwrite_all: Modifier pour tous overwrite_empty: Modifier si vide default_stock: Indiquer niveau de stock @@ -454,7 +465,7 @@ fr: inventory_to_reset: Dans le catalogue boutique, le stock des produits existants va être remis à zéro line: Ligne item_line: Ligne produit concernée - save: + save_results: final_results: Importer les informations produits confirmées products_created: produits crées products_updated: produits mis à jour @@ -464,6 +475,7 @@ fr: inventory_reset: produits ont vu leur niveau de stock remis à zéro dans le catalogue boutique all_saved: "Tous les produits ont été sauvegardés avec succès" some_saved: "produits sauvegardés avec succès" + save_errors: Sauvegarder les erreurs variant_overrides: loading_flash: loading_inventory: Catalogue boutique en cours de chargement... @@ -814,6 +826,10 @@ fr: schedule_present: Ce cycle de vente est lié à un rythme d'abonnement et ne peut pas être supprimé. Veuillez d'abord supprimer ce lien ou supprimer le rythme d'abonnement. bulk_update: no_data: Une erreur s'est produite. Aucune donnée trouvée. + date_warning: + msg: Ce cycle de vente est lié à %{n}abonnements ouverts. Changer cette date maintenant n'impactera pas les commandes déjà réalisée, mais nous vous déconseillons cette action néanmoins. Etes-vous sûrs de vouloir poursuivre ? + cancel: Annuler + proceed: Continuer producer_properties: index: title: Propriétés / labels du producteur @@ -928,7 +944,9 @@ fr: invalid_error: Oups! Veuillez remplir tous les champs obligatoires... allowed_payment_method_types_tip: Seules des méthodes de paiement de type "cash" ou "Stripe" peuvent être utilisées pour le moment credit_card: Carte de crédit - no_cards_available: Pas de carte disponible + charges_not_allowed: Le débit automatique n'a pas été autorisé par cet acheteur + no_default_card: L'acheteur n'a pas de carte de paiement disponible pour le débit + card_ok: L'acheteur a une carte de paiement disponible pour le débit loading_flash: loading: Abonnements en cours de chargement review: @@ -1006,6 +1024,7 @@ fr: require_customer_login: "La boutique est réservée aux membres." require_login_html: "Déjà inscrit? %{login}. Sinon, %{register} pour pouvoir faire vos achats." require_customer_html: "Veuillez %{contact} %{enterprise} pour devenir membre." + card_could_not_be_updated: La carte bancaire n'a pas pu être mise à jour card_could_not_be_saved: la carte n'a pas pu être sauvegardée spree_gateway_error_flash_for_checkout: "Il y a eu un problème avec vos informations de paiement : %{error}" invoice_billing_address: "Adresse de facturation :" @@ -1142,6 +1161,7 @@ fr: footer_legal_tos: "Termes et conditions" footer_legal_visit: "Nous trouver sur" footer_legal_text_html: "Open Food Network est une plateforme logicielle open source, libre et gratuite. Nos données sont protégées sous licence %{content_license} et notre code sous %{code_license}." + footer_skylight_dashboard_html: Les informations de performance sont disponibles sur %{dashboard}. home_shop: Faire mes courses brandstory_headline: "Des aliments porteurs de sens." brandstory_intro: "Parfois, le meilleur moyen de réparer le système, c'est d'en inventer un autre..." @@ -1553,6 +1573,17 @@ fr: reset_password: "Changer de mot de passe" who_is_managing_enterprise: "Qui gère %{enterprise}?" update_and_recalculate_fees: "Mettre à jour et recalculer les frais" + registration: + steps: + type: + headline: "Dernière étape pour ajouter %{enterprise} !" + question: "Etes-vous un producteur ?" + yes_producer: "Oui, je suis un producteur" + no_producer: "Non, je ne suis pas un producteur" + producer_field_error: "Veuillez faire un choix. Etes vous un producteur?" + yes_producer_help: "Un producteur fabrique de bonnes choses à boire et à manger. Vous êtes un producteur si vous les faites pousser, les élevez, les pétrissez, transformez, fermentez, les réduisez en grains, etc." + no_producer_help: "Si vous n'êtes pas un producteur, vous êtes probablement un revendeur ou distributeur alimentaire : un \"hub\", une coopérative, un groupement d'achat, un revendeur, un grossiste, ou autre." + create_profile: "Créer votre profil" enterprise: registration: modal: @@ -1591,13 +1622,6 @@ fr: phone_field_placeholder: 'ex : 06 24 53 26 53' type: title: 'Catégorie' - headline: "Dernière étape pour ajouter %{enterprise} !" - question: "Etes-vous un producteur ?" - yes_producer: "Oui, je suis un producteur" - no_producer: "Non, je ne suis pas un producteur" - producer_field_error: "Veuillez faire un choix. Etes vous un producteur?" - yes_producer_help: "Un producteur fabrique de bonnes choses à boire et à manger. Vous êtes un producteur si vous les faites pousser, les élevez, les pétrissez, transformez, fermentez, les réduisez en grains, etc." - no_producer_help: "Si vous n'êtes pas un producteur, vous êtes probablement un revendeur ou distributeur alimentaire : un \"hub\", une coopérative, un groupement d'achat, un revendeur, un grossiste, ou autre." about: title: 'A propos' images: @@ -1636,6 +1660,7 @@ fr: enterprise_about_headline: "Bien joué!" enterprise_about_message: "A présent, allons un peu plus dans les détails concernant" enterprise_success: "Opération réussie! %{enterprise} a été ajoutée à Open Food France" + enterprise_registration_exit_message: "Si vous quittez ce module, vous pourrez continuer la création de votre profile via l'interface d'administration." enterprise_description: "Description courte" enterprise_description_placeholder: "Une phrase pour décrire votre organisation" enterprise_long_desc: "Description longue" @@ -1685,7 +1710,6 @@ fr: registration_type_error: "Veuillez faire un choix. Etes vous un producteur?" registration_type_producer_help: "Un producteur fabrique de bonnes choses à boire et à manger. Vous êtes un producteur si vous les faites pousser, les élevez, les pétrissez, transformez, fermentez, les réduisez en grains, etc." registration_type_no_producer_help: "Si vous n'êtes pas un producteur, vous êtes probablement un revendeur ou distributeur alimentaire: un \"hub\", une coopérative, un groupement d'achat, un revendeur, un grossiste, ou autre." - create_profile: "Créer votre profil" registration_images_headline: "Merci!" registration_images_description: "Ajoutez maintenant de jolies photos pour que votre profil soit attractif! :)" registration_detail_headline: "Commençons" @@ -1744,7 +1768,6 @@ fr: you_have_no_orders_yet: "Vous n'avez pas encore de commande" running_balance: "Solde courant" outstanding_balance: "Solde restant" - admin_entreprise_relationships: "Permissions inter-entreprises" admin_entreprise_relationships_everything: "Tout" admin_entreprise_relationships_permits: "autorise" admin_entreprise_relationships_seach_placeholder: "Chercher" @@ -1846,7 +1869,7 @@ fr: spree_admin_single_enterprise_hint: "Astuce: Pour permettre aux gens de vous trouver, activez votre visibilité " spree_admin_eg_pickup_from_school: "ex : \"Retrait des produits à l'Ecole Marimati / Au Café du coin / chez Babette / ...\"" spree_admin_eg_collect_your_order: "ex : \"Veuillez récupérer votre commande au 34 rue Victor Hugo, 75018 Paris\"" - spree_classification_primary_taxon_error: "L'intitulé %{taxon}est l'intitulé de base pour %{product} et ne peut être supprimé" + spree_classification_primary_taxon_error: "La catégorie %{taxon}est utilisée par %{product} et ne peut être supprimée" spree_order_availability_error: "Le distributeur ne peut fournir les produits de votre panier pour ce cycle de vente." spree_order_populator_error: "Le distributeur ne peut fournir tous les produits de votre panier pour ce cycle de vente. Merci de choisir un autre distributeur ou un autre cycle de vente." spree_order_populator_availability_error: "Ce produit n'est pas disponible pour ce cycle de vente / distributeur." @@ -1868,8 +1891,6 @@ fr: edit_profile_details_etc: "Modifier la description, les images, etc." order_cycle: "Cycle de vente" order_cycles: "Cycles de Vente" - enterprises: "Entreprises" - enterprise_relationships: "Permissions inter-entreprises" remove_tax: "Retirer TVA" enterprise_terms_of_service: "Conditions Générales d'Utilisation" enterprises_require_tos: "Les entreprises doivent accepter les Conditions Générales d'Utilisation" @@ -1972,7 +1993,7 @@ fr: report_header_total_available: Total disponible report_header_unallocated: Non alloué report_header_max_quantity_excess: Dépassement Qté Max - report_header_taxons: Intitulés + report_header_taxons: Catégorie report_header_supplier: Fournisseur report_header_producer: Producteur report_header_producer_suburb: Ville Producteur @@ -2129,6 +2150,7 @@ fr: order_cycles_no_permission_to_coordinate_error: "Aucune de vos entreprises n'a les droits requis pour coordonner un cycle de vente" order_cycles_no_permission_to_create_error: "Vous n'avez pas les droits requis pour créer un cycle de vente coordonné par cette entreprise" back_to_orders_list: "Retour à la liste des commandes" + no_orders_found: "Aucune commande trouvée pour ces critères" order_information: "Info commande" date_completed: "Date d'opération" amount: "Montant" @@ -2153,6 +2175,7 @@ fr: choose: Choisir resolve_errors: Veuillez corriger les erreurs suivantes more_items: "+ %{count} en plus" + default_card_updated: La carte bancaire par défaut a été mise à jour admin: enterprise_limit_reached: "Vous avez atteint le nombre limite d'entreprises autorisées par défaut. Ecrivez à %{contact_email}si vous avez besoin d'augmenter cette limite." modals: @@ -2280,6 +2303,8 @@ fr: resolve: Résoudre new_tag_rule_dialog: select_rule_type: "Choisir le type de règle:" + resend_user_email_confirmation: + resend: "Renvoyer" out_of_stock: reduced_stock_available: Stock disponible out_of_stock_text: > @@ -2402,9 +2427,10 @@ fr: display_as: Unité affichéé category: Catégorie tax_category: TVA applicable - inherits_properties?: Hériter des propriétés producteur? + inherits_properties?: Hériter des propriétés? available_on: Disponible via av_on: "Disp. via" + import_date: "Date d'import (si import)" products_variant: variant_has_n_overrides: "Cette variante a été modifiée %{n} fois dans des catalogues boutiques" new_variant: "Nouvelle variante" @@ -2417,6 +2443,8 @@ fr: display_as: display_as: Unité affichéé reports: + table: + select_and_search: "Sélectionnez les filtres et cliquez sur RECHERCHER pour accéder à vos données." bulk_coop: bulk_coop_supplier_report: 'Achats groupés - Totaux par Producteur' bulk_coop_allocation: 'Achats groupés - Allocation' @@ -2533,5 +2561,12 @@ fr: total: Total paid?: Payé ? view: Afficher + saved_cards: + default?: Carte utilisée par défaut? + delete?: Supprimer? + cards: + authorised_shops: Boutiques autorisées. + authorised_shops_popover: Voilà la liste des boutiques que vous avez autorisées à débiter votre carte de paiement par défaut dans le cadre de vos abonnements en cours (commandes récurrentes). Les informations concernant votre carte de paiement sont sécurisées et ne sont pas accessibles par le gérant de la boutique. Vous recevrez systématiquement une notification avant tout débit sur votre carte. + saved_cards_popover: Voilà la liste des cartes de paiement que vous avez enregistrées. Votre carte par défaut sera automatiquement sélectionnée au moment de la finalisation d'une commande, et pourra être débitée par les boutiques auxquelles vous avez donné cette autorisation (voir à droite). localized_number: invalid_format: n'est pas un format valide. Veuillez entrer un nombre. From 0b9061df286e5c4e9d94e56f7b060a3c80e70453 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sat, 11 Aug 2018 22:17:12 +0100 Subject: [PATCH 044/122] removed Cart route, controller, model and specs: dead code --- .../open_food_network/cart_controller.rb | 39 ------ app/models/cart.rb | 28 ---- app/views/open_food_network/cart/show.v1.rabl | 6 - .../line_items/index.v1.rabl | 3 - .../open_food_network/line_items/show.v1.rabl | 4 - .../open_food_network/orders/index.v1.rabl | 3 - .../open_food_network/orders/show.v1.rabl | 7 - config/routes.rb | 6 - spec/controllers/cart_controller_spec.rb | 86 ------------ spec/models/cart_spec.rb | 131 ------------------ 10 files changed, 313 deletions(-) delete mode 100644 app/controllers/open_food_network/cart_controller.rb delete mode 100644 app/models/cart.rb delete mode 100644 app/views/open_food_network/cart/show.v1.rabl delete mode 100644 app/views/open_food_network/line_items/index.v1.rabl delete mode 100644 app/views/open_food_network/line_items/show.v1.rabl delete mode 100644 app/views/open_food_network/orders/index.v1.rabl delete mode 100644 app/views/open_food_network/orders/show.v1.rabl delete mode 100644 spec/controllers/cart_controller_spec.rb delete mode 100644 spec/models/cart_spec.rb diff --git a/app/controllers/open_food_network/cart_controller.rb b/app/controllers/open_food_network/cart_controller.rb deleted file mode 100644 index a4bc1c7b76b..00000000000 --- a/app/controllers/open_food_network/cart_controller.rb +++ /dev/null @@ -1,39 +0,0 @@ -module OpenFoodNetwork - class CartController < ApplicationController - respond_to :json - - # before_filter :authorize_read!, :except => [:index, :search, :create] - - def new - @cart = Cart.new(current_api_user) - if @cart.save - respond_with(@cart, :status => 201) - else - invalid_resource!(@cart) - end - end - - def show - @cart = Cart.find(params[:id]) - respond_with(@cart) - end - - def add_variant - @cart = Cart.find(params[:cart_id]) - distributor = Enterprise.find_by_permalink(params[:distributor_id]) - order_cycle = OrderCycle.find(params[:order_cycle_id]) if params[:order_cycle_id] - - if @cart.add_variant params[:variant_id], params[:quantity], distributor, order_cycle, current_currency - respond_with(@cart) - else - respond_with(@cart.populate_errors) - end - end - - private - - def current_currency - Spree::Config[:currency] - end - end -end diff --git a/app/models/cart.rb b/app/models/cart.rb deleted file mode 100644 index ecd1cfb94cf..00000000000 --- a/app/models/cart.rb +++ /dev/null @@ -1,28 +0,0 @@ -class Cart < ActiveRecord::Base - has_many :orders, :class_name => 'Spree::Order' - belongs_to :user, :class_name => Spree.user_class - - def add_variant variant_id, quantity, distributor, order_cycle, currency - order = create_or_find_order_for_distributor distributor, order_cycle, currency - - @populator = Spree::OrderPopulator.new(order, currency) - @populator.populate({ :variants => { variant_id => quantity } }) - end - - def create_or_find_order_for_distributor distributor, order_cycle, currency - order_for_distributor = orders.find { |order| order.distributor == distributor && order.order_cycle == order_cycle } - unless order_for_distributor - order_for_distributor = Spree::Order.create(:currency => currency, :distributor => distributor) - order_for_distributor.distributor = distributor - order_for_distributor.order_cycle = order_cycle - order_for_distributor.save! - orders << order_for_distributor - end - - order_for_distributor - end - - def populate_errors - @populator.errors - end -end diff --git a/app/views/open_food_network/cart/show.v1.rabl b/app/views/open_food_network/cart/show.v1.rabl deleted file mode 100644 index 056b439cd5a..00000000000 --- a/app/views/open_food_network/cart/show.v1.rabl +++ /dev/null @@ -1,6 +0,0 @@ -object @cart -attributes :id - -node( :orders ) do |p| - partial '/open_food_network/orders/index', object: p.orders -end diff --git a/app/views/open_food_network/line_items/index.v1.rabl b/app/views/open_food_network/line_items/index.v1.rabl deleted file mode 100644 index 3bc817063f5..00000000000 --- a/app/views/open_food_network/line_items/index.v1.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @line_items - -extends "open_food_network/line_items/show" diff --git a/app/views/open_food_network/line_items/show.v1.rabl b/app/views/open_food_network/line_items/show.v1.rabl deleted file mode 100644 index cf790085fe7..00000000000 --- a/app/views/open_food_network/line_items/show.v1.rabl +++ /dev/null @@ -1,4 +0,0 @@ -object @line_item -attributes :id, :quantity - -node(:name) { |p| p.variant.name } diff --git a/app/views/open_food_network/orders/index.v1.rabl b/app/views/open_food_network/orders/index.v1.rabl deleted file mode 100644 index 157b3c61323..00000000000 --- a/app/views/open_food_network/orders/index.v1.rabl +++ /dev/null @@ -1,3 +0,0 @@ -collection @orders - -extends "open_food_network/orders/show" diff --git a/app/views/open_food_network/orders/show.v1.rabl b/app/views/open_food_network/orders/show.v1.rabl deleted file mode 100644 index 6b49a458316..00000000000 --- a/app/views/open_food_network/orders/show.v1.rabl +++ /dev/null @@ -1,7 +0,0 @@ -object @order -attributes :id - -node( :distributor ) { |p| p.distributor.blank? ? "" : p.distributor.name } -node( :line_items ) do |p| - partial '/open_food_network/line_items/index', object: p.line_items -end diff --git a/config/routes.rb b/config/routes.rb index 42488bf3367..e6c446b6290 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -100,12 +100,6 @@ post '/product_images/:product_id', to: 'product_images#update_product_image' end - namespace :open_food_network do - resources :cart do - post :add_variant - end - end - get 'sitemap.xml', to: 'sitemap#index', defaults: { format: 'xml' } # Mount Spree's routes diff --git a/spec/controllers/cart_controller_spec.rb b/spec/controllers/cart_controller_spec.rb deleted file mode 100644 index 5d939b62542..00000000000 --- a/spec/controllers/cart_controller_spec.rb +++ /dev/null @@ -1,86 +0,0 @@ -require 'spec_helper' -require 'spree/api/testing_support/helpers' - -module OpenFoodNetwork - describe CartController, type: :controller do - render_views - - let(:user) { FactoryBot.create(:user) } - let(:product1) { FactoryBot.create(:product) } - let(:cart) { Cart.create(user: user) } - let(:distributor) { FactoryBot.create(:distributor_enterprise) } - - before do - end - - context "as a normal user" do - - context 'with an existing cart' do - - it "retrieves an empty cart" do - get :show, {id: cart, :format => :json } - json_response = JSON.parse(response.body) - - json_response['id'].should == cart.id - json_response['orders'].size.should == 0 - end - - context 'with an empty order' do - let(:order) { FactoryBot.create(:order, distributor: distributor) } - - before(:each) do - cart.orders << order - cart.save! - end - - it "retrieves a cart with a single order and line item" do - get :show, {id: cart, :format => :json } - json_response = JSON.parse(response.body) - - json_response['orders'].size.should == 1 - json_response['orders'].first['distributor'].should == order.distributor.name - json_response['orders'].first['line_items'].size.should == 0 - end - end - - context 'an order with line items' do - let(:product) { FactoryBot.create(:product, distributors: [ distributor ]) } - let(:order) { FactoryBot.create(:order, { distributor: distributor } ) } - let(:line_item) { FactoryBot.create(:line_item, { variant: product.master }) } - - before(:each) do - order.line_items << line_item - order.save - cart.orders << order - cart.save! - end - - it "retrieves a cart with a single order and line item" do - get :show, {id: cart, :format => :json } - json_response = JSON.parse(response.body) - - json_response['orders'].size.should == 1 - json_response['orders'].first['distributor'].should == order.distributor.name - json_response['orders'].first['line_items'].first["name"].should == product.name - json_response['orders'].first['line_items'].first["quantity"].should == line_item.quantity - end - end - - context 'adding a variant' do - - it 'should add variant to new order and return the order' do - product1.distributors << distributor - product1.save - variant = product1.variants.first - - put :add_variant, { cart_id: cart, variant_id: variant.id, quantity: (variant.on_hand-1), distributor_id: distributor, order_cycle_id: nil, max_quantity: nil } - - cart.orders.size.should == 1 - cart.orders.first.line_items.size.should == 1 - cart.orders.first.line_items.first.product.should == product1 - end - end - end - end - end -end diff --git a/spec/models/cart_spec.rb b/spec/models/cart_spec.rb deleted file mode 100644 index 08bc4ff3a89..00000000000 --- a/spec/models/cart_spec.rb +++ /dev/null @@ -1,131 +0,0 @@ -require 'spec_helper' - -# TODO this seems to be redundant -describe Cart do - - describe "associations" do - it { should have_many(:orders) } - end - - describe 'when adding a product' do - - let(:cart) { Cart.create(user: user) } - let(:distributor) { FactoryBot.create(:distributor_enterprise) } - let(:other_distributor) { FactoryBot.create(:distributor_enterprise) } - let(:currency) { "AUD" } - - let(:product) { FactoryBot.create(:product, :distributors => [distributor]) } - - let(:product_with_order_cycle) { create(:product) } - let(:order_cycle) { create(:simple_order_cycle, distributors: [distributor, other_distributor], variants: [product_with_order_cycle.master]) } - - describe 'to an empty cart' do - it 'should create an order for the product being added, and associate the product to the selected distribution' do - subject.add_variant product.master.id, 3, distributor, nil, currency - - subject.orders.size.should == 1 - order = subject.orders.first.reload - order.currency.should == currency - order.distributor.should == product.distributors.first - order.order_cycle.should be_nil - order.line_items.first.product.should == product - end - - it 'should create an order for the product being added, and associate the order with an order cycle and distributor' do - subject.add_variant product_with_order_cycle.master.id, 3, distributor, order_cycle, currency - - subject.orders.size.should == 1 - order = subject.orders.first.reload - order.currency.should == currency - order.distributor.should == distributor - order.order_cycle.should == order_cycle - order.line_items.first.product.should == product_with_order_cycle - end - end - - describe 'to a cart with an order for a distributor' do - let(:product_from_other_distributor) { FactoryBot.create(:product, :distributors => [other_distributor]) } - let(:order) { FactoryBot.create(:order, :distributor => distributor) } - - before do - FactoryBot.create(:line_item, :order => order, :product => product) - order.reload - subject.orders << order - subject.save! - end - - it 'should create a new order and add a line item to it when product added for different distributor' do - subject.add_variant product_from_other_distributor.master.id, 3, other_distributor, nil, currency - - subject.reload - subject.orders.size.should == 2 - new_order_for_other_distributor = subject.orders.find { |order| order.distributor == other_distributor } - new_order_for_other_distributor.order_cycle.should be_nil - order.line_items.size.should == 1 - new_order_for_other_distributor.line_items.size.should == 1 - new_order_for_other_distributor.line_items.first.product.should == product_from_other_distributor - end - - it 'should group line item in existing order, when product added for the same distributor' do - subject.add_variant product.master.id, 3, distributor, nil, currency - - subject.orders.size.should == 1 - order = subject.orders.first.reload - order.line_items.size.should == 2 - order.line_items.first.product.should == product - end - - it 'should create a new order for product in an order cycle' do - subject.add_variant product_with_order_cycle.master.id, 3, distributor, order_cycle, currency - - subject.orders.size.should == 2 - new_order_for_distributor = subject.orders.find { |order| order.order_cycle == order_cycle } - new_order_for_distributor.reload - new_order_for_distributor.line_items.first.product.should == product_with_order_cycle - end - end - - describe 'existing order for distributor and order cycle' do - let(:order) { FactoryBot.create(:order, :distributor => distributor, :order_cycle => order_cycle) } - - before do - subject.orders << order - subject.save! - end - - it 'should group line items in existing order when added for the same distributor and order cycle' do - subject.add_variant product_with_order_cycle.master.id, 3, distributor, order_cycle, currency - - subject.orders.size.should == 1 - order = subject.orders.first.reload - order.line_items.size.should == 1 - order.line_items.find{ |line_item| line_item.product == product_with_order_cycle }.should_not be_nil - end - - it 'should create line item in new order when product added is for a different order cycle' do - order_cycle2 = create(:simple_order_cycle, distributors: [distributor], variants: [product_with_order_cycle.master]) - - subject.add_variant product_with_order_cycle.master.id, 3, distributor, order_cycle2, currency - - subject.orders.size.should == 2 - new_order_for_second_order_cycle = subject.orders.find { |order| order.order_cycle == order_cycle2 } - new_order_for_second_order_cycle.reload - new_order_for_second_order_cycle.line_items.size.should == 1 - new_order_for_second_order_cycle.line_items.first.product.should == product_with_order_cycle - new_order_for_second_order_cycle.distributor.should == distributor - new_order_for_second_order_cycle.order_cycle.should == order_cycle2 - end - - it 'should create line_items in new order when added with different distributor, but same order_cycle' do - subject.add_variant product_with_order_cycle.master.id, 3, other_distributor, order_cycle, currency - - subject.orders.size.should == 2 - new_order_for_second_order_cycle = subject.orders.find { |order| order.distributor == other_distributor } - new_order_for_second_order_cycle.reload - new_order_for_second_order_cycle.line_items.size.should == 1 - new_order_for_second_order_cycle.line_items.find{ |line_item| line_item.product == product_with_order_cycle }.should_not be_nil - new_order_for_second_order_cycle.order_cycle.should == order_cycle - end - end - end -end From 4f751eb3e38be44715e89cd8fcb497c36084cee3 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Mon, 13 Aug 2018 17:08:33 +1000 Subject: [PATCH 045/122] Updating translations for config/locales/nb.yml --- config/locales/nb.yml | 163 ++++++++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 61 deletions(-) diff --git a/config/locales/nb.yml b/config/locales/nb.yml index ae77ae6d181..5cb20bd7bbc 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -19,7 +19,7 @@ nb: email: taken: "Det finnes allerede en konto for denne eposten. Vennligst logg inn eller tilbakestill passordet ditt." spree/order: - no_card: Det er ingen gyldige kredittkort tilgjengelig + no_card: Det er ingen gyldige kredittkort tilgjengelig for å trekke order_cycle: attributes: orders_close_at: @@ -41,11 +41,10 @@ nb: payment_method: not_available_to_shop: "er ikke tilgjengelig for %{shop}" invalid_type: "må være en Kontant eller Stripe metode" + charges_not_allowed: "^Kredittkortavgifter er ikke tillatt av denne kunden" + no_default_card: "^Ingen standardkort tilgjengelig for denne kunden" shipping_method: not_available_to_shop: "er ikke tilgjengelig for %{shop}" - credit_card: - not_available: "er ikke tilgjengelig" - blank: "er påkrevd" devise: confirmations: send_instructions: "Du vil motta en epost med instruksjoner om hvordan du bekrefter kontoen din om noen få minutter." @@ -160,6 +159,7 @@ nb: distributors: Distributører distribution: Distribusjon bulk_order_management: Bulk ordrehåndtering + enterprises: Bedrifter enterprise_groups: Grupper reports: Rapporter variant_overrides: Varelager @@ -310,6 +310,42 @@ nb: included_tax_tip: "Total avgift inkludert i eksemplet på månedlig regning, gitt innstillingene og omsetningen som er satt." total_monthly_bill_incl_tax: "Total Månedlig Regning (Inkl. Avgift)" total_monthly_bill_incl_tax_tip: "Eksempel på total månedlig regning inkludert avgift, gitt innstillingene og omsetningen som er satt." + cache_settings: + show: + title: Mellomlagring + distributor: Distributør + order_cycle: Bestillingsrunde + status: Status + diff: Forskjell + error: Feil + invoice_settings: + edit: + title: Fakturainnstillinger + invoice_style2?: Bruk den alternative fakturamodellen som inkluderer total avgiftsoppdeling pr rate og avgiftsrateinfo pr vare (passer ikke for land som viser priser ekskludert avgift) + enable_receipt_printing?: 'Vis valg for utskrift av kvitteringer ved bruk av kvitteringsprinter i nedtrekksmeny for bestillinger? ' + stripe_connect_settings: + edit: + title: "Stripe Connect" + settings: "Innstillinger" + stripe_connect_enabled: Sette butikker i stand til å godta betaling ved hjelp av Stripe Connect? + no_api_key_msg: Ingen Stripe-konto eksisterer for denne bedriften. + configuration_explanation_html: For detaljerte instruksjoner om konfigurering av Stripe Connect-integrasjonen, vennligst se denne veiledningen . + status: Status + ok: Ok + instance_secret_key: Instans Secret Key + account_id: Konto-ID + business_name: Bedriftsnavn + charges_enabled: Avgifter Aktivert + charges_enabled_warning: "Advarsel: Avgifter er ikke aktivert for kontoen din" + auth_fail_error: API-nøkkelen du oppga er ugyldig + empty_api_key_error_html: Ingen Stripe API-nøkkel er gitt. For å angi din API-nøkkelen, følg disse instruksjonene + matomo_settings: + edit: + title: "Matomo Innstillinger" + matomo_url: "Matomo URL" + matomo_site_id: "Matomo Site ID" + info_html: "Matomo er en web- og mobilanalyse. Du kan enten hoste Matomo selv eller bruke en skytjeneste. Se matomo.org for mer informasjon." + config_instructions_html: "Her kan du konfigurere OFN-Matomo integrasjonen. URL til Matomo nedenfor skal peke på Matomo-instansen der brukersporingsinformasjonen skal sendes til; Hvis den er tom, blir Matomo-brukersporing deaktivert. Site-ID feltet er ikke obligatorisk, men nyttig hvis du sporer mer enn ett nettsted på en enkelt Matomo-instans; den kan bli funnet på Matomo-konsollen." customers: index: add_customer: "Legge til kunde" @@ -332,16 +368,9 @@ nb: update_address: 'Oppdater Adresse' confirm_delete: 'Sikker på å slette?' search_by_email: "Søk på epost/kode..." + guest_label: 'Gjesteutsjekk' destroy: has_associated_orders: 'Sletting mislyktes: kunden har tilknyttede ordrer med sin butikk' - cache_settings: - show: - title: Mellomlagring - distributor: Distributør - order_cycle: Bestillingsrunde - status: Status - diff: Forskjell - error: Feil contents: edit: title: Innhold @@ -414,20 +443,29 @@ nb: index: select_file: Velg et regneark for å laste opp spreadsheet: Regneark - import_into: "Importer inn i:" + choose_import_type: Velg importtype + import_into: Importtype product_list: Produktliste inventories: Varelagre import: Import upload: Last opp + csv_templates: CSV-maler + product_list_template: Last ned mal for produktliste + inventory_template: Last ned Inventory mal + category_values: Tilgjengelige kategoriverdier + product_categories: Produktkategorier + tax_categories: Avgiftskategorier + shipping_categories: Fraktkategorier import: review: Anmeldelse - proceed: Fortsett + import: Import save: Lagre results: Resultater save_imported: Lagre importerte produkter no_valid_entries: Ingen gyldige oppføringer funnet none_to_save: Det er ingen oppføringer som kan lagres - some_invalid_entries: Importert fil inneholder noen ugyldige oppføringer + some_invalid_entries: Importert fil inneholder ugyldige oppføringer + fix_before_import: Vennligst rett disse feilene og prøv å importere filen igjen save_valid?: Lagre gyldige oppføringer for nå og forkast de andre? no_errors: Ingen feil oppdaget! save_all_imported?: Lagre alle importerte produkter? @@ -436,7 +474,8 @@ nb: not_found: bedriften kunne ikke bli funnet i databasen no_name: Ingen navn blank_supplier: noen produkter har tomt leverandørnavn - reset_absent?: Tilbakestill fraværende produkter? + reset_absent?: Tilbakestill fraværende produkter + reset_absent_tip: Sett lager til null for alle gjeldende produkter som ikke er til stede i filen overwrite_all: Overskrive alt overwrite_empty: Overskriv hvis tomt default_stock: Sett lagernivå @@ -454,7 +493,7 @@ nb: inventory_to_reset: Eksisterende vareobjekter vil få lager satt til null line: Linje item_line: Artikkellinje - save: + save_results: final_results: Importer endelige resultater products_created: Produkter opprettet products_updated: Produkter oppdatert @@ -465,8 +504,9 @@ nb: all_saved: "Alle elementer lagret vellykket" some_saved: "elementer lagret vellykket" save_errors: Lagre feil - view_products: Se produkter - view_inventory: Se beholdning + import_again: Last opp en annen fil + view_products: Gå til produktside + view_inventory: Gå til varelager variant_overrides: loading_flash: loading_inventory: LASTER VARELAGER @@ -684,7 +724,7 @@ nb: email_confirmed: "Epost bekreftet" email_not_confirmed: "Epost ikke bekreftet" actions: - edit_profile: Endre Profil + edit_profile: Innstillinger properties: Egenskaper payment_methods: Betalingsmetoder payment_methods_tip: Denne bedriften har ingen betalingsmetoder @@ -724,13 +764,14 @@ nb: no_enterprises_found: Ingen bedrifter funnet. search_placeholder: Søk på navn manage: Administrer + manage_link: Innstillinger new_form: owner: Eier owner_tip: Primærbrukeren ansvarlig for denne bedriften. i_am_producer: Jeg er en Produsent contact_name: Kontaktnavn edit: - editing: 'Endrer:' + editing: 'innstillinger:' back_link: Tilbake til bedriftsliste new: title: Ny Bedrift @@ -816,6 +857,10 @@ nb: schedule_present: Denne bestillingsrunden er knyttet til en tidsplan og kan ikke slettes. Vennligst fjern koblingen eller slett tidsplanen først. bulk_update: no_data: Hm, noe gikk galt. Ingen data for bestillingsrunde funnet. + date_warning: + msg: Denne bestillingsrunden er knyttet til %{n} åpne abonnementsordrer. Endring av denne dato vil ikke påvirke noen ordre som allerede er utført, men bør unngås hvis det er mulig. Er du sikker på at du vil fortsette? + cancel: Avbryt + proceed: Fortsett producer_properties: index: title: Produsentegenskaper @@ -827,11 +872,6 @@ nb: shared: user_guide_link: user_guide: Brukermanual - invoice_settings: - edit: - title: Fakturainnstillinger - invoice_style2?: Bruk den alternative fakturamodellen som inkluderer total avgiftsoppdeling pr rate og avgiftsrateinfo pr vare (passer ikke for land som viser priser ekskludert avgift) - enable_receipt_printing?: 'Vis valg for utskrift av kvitteringer ved bruk av kvitteringsprinter i nedtrekksmeny for bestillinger? ' overview: enterprises_header: ofn_with_tip: Bedrifter er Produsenter og / eller Hubs og er den grunnleggende organisasjonsenheten innen Open Food Network. @@ -925,12 +965,18 @@ nb: address: 2. Adresse products: 3. Legg til produkter review: 4. Se gjennom og lagre + subscription_line_items: + this_is_an_estimate: | + De viste prisene er bare et estimat og beregnet på det tidspunktet abonnementet endres. + Hvis du endrer priser eller avgifter, vil ordrer bli oppdatert, men abonnementet vil fortsatt vise de gamle verdiene. details: details: Detaljer invalid_error: Oops! Vennligst fyll inn alle obligatoriske felter... allowed_payment_method_types_tip: Bare Kontant og Stripe betalingsmetoder kan brukes for øyeblikket credit_card: Kredittkort - no_cards_available: Ingen kort tilgjengelig + charges_not_allowed: Korttrekk er ikke tillatt av denne kunden + no_default_card: Kunden har ingen kort tilgjengelig for å trekke + card_ok: Kunden har et kort tilgjengelig for å trekke loading_flash: loading: LASTER ABONNEMENT review: @@ -960,22 +1006,6 @@ nb: schedules: destroy: associated_subscriptions_error: Denne tidsplanen kan ikke slettes fordi den har tilknyttede abonnementer - stripe_connect_settings: - edit: - title: "Stripe Connect" - settings: "Innstillinger" - stripe_connect_enabled: Sette butikker i stand til å godta betaling ved hjelp av Stripe Connect? - no_api_key_msg: Ingen Stripe-konto eksisterer for denne bedriften. - configuration_explanation_html: For detaljerte instruksjoner om konfigurering av Stripe Connect-integrasjonen, vennligst se denne veiledningen . - status: Status - ok: Ok - instance_secret_key: Instans Secret Key - account_id: Konto-ID - business_name: Bedriftsnavn - charges_enabled: Avgifter Aktivert - charges_enabled_warning: "Advarsel: Avgifter er ikke aktivert for kontoen din" - auth_fail_error: API-nøkkelen du oppga er ugyldig - empty_api_key_error_html: Ingen Stripe API-nøkkel er gitt. For å angi din API-nøkkelen, følg disse instruksjonene controllers: enterprises: stripe_connect_cancelled: "Tilkobling til Stripe har blitt avbrutt" @@ -1235,6 +1265,7 @@ nb: email_confirmation_click_link: "Trykk på linken under for å bekrefte din epost og for å fortsette oppsettet av din profil." email_confirmation_link_label: "Bekreft denne epostadressen »" email_confirmation_help_html: "Etter du har bekreftet epostadressen din får du tilgang til din administrasjonskonto for denne bedriften. Se linken %{link} for å finne ut mer om %{sitename}s funksjoner og for å begynne å bruke din profil eller nettbutikk." + email_confirmation_notice_unexpected: "Du har mottatt denne meldingen fordi du registrerte deg på %{sitename}, eller ble invitert til å registrere deg av noen du sikkert kjenner. Hvis du ikke forstår hvorfor du mottar denne e-posten, skriv til %{contact}." email_social: "Her finner du oss:" email_contact: "Send oss en epost:" email_signoff: "Mvh," @@ -1557,6 +1588,17 @@ nb: reset_password: "Tilbakestill passord" who_is_managing_enterprise: "Hvem er ansvarlig for å administrere %{enterprise}?" update_and_recalculate_fees: "Oppdater og regn avgifter på nytt" + registration: + steps: + type: + headline: "Siste skritt for å legge til %{enterprise}!" + question: "Er du en produsent?" + yes_producer: "Ja, jeg er produsent" + no_producer: "Nei, jeg er ikke produsent" + producer_field_error: "Vennligst velg en. Er du produsent?" + yes_producer_help: "Produsenter lager deilige ting å spise og/eller drikke. Du er en produsent hvis du vokser den, hever den, brygger den, baker den, gjærer den, melker den eller støper den." + no_producer_help: "Hvis du ikke er produsent, er du sannsynligvis noen som selger og distribuerer mat. Du kan være en hub, kooperativ, kjøpegruppe, forhandler, grossist eller annet." + create_profile: "Opprett profil" enterprise: registration: modal: @@ -1595,13 +1637,6 @@ nb: phone_field_placeholder: 'f.eks. (03) 1234 5678' type: title: 'Type' - headline: "Siste skritt for å legge til %{enterprise}!" - question: "Er du en produsent?" - yes_producer: "Ja, jeg er produsent" - no_producer: "Nei, jeg er ikke produsent" - producer_field_error: "Vennligst velg en. Er du produsent?" - yes_producer_help: "Produsenter lager deilige ting å spise og/eller drikke. Du er en produsent hvis du vokser den, hever den, brygger den, baker den, gjærer den, melker den eller støper den." - no_producer_help: "Hvis du ikke er produsent, er du sannsynligvis noen som selger og distribuerer mat. Du kan være en hub, kooperativ, kjøpegruppe, forhandler, grossist eller annet." about: title: 'Om' images: @@ -1689,7 +1724,6 @@ nb: registration_type_error: "Vennligst velg en. Er du produsent?" 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!" registration_images_description: "La oss laste opp noen fine bilder så profilen din ser flott ut! :)" registration_detail_headline: "La oss komme i gang" @@ -1748,7 +1782,6 @@ nb: 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" @@ -1872,8 +1905,6 @@ nb: edit_profile_details_etc: "Endre din profilbeskrivelse, bilder, osv." order_cycle: "Bestillingsrunde" order_cycles: "Bestillingsrunder" - enterprises: "Bedrifter" - enterprise_relationships: "Bedriftsrelasjoner" remove_tax: "Fjern avgift" enterprise_terms_of_service: "Tjenestevilkår for Bedrifter" enterprises_require_tos: "Bedrifter må godta Tjenestevilkår" @@ -2137,7 +2168,8 @@ nb: amount: "Beløp" state_names: ready: Klar - pending: I påvente av + pending: Venter + shipped: Levert js: saving: 'Lagrer...' changes_saved: 'Endringene er lagret.' @@ -2155,10 +2187,14 @@ nb: choose: Velge resolve_errors: Vennligst løse følgende feil more_items: "+ %{count} Flere" + default_card_updated: Standardkort oppdatert admin: enterprise_limit_reached: "Du har nådd standardgrensen for bedrifter per konto. Skriv til %{contact_email} hvis du trenger å øke den." modals: got_it: Jeg forstår + close: "Lukk" + invite: "Inviter" + invite_title: "Inviter en uregistrert bruker" tag_rule_help: title: Regler for Merkelapper overview: Oversikt @@ -2271,6 +2307,8 @@ nb: resolve: Løse new_tag_rule_dialog: select_rule_type: "Velg en regeltype:" + resend_user_email_confirmation: + resend: "Send på nytt" out_of_stock: reduced_stock_available: Redusert lager tilgjengelig out_of_stock_text: > @@ -2332,6 +2370,8 @@ nb: email: Epost account_updated: "Konto oppdatert!" my_account: "Min konto" + date: "Dato" + time: "Tid" admin: orders: invoice: @@ -2386,12 +2426,13 @@ nb: products_head: name: Navn unit: Enhet - display_as: Vis Som + display_as: Vis som category: Kategori tax_category: Avgiftskategori - inherits_properties?: Arver Egenskaper? - available_on: Tilgjengelig På + inherits_properties?: Arver egenskaper? + available_on: Tilgjengelig på av_on: "Tilgj. På" + import_date: "Importdato" products_variant: variant_has_n_overrides: "Denne varianten har %{n} overstyring(er)" new_variant: "Ny variant" @@ -2409,9 +2450,6 @@ nb: bulk_coop_allocation: 'Bulk Co-op - Allokering' bulk_coop_packing_sheets: 'Bulk Co-op - Pakkseddel' bulk_coop_customer_payments: 'Bulk Co-op - Kunde Betalinger' - shared: - configuration_menu: - stripe_connect: Stripe Connect variants: autocomplete: producer_name: Produsent @@ -2519,5 +2557,8 @@ nb: total: Total paid?: Betalt? view: Vis + saved_cards: + default?: Standard? + delete?: Slett? localized_number: invalid_format: har et ugyldig format. Vennligst skriv inn et nummer. From 362ed8ed08a18f0d8ca8a9ef0eaa2704d75b459d Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sun, 24 Jun 2018 16:10:02 +0100 Subject: [PATCH 046/122] Changed modals max height from 120% to 100% so that the content in the modal is never outside the viewport --- app/assets/stylesheets/darkswarm/modals.css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/darkswarm/modals.css.scss b/app/assets/stylesheets/darkswarm/modals.css.scss index 85770cfd097..69ad042374d 100644 --- a/app/assets/stylesheets/darkswarm/modals.css.scss +++ b/app/assets/stylesheets/darkswarm/modals.css.scss @@ -28,7 +28,7 @@ dialog, .reveal-modal { // Medium and up - when modal IS NOT full screen @media only screen and (min-width: 641px) { top: 10%; - max-height: 120%; + max-height: 100%; } } From 08c5d8f3abf08119974d43c2d40a82e735d0cb0d Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sun, 24 Jun 2018 16:10:24 +0100 Subject: [PATCH 047/122] Added new cookies policy page and added a link to it in the footer (cookies policy link) --- .../cookies_policy/cookies_policy.html.haml | 89 +++++++++++++++++++ .../cookies_policy_modal_controller.js.coffee | 3 + .../cookies_policy_modal_directive.js.coffee | 5 ++ .../cookies_policy_modal_service.js.coffee | 16 ++++ .../darkswarm/cookies_policy_modal.css.scss | 15 ++++ app/views/shared/_footer.html.haml | 6 ++ config/locales/en.yml | 27 +++++- 7 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml create mode 100644 app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_controller.js.coffee create mode 100644 app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_directive.js.coffee create mode 100644 app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee create mode 100644 app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml new file mode 100644 index 00000000000..4599813a62c --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml @@ -0,0 +1,89 @@ +%h2 + {{ 'legal.cookies_policy.header' | t}} +%p + {{ 'legal.cookies_policy.desc_part_1' | t}} +%p + {{ 'legal.cookies_policy.desc_part_2' | t}} +%p + {{ 'legal.cookies_policy.desc_part_3' | t}} + +%h2 + {{ 'legal.cookies_policy.essential_cookies' | t}} +%p + {{ 'legal.cookies_policy.essential_cookies_desc' | t}} + +%table{ng: { controller:"CookiesPolicyModalCtrl"}} + %tr + %th + {{ 'legal.cookies_policy.cookie_name' | t}} + %th + {{ 'legal.cookies_policy.cookie_domain' | t}} + %th + {{ 'legal.cookies_policy.cookie_desc' | t}} + %tr + %td + _session_id + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_session_desc' | t}} + %tr + %td + remember_spree_user_token + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_remember_me_desc' | t}} + %tr + %td + qos_token + %td + openstreetmap.org + %td + {{ 'legal.cookies_policy.cookie_openstreemap_desc' | t}} + %tr + %td + m + %td + m.stripe.com + %td{rowspan:"4"} + {{ 'legal.cookies_policy.cookie_stripe_desc' | t}} + %tr + %td + nsr + %td + m.stripe.network + %tr + %td + __stripe_sid + %td + {{ instance_hostname }} + %tr + %td + __stripe_mid + %td + {{ instance_hostname }} +%p + {{ 'legal.cookies_policy.essential_cookies_note' | t}} +%h2 + {{ 'legal.cookies_policy.disabling_cookies_header' | t}} +%p + {{ 'legal.cookies_policy.disabling_cookies_desc' | t}} +%ul + %li + %a{ href: "{{'legal.cookies_policy.disabling_cookies_firefox_link' | t}}", target: "_blank" } + Firefox + %li + %a{ href: "{{ 'legal.cookies_policy.disabling_cookies_chrome_link' | t}}", target: "_blank" } + Chrome + %li + %a{ href: "{{ 'legal.cookies_policy.disabling_cookies_ie_link' | t}}", target: "_blank" } + Internet Explorer + %li + %a{ href: "{{ 'legal.cookies_policy.disabling_cookies_safari_link' | t}}", target: "_blank" } + Safari +%p + {{ 'legal.cookies_policy.disabling_cookies_note' | t}} + +%a.close-reveal-modal{"ng-click" => "$close()"} + %i.ofn-i_009-close diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_controller.js.coffee b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_controller.js.coffee new file mode 100644 index 00000000000..675f88e98f8 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_controller.js.coffee @@ -0,0 +1,3 @@ +Darkswarm.controller "CookiesPolicyModalCtrl", ($scope, $window)-> + + $scope.instance_hostname = $window.location.hostname diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_directive.js.coffee b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_directive.js.coffee new file mode 100644 index 00000000000..b007f11e463 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_directive.js.coffee @@ -0,0 +1,5 @@ +Darkswarm.directive 'cookiesPolicyModal', (CookiesPolicyModalService) -> + restrict: 'A' + link: (scope, elem, attrs) -> + elem.bind "click", -> + CookiesPolicyModalService.open '' diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee new file mode 100644 index 00000000000..43576d80b94 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee @@ -0,0 +1,16 @@ +Darkswarm.factory "CookiesPolicyModalService", (Navigation, $modal, $location)-> + + new class CookiesPolicyModalService + defaultPath: "/policies/cookies" + modalMessage: null + + constructor: -> + if $location.path() is @defaultPath || location.pathname is @defaultPath + @open '' + + open: (path = false, template = 'darkswarm/cookies_policy/cookies_policy.html') => + @modalInstance = $modal.open + templateUrl: template + windowClass: "cookies-policy-modal medium" + selectedPath = path || @defaultPath + Navigation.navigate selectedPath diff --git a/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss new file mode 100644 index 00000000000..ded91c61c91 --- /dev/null +++ b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss @@ -0,0 +1,15 @@ +.cookies-policy-modal { + background: #efefef; + border-bottom-color: #efefef; +} + +.cookies-policy-modal table { + display: block; + overflow-x: auto; +} + +.cookies-policy-modal.fade { + -webkit-transform: translate(0, 0) !important; + -ms-transform: translate(0, 0) !important; + transform: translate(0, 0) !important; +} diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index d18d7d03e32..9dc0f95a5bb 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -139,6 +139,12 @@ %a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub %p.text-small = t :footer_legal_text_html, {content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)')} + %p.text-small + %div + = t :footer_legal_data_text + = t :footer_legal_data_call + %a{'cookies-policy-modal'=> true} + = t :footer_legal_data_cookies_policy .medium-2.columns.text-center / Placeholder diff --git a/config/locales/en.yml b/config/locales/en.yml index db41bf15b92..8a0dcc58a04 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1264,8 +1264,33 @@ en: footer_legal_tos: "Terms and conditions" footer_legal_visit: "Find us on" footer_legal_text_html: "Open Food Network is a free and open source software platform. Our content is licensed with %{content_license} and our code with %{code_license}." - + footer_legal_data_text: "We take good care of your data." + footer_legal_data_call: "See our" + footer_legal_data_cookies_policy: "cookies policy" footer_skylight_dashboard_html: Performance data is available on %{dashboard}. + legal: + cookies_policy: + header: "How We Use Cookies" + desc_part_1: "Cookies are very small text files that are stored on your computer when you visit some websites." + desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics services for short food systems) but we are not yet there, and we won’t do it without your authorization :-)" + desc_part_3: "We use cookies mainly to remember who you are if you 'log in' to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website. Here is the list of cookies we use!" + essential_cookies: "Essential Cookies" + essential_cookies_desc: "The following cookies are strictly necessary for the operation of our website." + essential_cookies_note: "Most cookies only contain a unique identifier, but no other data, so your email address and password for instance are never contained in them and never exposed." + cookie_name: "Cookie Name" + cookie_domain: "Set By" + cookie_desc: "Description" + cookie_session_desc: "Used to allow the website to remember users between page visits, for example, remember items in your cart." + cookie_remember_me_desc: "Used if the user has requested the website to remember him. This cookie is automatically deleted after 12 days. If as a user you want that cookie to be deleted, you only need to logout. If you don’t want that cookie to be installed on your computer you shouldn’t check the “remember me” checkbox when logging in." + cookie_openstreemap_desc: "Used by our friendly open source mapping provider (OpenStreetMap) to ensure that it does not receive too many requests during a given time period, to prevent abuse of their services." + cookie_stripe_desc: "Data collected by our payment processor Stripe for fraud detection https://stripe.com/cookies-policy/legal. Not all shops use Stripe as a payment method but it is a good practice to prevent fraud to apply it to all pages. Stripe probably build a picture of which of our pages usually interact with their API and then flag anything unusual. So setting the Stripe cookie has a broader function than simply the provision of a payment method to a user. Removing it could affect the security of the service itself. You can learn more about Stripe and read its privacy policy at https://stripe.com/privacy." + disabling_cookies_header: "Warning on disabling cookies" + disabling_cookies_desc: "As a user you can always allow, block or delete Open Food Network’s or any other website cookies whenever you want to through your browser’s setting control. Each browser has a different operative. Here are the links:" + disabling_cookies_firefox_link: "https://support.mozilla.org/en-US/kb/enable-and-disable-cookies-website-preferences" + disabling_cookies_chrome_link: "https://support.google.com/chrome/answer/95647" + disabling_cookies_ie_link: "https://support.microsoft.com/en-us/help/17442/windows-internet-explorer-delete-manage-cookies" + disabling_cookies_safari_link: "https://www.apple.com/legal/privacy/en-ww/cookies/" + disabling_cookies_note: "But be aware that if you delete or modify the essential cookies used by Open Food Network, the website won’t work, you will not be able to add anything to your cart neither to checkout for instance." home_shop: Shop Now From 92f9cbd00af5b09a55a0bbc471c094da34404703 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Thu, 28 Jun 2018 01:52:09 +0100 Subject: [PATCH 048/122] Added new cookies banner (with link to cookie policy page and the accept cookies button) --- .../cookies_banner/cookies_banner.html.haml | 15 ++++++++++ .../cookies_banner_controller.js.coffee | 5 ++++ .../cookies_banner_directive.js.coffee | 5 ++++ .../cookies_banner_service.js.coffee | 20 +++++++++++++ .../cookies_policy_modal_service.js.coffee | 16 ++++++++++- .../darkswarm/cookies_banner.css.scss | 28 +++++++++++++++++++ .../api/cookies_consent_controller.rb | 26 +++++++++++++++++ app/services/cookies_consent.rb | 28 +++++++++++++++++++ app/views/shared/_footer.html.haml | 2 +- config/locales/en.yml | 7 +++++ config/routes.rb | 5 +++- 11 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/darkswarm/cookies_banner/cookies_banner.html.haml create mode 100644 app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_controller.js.coffee create mode 100644 app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee create mode 100644 app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_service.js.coffee create mode 100644 app/assets/stylesheets/darkswarm/cookies_banner.css.scss create mode 100644 app/controllers/api/cookies_consent_controller.rb create mode 100644 app/services/cookies_consent.rb diff --git a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner.html.haml b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner.html.haml new file mode 100644 index 00000000000..2343051cd79 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner.html.haml @@ -0,0 +1,15 @@ +.row + .large-9.columns + %p + {{ 'legal.cookies_banner.cookies_usage' | t}} + %p + {{ 'legal.cookies_banner.cookies_desc' | t}} + %p + {{ 'legal.cookies_banner.cookies_policy_link_desc' | t}} + -# + %a{ 'cookies-policy-modal'=> true} + {{ 'legal.cookies_banner.cookies_policy_link' | t}} + + .large-3.columns + %button{ng: { controller:"CookiesBannerCtrl", click: "acceptCookies()" }} + {{ 'legal.cookies_banner.cookies_accept_button' | t}} diff --git a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_controller.js.coffee b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_controller.js.coffee new file mode 100644 index 00000000000..69b8554c370 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_controller.js.coffee @@ -0,0 +1,5 @@ +Darkswarm.controller "CookiesBannerCtrl", ($scope, CookiesBannerService, $http, $window)-> + + $scope.acceptCookies = -> + $http.post('/api/cookies/consent') + CookiesBannerService.close() diff --git a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee new file mode 100644 index 00000000000..f3553018a2b --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee @@ -0,0 +1,5 @@ +Darkswarm.directive 'cookiesBanner', (CookiesBannerService) -> + restrict: 'A' + link: (scope, elm, attr)-> + CookiesBannerService.setActive() + CookiesBannerService.open() diff --git a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_service.js.coffee b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_service.js.coffee new file mode 100644 index 00000000000..8d8a9e49609 --- /dev/null +++ b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_service.js.coffee @@ -0,0 +1,20 @@ +Darkswarm.factory "CookiesBannerService", (Navigation, $modal, $location, Redirections, Loading)-> + + new class CookiesBannerService + modalMessage: null + isActive: false + + open: (path, template = 'darkswarm/cookies_banner/cookies_banner.html') => + return unless @isActive + @modalInstance = $modal.open + templateUrl: template + windowClass: "cookies-banner full" + backdrop: 'static' + keyboard: false + + close: => + return unless @isActive + @modalInstance.close() + + setActive: => + @isActive = true diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee index 43576d80b94..53770180892 100644 --- a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.factory "CookiesPolicyModalService", (Navigation, $modal, $location)-> +Darkswarm.factory "CookiesPolicyModalService", (Navigation, $modal, $location, CookiesBannerService)-> new class CookiesPolicyModalService defaultPath: "/policies/cookies" @@ -12,5 +12,19 @@ Darkswarm.factory "CookiesPolicyModalService", (Navigation, $modal, $location)-> @modalInstance = $modal.open templateUrl: template windowClass: "cookies-policy-modal medium" + + @closeCookiesBanner() + @onCloseReOpenCookiesBanner() + selectedPath = path || @defaultPath Navigation.navigate selectedPath + + closeCookiesBanner: => + setTimeout -> + CookiesBannerService.close() + , 200 + + onCloseReOpenCookiesBanner: => + @modalInstance.result.then( + -> CookiesBannerService.open(), + -> CookiesBannerService.open() ) diff --git a/app/assets/stylesheets/darkswarm/cookies_banner.css.scss b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss new file mode 100644 index 00000000000..2a2e2a057cb --- /dev/null +++ b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss @@ -0,0 +1,28 @@ +.cookies-banner { + background: #3b3b3b; + position: fixed; + bottom: 0; + z-index: 100000; + top: 20vh !important; + + @media only screen and (min-width: 640px) { + top: 20vh !important; + } + + @media only screen and (min-width: 800px) and (min-height: 400px) { + top: 40vh !important; + } + + @media only screen and (min-width: 1024px) and (min-height: 500px) { + top: 60vh !important; + } + + button { + background-color: green; + } + + p { + color: white; + font-size: 0.75rem; + } +} diff --git a/app/controllers/api/cookies_consent_controller.rb b/app/controllers/api/cookies_consent_controller.rb new file mode 100644 index 00000000000..89016c20661 --- /dev/null +++ b/app/controllers/api/cookies_consent_controller.rb @@ -0,0 +1,26 @@ +module Api + class CookiesConsentController < BaseController + include ActionController::Cookies + respond_to :json + + def show + render json: { cookies_consent: cookies_consent.exists? } + end + + def create + cookies_consent.set + show + end + + def destroy + cookies_consent.destroy + show + end + + private + + def cookies_consent + @cookies_consent ||= CookiesConsent.new(cookies, request.host) + end + end +end diff --git a/app/services/cookies_consent.rb b/app/services/cookies_consent.rb new file mode 100644 index 00000000000..8b35fa74027 --- /dev/null +++ b/app/services/cookies_consent.rb @@ -0,0 +1,28 @@ +class CookiesConsent + COOKIE_NAME = 'cookies_consent'.freeze + + def initialize(cookies, domain) + @cookies = cookies + @domain = domain + end + + def exists? + cookies.key?(COOKIE_NAME) + end + + def destroy + cookies.delete(COOKIE_NAME, domain: domain) + end + + def set + cookies[COOKIE_NAME] = { + value: COOKIE_NAME, + expires: 1.year.from_now, + domain: domain + } + end + + private + + attr_reader :cookies, :domain +end diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 9dc0f95a5bb..22eaff9bfa8 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -143,7 +143,7 @@ %div = t :footer_legal_data_text = t :footer_legal_data_call - %a{'cookies-policy-modal'=> true} + %a{'cookies-policy-modal'=> true, 'cookies-banner'=> !CookiesConsent.new(cookies, request.host).exists? } = t :footer_legal_data_cookies_policy .medium-2.columns.text-center diff --git a/config/locales/en.yml b/config/locales/en.yml index 8a0dcc58a04..1397a770562 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1291,6 +1291,13 @@ en: disabling_cookies_ie_link: "https://support.microsoft.com/en-us/help/17442/windows-internet-explorer-delete-manage-cookies" disabling_cookies_safari_link: "https://www.apple.com/legal/privacy/en-ww/cookies/" disabling_cookies_note: "But be aware that if you delete or modify the essential cookies used by Open Food Network, the website won’t work, you will not be able to add anything to your cart neither to checkout for instance." + cookies_banner: + cookies_usage: "This site uses cookies in order to make your navigation frictionless and secure, and to help us understand how you use it in order to improve the features we offer." + cookies_definition: "Cookies are very small text files that are stored on your computer when you visit some websites." + cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We use cookies mainly to remember who you are if you ‘log in’ to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website." + cookies_policy_link_desc: "If you want to learn more, check our" + cookies_policy_link: "cookies policy" + cookies_accept_button: "Accept Cookies" home_shop: Shop Now diff --git a/config/routes.rb b/config/routes.rb index 42488bf3367..ed4f517a4a4 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -95,6 +95,10 @@ get :job_queue end + scope '/cookies' do + resource :consent, only: [:show, :create, :destroy], :controller => "cookies_consent" + end + resources :customers, only: [:index, :update] post '/product_images/:product_id', to: 'product_images#update_product_image' @@ -110,5 +114,4 @@ # Mount Spree's routes mount Spree::Core::Engine, :at => '/' - end From d920c32376593fcbdd076f5fefcfa839247557fe Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Fri, 29 Jun 2018 14:39:31 +0100 Subject: [PATCH 049/122] Added cookies banner toggle and privacy URL to a new section called Legal Settings in the global settings in the BO --- .../cookies_banner_directive.js.coffee | 1 + .../spree/app_configuration_decorator.rb | 4 +- .../edit/legal_settings.html.haml.deface | 13 ++++ .../edit/tos_settings.html.haml.deface | 7 -- app/views/shared/_footer.html.haml | 56 ++++++++-------- config/locales/en.yml | 67 ++++++++++--------- 6 files changed, 80 insertions(+), 68 deletions(-) create mode 100644 app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface delete mode 100644 app/overrides/spree/admin/general_settings/edit/tos_settings.html.haml.deface diff --git a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee index f3553018a2b..ede3b1c9bf1 100644 --- a/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee +++ b/app/assets/javascripts/darkswarm/cookies_banner/cookies_banner_directive.js.coffee @@ -1,5 +1,6 @@ Darkswarm.directive 'cookiesBanner', (CookiesBannerService) -> restrict: 'A' link: (scope, elm, attr)-> + return if not attr.cookiesBanner? || attr.cookiesBanner == 'false' CookiesBannerService.setActive() CookiesBannerService.open() diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index b083edebc53..7eaedb1ccef 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -8,8 +8,10 @@ preference :enable_embedded_shopfronts, :boolean, default: false preference :embedded_shopfronts_whitelist, :text, default: nil - # Terms of Service Preferences + # Legal Preferences preference :enterprises_require_tos, :boolean, default: false + preference :privacy_policy_url, :string, default: nil + preference :cookies_consent_banner_toggle, :boolean, default: false # Tax Preferences preference :products_require_tax_category, :boolean, default: false diff --git a/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface new file mode 100644 index 00000000000..caa8ca6c5e9 --- /dev/null +++ b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface @@ -0,0 +1,13 @@ +/ insert_after "fieldset.security" + +%fieldset.legal.no-border-bottom + %legend{:align => "center"}= t('.legal_settings') + .field + = preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos)) + = label_tag(:enterprises_require_tos, t('.enterprises_require_tos')) + tag(:br) + .field + = preference_field_tag(:cookies_consent_banner_toggle, Spree::Config[:cookies_consent_banner_toggle], :type => Spree::Config.preference_type(:cookies_consent_banner_toggle)) + = label_tag(:cookies_consent_banner_toggle, t('.cookies_consent_banner_toggle')) + tag(:br) + .field + = label_tag(:privacy_policy_url, t('.privacy_policy_url')) + tag(:br) + = preference_field_tag(:privacy_policy_url, Spree::Config[:privacy_policy_url], type: Spree::Config.preference_type(:privacy_policy_url)) diff --git a/app/overrides/spree/admin/general_settings/edit/tos_settings.html.haml.deface b/app/overrides/spree/admin/general_settings/edit/tos_settings.html.haml.deface deleted file mode 100644 index e0a588d740b..00000000000 --- a/app/overrides/spree/admin/general_settings/edit/tos_settings.html.haml.deface +++ /dev/null @@ -1,7 +0,0 @@ -/ insert_after "fieldset.security" - -%fieldset.enterprise_toc.no-border-bottom - %legend{:align => "center"}= t(:enterprise_terms_of_service) - .field - = preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos)) - = label_tag(:enterprises_require_tos, t(:enterprises_require_tos)) + tag(:br) diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 22eaff9bfa8..d8a48902dc1 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -11,33 +11,32 @@ .row .small-12.medium-4.medium-offset-2.columns.text-center %h6 - = t :footer_global_headline + = t '.footer_global_headline' %p %a{href: "http://www.openfoodnetwork.org", target: "_blank"} - = t :footer_global_home + = t '.footer_global_home' %span | %a{href: "http://www.openfoodnetwork.org/news/", target: "_blank"} - = t :footer_global_news + = t '.footer_global_news' %span | %a{href: "http://www.openfoodnetwork.org/about/history-team/", target: "_blank"} - = t :footer_global_about + = t '.footer_global_about' %span | %a{href: "http://www.openfoodnetwork.org/contact/", target: "_blank"} - = t :footer_global_contact - + = t '.footer_global_contact' .small-12.medium-4.columns.text-center %h6 - = t :footer_sites_headline + = t '.footer_sites_headline' %p %a{href: "http://dev.openfoodnetwork.org", target: "_blank"} - = t :footer_sites_developer + = t '.footer_sites_developer' %span | %a{href: "http://community.openfoodnetwork.org", target: "_blank"} - = t :footer_sites_community + = t '.footer_sites_community' %span | %a{href: "http://www.openfoodnetwork.org/platform/user-guide/", target: "_blank"} - = t :footer_sites_userguide + = t '.footer_sites_userguide' .medium-2.columns.text-center / Placeholder @@ -49,9 +48,9 @@ %i.ofn-i_017-locked .small-12.medium-6.columns.text-center %p.text-big.secure-text - = t :footer_secure + = t '.footer_secure' %p.secure-text - = t :footer_secure_text + = t '.footer_secure_text' .small-12.medium-2.columns .row @@ -63,7 +62,7 @@ .small-6.medium-3.medium-offset-2.columns.text-left // This is the instance-managed set of links: %h4 - = t :footer_contact_headline + = t '.footer_contact_headline' %p.social-icons - if ContentConfig.footer_facebook_url.present? %a{href: ContentConfig.footer_facebook_url} @@ -86,13 +85,13 @@ - if ContentConfig.footer_email.present? %p %a{href: ContentConfig.footer_email.reverse, mailto: true, target: '_blank'} - = t :footer_contact_email + = t '.footer_contact_email' = render_markdown(ContentConfig.footer_links_md).html_safe .small-6.medium-3.columns.text-left %h4 - = t :footer_nav_headline + = t '.footer_nav_headline' %p %a{href: "/shops"} = t :label_shops @@ -111,11 +110,11 @@ .small-12.medium-2.columns.text-left %h4 - = t :footer_join_headline + = t '.footer_join_headline' %p - = t :footer_join_body + = t '.footer_join_body' %a{href: "/sell"} - = t :footer_join_cta + = t '.footer_join_cta' .medium-2.columns.text-center / Placeholder @@ -131,21 +130,22 @@ %img{src: ContentConfig.footer_logo.url, width: "220"} .small-12.medium-5.columns.text-left %p.text-small - = t :footer_legal_call + = t '.footer_legal_call' %a{href: ContentConfig.footer_tos_url} - = t :footer_legal_tos + = t '.footer_legal_tos' | - = t :footer_legal_visit + = t '.footer_legal_visit' %a{href:"https://github.com/openfoodfoundation/openfoodnetwork", target: "_blank"} GitHub %p.text-small - = t :footer_legal_text_html, {content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)')} + = t '.footer_legal_text_html', {content_license: link_to('CC BY-SA 3.0', 'https://creativecommons.org/licenses/by-sa/3.0/'), code_license: link_to('AGPL 3', 'https://tldrlegal.com/license/gnu-affero-general-public-license-v3-(agpl-3.0)' )} %p.text-small %div - = t :footer_legal_data_text - = t :footer_legal_data_call - %a{'cookies-policy-modal'=> true, 'cookies-banner'=> !CookiesConsent.new(cookies, request.host).exists? } - = t :footer_legal_data_cookies_policy - + - cookies_policy_link = link_to( t( '.footer_data_cookies_policy' ), '', 'cookies-policy-modal' => true, 'cookies-banner' => !CookiesConsent.new(cookies, request.host).exists? && Spree::Config.cookies_consent_banner_toggle) + - privacy_policy_link = link_to( t( '.footer_data_privacy_policy' ), Spree::Config.privacy_policy_url, :target => '_blank' ) + - if Spree::Config.privacy_policy_url.present? + = t '.footer_data_text_with_privacy_policy_html', {cookies_policy: cookies_policy_link.html_safe, privacy_policy: privacy_policy_link.html_safe } + - else + = t '.footer_data_text_without_privacy_policy_html', {cookies_policy: cookies_policy_link.html_safe } .medium-2.columns.text-center / Placeholder -if ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'].present? @@ -157,4 +157,4 @@ .row .small-12.medium-8.medium-offset-2.columns.text-center .text.small - = t :footer_skylight_dashboard_html, {dashboard: link_to('Skylight', ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'], target: "_blank")} + = t '.footer_skylight_dashboard_html', {dashboard: link_to('Skylight', ENV['SKYLIGHT_PUBLIC_DASHBOARD_URL'], target: "_blank")} diff --git a/config/locales/en.yml b/config/locales/en.yml index 1397a770562..f9a6fa032a8 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1099,6 +1099,33 @@ en: register_call: selling_on_ofn: "Interested in getting on the Open Food Network?" register: "Register here" + footer: + 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_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" + footer_legal_visit: "Find us on" + footer_legal_text_html: "Open Food Network is a free and open source software platform. Our content is licensed with %{content_license} and our code with %{code_license}." + footer_data_text_with_privacy_policy_html: "We take good care of your data. See our %{privacy_policy} and %{cookies_policy}" + footer_data_text_without_privacy_policy_html: "We take good care of your data. See our %{cookies_policy}" + footer_data_privacy_policy: "privacy policy" + footer_data_cookies_policy: "cookies policy" + footer_skylight_dashboard_html: Performance data is available on %{dashboard}. shop: messages: login: "login" @@ -1238,36 +1265,6 @@ en: 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_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" - footer_legal_visit: "Find us on" - footer_legal_text_html: "Open Food Network is a free and open source software platform. Our content is licensed with %{content_license} and our code with %{code_license}." - footer_legal_data_text: "We take good care of your data." - footer_legal_data_call: "See our" - footer_legal_data_cookies_policy: "cookies policy" - footer_skylight_dashboard_html: Performance data is available on %{dashboard}. legal: cookies_policy: header: "How We Use Cookies" @@ -2095,12 +2092,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using order_cycles: "Order Cycles" enterprise_relationships: "Enterprise permissions" remove_tax: "Remove tax" - enterprise_terms_of_service: "Enterprise Terms of Service" - enterprises_require_tos: "Enterprises must accept Terms of Service" + enterprise_tos_link: "Enterprise Terms of Service link" enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our " enterprise_tos_link_text: "Terms of Service." enterprise_tos_agree: "I agree to the above Terms of Service" + tax_settings: "Tax Settings" products_require_tax_category: "products require tax category" admin_shared_address_1: "Address" @@ -2650,6 +2647,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using variants: autocomplete: producer_name: Producer + general_settings: + edit: + legal_settings: "Legal Settings" + cookies_consent_banner_toggle: "Display cookies consent banner" + privacy_policy_url: "Privacy Policy URL" + enterprises_require_tos: "Enterprises must accept Terms of Service" checkout: payment: stripe: From ca35c59e527ed24cd72e94b2a3a84ba09b699278 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Fri, 20 Jul 2018 15:20:26 +0100 Subject: [PATCH 050/122] Moved the footer TOS URL from the content settings to the new section legal settings in the global settings --- app/controllers/admin/contents_controller.rb | 2 +- app/models/content_configuration.rb | 1 - app/models/spree/app_configuration_decorator.rb | 1 + .../general_settings/edit/legal_settings.html.haml.deface | 3 +++ app/views/layouts/mailer.html.haml | 2 +- app/views/registration/steps/_introduction.html.haml | 2 +- app/views/shared/_footer.html.haml | 2 +- config/locales/en.yml | 1 - 8 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/controllers/admin/contents_controller.rb b/app/controllers/admin/contents_controller.rb index 87e8995ac31..188b74440ff 100644 --- a/app/controllers/admin/contents_controller.rb +++ b/app/controllers/admin/contents_controller.rb @@ -8,7 +8,7 @@ def edit {name: I18n.t('admin.contents.edit.group_signup_page'), preferences: [:group_signup_pricing_table_html, :group_signup_case_studies_html, :group_signup_detail_html]}, {name: I18n.t('admin.contents.edit.footer_and_external_links'), preferences: [:footer_logo, :footer_facebook_url, :footer_twitter_url, :footer_instagram_url, :footer_linkedin_url, :footer_googleplus_url, :footer_pinterest_url, - :footer_email, :community_forum_url, :footer_links_md, :footer_about_url, :footer_tos_url]}] + :footer_email, :community_forum_url, :footer_links_md, :footer_about_url]}] end def update diff --git a/app/models/content_configuration.rb b/app/models/content_configuration.rb index 47038bcb9e9..2d65013a75f 100644 --- a/app/models/content_configuration.rb +++ b/app/models/content_configuration.rb @@ -53,5 +53,4 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration EOS preference :footer_about_url, :string, default: "http://www.openfoodnetwork.org/ofn-local/open-food-network-australia/" - preference :footer_tos_url, :string, default: "/Terms-of-service.pdf" end diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index 7eaedb1ccef..9f9d0515211 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -9,6 +9,7 @@ preference :embedded_shopfronts_whitelist, :text, default: nil # Legal Preferences + preference :footer_tos_url, :string, default: "/Terms-of-service.pdf" preference :enterprises_require_tos, :boolean, default: false preference :privacy_policy_url, :string, default: nil preference :cookies_consent_banner_toggle, :boolean, default: false diff --git a/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface index caa8ca6c5e9..d7368246b96 100644 --- a/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface +++ b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface @@ -2,6 +2,9 @@ %fieldset.legal.no-border-bottom %legend{:align => "center"}= t('.legal_settings') + .field + = label_tag(:footer_tos_url, t(:footer_tos_url)) + tag(:br) + = preference_field_tag(:footer_tos_url, Spree::Config[:footer_tos_url], type: Spree::Config.preference_type(:footer_tos_url)) .field = preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos)) = label_tag(:enterprises_require_tos, t('.enterprises_require_tos')) + tag(:br) diff --git a/app/views/layouts/mailer.html.haml b/app/views/layouts/mailer.html.haml index a00a35a5e09..7653ab56766 100644 --- a/app/views/layouts/mailer.html.haml +++ b/app/views/layouts/mailer.html.haml @@ -42,7 +42,7 @@ %tr %td{:align => "center"} %p - %a{:href => "#{ URI.join(spree.root_url, ContentConfig.footer_tos_url).to_s }", :target => "_blank"} + %a{:href => "#{ URI.join(spree.root_url, Spree::Config.footer_tos_url).to_s }", :target => "_blank"} = t :terms_of_service | %a{:href => "#{ spree.root_url }"} diff --git a/app/views/registration/steps/_introduction.html.haml b/app/views/registration/steps/_introduction.html.haml index 5c714cf1e59..f973ca055a1 100644 --- a/app/views/registration/steps/_introduction.html.haml +++ b/app/views/registration/steps/_introduction.html.haml @@ -37,7 +37,7 @@ .small-12.medium-6.columns{'ng-hide' => '!tos_required' } %p.tos-message #{t(:enterprise_tos_message)} - %a{href: ContentConfig.footer_tos_url, target: "_blank" } #{t(:enterprise_tos_link_text)} + %a{href: Spree::Config.footer_tos_url, target: "_blank" } #{t(:enterprise_tos_link_text)} %p.tos-checkbox %input{ type: 'checkbox', name: 'accept_terms', id: 'accept_terms', ng: { model: "tos_accepted" } } %label{for: "accept_terms"} #{t(:enterprise_tos_agree)} diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index d8a48902dc1..9c7126c999b 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -131,7 +131,7 @@ .small-12.medium-5.columns.text-left %p.text-small = t '.footer_legal_call' - %a{href: ContentConfig.footer_tos_url} + %a{href: Spree::Config.footer_tos_url, target: "_blank"} = t '.footer_legal_tos' | = t '.footer_legal_visit' diff --git a/config/locales/en.yml b/config/locales/en.yml index f9a6fa032a8..a7a828c45a6 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1183,7 +1183,6 @@ en: 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 From 4b64369ddbc0cdc49857e4b3b42856d307bdc2e3 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sat, 21 Jul 2018 15:09:03 +0100 Subject: [PATCH 051/122] Added GA and Matomo toggle in Legal Settings in the global settings in the BO and added GA and Matomo cookies details to the cookies policy page (according to what is configured in the BO) --- .../cookies_policy/cookies_policy.html.haml | 88 +++++++++++++++++++ .../spree/app_configuration_decorator.rb | 2 + .../edit/legal_settings.html.haml.deface | 8 +- config/locales/en.yml | 16 ++++ 4 files changed, 113 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml index 4599813a62c..2e9f5f1cd6a 100644 --- a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml @@ -27,6 +27,13 @@ {{ instance_hostname }} %td {{ 'legal.cookies_policy.cookie_session_desc' | t}} + %tr + %td + cookies_consent + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_consent_desc' | t}} %tr %td remember_spree_user_token @@ -65,6 +72,87 @@ {{ instance_hostname }} %p {{ 'legal.cookies_policy.essential_cookies_note' | t}} + +- if Spree::Config.cookies_policy_matomo_section || Spree::Config.cookies_policy_ga_section + %h2 + {{ 'legal.cookies_policy.statistics_cookies' | t}} + %p + {{ 'legal.cookies_policy.statistics_cookies_desc' | t}} + + - if Spree::Config.cookies_policy_ga_section + %p + {{ 'legal.cookies_policy.statistics_cookies_analytics_desc' | t}} + - if Spree::Config.cookies_policy_matomo_section + %p + {{ 'legal.cookies_policy.statistics_cookies_matomo_desc' | t}} + + %table{ng: { controller:"CookiesPolicyModalCtrl"}} + %tr + %th + {{ 'legal.cookies_policy.cookie_name' | t}} + %th + {{ 'legal.cookies_policy.cookie_domain' | t}} + %th + {{ 'legal.cookies_policy.cookie_desc' | t}} + - if Spree::Config.cookies_policy_ga_section + %tr + %td + __utma + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_analytics_utma_desc' | t}} + %tr + %td + __utmt + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_analytics_utmt_desc' | t}} + %tr + %td + __utmb + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_analytics_utmb_desc' | t}} + %tr + %td + __utmc + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_analytics_utmc_desc' | t}} + %tr + %td + __utmz + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_analytics_utmz_desc' | t}} + - if Spree::Config.cookies_policy_matomo_section + %tr + %td + _pk_ref, _pk_cvar, _pk_id and _pk_ses + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_matomo_basics_desc' | t}} + %tr + %td + _pk_hsr + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_matomo_heatmap_desc' | t}} + %tr + %td + piwik_ignore + %td + {{ instance_hostname }} + %td + {{ 'legal.cookies_policy.cookie_matomo_ignore_desc' | t}} + %h2 {{ 'legal.cookies_policy.disabling_cookies_header' | t}} %p diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index 9f9d0515211..992c39abe11 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -13,6 +13,8 @@ preference :enterprises_require_tos, :boolean, default: false preference :privacy_policy_url, :string, default: nil preference :cookies_consent_banner_toggle, :boolean, default: false + preference :cookies_policy_matomo_section, :boolean, default: false + preference :cookies_policy_ga_section, :boolean, default: false # Tax Preferences preference :products_require_tax_category, :boolean, default: false diff --git a/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface index d7368246b96..5cbe3a577f3 100644 --- a/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface +++ b/app/overrides/spree/admin/general_settings/edit/legal_settings.html.haml.deface @@ -3,7 +3,7 @@ %fieldset.legal.no-border-bottom %legend{:align => "center"}= t('.legal_settings') .field - = label_tag(:footer_tos_url, t(:footer_tos_url)) + tag(:br) + = label_tag(:footer_tos_url, t('.footer_tos_url')) + tag(:br) = preference_field_tag(:footer_tos_url, Spree::Config[:footer_tos_url], type: Spree::Config.preference_type(:footer_tos_url)) .field = preference_field_tag(:enterprises_require_tos, Spree::Config[:enterprises_require_tos], :type => Spree::Config.preference_type(:enterprises_require_tos)) @@ -11,6 +11,12 @@ .field = preference_field_tag(:cookies_consent_banner_toggle, Spree::Config[:cookies_consent_banner_toggle], :type => Spree::Config.preference_type(:cookies_consent_banner_toggle)) = label_tag(:cookies_consent_banner_toggle, t('.cookies_consent_banner_toggle')) + tag(:br) + .field + = preference_field_tag(:cookies_policy_matomo_section, Spree::Config[:cookies_policy_matomo_section], :type => Spree::Config.preference_type(:cookies_policy_matomo_section)) + = label_tag(:cookies_policy_matomo_section, t('.cookies_policy_matomo_section')) + tag(:br) + .field + = preference_field_tag(:cookies_policy_ga_section, Spree::Config[:cookies_policy_ga_section], :type => Spree::Config.preference_type(:cookies_policy_ga_section)) + = label_tag(:cookies_policy_ga_section, t('.cookies_policy_ga_section')) + tag(:br) .field = label_tag(:privacy_policy_url, t('.privacy_policy_url')) + tag(:br) = preference_field_tag(:privacy_policy_url, Spree::Config[:privacy_policy_url], type: Spree::Config.preference_type(:privacy_policy_url)) diff --git a/config/locales/en.yml b/config/locales/en.yml index a7a828c45a6..e8df84c9124 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1277,9 +1277,22 @@ en: cookie_domain: "Set By" cookie_desc: "Description" cookie_session_desc: "Used to allow the website to remember users between page visits, for example, remember items in your cart." + cookie_consent_desc: "Used to maintain status of user consent to store cookies" cookie_remember_me_desc: "Used if the user has requested the website to remember him. This cookie is automatically deleted after 12 days. If as a user you want that cookie to be deleted, you only need to logout. If you don’t want that cookie to be installed on your computer you shouldn’t check the “remember me” checkbox when logging in." cookie_openstreemap_desc: "Used by our friendly open source mapping provider (OpenStreetMap) to ensure that it does not receive too many requests during a given time period, to prevent abuse of their services." cookie_stripe_desc: "Data collected by our payment processor Stripe for fraud detection https://stripe.com/cookies-policy/legal. Not all shops use Stripe as a payment method but it is a good practice to prevent fraud to apply it to all pages. Stripe probably build a picture of which of our pages usually interact with their API and then flag anything unusual. So setting the Stripe cookie has a broader function than simply the provision of a payment method to a user. Removing it could affect the security of the service itself. You can learn more about Stripe and read its privacy policy at https://stripe.com/privacy." + statistics_cookies: "Statistics Cookies" + statistics_cookies_desc: "The following are not Strictly Necessary, but help to provide you with the best user experience by allowing us to analyse user behaviour, identify which features you use most, or don’t use, understand user experience issues, etc." + statistics_cookies_analytics_desc: "We use Google Analytics, as it was the default service connected with Spree (the e-commerce open source software that we built on) but our vision is to switch to Matomo (ex Piwik, open source analytics tool) as soon as we can." + statistics_cookies_matomo_desc: "We use Matomo (ex Piwik), an open source analytics tool." + cookie_analytics_utma_desc: "Used to distinguish users and sessions. The cookie is created when the javascript library executes and no existing __utma cookies exists. The cookie is updated every time data is sent to Google Analytics." + cookie_analytics_utmt_desc: "Used to throttle request rate." + cookie_analytics_utmb_desc: "Used to determine new sessions/visits. The cookie is created when the javascript library executes and no existing __utmb cookies exists. The cookie is updated every time data is sent to Google Analytics." + cookie_analytics_utmc_desc: "Not used in ga.js. Set for interoperability with urchin.js. Historically, this cookie operated in conjunction with the __utmb cookie to determine whether the user was in a new session/visit." + cookie_analytics_utmz_desc: "Stores the traffic source or campaign that explains how the user reached your site. The cookie is created when the javascript library executes and is updated every time data is sent to Google Analytics." + cookie_matomo_basics_desc: "Matomo first party cookies to collect statistics." + cookie_matomo_heatmap_desc: "Matomo Heatmap & Session Recording cookie." + cookie_matomo_ignore_desc: "Cookie used to exclude user from being tracked." disabling_cookies_header: "Warning on disabling cookies" disabling_cookies_desc: "As a user you can always allow, block or delete Open Food Network’s or any other website cookies whenever you want to through your browser’s setting control. Each browser has a different operative. Here are the links:" disabling_cookies_firefox_link: "https://support.mozilla.org/en-US/kb/enable-and-disable-cookies-website-preferences" @@ -2652,6 +2665,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using cookies_consent_banner_toggle: "Display cookies consent banner" privacy_policy_url: "Privacy Policy URL" enterprises_require_tos: "Enterprises must accept Terms of Service" + cookies_policy_matomo_section: "Display Matomo section on cookies policy page" + cookies_policy_ga_section: "Display Google Analytics section on cookies policy page" + footer_tos_url: "Terms of Service URL" checkout: payment: stripe: From bff5581a42629566ae75268818358cd4b79d3113 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sat, 4 Aug 2018 18:46:24 +0100 Subject: [PATCH 052/122] Added functional tests for cookies related features: cookies policy page, cookies banner and privacy policy link --- spec/features/consumer/cookies_spec.rb | 93 +++++++++++++++++++++ spec/features/consumer/footer_links_spec.rb | 30 +++++++ 2 files changed, 123 insertions(+) create mode 100644 spec/features/consumer/cookies_spec.rb create mode 100644 spec/features/consumer/footer_links_spec.rb diff --git a/spec/features/consumer/cookies_spec.rb b/spec/features/consumer/cookies_spec.rb new file mode 100644 index 00000000000..84f4f0d3b7e --- /dev/null +++ b/spec/features/consumer/cookies_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +feature "Cookies", js: true do + describe "banner", js: true do + describe "in the homepage" do + before do + Spree::Config[:cookies_consent_banner_toggle] = true + visit root_path + end + + scenario "does not show after cookies are accepted" do + click_button I18n.t('legal.cookies_banner.cookies_accept_button') + expect_not_visible_cookies_banner + + visit root_path + expect_not_visible_cookies_banner + end + + scenario "banner contains cookies policy link that opens coookies policy page and closes banner" do + find("p.ng-binding > a", :text => "cookies policy").click + expect_visible_cookies_policy_page + expect_not_visible_cookies_banner + + find("a.close-reveal-modal").click + expect_visible_cookies_banner + end + end + + describe "in product listing page" do + before do + Spree::Config[:cookies_consent_banner_toggle] = true + end + + scenario "it is showing" do + visit "/shops" + expect_visible_cookies_banner + end + end + + describe "disabled in the settings" do + scenario "it is not showing" do + Spree::Config[:cookies_consent_banner_toggle] = false + visit root_path + expect(page).to_not have_content I18n.t('legal.cookies_banner.cookies_usage') + end + end + end + + describe "policy page" do + scenario "showing session_id cookies description with correct instance domain" do + visit '/#/policies/cookies' + expect(page).to have_content('_session_id') + .and have_content('127.0.0.1') + end + + describe "with Matomo section configured" do + scenario "shows Matomo cookies details" do + Spree::Config[:cookies_policy_matomo_section] = true + visit '/#/policies/cookies' + # before { skip("test not working, settings are not picked up") } + # expect(page).to have_content matomo_description_text + end + end + + describe "without Matomo section configured" do + scenario "does not show Matomo cookies details" do + Spree::Config[:cookies_policy_matomo_section] = false + visit '/#/policies/cookies' + expect(page).to_not have_content matomo_description_text + end + end + end + + def matomo_description_text + I18n.t('legal.cookies_policy.statistics_cookies_matomo_desc') + end + + def expect_visible_cookies_policy_page + expect(page).to have_content I18n.t('legal.cookies_policy.header') + end + + def expect_visible_cookies_banner + expect(page).to have_css("button", :text => accept_cookies_button_text, :visible => true) + end + + def expect_not_visible_cookies_banner + expect(page).to_not have_css("button", :text => accept_cookies_button_text, :visible => true) + end + + def accept_cookies_button_text + I18n.t('legal.cookies_banner.cookies_accept_button') + end +end diff --git a/spec/features/consumer/footer_links_spec.rb b/spec/features/consumer/footer_links_spec.rb new file mode 100644 index 00000000000..52bfd3880a6 --- /dev/null +++ b/spec/features/consumer/footer_links_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +feature "Footer Links", js: true do + describe "policy link" do + scenario "showing" do + visit root_path + expect(page).to have_link "cookies policy" + end + + scenario "opens cookies policy page" do + visit root_path + click_link "cookies policy" + expect(page).to have_content I18n.t('legal.cookies_policy.header') + end + end + + describe "privacy policy link" do + scenario "not showing if it is empty" do + Spree::Config[:privacy_policy_url] = nil + visit root_path + expect(page).to_not have_link "privacy policy" + end + + scenario "showing configured privacy policy link" do + Spree::Config[:privacy_policy_url] = "link_to_privacy_policy" + visit root_path + expect(page).to have_link "privacy policy", :href => "link_to_privacy_policy" + end + end +end From 1c20967ca464e8e51e7dbf8f02b453b14413fa3c Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Sat, 4 Aug 2018 20:00:24 +0100 Subject: [PATCH 053/122] Added a button to close the cookies policy page at the bottom of the page to improve UX on mobile --- .../darkswarm/cookies_policy/cookies_policy.html.haml | 3 +++ app/assets/stylesheets/darkswarm/modals.css.scss | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml index 2e9f5f1cd6a..aaef3324c7c 100644 --- a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml @@ -175,3 +175,6 @@ %a.close-reveal-modal{"ng-click" => "$close()"} %i.ofn-i_009-close + +%a.mobile-close-reveal-modal{"ng-click" => "$close()"} + %i.ofn-i_009-close diff --git a/app/assets/stylesheets/darkswarm/modals.css.scss b/app/assets/stylesheets/darkswarm/modals.css.scss index 69ad042374d..f477ba92f8a 100644 --- a/app/assets/stylesheets/darkswarm/modals.css.scss +++ b/app/assets/stylesheets/darkswarm/modals.css.scss @@ -55,6 +55,17 @@ dialog .close-reveal-modal, .reveal-modal .close-reveal-modal { } } +.reveal-modal .mobile-close-reveal-modal, dialog .mobile-close-reveal-modal { + @extend .close-reveal-modal; + position: relative; + top: auto; + left: 90%; + + @media only screen and (min-width: 40.063em) { + display: none; + } +} + // Prevent body from scrolling when a modal is open body.modal-open { overflow: hidden; From ccd5147b113ee5fe6d893f9f99028f3aec490e1a Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Mon, 13 Aug 2018 17:25:51 +0100 Subject: [PATCH 054/122] Added angular templates route and controller to serve angular templates from the server, instead of precompiled assets. This was used to fix a problem with the cookies policy page template that was using a Spree configuration --- .../cookies_policy/cookies_policy_modal_service.js.coffee | 2 +- app/controllers/angular_templates_controller.rb | 5 +++++ .../angular_templates}/cookies_policy.html.haml | 0 config/routes.rb | 2 ++ spec/features/consumer/cookies_spec.rb | 5 ++--- 5 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 app/controllers/angular_templates_controller.rb rename app/{assets/javascripts/darkswarm/cookies_policy => views/angular_templates}/cookies_policy.html.haml (100%) diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee index 53770180892..0f91645cfd8 100644 --- a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee +++ b/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy_modal_service.js.coffee @@ -8,7 +8,7 @@ Darkswarm.factory "CookiesPolicyModalService", (Navigation, $modal, $location, C if $location.path() is @defaultPath || location.pathname is @defaultPath @open '' - open: (path = false, template = 'darkswarm/cookies_policy/cookies_policy.html') => + open: (path = false, template = 'angular-templates/cookies_policy.html') => @modalInstance = $modal.open templateUrl: template windowClass: "cookies-policy-modal medium" diff --git a/app/controllers/angular_templates_controller.rb b/app/controllers/angular_templates_controller.rb new file mode 100644 index 00000000000..44d870cc58e --- /dev/null +++ b/app/controllers/angular_templates_controller.rb @@ -0,0 +1,5 @@ +class AngularTemplatesController < ApplicationController + def show + render params[:id].to_s, layout: nil + end +end diff --git a/app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml b/app/views/angular_templates/cookies_policy.html.haml similarity index 100% rename from app/assets/javascripts/darkswarm/cookies_policy/cookies_policy.html.haml rename to app/views/angular_templates/cookies_policy.html.haml diff --git a/config/routes.rb b/config/routes.rb index ed4f517a4a4..a1ce680804c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -80,6 +80,8 @@ get '/:id/shop', to: 'enterprises#shop', as: 'enterprise_shop' get "/enterprises/:permalink", to: redirect("/") # Legacy enterprise URL + get "/angular-templates/:id", to: "angular_templates#show", constraints: { name: %r{[\/\w\.]+} } + namespace :api do resources :enterprises do post :update_image, on: :member diff --git a/spec/features/consumer/cookies_spec.rb b/spec/features/consumer/cookies_spec.rb index 84f4f0d3b7e..b9755ddc5a5 100644 --- a/spec/features/consumer/cookies_spec.rb +++ b/spec/features/consumer/cookies_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Cookies", js: true do - describe "banner", js: true do + describe "banner" do describe "in the homepage" do before do Spree::Config[:cookies_consent_banner_toggle] = true @@ -57,8 +57,7 @@ scenario "shows Matomo cookies details" do Spree::Config[:cookies_policy_matomo_section] = true visit '/#/policies/cookies' - # before { skip("test not working, settings are not picked up") } - # expect(page).to have_content matomo_description_text + expect(page).to have_content matomo_description_text end end From 86816184901a40a099fdb662d37199335194d20c Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Mon, 13 Aug 2018 18:44:38 +0100 Subject: [PATCH 055/122] Fixed CodeClimate scss feedback on cookies banner and policy page css --- .codeclimate.yml | 5 ++++ .../stylesheets/darkswarm/branding.css.scss | 1 + .../darkswarm/cookies_banner.css.scss | 12 ++++----- .../darkswarm/cookies_policy_modal.css.scss | 22 ++++++++-------- .../stylesheets/darkswarm/modals.css.scss | 26 ++++++++++++------- 5 files changed, 39 insertions(+), 27 deletions(-) diff --git a/.codeclimate.yml b/.codeclimate.yml index e892e73274c..9646b677e9a 100644 --- a/.codeclimate.yml +++ b/.codeclimate.yml @@ -5,6 +5,11 @@ plugins: channel: "rubocop-0-55" scss-lint: enabled: true + checks: + ImportantRule: + enabled: false + VendorPrefix: + enabled: false duplication: enabled: true exclude_patterns: diff --git a/app/assets/stylesheets/darkswarm/branding.css.scss b/app/assets/stylesheets/darkswarm/branding.css.scss index c9a68b513ba..95a7da3069f 100644 --- a/app/assets/stylesheets/darkswarm/branding.css.scss +++ b/app/assets/stylesheets/darkswarm/branding.css.scss @@ -35,3 +35,4 @@ $med-drk-grey: #444; $dark-grey: #333; $light-grey: #ddd; $black: #000; +$white: #fff; diff --git a/app/assets/stylesheets/darkswarm/cookies_banner.css.scss b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss index 2a2e2a057cb..cc6e80a727c 100644 --- a/app/assets/stylesheets/darkswarm/cookies_banner.css.scss +++ b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss @@ -1,9 +1,9 @@ .cookies-banner { - background: #3b3b3b; - position: fixed; + background: $dark-grey; bottom: 0; - z-index: 100000; + position: fixed; top: 20vh !important; + z-index: 100000; @media only screen and (min-width: 640px) { top: 20vh !important; @@ -18,11 +18,11 @@ } button { - background-color: green; + background-color: $clr-turquoise; } p { - color: white; - font-size: 0.75rem; + color: $white; + font-size: .75rem; } } diff --git a/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss index ded91c61c91..391e7e2e744 100644 --- a/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss +++ b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss @@ -1,15 +1,15 @@ .cookies-policy-modal { - background: #efefef; - border-bottom-color: #efefef; -} + background: $disabled-light; + border-bottom-color: $disabled-light; -.cookies-policy-modal table { - display: block; - overflow-x: auto; -} + table { + display: block; + overflow-x: auto; + } -.cookies-policy-modal.fade { - -webkit-transform: translate(0, 0) !important; - -ms-transform: translate(0, 0) !important; - transform: translate(0, 0) !important; + &.fade { + -ms-transform: translate(0, 0) !important; + -webkit-transform: translate(0, 0) !important; + transform: translate(0, 0) !important; + } } diff --git a/app/assets/stylesheets/darkswarm/modals.css.scss b/app/assets/stylesheets/darkswarm/modals.css.scss index f477ba92f8a..538a5622edb 100644 --- a/app/assets/stylesheets/darkswarm/modals.css.scss +++ b/app/assets/stylesheets/darkswarm/modals.css.scss @@ -1,7 +1,8 @@ @import "branding"; @import "mixins"; -dialog, .reveal-modal { +dialog +, .reveal-modal { border: none; outline: none; padding: 30px 20px 0 20px; @@ -37,15 +38,14 @@ dialog, .reveal-modal { position: fixed; } -dialog .close-reveal-modal, .reveal-modal .close-reveal-modal { - right: 0.25rem; - top: 0.25rem; +@mixin close-button($top) { background-color: rgba(205, 205, 205, 0.65); - text-shadow: none; + color: #666; font-size: 2rem; padding: 0.45rem; - color: #666; + text-shadow: none; z-index: 9999999; + top: $top; @include border-radius(999999rem); @@ -55,11 +55,17 @@ dialog .close-reveal-modal, .reveal-modal .close-reveal-modal { } } -.reveal-modal .mobile-close-reveal-modal, dialog .mobile-close-reveal-modal { - @extend .close-reveal-modal; - position: relative; - top: auto; +dialog .close-reveal-modal +, .reveal-modal .close-reveal-modal { + @include close-button(0.25rem); + right: 0.25rem; +} + +dialog .mobile-close-reveal-modal +, .reveal-modal .mobile-close-reveal-modal { + @include close-button(auto); left: 90%; + position: relative; @media only screen and (min-width: 40.063em) { display: none; From c9862535f82efd472daba7cccffdd2ba017a6156 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Tue, 14 Aug 2018 09:48:25 +1000 Subject: [PATCH 056/122] Import required colour definitions in SCSS This avoids asset compile errors like this one: Sass::SyntaxError: Undefined variable: "$disabled-light". --- app/assets/stylesheets/darkswarm/cookies_banner.css.scss | 2 ++ app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/assets/stylesheets/darkswarm/cookies_banner.css.scss b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss index cc6e80a727c..04d40753b67 100644 --- a/app/assets/stylesheets/darkswarm/cookies_banner.css.scss +++ b/app/assets/stylesheets/darkswarm/cookies_banner.css.scss @@ -1,3 +1,5 @@ +@import 'branding'; + .cookies-banner { background: $dark-grey; bottom: 0; diff --git a/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss index 391e7e2e744..5c27e27a76b 100644 --- a/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss +++ b/app/assets/stylesheets/darkswarm/cookies_policy_modal.css.scss @@ -1,3 +1,5 @@ +@import 'branding'; + .cookies-policy-modal { background: $disabled-light; border-bottom-color: $disabled-light; From d76112e0724b08b10ed0cae764dcce85d0f83414 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Tue, 14 Aug 2018 17:18:51 +1000 Subject: [PATCH 057/122] Updating translations for config/locales/de_DE.yml --- config/locales/de_DE.yml | 583 +++++++++++++++++++++------------------ 1 file changed, 311 insertions(+), 272 deletions(-) diff --git a/config/locales/de_DE.yml b/config/locales/de_DE.yml index 73551f49fd8..4f7616a9398 100644 --- a/config/locales/de_DE.yml +++ b/config/locales/de_DE.yml @@ -9,7 +9,7 @@ de_DE: number: Nummer email: E-Mail des Kunden spree/payment: - amount: Menge + amount: Betrag order_cycle: orders_close_at: Schlussdatum errors: @@ -19,7 +19,7 @@ de_DE: email: taken: "Es gibt bereits ein Konto für diese E-Mail-Adresse. Bitte versuchen Sie sich einzuloggen oder setzen Sie Ihr Passwort zurück." spree/order: - no_card: Es sind keine gültigen Kreditkarten verfügbar + no_card: Es gibt keine autorisierten Kreditkarten, auf die zugegriffen werden kann. order_cycle: attributes: orders_close_at: @@ -41,11 +41,10 @@ de_DE: payment_method: not_available_to_shop: "ist nicht verfügbar für %{shop}" invalid_type: "muss eine Bar- oder Stripe-Methode sein" + charges_not_allowed: "Kreditkartebehebungen von diesem Kunden sind nicht gestattet." + no_default_card: "^ Für diesen Kunden ist keine Standardkarte verfügbar" shipping_method: not_available_to_shop: "ist nicht verfügbar für %{shop}" - credit_card: - not_available: "ist nicht verfügbar" - blank: "wird benötigt" devise: confirmations: send_instructions: "Sie erhalten in einigen Minuten eine E-Mail mit Anweisungen zur Bestätigung Ihres Kontos." @@ -96,7 +95,7 @@ de_DE: title: Unzureichende Lagerbestände (%{count} Bestellungen) explainer: Diese Bestellungen wurden bearbeitet, aber für einige angeforderte Artikel war nicht genügend Lagerbestand verfügbar empty: - title: Keine Lagerbestellung (%{count} Bestellungen) + title: Kein Lagerbestand (%{count} Bestellungen) explainer: Diese Bestellungen konnten nicht bearbeitet werden, da für die angeforderten Artikel kein Bestand verfügbar war complete: title: Bereits verarbeitet (%{count} Bestellungen) @@ -112,8 +111,8 @@ de_DE: explainer: Die automatische Verarbeitung dieser Aufträge ist aus einem unbekannten Grund fehlgeschlagen. Dies sollte nicht geschehen, bitte kontaktieren Sie uns, wenn Sie dies sehen. home: "OFN" title: Open Food Network - welcome_to: 'Willkommen auf' - site_meta_description: "Wir starten von Grund auf, in dem die Landwirte und Landwirtinnen sowie die Erzeuger und Erzeugerinnen Ihre Geschichten voll Stolz und wahrhaftig erzählen können. Und indem die Verteilenden uns Konsumierende gerecht und ehrlich Zugang zu den Produkten bieten können. Mit Konsumierenden, die glauben, dass dies die bessere Entscheidung für den Wocheneinkauf darstellen kann." + welcome_to: 'Willkommen bei' + site_meta_description: "Wir starten ganz grundsätzlich. Mit LandwirtInnen und GärtnerInnen, die stolz und ehrlich ihre Geschichte erzählen. Mit Lieferanten, die Menschen fair und vertrauenswürdig mit Produkten verbinden. Mit KonsumentInnen, die glauben, daß ihre wöchentlichen Einkaufsentscheidungen..." search_by_name: Suche nach Name oder Ort... producers_join: 'Wir laden Deutsche Produzenten ein, jetzt dem Open Food Network beizutreten. ' charges_sales_tax: Berechnet Steuern? @@ -131,7 +130,7 @@ de_DE: must_have_valid_business_number: "%{enterprise_name} sollte eine gültige Steuer-ID-Nummer haben, bevor die Rechnung gesendet wird." invoice: "Rechnung" percentage_of_sales: "%{percentage} des Umsatzes" - capped_at_cap: "maximal festgelegt auf {cap}%" + capped_at_cap: "Maximum {cap}%" per_month: "pro Monat" free: "kostenlos" free_trial: "kostenloser Versuch" @@ -143,8 +142,8 @@ de_DE: ongoing: Laufend bill_address: Rechnungsadresse ship_address: Lieferanschrift - sort_order_cycles_on_shopfront_by: "Sortiere die Bestellungszyklen des Shops nach" - required_fields: Die erforderlichen Felder sind mit * bezeichnet + sort_order_cycles_on_shopfront_by: "Sortiere die Bestellungszyklen des Ladens nach" + required_fields: Die erforderlichen Felder sind mit * markiert select_continue: Auswählen und fortfahren remove: Entfernen or: oder @@ -157,12 +156,13 @@ de_DE: cancel: Abbrechen edit: Bearbeite clone: Klonen - distributors: Verteilende + distributors: Verteiler distribution: Verteilung bulk_order_management: Massenbearbeitung von Bestellungen + enterprises: Unternehmen enterprise_groups: Gruppen reports: Berichte - variant_overrides: Inventar + variant_overrides: Katalog spree_products: Spree Produkte all: Alle current: Aktuell @@ -170,11 +170,11 @@ de_DE: dashboard: Übersicht undefined: undefiniert unused: ungebraucht - admin_and_handling: Admin & Handhabung + admin_and_handling: Verwaltung & Handhabung profile: Profil supplier_only: Nur Anbieter weight: Gewicht - volume: Menge + volume: Volumen items: Artikel summary: Zusammenfassung detailed: Detailliert @@ -184,9 +184,9 @@ de_DE: y: 'J' n: 'N' powered_by: Unterstützt von - blocked_cookies_alert: "Ihr Browser blockiert möglicherweise Cookies, die für die Verwendung dieses Shops erforderlich sind. Klicken Sie unten, um Cookies zuzulassen und die Seite neu zu laden." - allow_cookies: "Erlaube Cookies" - notes: Notizen + blocked_cookies_alert: "Ihr Browser blockiert möglicherweise Cookies, die für die Verwendung dieses Ladens erforderlich sind. Klicken Sie unten, um Cookies zuzulassen und die Seite neu zu laden." + allow_cookies: "Cookies erlauben" + notes: Anmerkungen error: Fehler processing_payment: Bezahlung wird verarbeitet... show_only_unfulfilled_orders: Nur ausstehende Bestellungen anzeigen @@ -205,48 +205,48 @@ de_DE: ends_at: Endet um ends_on: Endet am name: Name - on_hand: verfügbar - on_demand: Auf Anfrage + on_hand: Verfügbar + on_demand: Unbegrenzt on_demand?: Unbegrenzt? order_cycle: Bestellungszyklus payment: Zahlung - payment_method: Bezahlverfahren + payment_method: Zahlungsart phone: Telefonnummer price: Preis - producer: Produzent + producer: Erzeuger image: Bild product: Produkt quantity: Menge schedule: Plan shipping: Versand shipping_method: Versandart - shop: Shop + shop: Laden sku: Artikelnummer - status_state: Zustand - tags: Stichworte + status_state: Status + tags: Markierwort variant: Variante weight: Gewicht - volume: Menge + volume: Volumen items: Artikel select_all: Alles auswählen obsolete_master: Überholter Master quick_search: Schnellsuche - clear_all: Alle löschen + clear_all: Alle leeren start_date: "Anfangsdatum" end_date: "Enddatum" form_invalid: "Das Formular beinhaltet fehlende oder ungültige Felder" - clear_filters: Filter löschen - clear: klar + clear_filters: Filter zurücksetzen + clear: Leeren save: Speichern cancel: Abrechen back: Zurück show_more: Mehr zeigen - show_n_more: Zeige %{num} mehr + show_n_more: '%{num} mehr zeigen' choose: "Wählen..." please_select: Bitte auswählen... columns: Spalten actions: Aktionen - viewing: "Anzeigen: %{current_view_name}" + viewing: "Zeigt: %{current_view_name}" description: Beschreibung whats_this: Was ist das? tag_has_rules: "Vorhandene Regeln für dieses Tag: %{num}" @@ -256,8 +256,8 @@ de_DE: unsaved_changes: "Sie haben ungespeicherte Änderungen" accounts_and_billing_settings: method_settings: - default_accounts_payment_method: "Zahlungsart des Standardkontos" - default_accounts_shipping_method: "Lieferart des Standardkontos" + default_accounts_payment_method: "Zahlungsmethode für Standardkonten" + default_accounts_shipping_method: "Standardmethode für den Kontoversand" edit: accounts_and_billing: "Konten und Abrechung" accounts_administration_distributor: "Kontenadministrator" @@ -267,7 +267,7 @@ de_DE: finalise_invoice: "Rechnungen fertigstellen" auto_finalise_invoices: "Rechnungen automatisch am 2. jedes Monats um 1.30 Uhr fertigstellen" manually_run_task: "Vorgang manuell ausführen" - update_user_invoice_explained: "Verwenden Sie diesen Button, um die Rechnungen für den jeweiligen Monat für jeden Unternehmensbenutzer im System sofort zu aktualisieren. Diese Aufgabe kann so eingerichtet werden, dass sie jede Nacht automatisch ausgeführt wird." + update_user_invoice_explained: "Verwenden Sie diesen Button, um die Rechnungen für den jetzigen Monat für alle Unternehmensbenutzer sofort zu aktualisieren. Diese Aufgabe kann so eingerichtet werden, dass sie jede Nacht automatisch ausgeführt wird." finalise_user_invoices: "Benutzerrechnungen fertigstellen" finalise_user_invoice_explained: "Verwenden Sie diesen Button, um die Rechnungen für den Vormonat zu aktualisieren. Diese Aufgabe kann so eingerichtet werden, dass sie einmal im Monat automatisch abläuft." update_user_invoices: "Benutzerrechungen aktualisieren" @@ -276,8 +276,8 @@ de_DE: default_payment_method: Muss gewählt werden, wenn Sie Rechnungen für Unternehmen erstellen möchten. default_shipping_method: Muss gewählt werden, wenn Sie Rechnungen für Unternehmen erstellen möchten. shopfront_settings: - embedded_shopfront_settings: "Eingebettete Shopfront-Einstellungen" - enable_embedded_shopfronts: "Eingebettete Shopfronts erlauben" + embedded_shopfront_settings: "Eingebettete Ladeneinstellungen" + enable_embedded_shopfronts: "Eingebettete Läden erlauben" embedded_shopfronts_whitelist: "Externe Domains Whitelist" number_localization: number_localization_settings: "Nummernlokalisierungseinstellungen" @@ -285,18 +285,18 @@ de_DE: business_model_configuration: edit: business_model_configuration: "Geschäftsmodel" - business_model_configuration_tip: "Konfigurieren Sie die Rate, mit der die Geschäfte jeden Monat für die Nutzung des Open Food Network berechnet werden." - bill_calculation_settings: "Rechnungsberechnungseinstellungen" + business_model_configuration_tip: "Konfigurieren Sie den Satz, mit dem Läden jeden Monat für die Nutzung des Open Food Network berechnet werden." + bill_calculation_settings: "Berechnungseinstellungen" bill_calculation_settings_tip: "Passen Sie den Betrag an, der Unternehmen jeden Monat für die Nutzung des OFN in Rechnung gestellt wird." shop_trial_length: "Laden Testlänge (Tage)" shop_trial_length_tip: "Die Zeitdauer (in Tagen), die Unternehmen, die als Geschäfte eingerichtet sind, als Testphase ausführen können." - fixed_monthly_charge: "feste Monatsgebühren" + fixed_monthly_charge: "feste Monatsgebühr" fixed_monthly_charge_tip: "Die monatliche Gebühr für Unternehmen, die als Laden laufen und ein Minimum an rechnungsfähigem Umsatz erreicht haben (falls verwendet)." percentage_of_turnover: "Prozentsatz des Umsatzes" percentage_of_turnover_tip: "Falls nicht null, wird dieser Prozentsatz (0.0 - 1.0) dem Umsatz eines Ladens angerechnet und zu jeglichen Festgebühren (links) addiert, um daraus die monatliche Rechnung zu erstellen. " monthly_cap_excl_tax: "Monatliche Obergrenze (exkl. Steuer)" monthly_cap_excl_tax_tip: "Falls größer als Null, wird dieser Wert als Obergrenze für den Betrag, den die Läden jeden Monat zahlen müssen, festgelegt." - tax_rate: "Steuerrate" + tax_rate: "Steuersatz" tax_rate_tip: "Steuersatz, der für die monatliche Rechnung gilt, die den Unternehmen für die Nutzung des Systems in Rechnung gestellt wird." minimum_monthly_billable_turnover: "Monatlicher Mindestumsatz" minimum_monthly_billable_turnover_tip: "Der monatliche Mindestumsatz unter dem ein Laden nicht berechnet wird. Geschäften die weniger umsetzen wird weder eine Festgebühr noch ein Prozentsatz in Rechnung gestellt. " @@ -305,11 +305,47 @@ de_DE: example_monthly_turnover: "Beispiel monatlicher Umsatz" example_monthly_turnover_tip: "Ein beispielhafter monatlicher Umsatz eines Unternehmens, mit dem unten eine Beispiel-Monatsrechnung erstellt wird." cap_reached?: "Limit erreicht ?" - cap_reached?_tip: "Ob die Kappe (links angegeben) erreicht wurde, unter Berücksichtigung der Einstellungen und des Umsatzes." + cap_reached?_tip: "Ob das Limit (links angegeben) erreicht wurde, unter Berücksichtigung der Einstellungen und des Umsatzes." included_tax: "inkl. Steuer" included_tax_tip: "Die Gesamtsteuer, die in der Beispiel-Monatsrechnung enthalten ist, unter Berücksichtigung der Einstellungen und des Umsatzes." total_monthly_bill_incl_tax: "Monatliche Gesamtkosten (inkl. Steuern)" total_monthly_bill_incl_tax_tip: "Die Beispiel-Gesamt-Monatsrechnung mit Steuern inklusive, unter Berücksichtigung der Einstellungen und des Umsatzes." + cache_settings: + show: + title: Cachen + distributor: Verteiler + order_cycle: Bestellungszyklus + status: Status + diff: Diff + error: Fehler + invoice_settings: + edit: + title: Rechnungseinstellungen + invoice_style2?: Verwenden Sie das alternative Rechnungsmodell, das die gesamte Steueraufschlüsselung pro Tarif- und Steuersatzinfo pro Artikel enthält (noch nicht für Länder mit Preisen ohne Steuern geeignet) + enable_receipt_printing?: Optionen zum Drucken von Belegen mit Thermodruckern in der Dropdown-Liste anzeigen? + stripe_connect_settings: + edit: + title: "Streifen verbinden" + settings: "die Einstellungen" + stripe_connect_enabled: Läden erlauben, Zahlungen über Stripe Connect anzunehmen? + no_api_key_msg: Für dieses Unternehmen existiert kein Stripe-Konto. + configuration_explanation_html: Detaillierte Anweisungen zur Konfiguration der Stripe Connect-Integration finden Sie unter konsultieren Sie diese Anleitung . + status: Status + ok: OK + instance_secret_key: Instanzgeheimschlüssel + account_id: Konto-ID + business_name: Geschäftsname + charges_enabled: Gebühren aktiviert + charges_enabled_warning: "Warnung: Gebühren sind für Ihr Konto nicht aktiviert" + auth_fail_error: Der von Ihnen angegebene API-Schlüssel ist ungültig + empty_api_key_error_html: Es wurde kein Stripe-API-Schlüssel bereitgestellt. Um den API-Schlüssel festzulegen, folgen Sie bitte diesen Anweisungen < / a> + matomo_settings: + edit: + title: "Matomo-Einstellungen" + matomo_url: "Matomo-URL" + matomo_site_id: "Matomo-Site-ID" + info_html: "Matomo ist eine Web- und Mobile Analytics. Sie können Matomo entweder lokal hosten oder einen von der Cloud gehosteten Dienst verwenden. Weitere Informationen finden Sie unter matomo.org ." + config_instructions_html: "Hier können Sie die OFN Matomo Integration konfigurieren. Die unten angegebene Matomo-URL sollte auf die Matomo-Instanz verweisen, an die die Benutzerverfolgungsinformationen gesendet werden. Wenn es leer bleibt, wird das Matomo-Benutzer-Tracking deaktiviert. Das Feld Site-ID ist nicht obligatorisch, aber nützlich, wenn Sie mehr als eine Website in einer einzelnen Matomo-Instanz verfolgen. Es kann auf der Matomo-Instanzkonsole gefunden werden." customers: index: add_customer: "Kunden hinzufügen" @@ -332,16 +368,9 @@ de_DE: update_address: 'Adresse aktualisieren' confirm_delete: 'Sicher zu löschen?' search_by_email: "Suche nach Email/Kode" + guest_label: 'Gäste Kasse' destroy: has_associated_orders: 'Löschen fehlgeschlagen: Kunde hat Bestellungen mit diesem Laden' - cache_settings: - show: - title: Cachen - distributor: Verteiler - order_cycle: Bestellungszyklus - status: Status - diff: Diff - error: Fehler contents: edit: title: Inhalt @@ -376,12 +405,12 @@ de_DE: display_as: Angezeigt als category: Kategorie tax_category: Steuerkategorie - inherits_properties?: Vererbt Eigenschaften? + inherits_properties?: Vererbt Eigenschaften available_on: Verfügbar am av_on: "Verfüg. am" import_date: Importiert upload_an_image: Bild hochladen - product_search_keywords: Keywords für die Produktsuche + product_search_keywords: Stichwörter für die Produktsuche product_search_tip: Geben Sie Wörter ein, um Ihre Produkte in den Geschäften zu suchen. Verwenden Sie Leerzeichen, um jedes Keyword zu trennen. SEO_keywords: SEO Schlüsselwörter seo_tip: Geben Sie Wörter ein, um Ihre Produkte im Internet zu durchsuchen. Verwenden Sie Leerzeichen, um jedes Keyword zu trennen. @@ -395,114 +424,125 @@ de_DE: group_buy_options: "Gruppenkaufoptionen" back_to_products_list: "Zurück zur Produktliste" product_import: - title: Produkt importieren + title: Produkte importieren file_not_found: Datei nicht gefunden oder konnte nicht geöffnet werden no_data: Keine Daten in der Tabelle gefunden - confirm_reset: "Dadurch wird der Lagerbestand für alle Produkte auf Null gesetzt\n Unternehmen, die in der hochgeladenen Datei nicht vorhanden sind" + confirm_reset: "Dadurch wird der Lagerbestand für alle Produkte dieses Unternehmens, die nicht in der hochgeladenen Datei vorhanden sind, auf Null gesetzt." model: no_file: "Fehler: keine Datei hochgeladen" - could_not_process: "Datei konnte nicht verarbeitet werden: ungültiger Dateityp" + could_not_process: "Datei konnte nicht verarbeitet werden: ungültiges Datenformat" incorrect_value: falscher Wert - conditional_blank: Kann nicht leer sein, wenn unit_type leer ist + conditional_blank: Kann nicht leer sein, wenn Einheitart leer ist no_product: hat keine Produkte in der Datenbank gefunden not_found: nicht in der Datenbank gefunden blank: kann nicht leer sein products_no_permission: Sie sind nicht berechtigt, Produkte für dieses Unternehmen zu verwalten - inventory_no_permission: Sie sind nicht berechtigt, Inventar für diesen Produzenten zu erstellen + inventory_no_permission: Sie sind nicht berechtigt, Bestand für diesen Produzenten zu erstellen none_saved: hat keine Produkte erfolgreich gespeichert - line: Linie + line: Zeile index: - select_file: Wählen Sie eine Tabelle zum Hochladen aus + select_file: Wählen Sie eine Tabelle zum Hochladen spreadsheet: Kalkulationstabelle - import_into: "Importieren in:" + choose_import_type: Wählen Sie den Importtyp aus + import_into: Importart product_list: Produktliste - inventories: Vorräte - import: Einführen + inventories: Bestände + import: Importieren upload: Hochladen + csv_templates: CSV Vorlage + product_list_template: Laden Sie die Produktlistenvorlage herunter + inventory_template: Katalogvorlage herunterladen. + category_values: Verfügbare Kategoriewerte + product_categories: Produktkategorien + tax_categories: Steuerkategorien + shipping_categories: Versandkategorien import: - review: Rezension - proceed: Vorgehen + review: Überprüfung + import: Importieren save: Speichern results: Ergebnisse - save_imported: Speichern Sie importierte Produkte + save_imported: Importierte Produkte speichern no_valid_entries: Keine gültigen Einträge gefunden none_to_save: Es gibt keine Einträge, die gespeichert werden können - some_invalid_entries: Importierte Datei enthält einige ungültige Einträge - save_valid?: Gültige Einträge für jetzt speichern und die anderen verwerfen? + some_invalid_entries: Die importierte Datei enthält ungültige Einträge + fix_before_import: Bitte beheben Sie diese Fehler und versuchen Sie erneut, die Datei zu importieren + save_valid?: Gültige Einträge speichern und die anderen verwerfen? no_errors: Keine Fehler gefunden! save_all_imported?: Alle importierten Produkte speichern? - options_and_defaults: Importoptionen und Standardwerte + options_and_defaults: Importoptionen und Voreinstellungen no_permission: Sie sind nicht berechtigt, dieses Unternehmen zu verwalten not_found: Unternehmen konnte nicht in der Datenbank gefunden werden no_name: Kein Name - blank_supplier: Einige Produkte haben einen leeren Lieferantennamen - reset_absent?: Fehlende Produkte zurücksetzen? + blank_supplier: Manche Produkte haben einen leeren Lieferantennamen + reset_absent?: Fehlende Produkte zurücksetzen + reset_absent_tip: Den Bestand für alle nicht in der Datei vorhandenen Produkte auf Null setzen overwrite_all: Alles überschreiben overwrite_empty: Überschreiben, wenn leer - default_stock: Stellen Sie den Lagerbestand ein - default_tax_cat: Stellen Sie die Steuerkategorie ein - default_shipping_cat: Legen Sie die Versandkategorie fest - default_available_date: Stellen Sie das verfügbare Datum ein + default_stock: Lagerbestand setzen + default_tax_cat: Steuerkategorie setzen + default_shipping_cat: Versandkategorie setzen + default_available_date: Verfügbar-Datum stetzen validation_overview: Validierungsübersicht importieren entries_found: Einträge in der importierten Datei gefunden entries_with_errors: Artikel enthalten Fehler und werden nicht importiert products_to_create: Produkte werden erstellt products_to_update: Produkte werden aktualisiert - inventory_to_create: Inventargegenstände werden erstellt - inventory_to_update: Inventargegenstände werden aktualisiert + inventory_to_create: Katalogeinträge werden erstellt + inventory_to_update: Katalogeinträge werden aktualisiert products_to_reset: Bestehende Produkte werden auf Null zurückgesetzt - inventory_to_reset: Bestehende Inventarartikel werden auf Null zurückgesetzt - line: Linie + inventory_to_reset: Bestehende Katalogeinträge werden auf null Bestand zurückgesetzt + line: Zeile item_line: Artikelzeile - save: - final_results: Importieren Sie die endgültigen Ergebnisse + save_results: + final_results: Endgültige Ergebnisse importieren products_created: Produkte erstellt products_updated: Produkte aktualisiert - inventory_created: Inventarelemente erstellt - inventory_updated: Inventargegenstände aktualisiert + inventory_created: Katalogeinträge erstellt + inventory_updated: Katalogeinträge aktualisiert products_reset: Bei den Produkten wurde der Lagerbestand auf Null zurückgesetzt - inventory_reset: Bei Inventarartikeln wurde der Lagerbestand auf Null zurückgesetzt + inventory_reset: Bei Katalogeinträgen wurde der Bestand auf null zurückgesetzt all_saved: "Alle Artikel wurden erfolgreich gespeichert" - some_saved: "Elemente wurden erfolgreich gespeichert" + some_saved: "Artikel wurden erfolgreich gespeichert" save_errors: Fehler speichern - view_products: Produkte anzeigen - view_inventory: Inventar anzeigen + import_again: Eine andere Datei hochladen + view_products: Zur Produktseite gehen + view_inventory: Zur Katalogseite gehen variant_overrides: loading_flash: - loading_inventory: LADEN INVENTAR + loading_inventory: KATALOG WIRD GELADEN index: - title: Inventar + title: Katalog description: Verwenden Sie diese Seite, um Bestände für Ihre Unternehmen zu verwalten. Alle hier eingestellten Produktdetails überschreiben diejenigen, die auf der Seite "Produkte" eingestellt sind enable_reset?: Lagerbestand zurücksetzbar? - inherit?: Übernehme - add: Füge hinzu - hide: Verstecke + inherit?: Übernehmen? + add: Hinzufügen + hide: Verbergen import_date: Importiert - select_a_shop: Wähle einen Laden - review_now: Überprüfe jetzt - new_products_alert_message: Es sind %{new_product_count} neue Produkte verfügbar, die ins Sortiment mit aufgenommen werden können - currently_empty: Deine Inventur ist momentan leer. - no_matching_products: Es wurden keine passenden Produkte in Deiner Inventur gefunden. - no_hidden_products: Aus diesem Inventar wurden keine Produkte ausgeblendet - no_matching_hidden_products: Keine versteckten Produkte entsprechen Ihren Suchkriterien - no_new_products: Es sind keine neuen Produkte verfügbar, die zu diesem Inventar hinzugefügt werden können + select_a_shop: Laden wählen + review_now: Prüfen + new_products_alert_message: Es sind %{new_product_count} neue Produkte verfügbar, die in den Katalog aufgenommen werden können + currently_empty: Ihr Katalog ist momentan leer. + no_matching_products: Es wurden keine passenden Produkte im Katalog gefunden. + no_hidden_products: In diesem Katalog wurden keine Produkte verborgen + no_matching_hidden_products: Keine verborgenen Produkte entsprechen Ihren Suchkriterien + no_new_products: Es sind keine neuen Produkte verfügbar, die zu diesem Katalog hinzugefügt werden können no_matching_new_products: Keine neuen Produkte entsprechen Ihren Suchkriterien - inventory_powertip: Dies ist Ihr Warenbestand. Um Produkte zu Ihrem Inventar hinzuzufügen, wählen Sie "Neue Produkte" aus dem Dropdown-Menü "Anzeigen". - hidden_powertip: Diese Produkte wurden in Ihrem Inventar versteckt und können nicht in Ihrem Shop hinzugefügt werden. Sie können auf "Hinzufügen" klicken, um ein Produkt zu Ihrem Inventar hinzuzufügen. - new_powertip: Diese Produkte können Ihrem Inventar hinzugefügt werden. Klicken Sie auf "Hinzufügen", um ein Produkt zu Ihrem Inventar hinzuzufügen, oder auf "Ausblenden", um es aus der Ansicht auszublenden. Du kannst deine Meinung später immer ändern! + inventory_powertip: Dies ist Ihr Produktkatalog. Um Produkte zu Ihrem Katalog hinzuzufügen, wählen Sie "Neue Produkte" aus dem Dropdown-Menü. + hidden_powertip: Diese Produkte wurden in Ihrem Katalog versteckt und können nicht in Ihrem Laden hinzugefügt werden. Sie können auf "Hinzufügen" klicken, um ein Produkt zu Ihrem Katalog hinzuzufügen. + new_powertip: Diese Produkte können Ihrem Katalog hinzugefügt werden. Klicken Sie auf "Hinzufügen", um ein Produkt zu Ihrem Katalog hinzuzufügen, oder auf "Ausblenden", um es aus der Ansicht auszublenden. Sie können Ihre Meinung später immer ändern! controls: - back_to_my_inventory: Zurück zu meinem Inventar + back_to_my_inventory: Zurück zu meinem Katalog orders: index: capture: "Erfassung" - ship: "Schiff" + ship: "Liefern" invoice_email_sent: 'Rechnungs-E-Mail wurde gesendet' - order_email_resent: 'E-Mail-Bestellung wurde erneut gesendet' + order_email_resent: 'Bestellungs-E-Mail wurde erneut gesendet' bulk_management: tip: "Verwenden Sie diese Seite, um Produktmengen über mehrere Bestellungen hinweg zu ändern. Produkte können bei Bedarf auch komplett aus Bestellungen entfernt werden." - shared: "Gemeinsame Ressource?" + shared: "Geteilte Ressource?" order_no: "Best.-Nr." - order_date: "Auftragsdatum" + order_date: "Bestelldatum" max: "Max" product_unit: "Produkt: Einheit" weight_volume: "Gewicht / Volumen" @@ -511,30 +551,30 @@ de_DE: actions_delete: "Ausgewählte löschen" loading: "Bestellungen werden geladen" no_results: "Keine Bestellungen gefunden." - group_buy_unit_size: "Gruppe Kaufen Einheitsgröße" + group_buy_unit_size: "Gruppen-Kauf Einheitsgröße" total_qtt_ordered: "Gesamtmenge bestellt" max_qtt_ordered: "Max Menge bestellt" current_fulfilled_units: "Aktuelle erfüllte Einheiten" max_fulfilled_units: "Max erfüllte Einheiten" - order_error: "Einige Fehler müssen behoben werden, bevor Sie Aufträge aktualisieren können.\nFelder mit roten Rahmen enthalten Fehler." - variants_without_unit_value: "WARNUNG: Einige Varianten haben keinen Einheitswert" + order_error: "Fehler müssen behoben werden, bevor Sie Aufträge aktualisieren können.\nFelder mit roten Rahmen enthalten Fehler." + variants_without_unit_value: "WARNUNG: Manche Varianten haben keinen Einheitswert" select_variant: "Wählen Sie eine Variante" enterprise: - select_outgoing_oc_products_from: Wählen Sie ausgehende OC-Produkte aus + select_outgoing_oc_products_from: Wählen Sie ausgehende BZ-Produkte von enterprises: index: title: Unternehmen - new_enterprise: Neue Unternehmung - producer?: "Produzent?" + new_enterprise: Neues Unternehmen + producer?: "Erzeuger?" package: Paket status: Status manage: Verwalten form: about_us: desc_short: Kurze Beschreibung - desc_short_placeholder: Erzähl uns von deinem Unternehmen in ein oder zwei Sätzen + desc_short_placeholder: Schreiben Sie etwas in ein oder zwei Sätzen über Ihr Unternehmen desc_long: Über uns - desc_long_placeholder: Erzähle Kunden von dir. Diese Information wird in Ihrem öffentlichen Profil angezeigt. + desc_long_placeholder: Schreiben Sie etwas über sich. Diese Information wird in Ihrem öffentlichen Profil angezeigt. business_details: abn: ABN abn_placeholder: z.B. 99 123 456 789 @@ -566,15 +606,15 @@ de_DE: promo_image_note3: Das Werbebild wird oben auf der Profilseite eines Unternehmens und in Pop-ups angezeigt. inventory_settings: text1: Sie können sich dafür entscheiden, Lagerbestände und Preise über Ihre zu verwalten - inventory: Inventar + inventory: Katalog text2: > - Wenn Sie das Inventar-Tool verwenden, können Sie auswählen, ob neue - Produkte, die von Ihren Lieferanten hinzugefügt wurden, zu Ihrem Inventar - hinzugefügt werden müssen, bevor sie gelagert werden können. Wenn Sie - Ihr Inventar nicht zur Verwaltung Ihrer Produkte verwenden, sollten - Sie die folgende Option auswählen: - preferred_product_selection_from_inventory_only_yes: Neue Produkte können in meine Shopfront gelegt werden (empfohlen) - preferred_product_selection_from_inventory_only_no: Neue Produkte müssen zu meinem Inventar hinzugefügt werden, bevor sie in meine Shopfront gelegt werden können + Wenn Sie das Katalog-Tool verwenden, können Sie auswählen, ob neue Produkte, + die von Ihren Lieferanten hinzugefügt wurden, zu Ihrem Katalog hinzugefügt + werden müssen, bevor sie verkauft werden können. Wenn Sie Ihren Katalog + nicht zur Verwaltung Ihrer Produkte verwenden, sollten Sie die folgende + Option auswählen: + preferred_product_selection_from_inventory_only_yes: Neue Produkte können in meinem Laden angeboten werden (empfohlen) + preferred_product_selection_from_inventory_only_no: Neue Produkte müssen zu meinem Katalog hinzugefügt werden, bevor sie in meinem Laden erscheinen können payment_methods: name: Name applies: Gilt? @@ -601,9 +641,9 @@ de_DE: visible: öffentlich sichtbar not_visible: nicht sichtbar permalink: Permalink (keine Leerzeichen) - permalink_tip: "Dieser Permalink wird verwendet, um die URL zu Ihrem Shop zu erstellen: %{link}your-shop-name / shop" - link_to_front: Link zum Online Shop - link_to_front_tip: Ein direkter Link zu Ihrer Ladenfront im Open Food Network. + permalink_tip: "Dieser Permalink wird verwendet, um die URL zu Ihrem Laden zu erstellen: %{link}name-ihres-ladens / laden" + link_to_front: Link zum Laden + link_to_front_tip: Ein direkter Link zu Ihrem Laden im Open Food Network. shipping_methods: name: Name applies: Gilt? @@ -612,8 +652,8 @@ de_DE: create_one_button: Erstelle jetzt einen no_method_yet: Sie haben noch keine Versandmethoden. shop_preferences: - shopfront_requires_login: "Öffentlich sichtbare Ladenfront?" - shopfront_requires_login_tip: "Wählen Sie aus, ob sich Kunden anmelden müssen, um die Shopfront zu sehen oder ob sie für alle sichtbar sind." + shopfront_requires_login: "Öffentlich sichtbarer Laden?" + shopfront_requires_login_tip: "Wählen Sie aus, ob sich Kunden anmelden müssen, um den Laden zu sehen oder ob sie für alle sichtbar sind." shopfront_requires_login_false: "Öffentlich sichtbar" shopfront_requires_login_true: "Nur für registrierte Nutzer sichtbar" recommend_require_login: "Wenn Bestellungen nachträglich geändert werden dürfen, dann emfehlen wir Einkauf nur für eingeloggte Nutzer." @@ -629,18 +669,18 @@ de_DE: enable_subscriptions_tip: "Abo-Funktionalität aktivieren?" enable_subscriptions_false: "Behindert" enable_subscriptions_true: "aktiviert" - shopfront_message: Shopfront-Nachricht + shopfront_message: Laden-Nachricht shopfront_message_placeholder: > Eine optionale Erklärung für Kunden, die detailliert beschreibt, wie - Ihr Shop funktioniert, wird oberhalb der Produktliste auf Ihrer Shop-Seite + Ihr Laden funktioniert, wird oberhalb der Produktliste auf Ihrer Laden-Seite angezeigt. - shopfront_closed_message: Geschlossene Shopfront-Nachricht + shopfront_closed_message: Laden Geschlossen Nachricht shopfront_closed_message_placeholder: > Eine Nachricht, die eine detailliertere Erklärung liefert, warum Ihr - Geschäft geschlossen ist und / oder wann Kunden erwarten können, dass - es wieder geöffnet wird. Dies wird in Ihrem Shop nur angezeigt, wenn - Sie keine aktiven Bestellzyklen haben (dh Shop ist geschlossen). - shopfront_category_ordering: Shopfront Kategorie Bestellung + Laden geschlossen ist und / oder wann Kunden erwarten können, dass er + wieder geöffnet wird. Dies wird in Ihrem Laden nur angezeigt, wenn Sie + keine aktiven Bestellzyklen haben (d.h. Laden ist geschlossen). + shopfront_category_ordering: Ordnung der Produktkategorien im Laden open_date: Öffnungsdatum close_date: Abschlussdatum social: @@ -686,7 +726,7 @@ de_DE: email_confirmed: "E-Mail bestätigt" email_not_confirmed: "E-Mail nicht bestätigt" actions: - edit_profile: Profil bearbeiten + edit_profile: Einstellungen properties: Eigenschaften payment_methods: Zahlungsarten payment_methods_tip: Dieses Unternehmen hat keine Zahlungsmethoden @@ -706,19 +746,19 @@ de_DE: connect_ofn: Verbindung über OFN herstellen always_free: IMMER FREI producer_description_text: Fügen Sie Ihre Produkte zu Open Food Network hinzu, damit Hubs Ihre Produkte in ihren Geschäften lagern können. - producer_shop: Produzent Laden + producer_shop: Erzeugerladen sell_your_produce: Verkaufen Sie Ihre eigenen Produkte - producer_shop_description_text: Verkaufen Sie Ihre Produkte direkt an Ihre Kunden über Ihre eigene Open Food Network-Ladenfront. - producer_shop_description_text2: Ein Producer Shop ist nur für Ihre Produkte bestimmt, wenn Sie Produkte verkaufen möchten, die außerhalb der Produktionsstätte angebaut werden, wählen Sie "Producer Hub". + producer_shop_description_text: Verkaufen Sie Ihre Produkte direkt an Ihre Kunden durch Ihren eigenen Laden im Open Food Network. + producer_shop_description_text2: Ein Erzeugerladen ist nur für Ihre eigenen Produkte bestimmt. Wenn Sie Produkte anderer verkaufen möchten, wählen Sie "Hub". producer_hub: Produzent Hub producer_hub_text: Verkaufe Produkte von dir selbst und anderen - producer_hub_description_text: Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. Sie können Ihre eigenen Produkte verkaufen und aggregierte Produkte von anderen Unternehmen über Ihre Ladenfront im Open Food Network produzieren. + producer_hub_description_text: Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. Sie können sowohl Ihre eigenen Produkte, als auch Produkte von anderen Unternehmen über Ihren Laden im Open Food Network verkaufen. profile: Profil nur get_listing: Holen Sie sich einen Eintrag profile_description_text: Menschen können Sie im Open Food Network finden und kontaktieren. Ihr Unternehmen wird auf der Karte angezeigt und kann in den Suchergebnissen durchsucht werden. - hub_shop: Hub-Shop + hub_shop: Hub hub_shop_text: Verkaufe Produkte von anderen - hub_shop_description_text: Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. Sie aggregieren Produkte von anderen Unternehmen und können sie über Ihr Geschäft im Open Food Network verkaufen. + hub_shop_description_text: Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. Sie aggregieren Produkte von anderen Unternehmen und verkaufen sie über Ihren Laden im Open Food Network. choose_option: Bitte wähle eine der oben genannten Optionen. change_now: Jetzt ändern enterprise_user_index: @@ -726,13 +766,14 @@ de_DE: no_enterprises_found: Keine Unternehmen gefunden. search_placeholder: Suche mit Name manage: Verwalten + manage_link: Einstellungen new_form: owner: Inhaber owner_tip: Der primäre Benutzer, der für dieses Unternehmen verantwortlich ist. i_am_producer: Ich bin ein Produzent contact_name: Kontaktname edit: - editing: 'Bearbeitung:' + editing: 'Die Einstellungen:' back_link: Zurück zur Unternehmensliste new: title: Neue Unternehmung @@ -763,8 +804,8 @@ de_DE: add_distributor: 'Händler hinzufügen' advanced_settings: title: Erweiterte Einstellungen - choose_product_tip: Sie können alle verfügbaren Produkte (sowohl eingehende als auch ausgehende) auf nur diejenigen im Inventar von %{inventory} beschränken. - preferred_product_selection_from_coordinator_inventory_only_here: Nur das Inventar des Koordinators + choose_product_tip: Sie können alle verfügbaren Produkte (sowohl eingehende als auch ausgehende) auf nur diejenigen im Katalog von %{inventory} beschränken. + preferred_product_selection_from_coordinator_inventory_only_here: Nur der Katalog des Koordinators preferred_product_selection_from_coordinator_inventory_only_all: Alle verfügbaren Produkte save_reload: Speichern und neu laden coordinator_fees: @@ -818,6 +859,10 @@ de_DE: schedule_present: Dieser Bestellzyklus ist mit einem Zeitplan verknüpft und kann nicht gelöscht werden. Bitte heben Sie die Verknüpfung auf oder löschen Sie den Zeitplan zuerst. bulk_update: no_data: Hm, etwas ist schief gelaufen. Keine Bestellzyklusdaten gefunden. + date_warning: + msg: Der Bestellvorgang verweist auf (...) noch offene, aber bereits gezeichnete Bestellungen. Dieses Datum zu ändern wird keine der bereits getätigten Bestellungen berühren, sollte wenn möglich aber vermieden werden. Sind Sie sicher, daß Sie fortfahren wollen? + cancel: Abrechen + proceed: Fortfahren producer_properties: index: title: Herstellereigenschaften @@ -829,11 +874,6 @@ de_DE: shared: user_guide_link: user_guide: Benutzerhandbuch - invoice_settings: - edit: - title: Rechnungseinstellungen - invoice_style2?: Verwenden Sie das alternative Rechnungsmodell, das die gesamte Steueraufschlüsselung pro Tarif- und Steuersatzinfo pro Artikel enthält (noch nicht für Länder mit Preisen ohne Steuern geeignet) - enable_receipt_printing?: Optionen zum Drucken von Belegen mit Thermodruckern in der Dropdown-Liste anzeigen? overview: enterprises_header: ofn_with_tip: Unternehmen sind Hersteller und / oder Hubs und sind die grundlegende Organisationseinheit innerhalb des Open Food Network. @@ -858,7 +898,7 @@ de_DE: totals_by_supplier: Order Cycle Distributor Summen nach Lieferant customer_totals: Bestellzyklus Kundensummen all_products: Alle Produkte - inventory: Aktueller Bestand) + inventory: Aktueller Bestand lettuce_share: SalatShare mailing_list: Mailingliste addresses: Adressen @@ -882,7 +922,7 @@ de_DE: customers: name: Kunden products_and_inventory: - name: Produkte und Inventar + name: Produkte und Katalog sales_total: name: Verkäufe insgesamt description: Gesamtumsatz für alle Bestellungen @@ -903,16 +943,16 @@ de_DE: new: Neues Abonnement create: Abonnement erstellen index: - please_select_a_shop: Bitte wählen Sie ein Geschäft + please_select_a_shop: Bitte wählen Sie einen Laden edit_subscription: Abonnement bearbeiten pause_subscription: Abo pausieren unpause_subscription: Abonnement aufheben cancel_subscription: Abonnement beenden setup_explanation: just_a_few_more_steps: 'Noch ein paar Schritte bevor Sie beginnen können:' - enable_subscriptions: "Aktivieren Sie Abonnements für mindestens einen Ihrer Shops" - enable_subscriptions_step_1_html: 1. Gehen Sie zur Seite %{enterprises_link}, suchen Sie Ihren Shop und klicken Sie auf "Verwalten" - enable_subscriptions_step_2: 2. Aktivieren Sie unter "Shop-Einstellungen" die Option Abonnements + enable_subscriptions: "Aktivieren Sie Abonnements für mindestens einen Ihrer Läden" + enable_subscriptions_step_1_html: 1. Gehen Sie zur Seite %{enterprises_link}, suchen Sie Ihren Laden und klicken Sie auf "Verwalten" + enable_subscriptions_step_2: 2. Aktivieren Sie unter "Ladeneinstellungen" die Option Abonnements set_up_shipping_and_payment_methods_html: Richten Sie die Methoden %{shipping_link} und %{payment_link} ein set_up_shipping_and_payment_methods_note_html: Beachten Sie, dass nur Bar- und Stripe-Zahlungsmethoden für Abonnements verwendet werden dürfen ensure_at_least_one_customer_html: Stellen Sie sicher, dass mindestens eine %{customer_link} vorhanden ist @@ -927,12 +967,18 @@ de_DE: address: 2. Adresse products: 3. Fügen Sie Produkte hinzu review: 4. Überprüfen und speichern + subscription_line_items: + this_is_an_estimate: | + Die angezeigten Preise sind nur Schätzungen und werden zum Zeitpunkt der Änderung des Abonnements berechnet. + Wenn Sie die Preise oder Gebühren ändern, werden die Bestellungen aktualisiert, aber das Abonnement zeigt weiterhin die alten Werte an. details: details: Einzelheiten invalid_error: Hoppla! Bitte füllen Sie alle erforderlichen Felder aus ... allowed_payment_method_types_tip: Zurzeit können nur Bar- und Stripe-Zahlungsmethoden verwendet werden credit_card: Kreditkarte - no_cards_available: Keine Karten verfügbar + charges_not_allowed: Aufträge dieses Kunden/dieser Kundin sind nicht gestattet. + no_default_card: Der Kunde/die Kundin hat keine Karte, die aufgeladen werden kann. + card_ok: Der Kunde/die Kundin hat eine Karte, die aufgeladen werden kann. loading_flash: loading: LADEN VON ABONNEMENTS review: @@ -962,22 +1008,6 @@ de_DE: schedules: destroy: associated_subscriptions_error: Dieser Zeitplan kann nicht gelöscht werden, da ihm Subskriptionen zugeordnet sind - stripe_connect_settings: - edit: - title: "Streifen verbinden" - settings: "die Einstellungen" - stripe_connect_enabled: Shops aktivieren, um Zahlungen über Stripe Connect zu akzeptieren? - no_api_key_msg: Für dieses Unternehmen existiert kein Stripe-Konto. - configuration_explanation_html: Detaillierte Anweisungen zur Konfiguration der Stripe Connect-Integration finden Sie unter konsultieren Sie diese Anleitung . - status: Status - ok: OK - instance_secret_key: Instanzgeheimschlüssel - account_id: Konto-ID - business_name: Geschäftsname - charges_enabled: Gebühren aktiviert - charges_enabled_warning: "Warnung: Gebühren sind für Ihr Konto nicht aktiviert" - auth_fail_error: Der von Ihnen angegebene API-Schlüssel ist ungültig - empty_api_key_error_html: Es wurde kein Stripe-API-Schlüssel bereitgestellt. Um den API-Schlüssel festzulegen, folgen Sie bitte diesen Anweisungen < / a> controllers: enterprises: stripe_connect_cancelled: "Die Verbindung zu Stripe wurde abgebrochen" @@ -991,8 +1021,8 @@ de_DE: message_html: "Sie haben bereits eine Bestellung für diesen Bestellzyklus. Überprüfen Sie die %{cart}, um die Artikel zu sehen, die Sie zuvor bestellt haben. Sie können Artikel auch stornieren, solange der Bestellzyklus geöffnet ist." shops: hubs: - show_closed_shops: "Geöffnete Geschäfte anzeigen" - hide_closed_shops: "Versteckte Geschäfte ausblenden" + show_closed_shops: "Geschlossene Läden anzeigen" + hide_closed_shops: "Geschlossene Läden ausblenden." show_on_map: "Zeige alle auf der Karte" shared: menu: @@ -1007,7 +1037,7 @@ de_DE: login: "Anmeldung" register: "registrieren" contact: "Kontakt" - require_customer_login: "Dieser Shop ist nur für Kunden." + require_customer_login: "Dieser Laden ist nur für Kunden." require_login_html: "Bitte %{login}, wenn Sie bereits ein Konto haben. Andernfalls, %{register}, um Kunde zu werden." require_customer_html: "Bitte %{contact} %{enterprise}, um Kunde zu werden." card_could_not_be_updated: Die Karte konnte nicht aktualisiert werden @@ -1078,8 +1108,8 @@ de_DE: no_shipping_or_payment: keine Versand- oder Zahlungsmethoden unconfirmed: unbestätigt days: Tage - label_shop: "Geschäft" - label_shops: "Shops" + label_shop: "Laden" + label_shops: "Läden" label_map: "Karte" label_producer: "Hersteller" label_producers: "Produzenten" @@ -1089,7 +1119,7 @@ de_DE: label_learn: "Lerne" label_blog: "Blog" label_support: "Unterstützung" - label_shopping: "Einkaufen" + label_shopping: "Einkauf" label_login: "Login" label_logout: "Logout" label_signup: "Registrieren" @@ -1100,7 +1130,7 @@ de_DE: label_less: "Weniger anzeigen" label_notices: "Notizen" cart_items: "Artikel" - cart_headline: "Ihr Einkaufswagen" + cart_headline: "Ihr Warenkorb" total: "Total" cart_updating: "Einkaufswagen aktualisieren..." cart_empty: "Leerer Einkaufswagen" @@ -1136,7 +1166,7 @@ de_DE: footer_sites_community: "Community" footer_sites_userguide: "Benutzerhandbuch" footer_secure: "Sicher und vertrauenswürdig." - footer_secure_text: "Open Food Network verwendet überall SSL-Verschlüsselung (2048 Bit RSA), um Ihre Einkaufs- und Zahlungsinformationen geheim zu halten. Unsere Server speichern Ihre Kreditkartendetails nicht und Zahlungen werden von PCI-konformen Services verarbeitet." + footer_secure_text: "Open Food Network verwendet überall SSL-Verschlüsselung (2048 Bit RSA), um Ihre Einkaufs- und Zahlungsinformationen geheim zu halten. Unsere Server speichern Ihre Kreditkartendetails nicht und Zahlungen werden von PCI-konformen Dienstleistern verarbeitet." footer_contact_headline: "Den Kontakt halten" footer_contact_email: "Schreiben Sie uns eine E-Mail" footer_nav_headline: "Navigieren" @@ -1163,17 +1193,17 @@ de_DE: connect_cta: "Erkunden" system_headline: "Einkaufen - so funktioniert es." system_step1: "1. Suche" - system_step1_text: "Durchsuchen Sie unsere verschiedenen, unabhängigen Geschäfte nach saisonalem lokalem Essen. Suche nach Nachbarschaft und Lebensmittelkategorie, oder ob Sie Lieferung oder Abholung bevorzugen." - system_step2: "2. Geschäft" + system_step1_text: "Durchsuchen Sie unsere verschiedenen, unabhängigen Geschäfte nach saisonalem, lokalem Essen. Suche nach Gegend und Lebensmittelkategorie, oder ob Sie Lieferung oder Abholung bevorzugen." + system_step2: "2. Laden" system_step2_text: "Transformieren Sie Ihre Transaktionen mit erschwinglichen lokalen Lebensmitteln von verschiedenen Herstellern und Hubs. Kenne die Geschichten hinter deinem Essen und den Menschen, die es schaffen!" system_step3: "3. Abholung / Lieferung" - system_step3_text: "Bleiben Sie für Ihre Lieferung oder besuchen Sie Ihren Hersteller oder Hub für eine persönlichere Verbindung mit Ihrem Essen. Lebensmitteleinkauf so vielfältig wie die Natur es beabsichtigt hat." - cta_headline: "Einkaufen, das die Welt zu einem besseren Ort macht." + system_step3_text: "Erhalten Sie eine Lieferung oder besuchen Sie Ihren Hersteller oder Hub für eine persönlichere Verbindung mit Ihrem Essen. Lebensmitteleinkauf so vielfältig wie die Natur es beabsichtigt hat." + cta_headline: "Einkaufen, das die Welt verbessert." cta_label: "Ich bin bereit" stats_headline: "Wir schaffen ein neues Ernährungssystem." stats_producers: "Nahrungsmittelproduzenten" stats_shops: "Lebensmittelgeschäfte" - stats_shoppers: "Lebensmitteleinkäufer" + stats_shoppers: "Lebensmittelkäufer" stats_orders: "Essen Bestellungen" checkout_title: Auschecken checkout_now: Checke jetzt aus @@ -1237,12 +1267,13 @@ de_DE: email_confirmation_click_link: "Bitte klicken Sie auf den unten stehenden Link, um Ihre E-Mail zu bestätigen und mit der Einrichtung Ihres Profils fortzufahren." email_confirmation_link_label: "E-Mail-Adresse bestätigen" email_confirmation_help_html: "Nachdem Sie Ihre E-Mail-Adresse bestätigt haben, können Sie auf Ihr Verwaltungskonto für dieses Unternehmen zugreifen. Sehen Sie sich die %{link} an, um mehr über die Funktionen von %{sitename} zu erfahren und Ihr Profil oder Ihren Online-Shop zu verwenden." + email_confirmation_notice_unexpected: "Sie haben diese Nachricht erhalten, weil Sie sich unter %{sitename} angemeldet haben oder von einer Person eingeladen wurden, die Sie wahrscheinlich kennen. Wenn Sie nicht verstehen, warum Sie diese E-Mail erhalten, schreiben Sie bitte an %{contact}." email_social: "Verbinde dich mit uns:" email_contact: "Schreiben Sie uns eine E-Mail:" email_signoff: "Prost," email_signature: "%{sitename} Team" email_confirm_customer_greeting: "Hallo %[name]," - email_confirm_customer_intro_html: "Vielen Dank für den Einkauf bei %{distributor} !" + email_confirm_customer_intro_html: "Vielen Dank für ihren Einkauf bei %{distributor} !" email_confirm_customer_number_html: "Bestellbestätigung # %{number} " email_confirm_customer_details_html: "Hier sind Ihre Bestelldetails von %{distributor} :" email_confirm_customer_signoff: "Mit freundlichen Grüßen," @@ -1316,7 +1347,7 @@ de_DE: enterprises_choose: "Wählen Sie, wann Sie Ihre Bestellung wünschen:" maps_open: "Öffnen" maps_closed: "Geschlossen" - hubs_buy: "Einkaufen:" + hubs_buy: "Suche nach:" hubs_shopping_here: "Hier einkaufen" hubs_orders_closed: "Momentan keine Bestellungen" hubs_profile_only: "Profil nur" @@ -1331,7 +1362,7 @@ de_DE: hubs_matches: "Meintest Du?" hubs_intro: Regional einkaufen hubs_distance: Am nächsten - hubs_distance_filter: "Zeig mir Shops in der Nähe von %{location}" + hubs_distance_filter: "Läden in der Nähe von %{location}suchen" shop_changeable_orders_alert_html: one: Ihre Bestellung mit %{shop} / %{order} kann bearbeitet werden. Sie können Änderungen bis %{oc_close} vornehmen. other: Sie haben %{count} Bestellungen mit %{shop} zur Überprüfung geöffnet. Sie können Änderungen bis %{oc_close} vornehmen. @@ -1351,13 +1382,13 @@ de_DE: products_update_error_data: "Speichern wegen ungültiger Daten fehlgeschlagen:" products_changes_saved: "Änderungen gespeichert" search_no_results_html: "Es wurden leider keine Ergebnisse für %{query} gefunden. Versuchen Sie eine andere Suche?" - components_profiles_popover: "Profile haben keine Ladenfront im Open Food Network, aber sie können ihren eigenen physischen oder Online-Shop an einem anderen Ort haben" + components_profiles_popover: "Profile haben keinen Laden im Open Food Network, verkaufen möglicherweise aber anderswo online oder offline." components_profiles_show: "Profile anzeigen" components_filters_nofilters: "Keine Filter" components_filters_clearfilters: "Alle Filter löschen" groups_title: Gruppen groups_headline: Gruppen / Regionen - groups_text: "Jeder Produzent ist einzigartig. Jedes Unternehmen hat etwas anderes zu bieten. Unsere Gruppen sind Kollektive von Produzenten, Hubs und Distributoren, die etwas gemeinsam haben, wie Standort, Bauernmarkt oder Philosophie. Dies erleichtert Ihr Einkaufserlebnis. Erkunden Sie unsere Gruppen und lassen Sie das Kuratieren für Sie erledigen." + groups_text: "Jeder Produzent ist einzigartig. Jedes Unternehmen hat etwas anderes zu bieten. Unsere Gruppen sind Kollektive von Produzenten, Hubs und Verteilern, die etwas gemeinsam haben, wie z B Standort, Bauernmarkt oder Philosophie. Dies erleichtert Ihr Einkaufserlebnis." groups_search: "Suchen Sie nach Name oder Stichwort" groups_no_groups: "Keine Gruppen gefunden" groups_about: "Über uns" @@ -1391,25 +1422,25 @@ de_DE: modal_hubs: "Essen Hubs" modal_hubs_abstract: Unsere Food-Hubs sind der Kontaktpunkt zwischen Ihnen und den Menschen, die Ihr Essen zubereiten! modal_hubs_content1: Sie können nach einem geeigneten Hub nach Standort oder Namen suchen. Einige Hubs haben mehrere Punkte, an denen Sie Ihre Einkäufe abholen können, und einige bieten auch Lieferoptionen. Jeder Food-Hub ist eine Verkaufsstelle mit eigenständigem Geschäftsbetrieb und Logistik - so sind Unterschiede zwischen den Hubs zu erwarten. - modal_hubs_content2: Sie können nur zu einem Zeitpunkt an einem Lebensmittelzentrum einkaufen. + modal_hubs_content2: Sie können nicht bei mehr als einem Hub gleichzeitig einkaufen. modal_groups: "Gruppen / Regionen" modal_groups_content1: Dies sind die Organisationen und Beziehungen zwischen Hubs, aus denen das Open Food Network besteht. modal_groups_content2: Einige Gruppen sind nach Standort oder Rat gruppiert, andere nach nichtgeographischen Ähnlichkeiten. modal_how: "Wie es funktioniert" - modal_how_shop: Einkaufen im Open Food Netzwerk - modal_how_shop_explained: Suchen Sie nach einem Lebensmittelzentrum in Ihrer Nähe, um mit dem Einkauf zu beginnen! Sie können jeden Food-Hub erweitern, um zu sehen, welche Arten von Goodies verfügbar sind, und klicken Sie, um den Einkauf zu starten. (Sie können jeweils nur einen Food-Hub kaufen.) + modal_how_shop: Einkaufen im Open Food Network + modal_how_shop_explained: Suchen Sie nach einem Hub in Ihrer Nähe, um mit dem Einkauf zu beginnen! Sie können ein Hub erweitern, um zu sehen, welche Arten von Produkten verfügbar sind. Klicken Sie durch, um dort einzukaufen. (Sie können jeweils nur bei einem Hub gleichzeitig einkaufen.) modal_how_pickup: Abhol-, Liefer- und Versandkosten - modal_how_pickup_explained: Einige Food-Hubs liefern an Ihre Tür, während andere Ihre Einkäufe abholen müssen. Sie können sehen, welche Optionen auf der Startseite verfügbar sind und welche Sie auf den Einkaufs- und Auscheck-Seiten auswählen möchten. Die Lieferung kostet mehr und die Preise unterscheiden sich von Hub zu Hub. Jeder Food-Hub ist eine Verkaufsstelle mit eigenständigem Geschäftsbetrieb und Logistik - so sind Schwankungen zwischen den Hubs zu erwarten. + modal_how_pickup_explained: Manche Hubs liefern an, bei anderen müssen Sie abholen. Sie können auf der Startseite sehen, welche Optionen verfügbar sind, und und diese dann an der Kasse wählen. Lieferungen kosten mehr und die Preise unterscheiden sich von Hub zu Hub. Jedes Hub ist eine Verkaufsstelle mit eigenständigem Geschäftsbetrieb und Logistik - so sind Schwankungen zwischen den Hubs zu erwarten. modal_how_more: Mehr erfahren modal_how_more_explained: "Wenn Sie mehr über das Open Food Network erfahren wollen, wie es funktioniert und sich einbringen, schauen Sie nach:" modal_producers: "Produzenten" - modal_producers_explained: "Unsere Produzenten stellen all das leckere Essen her, das Sie im Open Food Network einkaufen können." + modal_producers_explained: "Unsere Produzenten stellen all das leckere Essen her, das Sie im Open Food Network kaufen können." producers_about: Über uns - producers_buy: Einkaufen + producers_buy: Suchen producers_contact: Kontakt producers_contact_phone: Anruf producers_contact_social: Folgen - producers_buy_at_html: "Shop für %{enterprise} Produkte unter:" + producers_buy_at_html: "Suche nach %{enterprise} Produkten unter:" producers_filter: Filtern nach producers_filter_type: Art producers_filter_property: Eigentum @@ -1442,10 +1473,10 @@ de_DE: sell_hubs_detail: "Richten Sie im OFN ein Profil für Ihr Lebensmittelunternehmen oder Ihre Organisation ein. Sie können Ihr Profil jederzeit auf einen Multi-Producer-Shop upgraden." sell_groups_detail: "Richten Sie ein maßgeschneidertes Verzeichnis von Unternehmen (Produzenten und andere Lebensmittelunternehmen) für Ihre Region oder für Ihre Organisation ein." sell_user_guide: "Erfahren Sie mehr in unserem Benutzerhandbuch." - sell_listing_price: "Die Auflistung im OFN ist kostenlos. Das Öffnen und Betreiben eines Online-Shops ist kostenlos. Das Einrichten eines Gruppenverzeichnisses in OFN für Ihre Organisation oder Ihr regionales Netzwerk ist kostenlos." - sell_embed: "Wir können auch einen OFN-Shop in Ihre eigene Website einbetten oder eine maßgeschneiderte lokale Netzwerk-Website für Ihre Region erstellen." + sell_listing_price: "Die Auflistung im OFN ist kostenlos. Das Öffnen und Betreiben eines Ladens ist kostenlos. Das Einrichten eines Gruppenverzeichnisses im OFN für Ihre Organisation oder Ihr regionales Netzwerk ist kostenlos." + sell_embed: "Wir können auch einen OFN-Laden in Ihre eigene Website einbetten oder eine maßgeschneiderte Webseite für Ihr Lokalität oder Region erstellen." sell_ask_services: "Fragen Sie uns nach OFN-Diensten." - shops_title: Shops + shops_title: Läden shops_headline: Einkaufen, verwandelt. shops_text: Nahrung wächst in Zyklen, Bauern ernten in Zyklen und wir bestellen Nahrung in Zyklen. Wenn Sie feststellen, dass ein Bestellzyklus geschlossen ist, schauen Sie bald wieder vorbei. shops_signup_title: Melde dich als Hub an @@ -1459,10 +1490,10 @@ de_DE: shops_signup_detail: Hier ist das Detail. orders: Aufträge orders_fees: Gebühren... - orders_edit_title: Einkaufswagen - orders_edit_headline: Ihr Einkaufswagen + orders_edit_title: Warenkorb + orders_edit_headline: Ihr Warenkorb orders_edit_time: Bestellung bereit für - orders_edit_continue: Mit dem Einkaufen fortfahren + orders_edit_continue: Mit dem Einkauf fortfahren orders_edit_checkout: Auschecken orders_form_empty_cart: "Einkaufskorb leeren" orders_form_subtotal: Zwischensumme erzeugen @@ -1491,18 +1522,18 @@ de_DE: products_cart_distributor_choice: "Fairteiler Deiner Bestellung" products_cart_distributor_change: "Ihr Händler für diese Bestellung wird in %{name} geändert, wenn Sie dieses Produkt zu Ihrem Warenkorb hinzufügen." products_cart_distributor_is: "Ihr Händler für diese Bestellung ist %{name}." - products_distributor_error: "Bitte füllen Sie Ihre Bestellung unter %{link} aus, bevor Sie mit einem anderen Händler einkaufen." + products_distributor_error: "Bitte schließen Sie Ihre Bestellung bei %{link} ab, bevor Sie bei einem anderen Händler einkaufen." products_oc: "Bestellzyklus für Ihre Bestellung:" products_oc_change: "Ihr Bestellzyklus für diese Bestellung wird in %{name} geändert, wenn Sie dieses Produkt zu Ihrem Warenkorb hinzufügen." products_oc_is: "Ihr Bestellzyklus für diesen Auftrag lautet %{name}." - products_oc_error: "Bitte füllen Sie Ihre Bestellung von %{link} vor dem Einkauf in einem anderen Bestellzyklus." + products_oc_error: "Bitte schließen Sie Ihre Bestellung bei %{link} ab, bevor Sie in einem anderen Bestellzyklus einkaufen." products_oc_current: "Ihr aktueller Bestellzyklus" products_max_quantity: Max Menge products_distributor: Verteiler products_distributor_info: Wenn Sie einen Händler für Ihre Bestellung auswählen, werden hier ihre Adresse und Abholzeiten angezeigt. products_distribution_adjustment_label: "Produktverteilung von %{distributor} für %{product}" - shop_trial_expires_in: "Ihr Shopfront-Test läuft ab in" - shop_trial_expired_notice: "Gute Nachrichten! Wir haben uns entschieden, Shopfront-Tests bis auf weiteres zu verlängern." + shop_trial_expires_in: "Ihr Laden-Versuch läuft ab in" + shop_trial_expired_notice: "Gute Nachrichten! Wir haben uns entschieden, Laden-Versuche bis auf weiteres zu verlängern." password: Passwort remember_me: Erinnere dich an mich are_you_sure: "Bist du sicher?" @@ -1521,8 +1552,8 @@ de_DE: one_filter_applied: "1 Filter angewendet" x_filters_applied: " Filter angewendet" submitting_order: "Bestellung abschicken: Bitte warten" - confirm_hub_change: "Bist du sicher? Dadurch wird der ausgewählte Hub geändert und alle Artikel im Einkaufswagen entfernt." - confirm_oc_change: "Bist du sicher? Dies ändert den ausgewählten Bestellzyklus und entfernt alle Artikel in Ihrem Einkaufswagen." + confirm_hub_change: "Sind Sie sicher? Dadurch wird das ausgewählte Hub geändert und alle Artikel vom Warenkorb entfernt." + confirm_oc_change: "Sind Sie sicher? Dies ändert den ausgewählten Bestellzyklus und entfernt alle Artikel von Ihrem Warenkorb." location_placeholder: "Geben Sie einen Ort ein ..." error_required: "kann nicht leer sein" error_number: "muss nummer sein" @@ -1559,6 +1590,17 @@ de_DE: reset_password: "Passwort zurücksetzen" who_is_managing_enterprise: "Wer ist verantwortlich für die Verwaltung von %{enterprise}?" update_and_recalculate_fees: "Aktualisieren und Gebühren neu berechnen" + registration: + steps: + type: + headline: "Letzter Schritt zum Hinzufügen von %{enterprise}!" + question: "Sind Sie ein Produzent?" + yes_producer: "Ja, ich bin ein Produzent." + no_producer: "Nein, ich bin kein Produzent" + producer_field_error: "Bitte wählen Sie: Sind Sie ein Produzent?" + yes_producer_help: "Hersteller machen leckere Dinge zu essen und / oder zu trinken. Du bist ein Produzent, wenn du ihn anbaust, erziehst ihn, braue ihn, backe ihn, gähre ihn, melke ihn oder forme ihn." + no_producer_help: "Wenn Sie kein Produzent sind, sind Sie wahrscheinlich jemand, der Lebensmittel verkauft und verteilt. Sie könnten ein Hub, Coop, Einkaufsgruppe, Einzelhändler, Großhändler oder andere sein." + create_profile: "Profil erstellen" enterprise: registration: modal: @@ -1575,7 +1617,7 @@ de_DE: address1_field: "Anschrift Zeile 1:" address1_field_placeholder: "z.B. 123 Cranberry-Laufwerk" address1_field_error: "Bitte geben Sie eine Adresse an" - address2_field: "Adresszeile 2:" + address2_field: "Anschrift Zeile 2:" suburb_field: "Vorort:" suburb_field_placeholder: "z.B. Northcote" suburb_field_error: "Bitte geben Sie einen Vorort ein" @@ -1597,13 +1639,6 @@ de_DE: phone_field_placeholder: 'z.B. (03) 1234 5678' type: title: 'Art' - headline: "Letzter Schritt zum Hinzufügen von %{enterprise}!" - question: "Bist du ein Produzent?" - yes_producer: "Ja, ich bin ein Produzent" - no_producer: "Nein, ich bin kein Produzent" - producer_field_error: "Bitte wähle eines. Bist du Produzent?" - yes_producer_help: "Hersteller machen leckere Dinge zu essen und / oder zu trinken. Du bist ein Produzent, wenn du ihn anbaust, erziehst ihn, braue ihn, backe ihn, gähre ihn, melke ihn oder forme ihn." - no_producer_help: "Wenn Sie kein Produzent sind, sind Sie wahrscheinlich jemand, der Lebensmittel verkauft und verteilt. Sie könnten ein Hub, Coop, Einkaufsgruppe, Einzelhändler, Großhändler oder andere sein." about: title: 'Über' images: @@ -1642,6 +1677,7 @@ de_DE: enterprise_about_headline: "Schön!" enterprise_about_message: "Lassen Sie uns nun die Details darlegen" enterprise_success: "Erfolg! %{enterprise} wurde dem Open Food Network hinzugefügt" + enterprise_registration_exit_message: "Wenn Sie diesen Assistenten zu einem beliebigen Zeitpunkt beenden, können Sie weiterhin Ihr Profil erstellen, indem Sie zur Verwaltungsoberfläche wechseln." enterprise_description: "Kurze Beschreibung" enterprise_description_placeholder: "Ein kurzer Satz beschreibt Ihr Unternehmen" enterprise_long_desc: "Ausführliche Beschreibung" @@ -1691,7 +1727,6 @@ de_DE: registration_type_error: "Bitte wählen Sie: Sind Sie ein Produzent?" registration_type_producer_help: "Hersteller machen leckere Dinge zu essen und / oder zu trinken. Du bist ein Produzent, wenn du ihn anbaust, erziehst ihn, braue ihn, backe ihn, gähre ihn, melke ihn oder forme ihn." registration_type_no_producer_help: "Wenn Sie kein Produzent sind, sind Sie wahrscheinlich jemand, der Lebensmittel verkauft und verteilt. Sie könnten ein Hub, Coop, Einkaufsgruppe, Einzelhändler, Großhändler oder andere sein." - create_profile: "Profil erstellen" registration_images_headline: "Dankeschön!" registration_images_description: "Lass uns ein paar schöne Bilder hochladen, damit dein Profil gut aussieht! :)" registration_detail_headline: "Lass uns anfangen" @@ -1704,7 +1739,7 @@ de_DE: registration_detail_address1: "Anschrift Zeile 1:" registration_detail_address1_placeholder: "z.B. 123 Cranberry-Laufwerk" registration_detail_address1_error: "Bitte geben Sie eine Adresse an" - registration_detail_address2: "Adresszeile 2:" + registration_detail_address2: "Anschrift Zeile 2:" registration_detail_suburb: "Vorort:" registration_detail_suburb_placeholder: "z.B. Northcote" registration_detail_suburb_error: "Bitte geben Sie einen Vorort ein" @@ -1724,8 +1759,8 @@ de_DE: shop_variant_quantity_min: "Mindest" shop_variant_quantity_max: "max" follow: "Folgen" - shop_for_products_html: "Shop für %{enterprise} Produkte unter:" - change_shop: "Shop wechseln zu:" + shop_for_products_html: "Suche nach %{enterprise} Produkten unter:" + change_shop: "Laden ändern auf:" shop_at: "Kaufe jetzt bei:" price_breakdown: "Vollständige Preisaufschlüsselung" admin_fee: "Gebühr Administration" @@ -1750,7 +1785,7 @@ de_DE: you_have_no_orders_yet: "Du hast noch keine Bestellungen" running_balance: "Laufendes Gleichgewicht" outstanding_balance: "Offener Betrag" - admin_entreprise_relationships: "Unternehmensbeziehungen" + admin_entreprise_relationships: "Unternehmensberechtigungen" admin_entreprise_relationships_everything: "Alles" admin_entreprise_relationships_permits: "Genehmigungen" admin_entreprise_relationships_seach_placeholder: "Suche" @@ -1797,6 +1832,8 @@ de_DE: flat_percent_per_item: "Flache Prozent (pro Artikel)" flat_rate_per_item: "Pauschale (pro Stück)" flat_rate_per_order: "Pauschalpreis pro Bestellung)" + flexible_rate: "Flexible Rate" + price_sack: "Preis Sack" new_order_cycles: "Neue Bestellzyklen" new_order_cycle: "Neuer Bestellzyklus" select_a_coordinator_for_your_order_cycle: "Wählen Sie einen Koordinator für Ihren Bestellzyklus" @@ -1872,8 +1909,6 @@ de_DE: edit_profile_details_etc: "Ändern Sie Ihre Profilbeschreibung, Bilder usw." order_cycle: "Bestellungszyklus" order_cycles: "Bestellrunden" - enterprises: "Unternehmen" - enterprise_relationships: "Unternehmensbeziehungen" remove_tax: "Steuer entfernen" enterprise_terms_of_service: "Unternehmens-Nutzungsbedingungen" enterprises_require_tos: "Unternehmen müssen die Nutzungsbedingungen akzeptieren" @@ -1895,18 +1930,18 @@ de_DE: hub_sidebar_at_least: "Mindestens ein Hub muss ausgewählt sein" hub_sidebar_blue: "Blau" hub_sidebar_red: "rot" - shop_trial_in_progress: "Ihr Shopfront-Test läuft in %{days} ab." + shop_trial_in_progress: "Ihr Laden-Versuch läuft in %{days} ab." report_customers_distributor: "Verteiler" report_customers_supplier: "Zulieferer" report_customers_cycle: "Bestellungszyklus" - report_customers_type: "Berichtstyp" + report_customers_type: "Berichtsart" report_customers_csv: "Download als CSV" report_producers: "Erzeuger:" - report_type: "Berichtstyp:" + report_type: "Berichtsart:" report_hubs: "Naben:" report_payment: "Zahlungsarten:" report_distributor: "Verteiler:" - report_payment_by: 'Zahlungen nach Typ' + report_payment_by: 'Zahlungen nach Art' report_itemised_payment: 'Aufgeschlüsselte Zahlung Summen' report_payment_totals: 'Zahlungssummen' report_all: 'alle' @@ -2083,9 +2118,9 @@ de_DE: shipping_methods: "Lieferoptionen" payment_methods: "Zahlungsarten" payment_method_fee: "Transaktionsgebühr" - inventory_settings: "Inventareinstellungen" + inventory_settings: "Katalogeinstellungen" tag_rules: "Tag-Regeln" - shop_preferences: "Shop-Einstellungen" + shop_preferences: "Ladeneinstellungen" enterprise_fee_whole_order: Ganze Bestellung enterprise_fee_by: "%{type} Gebühr von %{role} %{enterprise_name}" validation_msg_relationship_already_established: "^ Diese Beziehung ist bereits etabliert." @@ -2096,11 +2131,12 @@ de_DE: content_configuration_pricing_table: "(TODO: Preistabelle)" content_configuration_case_studies: "(TODO: Fallstudien)" content_configuration_detail: "(Todo: Detail)" + enterprise_name_error: "wurde bereits genommen. Wenn dies Ihr Unternehmen ist und Sie die Eigentumsrechte beanspruchen möchten oder wenn Sie mit diesem Unternehmen handeln möchten, wenden Sie sich bitte an den aktuellen Manager dieses Profils unter %{email}." enterprise_owner_error: "^ %{email} darf keine weiteren Unternehmen besitzen (Limit ist %{enterprise_limit})." enterprise_role_uniqueness_error: "^ Diese Rolle ist bereits vorhanden." inventory_item_visibility_error: muss wahr oder falsch sein product_importer_file_error: "Fehler: keine Datei hochgeladen" - product_importer_spreadsheet_error: "Datei konnte nicht verarbeitet werden: ungültiger Dateityp" + product_importer_spreadsheet_error: "Datei konnte nicht verarbeitet werden: ungültiges Datenformat" product_importer_products_save_error: hat keine Produkte erfolgreich gespeichert product_import_file_not_found_notice: 'Datei nicht gefunden oder konnte nicht geöffnet werden' product_import_no_data_in_spreadsheet_notice: 'Keine Daten in der Tabelle gefunden' @@ -2108,7 +2144,7 @@ de_DE: order_cycle_selecting_notice: Ihr Bestellzyklus wurde ausgewählt. adjustments_tax_rate_error: "^ Bitte überprüfen Sie, ob der Steuersatz für diese Anpassung korrekt ist." active_distributors_not_ready_for_checkout_message_singular: >- - Der Hub %{distributor_names} ist in einem aktiven Bestellzyklus aufgeführt, + Das Hub %{distributor_names} ist in einem aktiven Bestellzyklus aufgeführt, hat jedoch keine gültigen Versand- und Zahlungsmethoden. Bis Sie diese einrichten, können Kunden nicht an diesem Hub einkaufen. active_distributors_not_ready_for_checkout_message_plural: >- @@ -2130,6 +2166,7 @@ de_DE: order_cycles_no_permission_to_coordinate_error: "Keines Ihrer Unternehmen ist berechtigt, einen Bestellzyklus zu koordinieren" order_cycles_no_permission_to_create_error: "Sie sind nicht berechtigt, einen von diesem Unternehmen koordinierten Bestellzyklus zu erstellen" back_to_orders_list: "Zurück zur Bestellliste" + no_orders_found: "Keine Bestellungen gefunden" order_information: "Bestellinformationen" date_completed: "Datum abgeschlossen" amount: "Menge" @@ -2150,10 +2187,11 @@ de_DE: unavailable: Nicht verfügbar profile: Profil hub: Nabe - shop: Geschäft + shop: Laden choose: Wählen resolve_errors: Bitte beheben Sie die folgenden Fehler more_items: "+ %{count} Mehr" + default_card_updated: Standardkarte aktualisiert admin: enterprise_limit_reached: "Sie haben die Standardgrenze für Unternehmen pro Konto erreicht. Schreiben Sie an %{contact_email}, wenn Sie es erhöhen müssen." modals: @@ -2192,11 +2230,11 @@ de_DE: hub_profile_text2: > Ein Profil zu haben und Verbindungen innerhalb Ihres lokalen Lebensmittelsystems über das Open Food Network herzustellen, wird immer kostenlos sein. - hub_shop: Hub-Shop + hub_shop: Hub hub_shop_text1: > Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. Sie aggregieren Produkte von anderen Unternehmen und können sie über - Ihr Geschäft im Open Food Network verkaufen. + Ihren Laden im Open Food Network verkaufen. hub_shop_text2: > Hubs können viele Formen annehmen, egal ob es sich um eine Lebensmittelkooperative, eine Einkaufsgruppe, ein Gemüsekistenprogramm oder ein lokales Lebensmittelgeschäft @@ -2218,25 +2256,24 @@ de_DE: Ein Profil macht dich sichtbar und kontaktierbar für andere und ist eine Möglichkeit, deine Geschichte zu teilen. profile_only_text2: > - Wenn Sie es vorziehen, sich auf die Produktion von Lebensmitteln zu - konzentrieren und die Arbeit, sie an jemand anderen zu verkaufen, aufgeben - möchten, benötigen Sie kein Geschäft im Open Food Network. + Wenn Sie es vorziehen, sich auf die Lebensmittelerzeugung zu konzentrieren, + und den Verkauf anderen zu überlassen, benötigen Sie keinen Laden im + Open Food Network. profile_only_text3: > Fügen Sie Ihre Produkte zu Open Food Network hinzu, damit Hubs Ihre Produkte in ihren Geschäften lagern können. - producer_shop: Produzent Laden + producer_shop: Erzeugerladen producer_shop_text1: > - Verkaufen Sie Ihre Produkte direkt an Ihre Kunden über Ihre eigene Open - Food Network-Ladenfront. + Verkaufen Sie Ihre Produkte direkt an Kunden über Ihren eigenen Laden + im Open Food Network. producer_shop_text2: > - Ein Producer Shop ist nur für Ihre Produkte bestimmt, wenn Sie Produkte - verkaufen möchten, die außerhalb der Produktionsstätte produziert / - hergestellt wurden, wählen Sie bitte "Producer Hub". + Ein Erzeugerladen ist nur für Ihre Produkte gedacht. Wenn Sie Produkte + anderer verkaufen möchten, wählen Sie bitte "Hub". producer_hub: Produzent Hub producer_hub_text1: > Ihr Unternehmen ist das Rückgrat Ihres lokalen Lebensmittelsystems. - Sie können Ihre eigenen Produkte verkaufen und aggregierte Produkte - von anderen Unternehmen über Ihre Ladenfront im Open Food Network produzieren. + Sie können sowohl Ihre eigenen Produkte als auch Produkte anderer Unternehmen + über Ihren Laden im Open Food Network verkaufen. producer_hub_text2: > Producer Hubs können viele Formen annehmen, sei es ein CSA, ein Veggie-Box-Programm oder eine Food Coop mit einem Dachgarten. @@ -2257,7 +2294,7 @@ de_DE: Produzent, wenn du ihn anbaust, erziehst ihn, braue ihn, backe ihn, gähre ihn, melke ihn oder forme ihn. producer_text2: > - Die Hersteller können auch andere Funktionen übernehmen, z. B. die Zusammenführung + Hersteller können auch andere Funktionen übernehmen, wie z. B. die Zusammenführung von Nahrungsmitteln anderer Unternehmen und den Verkauf über ein Geschäft im Open Food Network. non_producer: Nicht-Produzent @@ -2278,16 +2315,18 @@ de_DE: description: Beschreibung resolve: Entschlossenheit new_tag_rule_dialog: - select_rule_type: "Wählen Sie einen Regeltyp aus:" + select_rule_type: "Wählen Sie einen Regelart aus:" + resend_user_email_confirmation: + resend: "Erneut senden" out_of_stock: reduced_stock_available: Reduzierter Bestand verfügbar out_of_stock_text: > - Während des Einkaufs haben sich die Lagerbestände für eines oder mehrere - Produkte in Ihrem Warenkorb verringert. Hier ist, was sich geändert hat: + Während des Einkaufs haben sich die Lagerbestände für ein oder mehrere Produkte + in Ihrem Warenkorb verringert. Das Folgende hat sich geändert: now_out_of_stock: ist jetzt ausverkauft. only_n_remainging: "Jetzt hat nur noch %{num} übrig." variant_overrides: - inventory_products: "Inventarprodukte" + inventory_products: "Katalogprodukte" hidden_products: "Versteckte Produkte" new_products: "Neue Produkte" reset_stock_levels: Zurücksetzen der Bestandswerte auf Standardwerte @@ -2301,10 +2340,10 @@ de_DE: changing_on_hand_stock: Änderung der Lagerbestände ... stock_reset: Aktien werden auf Standardwerte zurückgesetzt. tag_rules: - show_hide_variants: 'Produkt Varianten im Shop anzeigen' + show_hide_variants: 'Produktvarianten im Laden anzeigen oder verbergen' show_hide_shipping: 'Versandarten im Shop anzeigen' show_hide_payment: 'Zahlungsmethoden im Shop anzeigen' - show_hide_order_cycles: 'Show or Hide Bestellzyklen in meiner Shopfront' + show_hide_order_cycles: 'Bestellzyklen in meinem Laden anzeigen order verbergen' visible: SICHTBAR not_visible: UNSICHTBAR services: @@ -2314,7 +2353,7 @@ de_DE: add_to_order_cycle: "zum Bestellzyklus hinzufügen" manage_products: "Produkte verwalten" edit_profile: "Profil bearbeiten" - add_products_to_inventory: "Produkte ins Sortiment nehmen" + add_products_to_inventory: "Produkte in den Katalog aufnehmen" resources: could_not_delete_customer: 'Der Kunde konnte nicht gelöscht werden' product_import: @@ -2328,7 +2367,7 @@ de_DE: producer: "Erzeuger" non_producer: "Widerverkäufer" customers: - select_shop: 'Bitte wählen Sie zuerst ein Geschäft aus' + select_shop: 'Bitte wählen Sie zuerst einen Laden aus' could_not_create: Es tut uns leid! Konnte nicht ... Erstellen subscriptions: closes: schließt @@ -2388,24 +2427,18 @@ de_DE: title: 'Neues Produkt' unit_name_placeholder: 'z.B. Trauben' index: - header: - title: Massenbearbeitung von Produkten indicators: title: LADE PRODUKTE - no_products: "Noch keine Produkte Warum fügst du nicht etwas hinzu?" - no_results: "Entschuldigung, keine Ergebnisse stimmen überein" + no_products: "Bisher sind keine Produkte gewählt worden. Warum fügen Sie nicht einige hinzu?" products_head: name: Name unit: Einheit - display_as: Darstellen als + display_as: Angezeigt als category: Kategorie tax_category: Steuerkategorie - inherits_properties?: Vererbt Eigenschaften? - available_on: Verfügbar auf - av_on: "Ein V. Auf" - products_variant: - variant_has_n_overrides: "Diese Variante hat %{n} override (s)" - new_variant: "Neue Variante" + inherits_properties?: Vererbt Eigenschaften + available_on: Verfügbar am + av_on: "Verfüg. am" product_name: Produktname primary_taxon_form: product_category: Produktkategorie @@ -2415,14 +2448,13 @@ de_DE: display_as: display_as: Darstellen als reports: + table: + select_and_search: "Wählen Sie Filter und klicken Sie auf SEARCH, um auf Ihre Daten zuzugreifen." bulk_coop: bulk_coop_supplier_report: 'Bulk Coop - Summen nach Lieferant' bulk_coop_allocation: 'Massenkoop - Zuteilung' bulk_coop_packing_sheets: 'Massenkoop - Verpackungsblätter' bulk_coop_customer_payments: 'Massenkoop - Kundenzahlungen' - shared: - configuration_menu: - stripe_connect: Streifen verbinden variants: autocomplete: producer_name: Produzent @@ -2437,7 +2469,7 @@ de_DE: date_picker: format: '% Y-% m-%d' js_format: 'JJ-MM-TT' - inventory: Inventar + inventory: Katalog orders: bought: item: "Bereits in dieser Reihenfolge bestellt" @@ -2512,7 +2544,7 @@ de_DE: transaction_history: Verlauf der Transaktionen open_orders: order: Bestellung - shop: Geschäft + shop: Laden changes_allowed_until: Änderungen erlaubt bis items: Artikel total: Gesamt @@ -2522,11 +2554,18 @@ de_DE: until: Bis past_orders: order: Auftrag - shop: Geschäft + shop: Laden completed_at: Erfolgt am items: Artikel total: Gesamt paid?: Bezahlt? view: Aussicht + saved_cards: + default?: Standard? + delete?: Löschen? + cards: + authorised_shops: Bevollmächtigte Läden + authorised_shops_popover: Dies ist die Liste der Shops, die Ihre Standardkreditkarte für eventuell vorhandene Abonnements (dh wiederkehrende Bestellungen) belasten dürfen. Ihre Kartendetails werden sicher aufbewahrt und nicht an Ladenbesitzer weitergegeben. Sie werden immer benachrichtigt, wenn Sie belastet werden. + saved_cards_popover: Dies ist die Liste der Karten, die Sie für die spätere Verwendung gespeichert haben. Ihr "Standard" wird automatisch beim Abschließen einer Bestellung ausgewählt und kann von allen Geschäften belastet werden, die Sie dazu berechtigt haben (siehe rechts). localized_number: invalid_format: hat ein ungültiges Format. Bitte gebe eine Nummer ein. From 91e57cb893c454fa8f6c9bd18c87cdc8cd418a40 Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Wed, 15 Aug 2018 23:29:28 +0100 Subject: [PATCH 058/122] Removed Cart table, its dependency on spree orders table and removed some more dead code related to this --- .../spree/orders_controller_decorator.rb | 14 -------------- app/models/spree/order_decorator.rb | 1 - app/models/spree/user_decorator.rb | 1 - db/migrate/20180812214434_drop_carts.rb | 7 +++++++ db/schema.rb | 12 +----------- 5 files changed, 8 insertions(+), 27 deletions(-) create mode 100644 db/migrate/20180812214434_drop_carts.rb diff --git a/app/controllers/spree/orders_controller_decorator.rb b/app/controllers/spree/orders_controller_decorator.rb index 47425bcbf2c..e435b645227 100644 --- a/app/controllers/spree/orders_controller_decorator.rb +++ b/app/controllers/spree/orders_controller_decorator.rb @@ -202,20 +202,6 @@ def populate_variant_attributes end end - def populate_cart hash - if spree_current_user - unless spree_current_user.cart - spree_current_user.build_cart - cart = Cart.create(user: spree_current_user) - spree_current_user.cart = cart - spree_current_user.save - end - distributor = Enterprise.find(hash[:distributor_id]) - order_cycle = OrderCycle.find(hash[:order_cycle_id]) if hash[:order_cycle_id] - spree_current_user.cart.add_variant hash[:variants].keys.first, hash[:variants].values.first, distributor, order_cycle, current_currency - end - end - # Rails to_json encodes Float::INFINITY as Infinity, which is not valid JSON # Return it as a large integer (max 32 bit signed int) def wrap_json_infinity(n) diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index c6def73d680..bc8142694bc 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -10,7 +10,6 @@ Spree::Order.class_eval do belongs_to :order_cycle belongs_to :distributor, class_name: 'Enterprise' - belongs_to :cart belongs_to :customer has_one :proxy_order has_one :subscription, through: :proxy_order diff --git a/app/models/spree/user_decorator.rb b/app/models/spree/user_decorator.rb index 8ae76a11b44..cf375e7e65d 100644 --- a/app/models/spree/user_decorator.rb +++ b/app/models/spree/user_decorator.rb @@ -9,7 +9,6 @@ has_many :owned_groups, class_name: 'EnterpriseGroup', foreign_key: :owner_id, inverse_of: :owner has_many :account_invoices has_many :billable_periods, foreign_key: :owner_id, inverse_of: :owner - has_one :cart has_many :customers has_many :credit_cards diff --git a/db/migrate/20180812214434_drop_carts.rb b/db/migrate/20180812214434_drop_carts.rb new file mode 100644 index 00000000000..f3dfb36ee77 --- /dev/null +++ b/db/migrate/20180812214434_drop_carts.rb @@ -0,0 +1,7 @@ +class DropCarts < ActiveRecord::Migration + def change + remove_foreign_key :spree_orders, column: :cart_id + remove_column :spree_orders, :cart_id + drop_table :carts + end +end diff --git a/db/schema.rb b/db/schema.rb index d3121a1f40d..13c0c125b85 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 => 20180510083800) do +ActiveRecord::Schema.define(:version => 20180812214434) do create_table "account_invoices", :force => true do |t| t.integer "user_id", :null => false @@ -53,12 +53,6 @@ add_index "billable_periods", ["account_invoice_id"], :name => "index_billable_periods_on_account_invoice_id" - create_table "carts", :force => true do |t| - t.integer "user_id" - end - - add_index "carts", ["user_id"], :name => "index_carts_on_user_id" - create_table "column_preferences", :force => true do |t| t.integer "user_id", :null => false t.string "action_name", :null => false @@ -621,7 +615,6 @@ t.integer "order_cycle_id" t.string "currency" t.string "last_ip_address" - t.integer "cart_id" t.integer "customer_id" end @@ -1203,8 +1196,6 @@ add_foreign_key "billable_periods", "enterprises", name: "bill_items_enterprise_id_fk" add_foreign_key "billable_periods", "spree_users", name: "bill_items_owner_id_fk", column: "owner_id" - add_foreign_key "carts", "spree_users", name: "carts_user_id_fk", column: "user_id" - 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" @@ -1285,7 +1276,6 @@ add_foreign_key "spree_option_values_variants", "spree_option_values", name: "spree_option_values_variants_option_value_id_fk", column: "option_value_id" add_foreign_key "spree_option_values_variants", "spree_variants", name: "spree_option_values_variants_variant_id_fk", column: "variant_id" - add_foreign_key "spree_orders", "carts", name: "spree_orders_cart_id_fk" add_foreign_key "spree_orders", "customers", name: "spree_orders_customer_id_fk" add_foreign_key "spree_orders", "enterprises", name: "spree_orders_distributor_id_fk", column: "distributor_id" add_foreign_key "spree_orders", "order_cycles", name: "spree_orders_order_cycle_id_fk" From c14e7ea8d50e23d1c124a0050ba91cd05ebc736e Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 16 Aug 2018 05:31:23 +0800 Subject: [PATCH 059/122] Allow bulk update of order cycle name --- .../resources/services/order_cycles.js.coffee | 2 +- app/views/admin/order_cycles/_row.html.haml | 3 +- .../admin/order_cycles_controller_spec.rb | 4 + spec/features/admin/order_cycles_spec.rb | 102 ++++++++++-------- .../services/order_cycles_spec.js.coffee | 4 +- 5 files changed, 67 insertions(+), 48 deletions(-) diff --git a/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee b/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee index e1d6569ca45..e2ea5dfb4f8 100644 --- a/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee +++ b/app/assets/javascripts/admin/resources/services/order_cycles.js.coffee @@ -66,7 +66,7 @@ angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCy changes attrsToSave: -> - ['orders_open_at','orders_close_at'] + ['name', 'orders_open_at','orders_close_at'] resetAttribute: (order_cycle, attribute) -> order_cycle[attribute] = @pristineByID[order_cycle.id][attribute] diff --git a/app/views/admin/order_cycles/_row.html.haml b/app/views/admin/order_cycles/_row.html.haml index 40f40e5126d..86b9eb9102f 100644 --- a/app/views/admin/order_cycles/_row.html.haml +++ b/app/views/admin/order_cycles/_row.html.haml @@ -1,7 +1,6 @@ %tr{ class: "order-cycle-{{orderCycle.id}} {{orderCycle.status}}", ng: { repeat: 'orderCycle in orderCycles | schedule:scheduleFilter | involving:involvingFilter | filter:{name: query} track by orderCycle.id' } } %td.name{ ng: { show: 'columns.name.visible' } } - %a{ ng: { href: '{{orderCycle.edit_path}}' } } - {{ orderCycle.name }} + %input{ id: 'oc{{::orderCycle.id}}_name', name: 'oc{{::orderCycle.id}}[name]', type: 'text', ng: { model: 'orderCycle.name', disabled: '!orderCycle.viewing_as_coordinator' } } %td.schedules{ ng: { show: 'columns.schedules.visible' } } %span{ ng: { repeat: 'schedule in orderCycle.schedules'} } %a{ 'schedule-dialog' => true, 'schedule-id' => '{{schedule.id}}' } diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 853ae6a174d..9ec07d26303 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -220,6 +220,7 @@ module Admin let(:params) do { format: :json, order_cycle_set: { collection_attributes: { '0' => { id: oc.id, + name: "Updated Order Cycle", orders_open_at: Date.current - 21.days, orders_close_at: Date.current + 21.days, } } } } @@ -230,6 +231,7 @@ module Admin it "updates order cycle properties" do spree_put :bulk_update, params oc.reload + expect(oc.name).to eq "Updated Order Cycle" expect(oc.orders_open_at.to_date).to eq Date.current - 21.days expect(oc.orders_close_at.to_date).to eq Date.current + 21.days end @@ -262,11 +264,13 @@ module Admin it "doesn't update order cycle properties" do spree_put :bulk_update, format: :json, order_cycle_set: { collection_attributes: { '0' => { id: oc.id, + name: "Updated Order Cycle", orders_open_at: Date.current - 21.days, orders_close_at: Date.current + 21.days, } } } oc.reload + expect(oc.name).to_not eq "Updated Order Cycle" expect(oc.orders_open_at.to_date).to_not eq Date.current - 21.days expect(oc.orders_close_at.to_date).to_not eq Date.current + 21.days end diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index bfb6d4d30e9..acaab40a7aa 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -32,8 +32,9 @@ # Then the order cycles should be ordered correctly expect(page).to have_selector "#listing_order_cycles tr td:first-child", count: 7 - page.all('#listing_order_cycles tr td:first-child').map(&:text).should == - ['oc0', 'oc1', 'oc2', 'oc3', 'oc4', 'oc5', 'oc6'] + + order_cycle_names = ["oc0", "oc1", "oc2", "oc3", "oc4", "oc5", "oc6"] + expect(all("#listing_order_cycles tr td:first-child input").map(&:value)).to eq order_cycle_names # And the rows should have the correct classes page.should have_selector "#listing_order_cycles tr.order-cycle-#{oc0.id}.undated" @@ -52,11 +53,10 @@ # And I should see all the details for an order cycle within('table#listing_order_cycles tbody tr:nth-child(2)') do # Then I should see the basic fields - page.should have_selector 'a', text: oc1.name - - page.should have_input "oc#{oc1.id}[orders_open_at]", value: oc1.orders_open_at - page.should have_input "oc#{oc1.id}[orders_close_at]", value: oc1.orders_close_at - page.should have_content oc1.coordinator.name + expect(page).to have_input "oc#{oc1.id}[name]", value: oc1.name + expect(page).to have_input "oc#{oc1.id}[orders_open_at]", value: oc1.orders_open_at + expect(page).to have_input "oc#{oc1.id}[orders_close_at]", value: oc1.orders_close_at + expect(page).to have_content oc1.coordinator.name # And I should see the suppliers and distributors oc1.suppliers.each { |s| page.should have_content s.name } @@ -250,10 +250,10 @@ find("div#columns-dropdown div.menu div.menu_item", text: "Shops").click find("div#columns-dropdown", :text => "COLUMNS").click - page.should have_selector 'a', text: 'Plums & Avos' - page.should have_input "oc#{oc.id}[orders_open_at]", value: order_cycle_opening_time - page.should have_input "oc#{oc.id}[orders_close_at]", value: order_cycle_closing_time - page.should have_content 'My coordinator' + expect(page).to have_input "oc#{oc.id}[name]", value: "Plums & Avos" + expect(page).to have_input "oc#{oc.id}[orders_open_at]", value: order_cycle_opening_time + expect(page).to have_input "oc#{oc.id}[orders_close_at]", value: order_cycle_closing_time + expect(page).to have_content "My coordinator" page.should have_selector 'td.producers', text: 'My supplier' page.should have_selector 'td.shops', text: 'My distributor' @@ -306,8 +306,11 @@ # When I go to its edit page quick_login_as_admin visit admin_order_cycles_path - click_link oc.name - wait_until { page.find('#order_cycle_name').value.present? } + within "tr.order-cycle-#{oc.id}" do + find("a.edit-order-cycle").click + end + + wait_for_edit_form_to_load_order_cycle(oc) # And I update it fill_in 'order_cycle_name', with: 'Plums & Avos' @@ -390,10 +393,10 @@ find("div#columns-dropdown div.menu div.menu_item", text: "Shops").click find("div#columns-dropdown", :text => "COLUMNS").click - page.should have_selector 'a', text: 'Plums & Avos' - page.should have_input "oc#{oc.id}[orders_open_at]", value: order_cycle_opening_time - page.should have_input "oc#{oc.id}[orders_close_at]", value: order_cycle_closing_time - page.should have_content coordinator.name + expect(page).to have_input "oc#{oc.id}[name]", value: "Plums & Avos" + expect(page).to have_input "oc#{oc.id}[orders_open_at]", value: order_cycle_opening_time + expect(page).to have_input "oc#{oc.id}[orders_close_at]", value: order_cycle_closing_time + expect(page).to have_content coordinator.name page.should have_selector 'td.producers', text: 'My supplier' page.should have_selector 'td.shops', text: 'My distributor' @@ -431,7 +434,8 @@ # When I edit it quick_login_as_admin visit edit_admin_order_cycle_path(oc) - wait_until { page.find('#order_cycle_name').value.present? } + + wait_for_edit_form_to_load_order_cycle(oc) # Then I should see the basic settings page.find('#order_cycle_name').value.should == oc.name @@ -532,13 +536,15 @@ # And I fill in some new opening/closing times and save them within("tr.order-cycle-#{oc1.id}") do - all('input').first.set '2040-12-01 12:00:00' - all('input').last.set '2040-12-01 12:00:01' + find("input#oc#{oc1.id}_name").set "Updated Order Cycle 1" + find("input#oc#{oc1.id}_orders_open_at").set "2040-12-01 12:00:00" + find("input#oc#{oc1.id}_orders_close_at").set "2040-12-01 12:00:01" end within("tr.order-cycle-#{oc2.id}") do - all('input').first.set '2040-12-01 12:00:02' - all('input').last.set '2040-12-01 12:00:03' + find("input#oc#{oc2.id}_name").set "Updated Order Cycle 2" + find("input#oc#{oc2.id}_orders_open_at").set "2040-12-01 12:00:02" + find("input#oc#{oc2.id}_orders_close_at").set "2040-12-01 12:00:03" end # And I fill in a time using the datepicker @@ -560,19 +566,22 @@ within("tr.order-cycle-#{oc3.id}") do # Then that date/time should appear on the form - expect(all('input').first.value).to eq '2040-12-01 00:00:00' + expect(find("input#oc#{oc3.id}_orders_open_at").value).to eq "2040-12-01 00:00:00" # Manually fill out time - all('input').first.set '2040-12-01 12:00:04' - all('input').last.set '2040-12-01 12:00:05' + find("input#oc#{oc3.id}_name").set "Updated Order Cycle 3" + find("input#oc#{oc3.id}_orders_open_at").set "2040-12-01 12:00:04" + find("input#oc#{oc3.id}_orders_close_at").set "2040-12-01 12:00:05" end click_button 'Save Changes' - # Then my times should have been saved + # Then my details should have been saved expect(page).to have_selector "#save-bar", text: "Order cycles have been updated." - OrderCycle.order('id ASC').map { |oc| oc.orders_open_at.sec }.should == [0, 2, 4] - OrderCycle.order('id ASC').map { |oc| oc.orders_close_at.sec }.should == [1, 3, 5] + order_cycles = OrderCycle.order("id ASC") + expect(order_cycles.map(&:name)).to eq ["Updated Order Cycle 1", "Updated Order Cycle 2", "Updated Order Cycle 3"] + expect(order_cycles.map { |oc| oc.orders_open_at.sec }).to eq [0, 2, 4] + expect(order_cycles.map { |oc| oc.orders_close_at.sec }).to eq [1, 3, 5] end scenario "cloning an order cycle" do @@ -693,9 +702,8 @@ click_link "Order Cycles" # I should see only the order cycle I am coordinating - page.should have_content oc_user_coordinating.name - page.should_not have_content oc_for_other_user.name - + expect(page).to have_selector "tr.order-cycle-#{oc_user_coordinating.id}" + expect(page).to_not have_selector "tr.order-cycle-#{oc_for_other_user.id}" find("div#columns-dropdown", :text => "COLUMNS").click find("div#columns-dropdown div.menu div.menu_item", text: "Producers").click @@ -1037,9 +1045,9 @@ oc = OrderCycle.last - page.should have_selector 'a', text: 'Plums & Avos' - page.should have_input "oc#{oc.id}[orders_open_at]", value: Time.zone.local(2040, 10, 17, 06, 00, 00).strftime("%F %T %z") - page.should have_input "oc#{oc.id}[orders_close_at]", value: Time.zone.local(2040, 10, 24, 17, 00, 00).strftime("%F %T %z") + expect(page).to have_input "oc#{oc.id}[name]", value: "Plums & Avos" + expect(page).to have_input "oc#{oc.id}[orders_open_at]", value: Time.zone.local(2040, 10, 17, 06, 00, 00).strftime("%F %T %z") + expect(page).to have_input "oc#{oc.id}[orders_close_at]", value: Time.zone.local(2040, 10, 24, 17, 00, 00).strftime("%F %T %z") # And it should have some variants selected oc.exchanges.incoming.first.variants.count.should == 2 @@ -1064,8 +1072,11 @@ # When I edit it quick_login_as_admin visit admin_order_cycles_path - click_link oc.name - wait_until { page.find('#order_cycle_name').value.present? } + within "tr.order-cycle-#{oc.id}" do + find("a.edit-order-cycle").click + end + + wait_for_edit_form_to_load_order_cycle(oc) # Then I should see the basic settings page.should have_field 'order_cycle_name', with: oc.name @@ -1094,7 +1105,8 @@ # When I edit it quick_login_as_admin visit edit_admin_order_cycle_path oc - wait_until { page.find('#order_cycle_name').value.present? } + + wait_for_edit_form_to_load_order_cycle(oc) # And I fill in the basic fields fill_in 'order_cycle_name', with: 'Plums & Avos' @@ -1126,9 +1138,9 @@ page.should have_content 'Your order cycle has been updated.' oc = OrderCycle.last - page.should have_selector 'a', text: 'Plums & Avos' - page.should have_input "oc#{oc.id}[orders_open_at]", value: Time.zone.local(2040, 10, 17, 06, 00, 00).strftime("%F %T %z") - page.should have_input "oc#{oc.id}[orders_close_at]", value: Time.zone.local(2040, 10, 24, 17, 00, 00).strftime("%F %T %z") + expect(page).to have_input "oc#{oc.id}[name]", value: "Plums & Avos" + expect(page).to have_input "oc#{oc.id}[orders_open_at]", value: Time.zone.local(2040, 10, 17, 06, 00, 00).strftime("%F %T %z") + expect(page).to have_input "oc#{oc.id}[orders_close_at]", value: Time.zone.local(2040, 10, 24, 17, 00, 00).strftime("%F %T %z") # And it should have a variant selected oc.exchanges.incoming.first.variants.should == [v2] @@ -1145,17 +1157,21 @@ end scenario "deleting an order cycle" do - create(:simple_order_cycle, name: "Translusent Berries") + order_cycle = create(:simple_order_cycle, name: "Translusent Berries") quick_login_as_admin visit admin_order_cycles_path - page.should have_content("Translusent Berries") + expect(page).to have_selector "tr.order-cycle-#{order_cycle.id}" first('a.delete-order-cycle').click - page.should_not have_content("Translusent Berries") + expect(page).to_not have_selector "tr.order-cycle-#{order_cycle.id}" end private + def wait_for_edit_form_to_load_order_cycle(order_cycle) + expect(page).to have_field "order_cycle_name", with: order_cycle.name + end + def select_incoming_variant(supplier, exchange_no, variant) page.find("table.exchanges tr.supplier-#{supplier.id} td.products").click check "order_cycle_incoming_exchange_#{exchange_no}_variants_#{variant.id}" diff --git a/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee index f1b12ecd1d8..f3046ed648a 100644 --- a/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee +++ b/spec/javascripts/unit/admin/order_cycles/services/order_cycles_spec.js.coffee @@ -106,8 +106,8 @@ describe "OrderCycles service", -> OrderCycles.pristineByID = { 23: { id: 23, name: "orderCycle321", orders_open_at: '123' } } it "returns a list of properties that have been altered, if they are in attrsToSave()", -> - spyOn(OrderCycles, "attrsToSave").and.returnValue(["orders_open_at"]) - expect(OrderCycles.diff({ id: 23, name: "orderCycle123", orders_open_at: '321' })).toEqual ["orders_open_at"] + spyOn(OrderCycles, "attrsToSave").and.returnValue(["name", "orders_open_at"]) + expect(OrderCycles.diff({ id: 23, name: "orderCycle123", orders_open_at: '321' })).toEqual ["name", "orders_open_at"] describe "resetAttribute", -> From 28b1fc076ab87d0d275639dea9b37917ccb1f25a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 16 Aug 2018 14:29:50 +0100 Subject: [PATCH 060/122] Remove empty SKU values if empty --- app/models/product_import/spreadsheet_entry.rb | 5 +++++ spec/models/product_importer_spec.rb | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/models/product_import/spreadsheet_entry.rb b/app/models/product_import/spreadsheet_entry.rb index b32c96a8112..b8db4b44d75 100644 --- a/app/models/product_import/spreadsheet_entry.rb +++ b/app/models/product_import/spreadsheet_entry.rb @@ -14,6 +14,7 @@ class SpreadsheetEntry def initialize(attrs) @validates_as = '' + remove_empty_skus attrs assign_units attrs end @@ -57,6 +58,10 @@ def invalid_attributes private + def remove_empty_skus(attrs) + attrs.delete('sku') if attrs.key?('sku') && attrs['sku'].blank? + end + def assign_units(attrs) units = UnitConverter.new(attrs) diff --git a/spec/models/product_importer_spec.rb b/spec/models/product_importer_spec.rb index 4df09d328c0..b1fd165fa17 100644 --- a/spec/models/product_importer_spec.rb +++ b/spec/models/product_importer_spec.rb @@ -254,9 +254,9 @@ describe "updating various fields" do before do csv_data = CSV.generate do |csv| - csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type", "on_demand"] - csv << ["Beetroot", "And Another Enterprise", "Vegetables", "5", "3.50", "500", "g", "0"] - csv << ["Tomato", "And Another Enterprise", "Vegetables", "6", "5.50", "500", "g", "1"] + csv << ["name", "supplier", "category", "on_hand", "price", "units", "unit_type", "on_demand", "sku"] + csv << ["Beetroot", "And Another Enterprise", "Vegetables", "5", "3.50", "500", "g", "0", nil] + csv << ["Tomato", "And Another Enterprise", "Vegetables", "6", "5.50", "500", "g", "1", "TOMS"] end File.write('/tmp/test-m.csv', csv_data) file = File.new('/tmp/test-m.csv') From 7dccbb5213ff1c3ef9df91bdf28b77f4b0912ae3 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 17 Aug 2018 17:00:15 +1000 Subject: [PATCH 061/122] Enable embedded shopping spec It was disabled in https://github.com/openfoodfoundation/openfoodnetwork/pull/2232, because it was very unreliable. But it seems stable again since https://github.com/openfoodfoundation/openfoodnetwork/pull/2468. --- spec/features/consumer/shopping/embedded_shopfronts_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 2476bdabd9f..39a79aba2ea 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -43,7 +43,7 @@ end end - xit "allows shopping and checkout" do + it "allows shopping and checkout" do on_embedded_page do fill_in "variants[#{variant.id}]", with: 1 wait_until_enabled 'input.add_to_cart' From 56879377d53c0b5e8c543dae345cadb49004b9dd Mon Sep 17 00:00:00 2001 From: luisramos0 Date: Fri, 17 Aug 2018 21:19:49 +0100 Subject: [PATCH 062/122] Added httponly to cookieConsent cookie, this makes this cookie secure, cannot be altered by javascript --- app/services/cookies_consent.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/cookies_consent.rb b/app/services/cookies_consent.rb index 8b35fa74027..64c4dfa083a 100644 --- a/app/services/cookies_consent.rb +++ b/app/services/cookies_consent.rb @@ -18,7 +18,8 @@ def set cookies[COOKIE_NAME] = { value: COOKIE_NAME, expires: 1.year.from_now, - domain: domain + domain: domain, + httponly: true } end From fbbbc93aba9b96edd60e3e54560dabb87d89ac23 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 18 Aug 2018 11:28:54 +0100 Subject: [PATCH 063/122] Class descriptions for Product Import --- app/models/product_import/entry_processor.rb | 4 ++++ app/models/product_import/entry_validator.rb | 4 ++++ app/models/product_import/product_importer.rb | 7 +++++++ app/models/product_import/spreadsheet_data.rb | 7 +++++++ app/models/product_import/spreadsheet_entry.rb | 4 ++++ app/models/product_import/unit_converter.rb | 16 ++++++++++------ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/app/models/product_import/entry_processor.rb b/app/models/product_import/entry_processor.rb index a07b5273383..e71f24e868b 100644 --- a/app/models/product_import/entry_processor.rb +++ b/app/models/product_import/entry_processor.rb @@ -1,3 +1,7 @@ +# This class handles the saving of new product, variant, and inventory records created during +# product import. It also collates data regarding this process for user feedback, as the import +# is processed in small stages sequentially over a number of requests. + module ProductImport class EntryProcessor attr_reader :inventory_created, :inventory_updated, :products_created, :variants_created, :variants_updated, :products_reset_count, :supplier_products, :total_supplier_products diff --git a/app/models/product_import/entry_validator.rb b/app/models/product_import/entry_validator.rb index d3632911ad1..ea404092bd3 100644 --- a/app/models/product_import/entry_validator.rb +++ b/app/models/product_import/entry_validator.rb @@ -1,3 +1,7 @@ +# This class handles a number of custom validation processes that take place during product import, +# as a spreadsheet entry is checked to see if it is a valid product, variant, or inventory item. +# It also handles error messages and user feedback for the validation process. + module ProductImport class EntryValidator def initialize(current_user, import_time, spreadsheet_data, editable_enterprises, inventory_permissions, reset_counts, import_settings) diff --git a/app/models/product_import/product_importer.rb b/app/models/product_import/product_importer.rb index 6ec06957682..afc1aad9738 100644 --- a/app/models/product_import/product_importer.rb +++ b/app/models/product_import/product_importer.rb @@ -1,3 +1,10 @@ +# This is the main class for product import. It handles the initial processing of the CSV file, +# and begins the processing of the spreadsheet entries by the other product import classes. +# As spreadsheets can contain any number of entries (1000+), the import is split into smaller chunks +# of 100 items, and processed sequentially over a number of requests to avoid server timeouts. +# The various bits of collated information such as file upload status, per-item errors or user feedback +# on the saving process are made available to the controller through this object. + require 'roo' module ProductImport diff --git a/app/models/product_import/spreadsheet_data.rb b/app/models/product_import/spreadsheet_data.rb index 303cf1a93b3..3c956d6d2c9 100644 --- a/app/models/product_import/spreadsheet_data.rb +++ b/app/models/product_import/spreadsheet_data.rb @@ -1,3 +1,10 @@ +# This class encapsulates a number of "indexes" used during product import. These contain hashes +# of information that need to be accessed at various stages of the import, and are built in order +# to minimise the number of queries that take place. So for instance, if a spreadsheet has 4000 +# products for 5 different enterprises and we need to check the enterprise permissions for each +# product during validation, we have a small index for that data that gets built at the beginning +# so we don't have to make 4000 queries. + module ProductImport class SpreadsheetData def initialize(entries) diff --git a/app/models/product_import/spreadsheet_entry.rb b/app/models/product_import/spreadsheet_entry.rb index b32c96a8112..df043e0d1b1 100644 --- a/app/models/product_import/spreadsheet_entry.rb +++ b/app/models/product_import/spreadsheet_entry.rb @@ -1,3 +1,7 @@ +# Objects of this class represent a line from a spreadsheet that will be processed and used +# to create either product, variant, or inventory records. These objects are referred to as +# "entry" or "entries" throughout product import. + module ProductImport class SpreadsheetEntry extend ActiveModel::Naming diff --git a/app/models/product_import/unit_converter.rb b/app/models/product_import/unit_converter.rb index d7f9fdc3c07..fcc8d3686a1 100644 --- a/app/models/product_import/unit_converter.rb +++ b/app/models/product_import/unit_converter.rb @@ -1,3 +1,13 @@ +# This class handles conversion of human-readable unit weights for products/variants into +# the non-human-readable format needed by the database. The table below shows how fields +# from a spreadsheet (left) become database fields (right): +# +# units unit_type variant_unit_name -> unit_value variant_unit_scale variant_unit +# 250 ml nil -> 0.25 0.001 volume +# 50 g nil -> 50 1 weight +# 2 kg nil -> 2000 1000 weight +# 1 nil bunches -> 1 nil items + module ProductImport class UnitConverter def initialize(attrs) @@ -12,12 +22,6 @@ def converted_attributes private def convert_custom_unit_fields - # units unit_type variant_unit_name -> unit_value variant_unit_scale variant_unit - # 250 ml nil .... 0.25 0.001 volume - # 50 g nil .... 50 1 weight - # 2 kg nil .... 2000 1000 weight - # 1 nil bunches .... 1 null items - init_unit_values assign_weight_or_volume_attributes if units_and_unit_type_present? From 8272aebe29072820ed27f40fc30e0b64eaca730c Mon Sep 17 00:00:00 2001 From: stveep Date: Sun, 17 Jun 2018 18:15:41 +0100 Subject: [PATCH 064/122] Add Stripe form and duplicate Stripe Elements in backend Angular app --- .../payments/controllers/payment.js.coffee | 9 ++++ .../directives/stripe_elements.js.coffee | 35 ++++++++++++++ .../admin/payments/payments.js.coffee | 1 + .../admin/payments/services/payment.js.coffee | 47 +++++++++++++++++++ .../services/stripe_elements.js.coffee | 47 +++++++++++++++++++ .../resources/payment_resource.js.coffee | 5 ++ .../new/add_angular_to_form.html.erb.deface | 4 ++ ...verride_submit_for_button.html.haml.deface | 2 + app/views/spree/admin/payments/_form.html.erb | 4 +- .../payments/source_forms/_stripe.html.haml | 16 ++++++- 10 files changed, 166 insertions(+), 4 deletions(-) create mode 100644 app/assets/javascripts/admin/payments/controllers/payment.js.coffee create mode 100644 app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee create mode 100644 app/assets/javascripts/admin/payments/payments.js.coffee create mode 100644 app/assets/javascripts/admin/payments/services/payment.js.coffee create mode 100644 app/assets/javascripts/admin/payments/services/stripe_elements.js.coffee create mode 100644 app/assets/javascripts/admin/resources/resources/payment_resource.js.coffee create mode 100644 app/overrides/spree/admin/payments/new/add_angular_to_form.html.erb.deface create mode 100644 app/overrides/spree/admin/payments/new/override_submit_for_button.html.haml.deface diff --git a/app/assets/javascripts/admin/payments/controllers/payment.js.coffee b/app/assets/javascripts/admin/payments/controllers/payment.js.coffee new file mode 100644 index 00000000000..e69ef1190db --- /dev/null +++ b/app/assets/javascripts/admin/payments/controllers/payment.js.coffee @@ -0,0 +1,9 @@ +angular.module("admin.payments").controller "PaymentCtrl", ($scope, Payment, Loading) -> + $scope.form_data = Payment.form_data + $scope.submitted = false + + $scope.submitPayment = () -> + return false if $scope.submitted == true + $scope.submitted = true + Loading.message = t("submitting_payment") + Payment.purchase() diff --git a/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee b/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee new file mode 100644 index 00000000000..418402b3c49 --- /dev/null +++ b/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee @@ -0,0 +1,35 @@ +angular.module("admin.payments").directive "stripeElements", ($injector, StripeElements) -> + restrict: 'E' + template: "" + + link: (scope, elem, attr)-> + if $injector.has('stripeObject') + stripe = $injector.get('stripeObject') + + card = stripe.elements().create 'card', + hidePostalCode: false + style: + base: + fontFamily: "Roboto, Arial, sans-serif" + fontSize: '16px' + color: '#5c5c5c' + '::placeholder': + color: '#6c6c6c' + card.mount('#card-element') + + # Elements validates user input as it is typed. To help your customers + # catch mistakes, you should listen to change events on the card Element + # and display any errors: + card.addEventListener 'change', (event) -> + displayError = document.getElementById('card-errors') + if event.error + displayError.textContent = event.error.message + else + displayError.textContent = '' + return + + StripeElements.stripe = stripe + StripeElements.card = card diff --git a/app/assets/javascripts/admin/payments/payments.js.coffee b/app/assets/javascripts/admin/payments/payments.js.coffee new file mode 100644 index 00000000000..16b943f05f7 --- /dev/null +++ b/app/assets/javascripts/admin/payments/payments.js.coffee @@ -0,0 +1 @@ +angular.module("admin.payments", ['OfnStripe','Loading','RailsFlashLoader','ngResource','admin.resources', 'ofn.admin','Navigation']) diff --git a/app/assets/javascripts/admin/payments/services/payment.js.coffee b/app/assets/javascripts/admin/payments/services/payment.js.coffee new file mode 100644 index 00000000000..167fade9bfd --- /dev/null +++ b/app/assets/javascripts/admin/payments/services/payment.js.coffee @@ -0,0 +1,47 @@ +angular.module('admin.payments').factory 'Payment', (StripeElements, currentOrderNumber, paymentMethods, PaymentMethods, PaymentResource, Navigation, RailsFlashLoader)-> + new class Payment + order: currentOrderNumber + form_data: {} + + paymentMethodType: -> + PaymentMethods.byID[@form_data.payment_method].method_type + + preprocess: -> + munged_payment = {} + munged_payment["payment"] = {payment_method_id: @form_data.payment_method, amount: @form_data.amount} + munged_payment["order_id"] = @order + # Not tested with Gateway other than Stripe. Could fall back to Rails for this? + # Works ok without extra source_attrs for Cash, Bank Transfer etc. + switch @paymentMethodType() + when 'gateway' + angular.extend munged_payment.payment, { + source_attributes: + number: @form_data.card_number + month: @form_data.card_month + year: @form_data.card_year + verification_value: @form_data.card_verification_value + } + when 'stripe' + angular.extend munged_payment.payment, { + source_attributes: + gateway_payment_profile_id: @form_data.token + cc_type: @form_data.cc_type + last_digits: @form_data.card.last4 + month: @form_data.card.exp_month + year: @form_data.card.exp_year + } + munged_payment + + purchase: -> + if @paymentMethodType() == 'stripe' + StripeElements.requestToken(@form_data, @submit) + else + @submit() + + submit: => + munged = @preprocess() + PaymentResource.create({order_id: munged.order_id}, munged, (response, headers, status)=> + Navigation.go "/admin/orders/" + munged.order_id + "/payments" + , (response) -> + RailsFlashLoader.loadFlash({error: t("error saving payment")}) + ) diff --git a/app/assets/javascripts/admin/payments/services/stripe_elements.js.coffee b/app/assets/javascripts/admin/payments/services/stripe_elements.js.coffee new file mode 100644 index 00000000000..23c9a48e56b --- /dev/null +++ b/app/assets/javascripts/admin/payments/services/stripe_elements.js.coffee @@ -0,0 +1,47 @@ +angular.module("admin.payments").factory 'StripeElements', ($rootScope, Loading, RailsFlashLoader) -> + new class StripeElements + # TODO: add locale here for translations of error messages etc. from Stripe + + # These are both set from the StripeElements directive + stripe: null + card: null + + # New Stripe Elements method + requestToken: (secrets, submit, loading_message = t("processing_payment")) -> + return unless @stripe? && @card? + + Loading.message = loading_message + cardData = @makeCardData(secrets) + + @stripe.createToken(@card, cardData).then (response) => + if(response.error) + Loading.clear() + RailsFlashLoader.loadFlash({error: t("error") + ": #{response.error.message}"}) + else + secrets.token = response.token.id + secrets.cc_type = @mapCC(response.token.card.brand) + secrets.card = response.token.card + submit() + + # Maps the brand returned by Stripe to that required by activemerchant + mapCC: (ccType) -> + if ccType == 'MasterCard' + return 'master' + else if ccType == 'Visa' + return 'visa' + else if ccType == 'American Express' + return 'american_express' + else if ccType == 'Discover' + return 'discover' + else if ccType == 'JCB' + return 'jcb' + else if ccType == 'Diners Club' + return 'diners_club' + return + + # It doesn't matter if any of these are nil, all are optional. + makeCardData: (secrets) -> + {'name': secrets.name, + 'address1': secrets.address1, + 'city': secrets.city, + 'zipcode': secrets.zipcode} diff --git a/app/assets/javascripts/admin/resources/resources/payment_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/payment_resource.js.coffee new file mode 100644 index 00000000000..c3dba12b646 --- /dev/null +++ b/app/assets/javascripts/admin/resources/resources/payment_resource.js.coffee @@ -0,0 +1,5 @@ +angular.module("admin.resources").factory 'PaymentResource', ($resource) -> + $resource('/admin/orders/:order_id/payments.json', {order_id: "@order_id"}, { + 'create': + method: 'POST' + }) diff --git a/app/overrides/spree/admin/payments/new/add_angular_to_form.html.erb.deface b/app/overrides/spree/admin/payments/new/add_angular_to_form.html.erb.deface new file mode 100644 index 00000000000..6ace1ee579a --- /dev/null +++ b/app/overrides/spree/admin/payments/new/add_angular_to_form.html.erb.deface @@ -0,0 +1,4 @@ + +<%= form_for @payment, :url => admin_order_payments_path(@order), + :html => {"ng-app" => "admin.payments", + "ng-controller" => "PaymentCtrl"} do |f| %> diff --git a/app/overrides/spree/admin/payments/new/override_submit_for_button.html.haml.deface b/app/overrides/spree/admin/payments/new/override_submit_for_button.html.haml.deface new file mode 100644 index 00000000000..4fb4d91ad53 --- /dev/null +++ b/app/overrides/spree/admin/payments/new/override_submit_for_button.html.haml.deface @@ -0,0 +1,2 @@ +/replace 'code[erb-loud]:contains("button @order.cart?")' += button_tag t(:update), type: 'button', "ng-click" => "submitPayment()" diff --git a/app/views/spree/admin/payments/_form.html.erb b/app/views/spree/admin/payments/_form.html.erb index fe019007b18..4b7d576db53 100644 --- a/app/views/spree/admin/payments/_form.html.erb +++ b/app/views/spree/admin/payments/_form.html.erb @@ -2,7 +2,7 @@
<%= f.label :amount, t(:amount) %> - <%= f.text_field :amount, :value => @order.outstanding_balance, :class => 'fullwidth' %> + <%= f.text_field :amount, :value => @order.outstanding_balance, :class => 'fullwidth', "watch-value-as" => 'form_data.amount', "ng-init" => "form_data.amount=#{@order.outstanding_balance}" %>
@@ -12,7 +12,7 @@ <% @payment_methods.each do |method| %>
  • diff --git a/app/views/spree/admin/payments/source_forms/_stripe.html.haml b/app/views/spree/admin/payments/source_forms/_stripe.html.haml index 24bde74a312..99e16aafb21 100644 --- a/app/views/spree/admin/payments/source_forms/_stripe.html.haml +++ b/app/views/spree/admin/payments/source_forms/_stripe.html.haml @@ -1,4 +1,16 @@ -# = render "spree/admin/payments/source_forms/gateway", payment_method: payment_method +.stripe + %script{:src => "https://js.stripe.com/v3/", :type => "text/javascript"} + - if Stripe.publishable_key + :javascript + angular.module('admin.payments').value("stripeObject", Stripe("#{Stripe.publishable_key}")) -%strong - = t('.no_payment_via_admin_backend') + = admin_inject_json "admin.payments", "railsFlash", "flash" + = admin_inject_json "admin.payments", "currentOrderNumber", @order.number + = admin_inject_json_ams_array "admin.payments", "paymentMethods", @payment_methods, Api::PaymentMethodSerializer + .row + .three.columns + = label_tag :cardholder_name, t(:cardholder_name) + .six.columns + = text_field_tag :cardholder_name, nil, {size: 40, "ng-model" => 'form_data.name'} + %stripe-elements From a848b9172ecd4f35d9ca80e0bb2017b464a48842 Mon Sep 17 00:00:00 2001 From: stveep Date: Sun, 17 Jun 2018 20:38:48 +0100 Subject: [PATCH 065/122] Change name to AdminStripeElements to avoid confusion; add status bar for StatusMessages --- .../admin/payments/controllers/payment.js.coffee | 5 +++-- .../payments/directives/stripe_elements.js.coffee | 6 +++--- .../javascripts/admin/payments/payments.js.coffee | 2 +- .../admin/payments/services/payment.js.coffee | 8 ++++---- .../payments/services/stripe_elements.js.coffee | 13 +++++-------- .../payments/new/add_save_bar.html.haml.deface | 3 +++ 6 files changed, 19 insertions(+), 18 deletions(-) create mode 100644 app/overrides/spree/admin/payments/new/add_save_bar.html.haml.deface diff --git a/app/assets/javascripts/admin/payments/controllers/payment.js.coffee b/app/assets/javascripts/admin/payments/controllers/payment.js.coffee index e69ef1190db..6c763b778c1 100644 --- a/app/assets/javascripts/admin/payments/controllers/payment.js.coffee +++ b/app/assets/javascripts/admin/payments/controllers/payment.js.coffee @@ -1,9 +1,10 @@ -angular.module("admin.payments").controller "PaymentCtrl", ($scope, Payment, Loading) -> +angular.module("admin.payments").controller "PaymentCtrl", ($scope, Payment, StatusMessage) -> $scope.form_data = Payment.form_data $scope.submitted = false + $scope.StatusMessage = StatusMessage $scope.submitPayment = () -> return false if $scope.submitted == true $scope.submitted = true - Loading.message = t("submitting_payment") + StatusMessage.display 'progress', t("submitting_payment") Payment.purchase() diff --git a/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee b/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee index 418402b3c49..b478a3f9704 100644 --- a/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee +++ b/app/assets/javascripts/admin/payments/directives/stripe_elements.js.coffee @@ -1,4 +1,4 @@ -angular.module("admin.payments").directive "stripeElements", ($injector, StripeElements) -> +angular.module('admin.payments').directive "stripeElements", ($injector, AdminStripeElements) -> restrict: 'E' template: "