diff --git a/Gemfile b/Gemfile index 187c525b32..aaefa0a822 100644 --- a/Gemfile +++ b/Gemfile @@ -21,6 +21,7 @@ if ENV['DEPENDENCIES_NEXT'] gem 'responders' gem 'sass', '<= 4.7.1' gem 'sass-rails', '< 6.0.0' + gem 'libv8', '< 8' else gem 'rails', '~> 4.2' @@ -34,6 +35,10 @@ else gem 'db2fog' gem 'unicorn' + + group :test do + gem 'test_after_commit' # needed to test Devise callbacks + end end gem 'i18n' @@ -160,7 +165,6 @@ end group :test do gem 'simplecov', require: false gem 'test-prof' - gem 'test_after_commit' # needed to test Devise callbacks gem 'webmock' # See spec/spec_helper.rb for instructions # gem 'perftools.rb' diff --git a/Gemfile.lock b/Gemfile.lock index f67e3394f1..8157f8ec0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -166,7 +166,7 @@ GEM compass (~> 1.0.0) sass-rails (< 5.1) sprockets (< 4.0) - concurrent-ruby (1.1.7) + concurrent-ruby (1.1.8) crack (0.4.5) rexml crass (1.0.6) @@ -179,7 +179,7 @@ GEM activerecord (>= 3.2.0, < 5.0) fog (~> 1.0) rails (>= 3.2.0, < 5.0) - ddtrace (0.44.0) + ddtrace (0.45.0) msgpack debugger-linecache (1.2.0) delayed_job (4.1.9) @@ -438,7 +438,7 @@ GEM letter_opener (1.7.0) launchy (~> 2.2) libv8 (7.3.492.27.1) - loofah (2.8.0) + loofah (2.9.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) mail (2.7.1) @@ -456,7 +456,7 @@ GEM money (~> 6.12) money (6.14.0) i18n (>= 0.6.4, <= 2) - msgpack (1.3.3) + msgpack (1.4.1) multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) @@ -598,17 +598,17 @@ GEM rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.10.1) - rswag (2.3.1) - rswag-api (= 2.3.1) - rswag-specs (= 2.3.1) - rswag-ui (= 2.3.1) - rswag-api (2.3.1) + rswag (2.3.2) + rswag-api (= 2.3.2) + rswag-specs (= 2.3.2) + rswag-ui (= 2.3.2) + rswag-api (2.3.2) railties (>= 3.1, < 7.0) - rswag-specs (2.3.1) + rswag-specs (2.3.2) activesupport (>= 3.1, < 7.0) json-schema (~> 2.2) railties (>= 3.1, < 7.0) - rswag-ui (2.3.1) + rswag-ui (2.3.2) actionpack (>= 3.1, < 7.0) railties (>= 3.1, < 7.0) rubocop (1.8.1) @@ -642,7 +642,7 @@ GEM selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) - shoulda-matchers (4.5.0) + shoulda-matchers (4.5.1) activesupport (>= 4.2.0) simplecov (0.18.5) docile (~> 1.1) diff --git a/Gemfile_next.lock b/Gemfile_next.lock index 437a99d5e7..70dbeba73b 100644 --- a/Gemfile_next.lock +++ b/Gemfile_next.lock @@ -270,7 +270,7 @@ GEM addressable (~> 2.3) letter_opener (1.7.0) launchy (~> 2.2) - libv8 (8.4.255.0) + libv8 (7.3.492.27.1) loofah (2.7.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) @@ -502,8 +502,6 @@ GEM test-prof (0.7.5) test-unit (3.3.7) power_assert - test_after_commit (1.1.0) - activerecord (>= 3.2) thor (0.20.3) thread_safe (0.3.6) tilt (2.0.10) @@ -608,6 +606,7 @@ DEPENDENCIES kaminari (~> 1.2.1) knapsack letter_opener (>= 1.4.1) + libv8 (< 8) mini_racer (= 0.2.15) monetize (~> 1.1) oauth2 (~> 1.4.4) @@ -649,7 +648,6 @@ DEPENDENCIES stripe test-prof test-unit (~> 3.3) - test_after_commit timecop uglifier (>= 1.0.3) unicorn-rails diff --git a/app/assets/javascripts/admin/all.js b/app/assets/javascripts/admin/all.js index d328a39148..dea5ac04a9 100644 --- a/app/assets/javascripts/admin/all.js +++ b/app/assets/javascripts/admin/all.js @@ -15,8 +15,6 @@ //= require jquery.cookie //= require jquery.jstree/jquery.jstree //= require jquery.vAlign -//= require jquery.horizontalNav -//= require jquery.adaptivemenu //= require angular //= require angular-resource //= require angular-animate diff --git a/app/assets/javascripts/admin/spree/base.js.erb b/app/assets/javascripts/admin/spree/base.js.erb index 5c28559002..4b9bf8216f 100644 --- a/app/assets/javascripts/admin/spree/base.js.erb +++ b/app/assets/javascripts/admin/spree/base.js.erb @@ -8,27 +8,10 @@ Hopefully, this will evolve into a propper class. **/ jQuery(function($) { - // Make main menu use full width - mainMenu = $('.fullwidth-menu') - if (typeof mainMenu.horizontalNav === 'function' ) - mainMenu.horizontalNav({ - tableDisplay: false, - responsiveDelay: 0 - }); - // Vertical align of checkbox fields if (typeof $('.field.checkbox label').vAlign === 'function' ) $('.field.checkbox label').vAlign() - // We activate AdaptiveMenu only if not on webdriver - // Re-adjusting the admin menu during tests causes tests to fail. - if (!navigator.webdriver && typeof Spree !== 'undefined') { - $('.main-menu-wrapper ul').AdaptiveMenu({ - text: " " + Spree.translations.more + "", - klass: "dropdown" - }); - } - // Add some tips if (typeof $('.with-tip').powerTip === 'function' ) { $('.with-tip').powerTip({ diff --git a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb index 0bc4ba3f92..060b212da7 100644 --- a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb +++ b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb @@ -45,7 +45,7 @@ $(document).ready(function() { if (quantity > maxQuantity) { quantity = maxQuantity; save.parents('tr').find('input.line_item_quantity').val(maxQuantity); - alert('<%= I18n.t("js.admin.orders.quantity_adjusted") %>'); + alert(t("js.admin.orders.quantity_adjusted")); } toggleItemEdit(); @@ -84,7 +84,7 @@ adjustItems = function(shipment_number, variant_id, quantity){ url += '.json'; if (new_quantity == 0) { - alert('<%= I18n.t("js.admin.orders.quantity_unchanged") %>'); + alert(t("js.admin.orders.quantity_unchanged")); } else { $.ajax({ type: "PUT", diff --git a/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee index adc25f4ad7..825bc9f39f 100644 --- a/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee +++ b/app/assets/javascripts/darkswarm/controllers/shop_variant_controller.js.coffee @@ -6,28 +6,62 @@ Darkswarm.controller "ShopVariantCtrl", ($scope, $modal, Cart) -> return if old_value[0] == null && new_value[0] == null Cart.adjust($scope.variant.line_item) - $scope.add = (quantity) -> + $scope.variant.line_item.quantity ||= 0 + + $scope.$watch "variant.line_item.quantity", -> item = $scope.variant.line_item - item.quantity += quantity - if $scope.variant.product.group_buy + if item.quantity > $scope.available() + item.quantity = $scope.available() + + $scope.$watch "variant.line_item.max_quantity", -> + item = $scope.variant.line_item + if item.max_quantity > $scope.available() + item.max_quantity = $scope.available() + + if $scope.variant.product.group_buy + $scope.$watch "variant.line_item.quantity", -> + item = $scope.variant.line_item if item.quantity < 1 || item.max_quantity < item.quantity item.max_quantity = item.quantity + $scope.$watch "variant.line_item.max_quantity", -> + item = $scope.variant.line_item + if item.max_quantity < item.quantity + item.quantity = item.max_quantity + + $scope.quantity = -> + $scope.variant.line_item.quantity || 0 + + $scope.maxQuantity = -> + $scope.variant.line_item.max_quantity || $scope.sanitizedQuantity() + + $scope.sanitizedQuantity = -> + Math.max(0, Math.min($scope.quantity(), $scope.available())) + + $scope.sanitizedMaxQuantity = -> + Math.max($scope.sanitizedQuantity(), Math.min($scope.maxQuantity(), $scope.available())) + + $scope.add = (quantity) -> + item = $scope.variant.line_item + item.quantity = $scope.sanitizedQuantity() + quantity + $scope.addMax = (quantity) -> item = $scope.variant.line_item - item.max_quantity += quantity - if item.max_quantity < item.quantity - item.quantity = item.max_quantity + item.max_quantity = $scope.sanitizedMaxQuantity() + quantity $scope.canAdd = (quantity) -> - wantedQuantity = $scope.variant.line_item.quantity + quantity + wantedQuantity = $scope.sanitizedQuantity() + quantity $scope.quantityValid(wantedQuantity) $scope.canAddMax = (quantity) -> variant = $scope.variant - wantedQuantity = variant.line_item.max_quantity + quantity + wantedQuantity = $scope.sanitizedMaxQuantity() + quantity $scope.quantityValid(wantedQuantity) && variant.line_item.quantity > 0 + $scope.available = -> + variant = $scope.variant + variant.on_demand && Infinity || variant.on_hand + $scope.quantityValid = (quantity) -> variant = $scope.variant minimum = 0 diff --git a/app/assets/javascripts/darkswarm/directives/tabset_ctrl.js.coffee b/app/assets/javascripts/darkswarm/directives/tabset_ctrl.js.coffee index dd8d9a279b..4587a7cca4 100644 --- a/app/assets/javascripts/darkswarm/directives/tabset_ctrl.js.coffee +++ b/app/assets/javascripts/darkswarm/directives/tabset_ctrl.js.coffee @@ -1,4 +1,4 @@ -Darkswarm.directive "tabsetCtrl", (Tabsets, $location) -> +Darkswarm.directive "tabsetCtrl", (Tabsets, $location, $rootScope) -> restrict: "C" scope: id: "@" @@ -9,7 +9,13 @@ Darkswarm.directive "tabsetCtrl", (Tabsets, $location) -> if $scope.navigate path = $location.path()?.match(/^\/\w+$/)?[0] $scope.selected = path[1..] if path - + + # Watch location change success event to operate back/forward buttons + $rootScope.$on "$locationChangeSuccess", -> + if $scope.navigate + path = $location.path()?.match(/^\/\w+$/)?[0] + Tabsets.toggle($scope.id, path[1..] if path) + this.toggle = (name) -> Tabsets.toggle($scope.id, name) diff --git a/app/assets/javascripts/darkswarm/services/variants.js.coffee b/app/assets/javascripts/darkswarm/services/variants.js.coffee index f5ba1af757..bcca5be825 100644 --- a/app/assets/javascripts/darkswarm/services/variants.js.coffee +++ b/app/assets/javascripts/darkswarm/services/variants.js.coffee @@ -23,5 +23,5 @@ Darkswarm.factory 'Variants', -> lineItemFor: (variant) -> variant: variant - quantity: null - max_quantity: null + quantity: 0 + max_quantity: 0 diff --git a/app/assets/javascripts/templates/bulk_buy_modal.html.haml b/app/assets/javascripts/templates/bulk_buy_modal.html.haml index 9625c1bd8f..5e26551419 100644 --- a/app/assets/javascripts/templates/bulk_buy_modal.html.haml +++ b/app/assets/javascripts/templates/bulk_buy_modal.html.haml @@ -9,27 +9,33 @@ {{ variant.line_item.total_price | localizeCurrency }} .row - .columns.small-6 + .columns.small-12.medium-6 .variant-bulk-buy-quantity-label {{ "js.shopfront.bulk_buy_modal.min_quantity" | t }} %div %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "add(-1)", disabled: "!canAdd(-1)"}}> -# U+FF0D Fullwidth Hyphen-Minus - - %span.bulk-buy.variant-quantity> - {{ variant.line_item.quantity }} + %input.bulk-buy.variant-quantity{ + type: "number", + min: "0", + max: "{{ available() }}", + ng: {model: "variant.line_item.quantity", max: "Infinity"}}> %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}} -# U+FF0B Fullwidth Plus Sign + - .columns.small-6 + .columns.small-12.medium-6 .variant-bulk-buy-quantity-label {{ "js.shopfront.bulk_buy_modal.max_quantity" | t }} %div %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "addMax(-1)", disabled: "!canAddMax(-1)"}}> -# U+FF0D Fullwidth Hyphen-Minus - - %span.bulk-buy.variant-quantity> - {{ variant.line_item.max_quantity }} + %input.bulk-buy.variant-quantity{ + type: "number", + min: "0", + max: "{{ available() }}", + ng: {model: "variant.line_item.max_quantity", max: "Infinity"}}> %button.bulk-buy-add.variant-quantity{type: "button", ng: {click: "addMax(1)", disabled: "!canAddMax(1)"}} -# U+FF0B Fullwidth Plus Sign + diff --git a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml index 0d6563bc2a..ad8abdf747 100644 --- a/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml +++ b/app/assets/javascripts/templates/partials/shop_variant_no_group_buy.html.haml @@ -1,14 +1,22 @@ -.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::!variant.product.group_buy"} +.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::!variant.product.group_buy"} - %button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "add(1)", disabled: "!canAdd(1)"}} - {{ "js.shopfront.variant.add_to_cart" | t }} - %button.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "add(-1)"}}> - -# U+FF0D Fullwidth Hyphen-Minus - - - %button.variant-quantity{type: "button", ng: {if: "variant.line_item.quantity", click: "add(1)", disabled: "!canAdd(1)"}} - -# U+FF0B Fullwidth Plus Sign - + - %br + .variant-quantity-inputs{ng: {if: "variant.line_item.quantity == 0"}} + %button.add-variant{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}} + {{ "js.shopfront.variant.add_to_cart" | t }} + + .variant-quantity-inputs{ng: {if: "variant.line_item.quantity != 0"}} + %button.variant-quantity{type: "button", ng: {click: "add(-1)", disabled: "!canAdd(-1)"}}> + -# U+FF0D Fullwidth Hyphen-Minus + - + %input.variant-quantity{ + type: "number", + min: "0", + max: "{{ available() }}", + ng: {model: "variant.line_item.quantity", max: "Infinity"} + }> + %button.variant-quantity{type: "button", ng: {click: "add(1)", disabled: "!canAdd(1)"}} + -# U+FF0B Fullwidth Plus Sign + + .variant-quantity-display{ng: {class: "{visible: variant.line_item.quantity}"}} {{ "js.shopfront.variant.quantity_in_cart" | t:{quantity: variant.line_item.quantity || 0} }} %input{type: :hidden, diff --git a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml index 18f46e5490..262ec20e3e 100644 --- a/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml +++ b/app/assets/javascripts/templates/partials/shop_variant_with_group_buy.html.haml @@ -1,4 +1,4 @@ -.small-5.medium-3.large-3.columns.text-right{"ng-if" => "::variant.product.group_buy"} +.small-5.medium-3.large-3.columns.variant-quantity-column.text-right{"ng-if" => "::variant.product.group_buy"} %button.add-variant{type: "button", ng: {if: "!variant.line_item.quantity", click: "addBulk(1)", disabled: "!canAdd(1)"}} {{ "js.shopfront.variant.add_to_cart" | t }} diff --git a/app/assets/javascripts/templates/shop_variant.html.haml b/app/assets/javascripts/templates/shop_variant.html.haml index 1435f33399..f5906ee59c 100644 --- a/app/assets/javascripts/templates/shop_variant.html.haml +++ b/app/assets/javascripts/templates/shop_variant.html.haml @@ -1,5 +1,5 @@ .variants.row - .small-4.medium-4.large-6.columns.variant-name + .small-4.medium-4.large-5.columns.variant-name .inline{"ng-if" => "::variant.display_name"} {{ ::variant.display_name }} .variant-unit {{ ::variant.unit_to_display }} .small-3.medium-3.large-2.columns.variant-price @@ -8,7 +8,7 @@ "price-breakdown-placement" => "bottom", "price-breakdown-animation" => true} {{ variant.price_with_fees | localizeCurrency }} - .medium-2.large-1.columns.total-price + .medium-2.large-2.columns.total-price %span{"ng-class" => "{filled: variant.line_item.total_price}"} {{ variant.line_item.total_price | localizeCurrency }} diff --git a/app/assets/stylesheets/admin/all.scss b/app/assets/stylesheets/admin/all.scss index 65d555e561..9784acf9c1 100644 --- a/app/assets/stylesheets/admin/all.scss +++ b/app/assets/stylesheets/admin/all.scss @@ -5,7 +5,6 @@ * *= require normalize - *= require skeleton *= require responsive-tables *= require jquery.powertip *= require jquery.ui.datepicker diff --git a/app/assets/stylesheets/admin/components/navigation.scss b/app/assets/stylesheets/admin/components/navigation.scss index c90f4b736a..4616cc3b4c 100644 --- a/app/assets/stylesheets/admin/components/navigation.scss +++ b/app/assets/stylesheets/admin/components/navigation.scss @@ -65,12 +65,17 @@ nav.menu { #admin-menu { background-color: $color-3; + ul { + display: flex; + } + li { min-width: 90px; + flex-grow: 1; a { display: block; - padding: 25px 20px; + padding: 25px 5px; color: $color-1 !important; text-transform: uppercase; position: relative; @@ -160,3 +165,11 @@ nav.menu { } } } + +#header figure { + margin: 0.25em 0; +} + +#login-nav { + line-height: 1.75em; +} diff --git a/app/assets/stylesheets/admin/dashboard_item.scss b/app/assets/stylesheets/admin/dashboard_item.scss index 5cc670a238..38d3e81786 100644 --- a/app/assets/stylesheets/admin/dashboard_item.scss +++ b/app/assets/stylesheets/admin/dashboard_item.scss @@ -66,7 +66,6 @@ div.dashboard_item { a { border-radius: 0px 4px 0px 0px; - margin-left: 8px; height: 100%; padding: 15px 2px 0px 2px; } diff --git a/app/assets/stylesheets/admin/grid.scss b/app/assets/stylesheets/admin/grid.scss new file mode 100644 index 0000000000..b47efe48a0 --- /dev/null +++ b/app/assets/stylesheets/admin/grid.scss @@ -0,0 +1,134 @@ +// Grid Calculations +// Adjust $col-gutter (space between columns, as percentage) to adjust everything else automatically + +$col-gutter: 2; +$total-gutter: $col-gutter * 15; +$total-colspace: 100 - $total-gutter; +$gutter-width: $col-gutter / 100; +$col-width: ($total-colspace / 16) / 100; + +$col-1: $col-width; +$col-2: ($col-width * 2) + $gutter-width; +$col-3: ($col-width * 3) + ($gutter-width * 2); +$col-4: ($col-width * 4) + ($gutter-width * 3); +$col-5: ($col-width * 5) + ($gutter-width * 4); +$col-6: ($col-width * 6) + ($gutter-width * 5); +$col-7: ($col-width * 7) + ($gutter-width * 6); +$col-8: ($col-width * 8) + ($gutter-width * 7); +$col-9: ($col-width * 9) + ($gutter-width * 8); +$col-10: ($col-width * 10) + ($gutter-width * 9); +$col-11: ($col-width * 11) + ($gutter-width * 10); +$col-12: ($col-width * 12) + ($gutter-width * 11); +$col-13: ($col-width * 13) + ($gutter-width * 12); +$col-14: ($col-width * 14) + ($gutter-width * 13); +$col-15: ($col-width * 15) + ($gutter-width * 14); +$col-16: 100; + +// Grid Classes + +.container { + position: relative; + width: 100%; + margin: 0 auto; + padding: 0 1.5%; + box-sizing: border-box; + display: flex; + max-width: 1400px; + + &.no-gutter { + padding: 0; + } + + .row { + width: 100%; + margin-bottom: 1.5em; + } +} + +.container::after, +.row::after, +.clearfix::after, +.clear::after { + content: ""; + display: table; + clear: both; +} + +.column, +.columns { + margin-left: percentage($gutter-width); + float: left; + box-sizing: border-box; +} + +.column.one, +.columns.one { width: percentage($col-1); } + +.columns.two { width: percentage($col-2); } + +.columns.three { width: percentage($col-3); } + +.columns.four { width: percentage($col-4); } + +.columns.five { width: percentage($col-5); } + +.columns.six { width: percentage($col-6); } + +.columns.seven { width: percentage($col-7); } + +.columns.eight { width: percentage($col-8); } + +.columns.nine { width: percentage($col-9); } + +.columns.ten { width: percentage($col-10); } + +.columns.eleven { width: percentage($col-11); } + +.columns.twelve { width: percentage($col-12); } + +.columns.thirteen { width: percentage($col-13); } + +.columns.fourteen { width: percentage($col-14);} + +.columns.fifteen { width: percentage($col-15); } + +.columns.sixteen { width: 100%; } + +.column.offset-by-one, +.columns.offset-by-one { margin-left: $col-2; } + +.columns.offset-by-two { margin-left: $col-3; } + +.columns.offset-by-three { margin-left: $col-4; } + +.columns.offset-by-four { margin-left: $col-5; } + +.columns.offset-by-five { margin-left: $col-6; } + +.columns.offset-by-six { margin-left: $col-7; } + +.columns.offset-by-seven { margin-left: $col-8; } + +.columns.offset-by-eight { margin-left: $col-9; } + +.columns.offset-by-nine { margin-left: $col-10; } + +.columns.offset-by-ten { margin-left: $col-11; } + +.columns.offset-by-eleven { margin-left: $col-12; } + +.columns.offset-by-twelve { margin-left: $col-13; } + +.columns.offset-by-thirteen { margin-left: $col-14; } + +.columns.offset-by-fourteen { margin-left: $col-15; } + +.columns.offset-by-fifteen { margin-left: 100%; } + +.column.alpha, +.columns.alpha, +.columns.sixteen, +.column:first-child, +.columns:first-child { + margin-left: 0; +} diff --git a/app/assets/stylesheets/admin/shared/forms.scss b/app/assets/stylesheets/admin/shared/forms.scss index 9da2543fb8..d034595fd3 100644 --- a/app/assets/stylesheets/admin/shared/forms.scss +++ b/app/assets/stylesheets/admin/shared/forms.scss @@ -185,6 +185,7 @@ fieldset { text-transform: uppercase; text-align: center; padding: 8px 15px; + margin: 0 auto; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; diff --git a/app/assets/stylesheets/darkswarm/_shop-inputs.scss b/app/assets/stylesheets/darkswarm/_shop-inputs.scss index 591cc320b9..e9bc97eb86 100644 --- a/app/assets/stylesheets/darkswarm/_shop-inputs.scss +++ b/app/assets/stylesheets/darkswarm/_shop-inputs.scss @@ -6,15 +6,25 @@ .darkswarm { // #search @include placeholder(rgba(0, 0, 0, 0.4), #777); + + .row .columns.variant-quantity-column { + padding-left: 0; + } } .reveal-modal.product-bulk-modal { - width: 26em; + width: 27em; } // Components to add variants to cart and change quantities // // They are not nested so that they can be used in modals. + +.variant-quantity-inputs { + height: 2.5rem; + white-space: nowrap; +} + button.add-variant, button.variant-quantity { height: 2.5rem; border-radius: 0; @@ -48,7 +58,7 @@ button.add-variant, button.variant-quantity { } button.add-variant { - min-width: 6rem; + min-width: 7rem; padding: 0 1em; &[disabled] { @@ -59,7 +69,7 @@ button.add-variant { } button.variant-quantity { - width: 3rem; + width: 2.25rem; &:nth-of-type(1):not(.bulk-buy):not(.bulk-buy-add) { border-right: .1em solid $orange-400; @@ -71,7 +81,7 @@ button.variant-quantity { font-size: 0.875em; margin-top: 0.25em; text-align: center; - width: 6rem; + width: 7rem; visibility: hidden; &.visible { @@ -83,20 +93,28 @@ button.bulk-buy.variant-quantity { background-color: transparent; border: .1em solid $grey-200; color: inherit; + width: 3.5rem; } button.bulk-buy-add.variant-quantity { width: 2.5rem; } -span.bulk-buy.variant-quantity { +[type="number"].variant-quantity { border: .1em solid $grey-200; height: 2.5rem; display: inline-block; - min-width: 3em; - padding: .5em; + width: 2.5rem; + padding: 0; text-align: center; vertical-align: top; + appearance: none; + -webkit-appearance: none; + -moz-appearance: textfield; + + &.bulk-buy { + width: 5rem; + } } .variant-bulk-buy-price-summary { diff --git a/app/assets/stylesheets/darkswarm/sidebar.scss b/app/assets/stylesheets/darkswarm/sidebar.scss index 18718062da..2e6a7d0a2e 100644 --- a/app/assets/stylesheets/darkswarm/sidebar.scss +++ b/app/assets/stylesheets/darkswarm/sidebar.scss @@ -3,9 +3,9 @@ // See https://github.com/zurb/foundation/issues/3855#issuecomment-30372252 @import "variables"; -@import "components/global"; -@import "components/buttons"; -@import "components/panels"; +@import "foundation/components/global"; +@import "foundation/components/buttons"; +@import "foundation/components/panels"; #sidebar { margin-top: 1.875em; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f39af8eff0..3f16322e7d 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -135,7 +135,6 @@ class ApplicationController < ActionController::Base def check_order_cycle_expiry if current_order_cycle.andand.closed? - session[:expired_order_cycle_id] = current_order_cycle.id current_order.empty! current_order.set_order_cycle! nil flash[:info] = I18n.t('order_cycle_closed') diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index ca7df8be49..ce04528410 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -142,7 +142,7 @@ class CheckoutController < ::BaseController def handle_redirect_from_stripe if OrderWorkflow.new(@order).next && order_complete? checkout_succeeded - redirect_to(spree.order_path(@order)) && return + redirect_to(order_path(@order)) && return else checkout_failed end @@ -202,10 +202,10 @@ class CheckoutController < ::BaseController def update_succeeded_response respond_to do |format| format.html do - respond_with(@order, location: spree.order_path(@order)) + respond_with(@order, location: order_path(@order)) end format.json do - render json: { path: spree.order_path(@order) }, status: :ok + render json: { path: order_path(@order) }, status: :ok end end end diff --git a/app/controllers/spree/admin/payments_controller.rb b/app/controllers/spree/admin/payments_controller.rb index af913d50a8..b93034750a 100644 --- a/app/controllers/spree/admin/payments_controller.rb +++ b/app/controllers/spree/admin/payments_controller.rb @@ -153,7 +153,7 @@ module Spree def authorize_stripe_sca_payment return unless @payment.payment_method.class == Spree::Gateway::StripeSCA - @payment.authorize!(spree.order_path(@payment.order, only_path: false)) + @payment.authorize!(main_app.order_path(@payment.order, only_path: false)) raise Spree::Core::GatewayError, I18n.t('authorization_failure') unless @payment.pending? diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 48e65ddbb1..b343875e4d 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -85,7 +85,7 @@ module Spree @order.next_transition.run_callbacks if @order.cart? redirect_to checkout_state_path(@order.checkout_steps.first) elsif @order.complete? - redirect_to spree.order_path(@order) + redirect_to order_path(@order) else redirect_to main_app.cart_path end @@ -132,17 +132,6 @@ module Spree end end - def clear - @order = current_order(true) - @order.empty! - @order.set_order_cycle! nil - redirect_to main_app.enterprise_path(@order.distributor.id) - end - - def order_cycle_expired - @order_cycle = OrderCycle.find session[:expired_order_cycle_id] - end - def cancel @order = Spree::Order.find_by!(number: params[:id]) authorize! :cancel, @order @@ -152,7 +141,7 @@ module Spree else flash[:error] = I18n.t(:orders_could_not_cancel) end - redirect_to request.referer || spree.order_path(@order) + redirect_to request.referer || order_path(@order) end private @@ -216,7 +205,7 @@ module Spree if items.empty? flash[:error] = I18n.t(:orders_cannot_remove_the_final_item) - redirect_to spree.order_path(order_to_update) + redirect_to order_path(order_to_update) end end diff --git a/app/controllers/spree/paypal_controller.rb b/app/controllers/spree/paypal_controller.rb index 81f7433c22..5ca339f52f 100644 --- a/app/controllers/spree/paypal_controller.rb +++ b/app/controllers/spree/paypal_controller.rb @@ -234,7 +234,7 @@ module Spree end def completion_route(order) - spree.order_path(order, token: order.token) + main_app.order_path(order, token: order.token) end def address_required? diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb index 1fb03af1f9..c9ee2e15fe 100644 --- a/app/controllers/spree/users_controller.rb +++ b/app/controllers/spree/users_controller.rb @@ -12,9 +12,13 @@ module Spree before_action :set_locale before_action :enable_embedded_shopfront - # Ignores invoice orders, only order where state: 'complete' def show - @orders = @user.orders.where(state: 'complete').order('completed_at desc') + @orders = orders_collection + + customers = spree_current_user.customers + @shops = Enterprise + .where(id: @orders.pluck(:distributor_id).uniq | customers.pluck(:enterprise_id)) + @unconfirmed_email = spree_current_user.unconfirmed_email end @@ -54,6 +58,14 @@ module Spree private + def orders_collection + if OpenFoodNetwork::FeatureToggle.enabled?(:customer_balance, spree_current_user) + CompleteOrdersWithBalance.new(@user).query + else + @user.orders.where(state: 'complete').order('completed_at desc') + end + end + def load_object @user ||= spree_current_user if @user diff --git a/app/helpers/spree/orders_helper.rb b/app/helpers/spree/orders_helper.rb index 9062689191..2ade8790d2 100644 --- a/app/helpers/spree/orders_helper.rb +++ b/app/helpers/spree/orders_helper.rb @@ -28,7 +28,7 @@ module Spree end def changeable_orders_link_path - changeable_orders.one? ? spree.order_path(changeable_orders.first) : spree.account_path + changeable_orders.one? ? order_path(changeable_orders.first) : spree.account_path end def shop_changeable_orders_alert_html diff --git a/app/models/spree/app_configuration.rb b/app/models/spree/app_configuration.rb index 1edba583de..67b843a4ce 100644 --- a/app/models/spree/app_configuration.rb +++ b/app/models/spree/app_configuration.rb @@ -92,7 +92,6 @@ module Spree preference :s3_host_alias, :string # Default mail headers settings - preference :enable_mail_delivery, :boolean, default: false preference :mails_from, :string, default: 'ofn@example.com' preference :mail_bcc, :string, default: 'ofn@example.com' preference :intercept_email, :string, default: nil diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index ceb603e275..900cf0fe76 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -130,6 +130,11 @@ module Spree where("state != ?", state) } + # All the states an order can be in after completing the checkout + FINALIZED_STATES = %w(complete canceled resumed awaiting_return returned).freeze + + scope :finalized, -> { where(state: FINALIZED_STATES) } + def self.by_number(number) where(number: number) end @@ -723,15 +728,7 @@ module Spree end def total_tax - (adjustments.to_a + price_adjustments.to_a).sum(&:included_tax) - end - - def price_adjustments - adjustments = [] - - line_items.each { |line_item| adjustments.concat line_item.adjustments } - - adjustments + (adjustments.to_a + line_item_adjustments.to_a).sum(&:included_tax) end def price_adjustment_totals diff --git a/app/models/spree/payment/processing.rb b/app/models/spree/payment/processing.rb index 1648b0ce36..aabafeac37 100644 --- a/app/models/spree/payment/processing.rb +++ b/app/models/spree/payment/processing.rb @@ -5,7 +5,6 @@ module Spree module Processing def process! return unless validate! - return if cvv_response_message.present? if payment_method.auto_capture? purchase! @@ -16,7 +15,6 @@ module Spree def process_offline! return unless validate! - return if cvv_response_message.present? if payment_method.auto_capture? charge_offline! diff --git a/app/models/spree/tax_rate.rb b/app/models/spree/tax_rate.rb index 064baf8852..eeee5673aa 100644 --- a/app/models/spree/tax_rate.rb +++ b/app/models/spree/tax_rate.rb @@ -83,8 +83,8 @@ module Spree order.adjustments(:reload) order.line_items(:reload) # TaxRate adjustments (order.adjustments.tax) - # and price adjustments (tax included on line items) consist of 100% tax - (order.adjustments.tax + order.price_adjustments).each do |adjustment| + # and line item adjustments (tax included on line items) consist of 100% tax + (order.adjustments.tax + order.line_item_adjustments.reload).each do |adjustment| adjustment.set_absolute_included_tax! adjustment.amount end end diff --git a/app/queries/complete_orders_with_balance.rb b/app/queries/complete_orders_with_balance.rb new file mode 100644 index 0000000000..57223e5c6e --- /dev/null +++ b/app/queries/complete_orders_with_balance.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +# Fetches complete orders of the specified user including their balance as a computed column +class CompleteOrdersWithBalance + def initialize(user) + @user = user + end + + def query + OutstandingBalance.new(sorted_finalized_orders).query + end + + private + + def sorted_finalized_orders + @user.orders + .finalized + .select('spree_orders.*') + .order(completed_at: :desc) + end +end diff --git a/app/queries/customers_with_balance.rb b/app/queries/customers_with_balance.rb new file mode 100644 index 0000000000..4abd070d34 --- /dev/null +++ b/app/queries/customers_with_balance.rb @@ -0,0 +1,39 @@ +# frozen_string_literal: true + +# Fetches the customers of the specified enterprise including the aggregated balance across the +# customer's orders. That is, we get the total balance for each customer with this enterprise. +class CustomersWithBalance + def initialize(enterprise) + @enterprise = enterprise + end + + def query + Customer.of(enterprise). + joins(left_join_complete_orders). + group("customers.id"). + select("customers.*"). + select(outstanding_balance_sum) + end + + private + + attr_reader :enterprise + + def outstanding_balance_sum + "SUM(#{OutstandingBalance.new.statement}) AS balance_value" + end + + # The resulting orders are in states that belong after the checkout. Only these can be considered + # for a customer's balance. + def left_join_complete_orders + <<-SQL.strip_heredoc + LEFT JOIN spree_orders ON spree_orders.customer_id = customers.id + AND #{finalized_states.to_sql} + SQL + end + + def finalized_states + states = Spree::Order::FINALIZED_STATES.map { |state| Arel::Nodes.build_quoted(state) } + Arel::Nodes::In.new(Spree::Order.arel_table[:state], states) + end +end diff --git a/app/queries/outstanding_balance.rb b/app/queries/outstanding_balance.rb new file mode 100644 index 0000000000..ce4d4d78f4 --- /dev/null +++ b/app/queries/outstanding_balance.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# Encapsulates the SQL statement that computes the balance of an order as a new column in the result +# set. This can then be reused chaining it with the ActiveRecord::Relation objects you pass in the +# constructor. +# +# Alternatively, you can get the SQL by calling #statement, which is suitable for more complex +# cases. +# +# See CompleteOrdersWithBalance or CustomersWithBalance as examples. +class OutstandingBalance + # All the states of a finished order but that shouldn't count towards the balance (the customer + # didn't get the order for whatever reason). Note it does not include complete + FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze + + # The relation must be an ActiveRecord::Relation object with `spree_orders` in the SQL statement + # FROM for #statement to work. + def initialize(relation = nil) + @relation = relation + end + + def query + relation.select("#{statement} AS balance_value") + end + + # Arel doesn't support CASE statements until v7.1.0 so we'll have to wait with SQL literals + # a little longer. See https://github.com/rails/arel/pull/400 for details. + def statement + <<-SQL.strip_heredoc + CASE WHEN state IN #{non_fulfilled_states_group.to_sql} THEN payment_total + WHEN state IS NOT NULL THEN payment_total - total + ELSE 0 END + SQL + end + + private + + attr_reader :relation + + def non_fulfilled_states_group + states = FINALIZED_NON_SUCCESSFUL_STATES.map { |state| Arel::Nodes.build_quoted(state) } + Arel::Nodes::Grouping.new(states) + end +end diff --git a/app/serializers/api/order_serializer.rb b/app/serializers/api/order_serializer.rb index 427c222ea2..958187a0b5 100644 --- a/app/serializers/api/order_serializer.rb +++ b/app/serializers/api/order_serializer.rb @@ -7,6 +7,14 @@ module Api has_many :payments, serializer: Api::PaymentSerializer + def outstanding_balance + if OpenFoodNetwork::FeatureToggle.enabled?(:customer_balance, object.user) + -object.balance_value + else + object.outstanding_balance + end + end + def payments object.payments.joins(:payment_method).completed end @@ -42,13 +50,13 @@ module Api end def path - Spree::Core::Engine.routes.url_helpers.order_path(object) + order_path(object) end def cancel_path return nil unless object.changes_allowed? - Spree::Core::Engine.routes.url_helpers.cancel_order_path(object) + cancel_order_path(object) end def changes_allowed diff --git a/app/services/customers_with_balance.rb b/app/services/customers_with_balance.rb deleted file mode 100644 index 56a3c2d171..0000000000 --- a/app/services/customers_with_balance.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -class CustomersWithBalance - def initialize(enterprise) - @enterprise = enterprise - end - - def query - Customer.of(enterprise). - joins(left_join_complete_orders). - group("customers.id"). - select("customers.*"). - select(outstanding_balance) - end - - private - - attr_reader :enterprise - - # Arel doesn't support CASE statements until v7.1.0 so we'll have to wait with SQL literals - # a little longer. See https://github.com/rails/arel/pull/400 for details. - def outstanding_balance - <<-SQL.strip_heredoc - SUM( - CASE WHEN state IN #{non_fulfilled_states_group.to_sql} THEN payment_total - WHEN state IS NOT NULL THEN payment_total - total - ELSE 0 END - ) AS balance_value - SQL - end - - # The resulting orders are in states that belong after the checkout. Only these can be considered - # for a customer's balance. - def left_join_complete_orders - <<-SQL.strip_heredoc - LEFT JOIN spree_orders ON spree_orders.customer_id = customers.id - AND #{complete_orders.to_sql} - SQL - end - - def complete_orders - states_group = prior_to_completion_states.map { |state| Arel::Nodes.build_quoted(state) } - Arel::Nodes::NotIn.new(Spree::Order.arel_table[:state], states_group) - end - - def non_fulfilled_states_group - states_group = non_fulfilled_states.map { |state| Arel::Nodes.build_quoted(state) } - Arel::Nodes::Grouping.new(states_group) - end - - # All the states an order can be in before completing the checkout - def prior_to_completion_states - %w(cart address delivery payment) - end - - # All the states of a complete order but that shouldn't count towards the balance. Those that the - # customer won't enjoy. - def non_fulfilled_states - %w(canceled returned) - end -end diff --git a/app/views/admin/enterprise_fees/_calculator_settings.html.haml b/app/views/admin/enterprise_fees/_calculator_settings.html.haml index be05330d6c..9b809020ed 100644 --- a/app/views/admin/enterprise_fees/_calculator_settings.html.haml +++ b/app/views/admin/enterprise_fees/_calculator_settings.html.haml @@ -8,9 +8,9 @@ .calculator-settings = f.fields_for :calculator do |calculator_form| - preference_fields(enterprise_fee.calculator, calculator_form).each do |field| - .field.alpha.one.columns + %span.field = field[:label] - .field.omega.two.columns + %p.field = field[:field] = calculator_form_string diff --git a/app/views/admin/enterprise_groups/_form.html.haml b/app/views/admin/enterprise_groups/_form.html.haml index 39a4b8bd1e..4bc31bd81a 100644 --- a/app/views/admin/enterprise_groups/_form.html.haml +++ b/app/views/admin/enterprise_groups/_form.html.haml @@ -6,7 +6,7 @@ .four.columns.alpha = render 'admin/shared/side_menu' .one.column   - .eleven.columns.omega.fullwidth_inputs + .eight.columns.omega.fullwidth_inputs = render 'form_primary_details', f: f = render 'form_users', f: f = render 'form_about', f: f diff --git a/app/views/admin/enterprises/form/_address.html.haml b/app/views/admin/enterprises/form/_address.html.haml index cb278df5e0..88dc9f6520 100644 --- a/app/views/admin/enterprises/form/_address.html.haml +++ b/app/views/admin/enterprises/form/_address.html.haml @@ -31,8 +31,7 @@ \/ = af.label :country_id, t(:country) %span.required * - %div{ "ng-controller" => "countryCtrl" } - .four.columns - %input.ofn-select2.fullwidth#enterprise_address_attributes_state_id{ name: 'enterprise[address_attributes][state_id]', type: 'number', data: 'countriesById[Enterprise.address.country_id].states', placeholder: t('admin.choose'), ng: { model: 'Enterprise.address.state_id' } } - .four.columns.omega - %input.ofn-select2.fullwidth#enterprise_address_attributes_country_id{ name: 'enterprise[address_attributes][country_id]', type: 'number', data: 'countries', placeholder: t('admin.choose'), ng: { model: 'Enterprise.address.country_id' } } + .four.columns{ "ng-controller" => "countryCtrl" } + %input.ofn-select2.fullwidth#enterprise_address_attributes_state_id{ name: 'enterprise[address_attributes][state_id]', type: 'number', data: 'countriesById[Enterprise.address.country_id].states', placeholder: t('admin.choose'), ng: { model: 'Enterprise.address.state_id' } } + .four.columns.omega{ "ng-controller" => "countryCtrl" } + %input.ofn-select2.fullwidth#enterprise_address_attributes_country_id{ name: 'enterprise[address_attributes][country_id]', type: 'number', data: 'countries', placeholder: t('admin.choose'), ng: { model: 'Enterprise.address.country_id' } } diff --git a/app/views/admin/enterprises/form/_payment_methods.html.haml b/app/views/admin/enterprises/form/_payment_methods.html.haml index 30a5852816..d38fb4632a 100644 --- a/app/views/admin/enterprises/form/_payment_methods.html.haml +++ b/app/views/admin/enterprises/form/_payment_methods.html.haml @@ -16,11 +16,11 @@ %td= link_to t(:edit), edit_admin_payment_method_path(payment_method) %br .row - .six.columns.alpha + .eight.columns %a.button{ href: "#{admin_payment_methods_path}"} = t('.manage') %i.icon-arrow-right - .five.columns.omega.text-right + .eight.columns.text-right %a.button{ href: "#{new_admin_payment_method_path}"} = t('.create_button') %i.icon-plus diff --git a/app/views/admin/enterprises/form/_primary_details.html.haml b/app/views/admin/enterprises/form/_primary_details.html.haml index 5fccc81904..6331d7c25f 100644 --- a/app/views/admin/enterprises/form/_primary_details.html.haml +++ b/app/views/admin/enterprises/form/_primary_details.html.haml @@ -1,19 +1,17 @@ .row - .alpha.eleven.columns - .three.columns.alpha - = f.label :name, t('.name') - %span.required * - .eight.columns.omega - = f.text_field :name, { placeholder: t('.name_placeholder') } + .three.columns.alpha + = f.label :name, t('.name') + %span.required * + .eight.columns.omega + = f.text_field :name, { placeholder: t('.name_placeholder') } - if @groups.present? .row - .alpha.eleven.columns - .three.columns.alpha - = f.label :group_ids, t('.groups') - %div{'ofn-with-tip' => t('.groups_tip')} - %a= t('admin.whats_this') - .eight.columns.omega - = f.collection_select :group_ids, @groups, :id, :name, {}, class: "select2 fullwidth", multiple: true, placeholder: t('.groups_placeholder') + .three.columns.alpha + = f.label :group_ids, t('.groups') + %div{'ofn-with-tip' => t('.groups_tip')} + %a= t('admin.whats_this') + .eight.columns.omega + = f.collection_select :group_ids, @groups, :id, :name, {}, class: "select2 fullwidth", multiple: true, placeholder: t('.groups_placeholder') .row .three.columns.alpha @@ -25,20 +23,19 @@ = f.label :is_primary_producer, t('.producer') - if spree_current_user.admin? .row - .alpha.eleven.columns - .three.columns.alpha - = f.label :sells, t('.sells') - %div{'ofn-with-tip' => t('.sells_tip')} - %a= t('admin.whats_this') - .two.columns - = f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells' - = f.label :sells, t('.none'), value: "none" - .two.columns - = f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells' - = f.label :sells, t('.own'), value: "own" - .four.columns.omega - = f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells' - = f.label :sells, t('.any'), value: "any" + .three.columns.alpha + = f.label :sells, t('.sells') + %div{'ofn-with-tip' => t('.sells_tip')} + %a= t('admin.whats_this') + .two.columns + = f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells' + = f.label :sells, t('.none'), value: "none" + .two.columns + = f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells' + = f.label :sells, t('.own'), value: "own" + .four.columns.omega + = f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells' + = f.label :sells, t('.any'), value: "any" .row .three.columns.alpha %label= t('.visible_in_search') @@ -56,7 +53,7 @@ = f.label :permalink, t('.permalink') %div{'ofn-with-tip' => t('.permalink_tip', link: main_app.root_url)} %a= t('admin.whats_this') - .six.columns + .eight.columns = f.text_field :permalink, { 'ng-model' => "Enterprise.permalink", placeholder: "eg. your-shop-name", 'ng-model-options' => "{ updateOn: 'default blur', debounce: {'default': 300, 'blur': 0} }" } .two.columns.omega %div{ng: {show: "checking", cloak: true}, style: "width: 30px; height: 30px;"} diff --git a/app/views/admin/enterprises/form/_shipping_methods.html.haml b/app/views/admin/enterprises/form/_shipping_methods.html.haml index 68f7332ef3..e210d1fb1e 100644 --- a/app/views/admin/enterprises/form/_shipping_methods.html.haml +++ b/app/views/admin/enterprises/form/_shipping_methods.html.haml @@ -15,11 +15,11 @@ %td= link_to t(:edit), edit_admin_shipping_method_path(shipping_method) %br .row - .six.columns.alpha + .eight.columns %a.button{ href: "#{admin_shipping_methods_path}"} = t('.manage') %i.icon-arrow-right - .five.columns.omega.text-right + .eight.columns.text-right %a.button{ href: "#{new_admin_shipping_method_path}"} = t('.create_button') %i.icon-plus diff --git a/app/views/admin/enterprises/form/_shop_preferences.html.haml b/app/views/admin/enterprises/form/_shop_preferences.html.haml index 15fd2daad4..a04b09508f 100644 --- a/app/views/admin/enterprises/form/_shop_preferences.html.haml +++ b/app/views/admin/enterprises/form/_shop_preferences.html.haml @@ -1,104 +1,95 @@ .row - .alpha.eleven.columns - .three.columns.alpha - = f.label "enterprise_preferred_shopfront_message", t('.shopfront_message') - .eight.columns.omega - %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true, - 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", - 'placeholder' => t('.shopfront_message_placeholder')} + .three.columns.alpha + = f.label "enterprise_preferred_shopfront_message", t('.shopfront_message') + .eight.columns.omega + %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_message', 'id' => 'enterprise_preferred_shopfront_message', 'name' => 'enterprise[preferred_shopfront_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true, + 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", + 'placeholder' => t('.shopfront_message_placeholder')} .row - .alpha.eleven.columns - .three.columns.alpha - = f.label "enterprise_preferred_shopfront_closed_message", t('.shopfront_closed_message') - .eight.columns.omega - %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true, - 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", - 'placeholder' => t('.shopfront_closed_message_placeholder')} + .three.columns.alpha + = f.label "enterprise_preferred_shopfront_closed_message", t('.shopfront_closed_message') + .eight.columns.omega + %text-angular{'ng-model' => 'Enterprise.preferred_shopfront_closed_message', 'id' => 'enterprise_preferred_shopfront_closed_message', 'name' => 'enterprise[preferred_shopfront_closed_message]', 'class' => 'text-angular textangular-strip', 'ta-paste' => "stripFormatting($html)", "textangular-links-target-blank" => true, + 'ta-toolbar' => "[['h1','h2','h3','h4','p'],['bold','italics','underline','clear'],['insertLink']]", + 'placeholder' => t('.shopfront_closed_message_placeholder')} .row - .alpha.eleven.columns - .three.columns.alpha - = f.label "enterprise_preferred_shopfront_taxon_order", t('.shopfront_category_ordering') - %br - = t('.shopfront_category_ordering_note') - .eight.columns.omega - %textarea.fullwidth{ id: 'enterprise_preferred_shopfront_taxon_order', name: 'enterprise[preferred_shopfront_taxon_order]', rows: 6, 'ng-model' => 'Enterprise.preferred_shopfront_taxon_order', 'ofn-taxon-autocomplete' => '', 'multiple-selection' => 'true', placeholder: 'Category' } + .three.columns.alpha + = f.label "enterprise_preferred_shopfront_taxon_order", t('.shopfront_category_ordering') + %br + = t('.shopfront_category_ordering_note') + .eight.columns.omega + %textarea.fullwidth{ id: 'enterprise_preferred_shopfront_taxon_order', name: 'enterprise[preferred_shopfront_taxon_order]', rows: 6, 'ng-model' => 'Enterprise.preferred_shopfront_taxon_order', 'ofn-taxon-autocomplete' => '', 'multiple-selection' => 'true', placeholder: 'Category' } .row - .alpha.eleven.columns - .three.columns.alpha - = f.label "enterprise_preferred_shopfront_order_cycle_order", t(:sort_order_cycles_on_shopfront_by) - .three.columns - = radio_button :enterprise, :preferred_shopfront_order_cycle_order, :orders_open_at, { 'ng-model' => 'Enterprise.preferred_shopfront_order_cycle_order' } - = label :enterprise, :preferred_shopfront_order_cycle_order_orders_open_at, t('.open_date') - .five.columns.omega - = radio_button :enterprise, :preferred_shopfront_order_cycle_order, :orders_close_at, { 'ng-model' => 'Enterprise.preferred_shopfront_order_cycle_order' } - = label :enterprise, :preferred_shopfront_order_cycle_order_orders_close_at, t('.close_date') + .three.columns.alpha + = f.label "enterprise_preferred_shopfront_order_cycle_order", t(:sort_order_cycles_on_shopfront_by) + .three.columns + = radio_button :enterprise, :preferred_shopfront_order_cycle_order, :orders_open_at, { 'ng-model' => 'Enterprise.preferred_shopfront_order_cycle_order' } + = label :enterprise, :preferred_shopfront_order_cycle_order_orders_open_at, t('.open_date') + .five.columns.omega + = radio_button :enterprise, :preferred_shopfront_order_cycle_order, :orders_close_at, { 'ng-model' => 'Enterprise.preferred_shopfront_order_cycle_order' } + = label :enterprise, :preferred_shopfront_order_cycle_order_orders_close_at, t('.close_date') .row - .alpha.eleven.columns - .three.columns.alpha - %label= t '.shopfront_requires_login' - %div{'ofn-with-tip' => t('.shopfront_requires_login_tip')} - %a= t 'admin.whats_this' - .three.columns - = f.radio_button :require_login, false, "ng-model" => "Enterprise.require_login", "ng-value" => "false" - = f.label :require_login, t('.shopfront_requires_login_false'), value: :false - .five.columns.omega - = f.radio_button :require_login, true, "ng-model" => "Enterprise.require_login", "ng-value" => "true" - = f.label :require_login, t('.shopfront_requires_login_true'), value: :true + .three.columns.alpha + %label= t '.shopfront_requires_login' + %div{'ofn-with-tip' => t('.shopfront_requires_login_tip')} + %a= t 'admin.whats_this' + .three.columns + = f.radio_button :require_login, false, "ng-model" => "Enterprise.require_login", "ng-value" => "false" + = f.label :require_login, t('.shopfront_requires_login_false'), value: :false + .five.columns.omega + = f.radio_button :require_login, true, "ng-model" => "Enterprise.require_login", "ng-value" => "true" + = f.label :require_login, t('.shopfront_requires_login_true'), value: :true .row{ng: {if: "!Enterprise.require_login"}} - .alpha.eleven.columns - .three.columns.alpha - %label= t '.allow_guest_orders' - %div{'ofn-with-tip' => t('.allow_guest_orders_tip')} - %a= t 'admin.whats_this' - .eight.columns.omega - .row - .three.columns.alpha - = f.radio_button :allow_guest_orders, true, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "true" - = f.label :allow_guest_orders, t('.allow_guest_orders_true'), value: :true - .five.columns.omega - = f.radio_button :allow_guest_orders, false, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "false" - = f.label :allow_guest_orders, t('.allow_guest_orders_false'), value: :false - .row.warning{ng: {show: 'Enterprise.allow_guest_orders && Enterprise.allow_order_changes'}} - .eight.columns.alpha.omega - %i.icon-warning-sign - = t '.recommend_require_login' + .three.columns.alpha + %label= t '.allow_guest_orders' + %div{'ofn-with-tip' => t('.allow_guest_orders_tip')} + %a= t 'admin.whats_this' + .eight.columns.omega + .row + .three.columns.alpha + = f.radio_button :allow_guest_orders, true, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "true" + = f.label :allow_guest_orders, t('.allow_guest_orders_true'), value: :true + .five.columns.omega + = f.radio_button :allow_guest_orders, false, "ng-model" => "Enterprise.allow_guest_orders", "ng-value" => "false" + = f.label :allow_guest_orders, t('.allow_guest_orders_false'), value: :false + .row.warning{ng: {show: 'Enterprise.allow_guest_orders && Enterprise.allow_order_changes'}} + .eight.columns.alpha.omega + %i.icon-warning-sign + = t '.recommend_require_login' .row - .alpha.eleven.columns - .three.columns.alpha - %label= t '.allow_order_changes' - %div{'ofn-with-tip' => t('.allow_order_changes_tip')} - %a= t 'admin.whats_this' - .three.columns - = f.radio_button :allow_order_changes, false, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "false" - = f.label :allow_order_changes, t('.allow_order_changes_false'), value: :false - .five.columns.omega - = f.radio_button :allow_order_changes, true, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "true" - = f.label :allow_order_changes, t('.allow_order_changes_true'), value: :true + .three.columns.alpha + %label= t '.allow_order_changes' + %div{'ofn-with-tip' => t('.allow_order_changes_tip')} + %a= t 'admin.whats_this' + .three.columns + = f.radio_button :allow_order_changes, false, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "false" + = f.label :allow_order_changes, t('.allow_order_changes_false'), value: :false + .five.columns.omega + = f.radio_button :allow_order_changes, true, "ng-model" => "Enterprise.allow_order_changes", "ng-value" => "true" + = f.label :allow_order_changes, t('.allow_order_changes_true'), value: :true .row - .alpha.eleven.columns - .three.columns.alpha - %label= t '.enable_subscriptions' - %div{'ofn-with-tip' => t('.enable_subscriptions_tip')} - %a= t 'admin.whats_this' - .three.columns - = f.radio_button :enable_subscriptions, true - = f.label :enable_subscriptions, t('.enable_subscriptions_true'), value: :true - .five.columns.omega - = f.radio_button :enable_subscriptions, false - = f.label :enable_subscriptions, t('.enable_subscriptions_false'), value: :false + .three.columns.alpha + %label= t '.enable_subscriptions' + %div{'ofn-with-tip' => t('.enable_subscriptions_tip')} + %a= t 'admin.whats_this' + .three.columns + = f.radio_button :enable_subscriptions, true + = f.label :enable_subscriptions, t('.enable_subscriptions_true'), value: :true + .five.columns.omega + = f.radio_button :enable_subscriptions, false + = f.label :enable_subscriptions, t('.enable_subscriptions_false'), value: :false .row - .alpha.eleven.columns - .three.columns.alpha - %label= t '.customer_names_in_reports' - %div{'ofn-with-tip' => t('.customer_names_tip')} - %a= t 'admin.whats_this' - .three.columns - = radio_button :enterprise, :preferred_show_customer_names_to_suppliers, true - = label :enterprise_preferred_show_customer_names_to_suppliers, t('.customer_names_true'), value: :true - .five.columns.omega - = radio_button :enterprise, :preferred_show_customer_names_to_suppliers, false - = label :enterprise_preferred_show_customer_names_to_suppliers, t('.customer_names_false'), value: :false + .three.columns.alpha + %label= t '.customer_names_in_reports' + %div{'ofn-with-tip' => t('.customer_names_tip')} + %a= t 'admin.whats_this' + .three.columns + = radio_button :enterprise, :preferred_show_customer_names_to_suppliers, true + = label :enterprise_preferred_show_customer_names_to_suppliers, t('.customer_names_true'), value: :true + .five.columns.omega + = radio_button :enterprise, :preferred_show_customer_names_to_suppliers, false + = label :enterprise_preferred_show_customer_names_to_suppliers, t('.customer_names_false'), value: :false diff --git a/app/views/admin/enterprises/index.html.haml b/app/views/admin/enterprises/index.html.haml index 499f8f9db6..d4468f45ad 100644 --- a/app/views/admin/enterprises/index.html.haml +++ b/app/views/admin/enterprises/index.html.haml @@ -5,7 +5,8 @@ = "admin.enterprises" - content_for :page_actions do - = render 'admin/shared/user_guide_link' + %li#user_guide_link + = render 'admin/shared/user_guide_link' %li#new_product_link - button_href = spree_current_user.can_own_more_enterprises? ? main_app.new_admin_enterprise_path : '#' diff --git a/app/views/admin/order_cycles/_name_and_timing_form.html.haml b/app/views/admin/order_cycles/_name_and_timing_form.html.haml index 0419dc619f..d5f54dd76a 100644 --- a/app/views/admin/order_cycles/_name_and_timing_form.html.haml +++ b/app/views/admin/order_cycles/_name_and_timing_form.html.haml @@ -2,14 +2,14 @@ .alpha.two.columns = f.label :name, t('.name') %span.required * - .six.columns.omega + .six.columns.omega.fullwidth_inputs - if viewing_as_coordinator_of?(@order_cycle) = f.text_field :name, 'ng-model' => 'order_cycle.name', 'required' => true, 'ng-disabled' => '!loaded()' - else {{ order_cycle.name }} .two.columns = f.label :orders_open_at, t('.orders_open') - .omega.six.columns + .omega.six.columns.fullwidth_inputs - if viewing_as_coordinator_of?(@order_cycle) = f.text_field :orders_open_at, 'datetimepicker' => 'order_cycle.orders_open_at', 'ng-model' => 'order_cycle.orders_open_at', 'ng-disabled' => '!loaded()', 'change-warning' => 'order_cycle' - else @@ -18,11 +18,11 @@ .row .alpha.two.columns = f.label :coordinator, t('.coordinator') - .six.columns.omega + .six.columns.omega.fullwidth_inputs = @order_cycle.coordinator.name .two.columns = f.label :orders_close, t('.orders_close') - .six.columns.omega + .six.columns.omega.fullwidth_inputs - if viewing_as_coordinator_of?(@order_cycle) = f.text_field :orders_close_at, 'datetimepicker' => 'order_cycle.orders_close_at', 'ng-model' => 'order_cycle.orders_close_at', 'ng-disabled' => '!loaded()', 'change-warning' => 'order_cycle' - else @@ -33,7 +33,7 @@ .row .two.columns.alpha = f.label :schedule_ids, t('admin.order_cycles.index.schedules') - .twelve.columns + .six.columns - if viewing_as_coordinator_of?(@order_cycle) %input.fullwidth.ofn-select2#schedule_ids{ name: 'order_cycle[schedule_ids]', data: 'schedules', @@ -43,5 +43,3 @@ ng: { model: 'order_cycle.schedule_ids' } } - else %schedule-list{ 'order-cycle' => 'order_cycle' } - .two.columns.omega -   diff --git a/app/views/admin/order_cycles/_simple_form.html.haml b/app/views/admin/order_cycles/_simple_form.html.haml index 3f6372175d..3c828d7777 100644 --- a/app/views/admin/order_cycles/_simple_form.html.haml +++ b/app/views/admin/order_cycles/_simple_form.html.haml @@ -4,14 +4,14 @@ .alpha.two.columns = label_tag t('.ready_for') %span.required * - .six.columns - = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'required' => 'required', 'placeholder' => t('.ready_for_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_time', 'size' => 30, 'maxlength' => 35 %span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.exchange_form.pickup_time_tip')} + .six.columns.fullwidth_inputs + = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_time', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_time', 'required' => 'required', 'placeholder' => t('.ready_for_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_time', 'maxlength' => 35 .two.columns = label_tag t('.customer_instructions') - .six.columns.omega - = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => t('.customer_instructions_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_instructions', 'size' => 30 %span.icon-question-sign{'ofn-with-tip' => t('admin.order_cycles.exchange_form.pickup_instructions_tip')} + .six.columns.omega.fullwidth_inputs + = text_field_tag 'order_cycle_outgoing_exchange_0_pickup_instructions', '', 'id' => 'order_cycle_outgoing_exchange_0_pickup_instructions', 'placeholder' => t('.customer_instructions_placeholder'), 'ng-model' => 'outgoing_exchange.pickup_instructions', 'size' => 30 = label_tag t('.products') %table.exchanges diff --git a/app/views/admin/variant_overrides/_hidden_products.html.haml b/app/views/admin/variant_overrides/_hidden_products.html.haml index ed3e2555c8..b8cdc1af01 100644 --- a/app/views/admin/variant_overrides/_hidden_products.html.haml +++ b/app/views/admin/variant_overrides/_hidden_products.html.haml @@ -2,7 +2,7 @@ %table#hidden-products{ ng: { show: 'filteredProducts.length > 0' } } %col.producer{ width: "20%" } %col.product{ width: "20%" } - %col.variant{ width: "30%" } + %col.variant{ width: "20%" } %col.add{ width: "15%" } %thead %tr diff --git a/app/views/admin/variant_overrides/_new_products.html.haml b/app/views/admin/variant_overrides/_new_products.html.haml index 77eda7ae37..731535d06d 100644 --- a/app/views/admin/variant_overrides/_new_products.html.haml +++ b/app/views/admin/variant_overrides/_new_products.html.haml @@ -1,9 +1,9 @@ %table#new-products{ ng: { show: 'views.new.visible && filteredProducts.length > 0' } } %col.producer{ width: "20%" } %col.product{ width: "20%" } - %col.variant{ width: "30%" } - %col.add{ width: "15%" } - %col.hide{ width: "15%" } + %col.variant{ width: "20%" } + %col.add{ width: "10%" } + %col.hide{ width: "10%" } %thead %tr %th.producer=t('admin.producer') diff --git a/app/views/checkout/_form.html.haml b/app/views/checkout/_form.html.haml index e755af01e4..362586974c 100644 --- a/app/views/checkout/_form.html.haml +++ b/app/views/checkout/_form.html.haml @@ -4,6 +4,7 @@ = inject_saved_credit_cards = form_for current_order, + url: order_path(current_order), html: {name: "checkout", id: "checkout_form", novalidate: true, diff --git a/app/views/spree/admin/mail_methods/_form.html.haml b/app/views/spree/admin/mail_methods/_form.html.haml index 02b7ea11dd..f987a5b28b 100644 --- a/app/views/spree/admin/mail_methods/_form.html.haml +++ b/app/views/spree/admin/mail_methods/_form.html.haml @@ -2,9 +2,6 @@ .row %fieldset.no-border-bottom %legend{align: "center"}= t("spree.general") - .field - = preference_field_tag("enable_mail_delivery", Spree::Config[:enable_mail_delivery], type: :boolean) - = label_tag :enable_mail_delivery, t("spree.enable_mail_delivery") .field = label_tag :mails_from, t("spree.send_mails_as") %br/ diff --git a/app/views/spree/admin/orders/_filters.html.haml b/app/views/spree/admin/orders/_filters.html.haml index 3a33806f6f..9d5860bd9e 100644 --- a/app/views/spree/admin/orders/_filters.html.haml +++ b/app/views/spree/admin/orders/_filters.html.haml @@ -1,5 +1,5 @@ %div{"data-hook" => "admin_orders_index_search"} - = form_tag :orders, {name: "orders_form", "ng-submit" => "fetchResults()"} do + = form_tag :admin_orders, {name: "orders_form", "ng-submit" => "fetchResults()"} do .field-block.alpha.four.columns .date-range-filter.field = label_tag nil, t(:date_range) diff --git a/app/views/spree/admin/orders/_form.html.haml b/app/views/spree/admin/orders/_form.html.haml index 3a0b74b56e..6bc77012bc 100644 --- a/app/views/spree/admin/orders/_form.html.haml +++ b/app/views/spree/admin/orders/_form.html.haml @@ -4,7 +4,7 @@ = render :partial => "spree/admin/orders/shipment", :collection => @order.shipments, :locals => { :order => order } - = render :partial => "spree/admin/orders/_form/adjustments", :locals => { :adjustments => @order.price_adjustments, :title => t(".line_item_adjustments")} + = render :partial => "spree/admin/orders/_form/adjustments", :locals => { :adjustments => @order.line_item_adjustments, :title => t(".line_item_adjustments")} = render :partial => "spree/admin/orders/_form/adjustments", :locals => { :adjustments => order_adjustments_for_display(@order), :title => t(".order_adjustments")} - if order.line_items.exists? diff --git a/app/views/spree/admin/orders/_shipment.html.haml b/app/views/spree/admin/orders/_shipment.html.haml index 0175faf001..3fe2b5ab4d 100644 --- a/app/views/spree/admin/orders/_shipment.html.haml +++ b/app/views/spree/admin/orders/_shipment.html.haml @@ -54,9 +54,8 @@ %td.actions - if can? :update, shipment - = link_to '', '#', :class => 'save-method icon_link icon-ok no-text with-tip', :data => { 'shipment-number' => shipment.number, :action => 'save' }, title: I18n.t('actions.save') - = link_to '', '#', :class => 'cancel-method icon_link icon-cancel no-text with-tip', :data => { :action => 'cancel' }, :title => I18n.t('actions.cancel') - + = link_to '', '', :class => 'save-method icon_link icon-ok no-text with-tip', :data => { 'shipment-number' => shipment.number, :action => 'save' }, title: I18n.t('actions.save') + = link_to '', '', :class => 'cancel-method icon_link icon-cancel no-text with-tip', :data => { :action => 'cancel' }, :title => I18n.t('actions.cancel') %tr.show-method.total %td{ :colspan => "4" } - if shipment.adjustment.present? @@ -73,7 +72,7 @@ - if shipment.adjustment.present? && !shipment.shipped? %td.actions - if can? :update, shipment - = link_to '', '#', :class => 'edit-method icon_link icon-edit no-text with-tip', :data => { :action => 'edit' }, :title => Spree.t('edit') + = link_to '', '', :class => 'edit-method icon_link icon-edit no-text with-tip', :data => { :action => 'edit' }, :title => Spree.t('edit') %tr.edit-tracking.hidden.total %td{ :colspan => "5" } @@ -83,8 +82,8 @@ %td.actions - if can? :update, shipment - = link_to '', '#', :class => 'save-tracking icon_link icon-ok no-text with-tip', :data => { 'shipment-number' => shipment.number, :action => 'save' }, :title => I18n.t('actions.save') - = link_to '', '#', :class => 'cancel-tracking icon_link icon-cancel no-text with-tip', :data => { :action => 'cancel' }, :title => I18n.t('actions.cancel') + = link_to '', '', :class => 'save-tracking icon_link icon-ok no-text with-tip', :data => { 'shipment-number' => shipment.number, :action => 'save' }, :title => I18n.t('actions.save') + = link_to '', '', :class => 'cancel-tracking icon_link icon-cancel no-text with-tip', :data => { :action => 'cancel' }, :title => I18n.t('actions.cancel') %tr.show-tracking.total %td{ :colspan => "5" } @@ -97,4 +96,4 @@ %td.actions - if can? :update, shipment - = link_to '', '#', :class => 'edit-tracking icon_link icon-edit no-text with-tip', :data => { :action => 'edit' }, :title => Spree.t('edit') + = link_to '', '', :class => 'edit-tracking icon_link icon-edit no-text with-tip', :data => { :action => 'edit' }, :title => Spree.t('edit') diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml index 50fff333aa..5f66f2f47d 100644 --- a/app/views/spree/admin/orders/bulk_management.html.haml +++ b/app/views/spree/admin/orders/bulk_management.html.haml @@ -21,12 +21,12 @@ %label{ :for => 'start_date_filter' } = t("admin.start_date") %br - %input{ :class => "two columns alpha", :type => "text", :id => 'start_date_filter', 'ng-model' => 'startDate', 'datepicker' => "startDate", 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()', 'ng-model-options' => '{ debounce: 1000 }' } + %input.fullwidth{ :type => "text", :id => 'start_date_filter', 'ng-model' => 'startDate', 'datepicker' => "startDate", 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()', 'ng-model-options' => '{ debounce: 1000 }' } .date_filter{ :class => "two columns" } %label{ :for => 'end_date_filter' } = t("admin.end_date") %br - %input{ :class => "two columns alpha", :type => "text", :id => 'end_date_filter', 'ng-model' => 'endDate', 'datepicker' => "endDate", 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()', 'ng-model-options' => '{ debounce: 1000 }' } + %input.fullwidth{ :type => "text", :id => 'end_date_filter', 'ng-model' => 'endDate', 'datepicker' => "endDate", 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()', 'ng-model-options' => '{ debounce: 1000 }' } .one.column   .filter_select{ :class => "three columns" } %label{ :for => 'supplier_filter' } @@ -98,9 +98,10 @@ .controls.sixteen.columns.alpha.omega{ ng: { hide: 'RequestMonitor.loading || line_items.length == 0' } } %div.three.columns.alpha %input.fullwidth{ :type => "text", :id => 'quick_search', 'ng-model' => 'quickSearch', :placeholder => 'Quick Search' } - = render 'admin/shared/bulk_actions_dropdown' - %div.seven.columns   - %columns-dropdown{ action: "#{controller_name}_#{action_name}" } + %div.three.columns + = render 'admin/shared/bulk_actions_dropdown' + %div.ten.columns + %columns-dropdown{ action: "#{controller_name}_#{action_name}" } %div.sixteen.columns.alpha#loading{ 'ng-if' => 'RequestMonitor.loading' } = render partial: "components/spinner" diff --git a/app/views/spree/admin/orders/customer_details/_form.html.haml b/app/views/spree/admin/orders/customer_details/_form.html.haml index 5ac4e15a52..772dc48df1 100644 --- a/app/views/spree/admin/orders/customer_details/_form.html.haml +++ b/app/views/spree/admin/orders/customer_details/_form.html.haml @@ -7,13 +7,13 @@ = f.label :email, Spree.t(:email) + ':' = f.email_field :email, :class => 'fullwidth' - .alpha.six.columns{"data-hook" => "bill_address_wrapper"} + .alpha.eight.columns{"data-hook" => "bill_address_wrapper"} %fieldset.no-border-bottom %legend{:align => "center"}= Spree.t(:billing_address) = f.fields_for :bill_address do |ba_form| = render :partial => 'address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false } - .omega.six.columns{"data-hook" => "ship_address_wrapper"} + .omega.eight.columns{"data-hook" => "ship_address_wrapper"} %fieldset.no-border-bottom %legend{:align => "center"}= Spree.t(:shipping_address) = f.fields_for :ship_address do |sa_form| diff --git a/app/views/spree/admin/overview/_order_cycles.html.haml b/app/views/spree/admin/overview/_order_cycles.html.haml index 0831c50e17..3d26daa37f 100644 --- a/app/views/spree/admin/overview/_order_cycles.html.haml +++ b/app/views/spree/admin/overview/_order_cycles.html.haml @@ -1,21 +1,21 @@ - color_class = @order_cycle_count > 0 ? "blue" : "orange" - icon_class = @order_cycle_count > 0 ? "icon-ok-sign" : "icon-warning-sign" %div.dashboard_item.seven.columns.omega#order_cycles - %div.header.seven.columns.alpha{class: color_class} - %h3.four.columns.alpha + %div.header.sixteen.columns.alpha{class: color_class} + %h3.ten.columns.alpha = t ".order_cycles" - if @order_cycle_count > 0 - %a.three.columns.omega.icon-plus.button.blue{ href: main_app.new_admin_order_cycle_path } + %a.six.columns.omega.icon-plus.button.blue{ href: main_app.new_admin_order_cycle_path } = t "spree_admin_enterprises_create_new" - else %a{ "ofn-with-tip" => t(".order_cycles_tip") } = t "admin.whats_this" - %div.seven.columns.alpha.list - %div.seven.columns.alpha.list-item{class: color_class} - %span.six.columns.alpha + %div.sixteen.columns.alpha.list + %div.sixteen.columns.alpha.list-item{class: color_class} + %span.thirteen.columns.alpha = t('.you_have_active', count: @order_cycle_count) - %span.one.column.omega + %span.three.columns.omega %span{class: icon_class} - %a.seven.columns.alpha.button.bottom{ href: main_app.admin_order_cycles_path, class: color_class } + %a.sixteen.columns.alpha.button.bottom{ href: main_app.admin_order_cycles_path, class: color_class } = t ".manage_order_cycles" %span.icon-arrow-right diff --git a/app/views/spree/admin/overview/_products.html.haml b/app/views/spree/admin/overview/_products.html.haml index 539eecd943..3d92aaee85 100644 --- a/app/views/spree/admin/overview/_products.html.haml +++ b/app/views/spree/admin/overview/_products.html.haml @@ -1,29 +1,29 @@ %div.dashboard_item.seven.columns.alpha#products - %div.header.seven.columns.alpha{ :class => "#{@product_count > 0 ? "" : "red"}"} - %h3.four.columns.alpha + %div.header.sixteen.columns.alpha{ :class => "#{@product_count > 0 ? "" : "red"}"} + %h3.ten.columns.alpha = t "products" - if @product_count > 0 - %a.three.columns.omega.icon-plus.button.blue{ href: "#{new_admin_product_path}" } + %a.six.columns.omega.icon-plus.button.blue{ href: "#{new_admin_product_path}" } = t "spree_admin_enterprises_create_new" - else %a{ "ofn-with-tip" => "The products that you sell through the Open Food Network." } = t "admin.whats_this" - %div.seven.columns.alpha.list + %div.sixteen.columns.alpha.list - if @product_count > 0 - %div.seven.columns.alpha.list-item - %span.six.columns.alpha + %div.sixteen.columns.alpha.list-item + %span.thirteen.columns.alpha = t(".active_products", count: @product_count ) - %span.one.column.omega + %span.three.columns.omega %span.icon-ok-sign - %a.seven.columns.alpha.button.bottom.blue{ href: "#{admin_products_path}" } + %a.sixteen.columns.alpha.button.bottom.blue{ href: "#{admin_products_path}" } = t "spree_admin_enterprises_producers_manage_products" %span.icon-arrow-right - else - %div.seven.columns.alpha.list-item.red - %span.six.columns.alpha + %div.sixteen.columns.alpha.list-item.red + %span.thirteen.columns.alpha = t(".active_products", count: @product_count ) - %span.one.column.omega + %span.three.columns.omega %span.icon-remove-sign - %a.seven.columns.alpha.button.bottom.red{ href: "#{new_admin_product_path}" } + %a.eight.columns.alpha.button.bottom.red{ href: "#{new_admin_product_path}" } = t "spree_admin_enterprises_create_new_product" %span.icon-arrow-right diff --git a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml index e53f9e436e..5004d1d987 100644 --- a/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml +++ b/app/views/spree/admin/overview/single_enterprise_dashboard.html.haml @@ -34,7 +34,7 @@ %a.close{ href: "#" } × .row - .alpha.seven.columns.dashboard_item.single-ent#map + .alpha.eight.columns.dashboard_item.single-ent#map .header %h3 %span.icon-user @@ -45,10 +45,8 @@ = @enterprise.name = t "live" %span.icon-arrow-right - .two.columns -   - .seven.columns.omega.dashboard_item.single-ent#edit + .eight.columns.omega.dashboard_item.single-ent#edit .header %h3 %span.icon-edit @@ -63,7 +61,7 @@ .row - if can? :admin, Spree::Product - .seven.columns.alpha.dashboard_item.single-ent#products + .eight.columns.alpha.dashboard_item.single-ent#products .header %h3 %span.icon-th-large @@ -73,11 +71,8 @@ = t "manage_products" %span.icon-arrow-right - .two.columns -   - - if can? :admin, OrderCycle - .seven.columns.omega.dashboard_item.single-ent#order_cycles + .eight.columns.omega.dashboard_item.single-ent#order_cycles .header %h3 %span.icon-shopping-cart diff --git a/app/views/spree/admin/products/_form.html.haml b/app/views/spree/admin/products/_form.html.haml index 08386e10dd..ff97183eca 100644 --- a/app/views/spree/admin/products/_form.html.haml +++ b/app/views/spree/admin/products/_form.html.haml @@ -1,5 +1,5 @@ %div{"data-hook" => "admin_product_form_fields"} - .left.eight.columns.alpha + .left.twelve.columns.alpha = f.field_container :name do = f.label :name, raw(t(:name) + content_tag(:span, ' *', :class => 'required')) = f.text_field :name, :class => 'fullwidth title' diff --git a/app/views/spree/admin/reports/index.html.haml b/app/views/spree/admin/reports/index.html.haml index cc5205c885..533eab2de1 100644 --- a/app/views/spree/admin/reports/index.html.haml +++ b/app/views/spree/admin/reports/index.html.haml @@ -1,13 +1,14 @@ - content_for :page_title do = t(:listing_reports) -%table.index - %thead - %tr - %th= t(:name) - %th= t(:description) - %tbody - - @reports.each do |key, value| +.columns.twelve + %table.index + %thead %tr - %td= link_to value[:name], value[:url] - %td= value[:description] + %th= t(:name) + %th= t(:description) + %tbody + - @reports.each do |key, value| + %tr + %td= link_to value[:name], value[:url] + %td= value[:description] diff --git a/app/views/spree/admin/shared/_hubs_sidebar.html.haml b/app/views/spree/admin/shared/_hubs_sidebar.html.haml index e1c1c3577d..ab570b1971 100644 --- a/app/views/spree/admin/shared/_hubs_sidebar.html.haml +++ b/app/views/spree/admin/shared/_hubs_sidebar.html.haml @@ -1,27 +1,28 @@ - hubs_color = @hubs.count > 0 ? "blue" : "red" - hubs_color = 'red' if (controller.action_name == 'create' || controller.action_name == 'update') && @object.errors.full_messages.include?(t(:hub_sidebar_at_least)) + .sidebar_item.omega.four.columns#hubs - .four.columns.alpha.header{ class: "#{hubs_color}" } + .sixteen.columns.alpha.header{ class: "#{hubs_color}" } %span.four.columns.alpha.centered = t(:hub_sidebar_hubs) - .four.columns.alpha.list{ class: "#{hubs_color}" } + .sixteen.columns.alpha.list{ class: "#{hubs_color}" } - if @hubs.count > 0 = hidden_field klass, :distributor_ids, :multiple => true, value: nil - @hubs.each do |hub| - %span.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}" } - %span.four.columns - %span.three.columns.alpha + %span.sixteen.columns.alpha.list-item{ class: "#{cycle('odd','even')}" } + %span.sixteen.columns + %span.fourteen.columns.alpha %label = check_box klass, :distributor_ids, { multiple: true }.merge(add_check_if_single(@hubs.count)), hub.id, nil = hub.name - %a.one.column.omega{ href: "#{main_app.edit_admin_enterprise_path(hub)}" } + %a.two.columns.omega{ href: "#{main_app.edit_admin_enterprise_path(hub)}" } %span.icon-arrow-right - else - .four.columns.alpha.list-item - %span.three.columns.alpha + .sixteen.columns.alpha.list-item + %span.twelve.columns.alpha = t(:hub_sidebar_none_available) - %span.one.column.omega + %span.four.column.omega %span.icon-remove-sign - %a.four.columns.alpha.button{ href: "#{main_app.admin_enterprises_path}", class: "#{hubs_color}" } + %a.sixteen.columns.alpha.button{ href: "#{main_app.admin_enterprises_path}", class: "#{hubs_color}" } = t(:hub_sidebar_manage) %span.icon-arrow-right diff --git a/app/views/spree/layouts/_admin_body.html.haml b/app/views/spree/layouts/_admin_body.html.haml index 1f3dcce205..fc798d0fc3 100644 --- a/app/views/spree/layouts/_admin_body.html.haml +++ b/app/views/spree/layouts/_admin_body.html.haml @@ -19,9 +19,9 @@ = render :partial => 'spree/layouts/admin/login_nav' %nav#admin-menu{ data: { hook: '' }} - .container + .container.no-gutter .sixteen.columns.main-menu-wrapper - %ul.inline-menu.fullwidth-menu{"data-hook" => "admin_tabs"} + %ul.inline-menu{"data-hook" => "admin_tabs"} = render :partial => 'spree/admin/shared/tabs' - if content_for?(:sub_menu) diff --git a/app/views/spree/orders/form/_update_buttons.html.haml b/app/views/spree/orders/form/_update_buttons.html.haml index 476e7d23d6..012bfc9171 100644 --- a/app/views/spree/orders/form/_update_buttons.html.haml +++ b/app/views/spree/orders/form/_update_buttons.html.haml @@ -12,7 +12,7 @@ - if order.changes_allowed? .columns.show-for-medium-up.medium-3   .columns.small-12.medium-3 - = link_to spree.cancel_order_path(@order), method: :put, :class => "button secondary expand", "confirm-link-click" => t('orders_confirm_cancel') do + = link_to cancel_order_path(@order), method: :put, :class => "button secondary expand", "confirm-link-click" => t('orders_confirm_cancel') do %i.ofn-i_009-close = t(:cancel_order) .columns.small-12.medium-3 diff --git a/app/views/spree/shared/_order_details.html.haml b/app/views/spree/shared/_order_details.html.haml index f4861d8148..5735136d35 100644 --- a/app/views/spree/shared/_order_details.html.haml +++ b/app/views/spree/shared/_order_details.html.haml @@ -41,7 +41,7 @@ = t(:orders_changeable_orders_alert_html, oc_close: l(order.order_cycle.orders_close_at, format: "%b %d, %Y %H:%M")) %a.close{ "ng-click" => "close()" } × - = form_for order, html: {id: 'update-order', name: 'update_order_form' } do |order_form| + = form_for order, url: order_path(order), html: {id: 'update-order', name: 'update_order_form' } do |order_form| - if order.changes_allowed? = render 'spree/orders/form', order_form: order_form -else diff --git a/app/views/spree/users/show.html.haml b/app/views/spree/users/show.html.haml index bddce94ce9..6fa0d875e2 100644 --- a/app/views/spree/users/show.html.haml +++ b/app/views/spree/users/show.html.haml @@ -1,7 +1,8 @@ - content_for :injection_data do - = inject_orders - = inject_shops + = inject_json_array("orders", @orders.all, Api::OrderSerializer) + = inject_json_array("shops", @shops.all, Api::ShopForOrdersSerializer) = inject_saved_credit_cards + - if Stripe.publishable_key :javascript angular.module('Darkswarm').value("stripeObject", Stripe("#{Stripe.publishable_key}")) @@ -22,14 +23,14 @@ .row.tabset-ctrl#account-tabs{ style: 'margin-bottom: 100px', navigate: 'true', selected: 'orders', prefix: 'account' } .small.12.medium-3.columns.tab{ name: "orders" } - %a{ href: 'javascript:void(0)' }=t('.tabs.orders') + %a=t('.tabs.orders') - if Spree::Config.stripe_connect_enabled && Stripe.publishable_key .small.12.medium-3.columns.tab{ name: "cards" } - %a{ href: 'javascript:void(0)' }=t('.tabs.cards') + %a=t('.tabs.cards') .small.12.medium-3.columns.tab{ name: "transactions" } - %a{ href: 'javascript:void(0)' }=t('.tabs.transactions') + %a=t('.tabs.transactions') .small.12.medium-3.columns.tab{ name: "settings" } - %a{ href: 'javascript:void(0)' }=t('.tabs.settings') + %a=t('.tabs.settings') .small-12.columns.tab-view = render partial: "shared/footer" diff --git a/app/views/subscription_mailer/_summary_detail.html.haml b/app/views/subscription_mailer/_summary_detail.html.haml index 8f4bf7b906..9e99633dcb 100644 --- a/app/views/subscription_mailer/_summary_detail.html.haml +++ b/app/views/subscription_mailer/_summary_detail.html.haml @@ -6,7 +6,7 @@ - separator = messages.values.any? ? ": " : ", " - orders.each_with_index do |order, i| - %a{ href: spree.order_url(order) }>= order.number + %a{ href: order_url(order) }>= order.number = separator if messages.values.any? || i < orders.count - 1 - if messages.values.any? = messages[order.id] || t(".no_message_provided") @@ -17,5 +17,5 @@ %h4= t(".other.title", count: orders.count) %p= t(".other.explainer") - orders.each_with_index do |order, i| - %a{ href: spree.order_url(order) }>= order.number + %a{ href: order_url(order) }>= order.number = ", " if i < orders.count - 1 diff --git a/app/views/subscription_mailer/confirmation_email.html.haml b/app/views/subscription_mailer/confirmation_email.html.haml index 3af1ef2d21..5a8d4d4ded 100644 --- a/app/views/subscription_mailer/confirmation_email.html.haml +++ b/app/views/subscription_mailer/confirmation_email.html.haml @@ -6,7 +6,7 @@ - if @order.user.present? = t("email_so_edit_false_html", orders_close_at: l(@order.order_cycle.orders_close_at, format: mail_long_datetime_format), - order_url: spree.order_url(@order)) + order_url: order_url(@order)) = t("email_so_contact_distributor_html", distributor: @order.distributor.name, email: @order.distributor.contact.email) %p   diff --git a/app/views/subscription_mailer/failed_payment_email.html.haml b/app/views/subscription_mailer/failed_payment_email.html.haml index 36fa8d8741..275c2dbce5 100644 --- a/app/views/subscription_mailer/failed_payment_email.html.haml +++ b/app/views/subscription_mailer/failed_payment_email.html.haml @@ -5,7 +5,7 @@ - if @order.user.present? = t("email_so_edit_false_html", orders_close_at: l(@order.order_cycle.orders_close_at, format: mail_long_datetime_format), - order_url: spree.order_url(@order)) + order_url: order_url(@order)) = t("email_so_contact_distributor_html", distributor: @order.distributor.name, email: @order.distributor.contact.email) - if @order.errors.any? diff --git a/app/views/subscription_mailer/placement_email.html.haml b/app/views/subscription_mailer/placement_email.html.haml index 9acb8aa7a1..c146935fc3 100644 --- a/app/views/subscription_mailer/placement_email.html.haml +++ b/app/views/subscription_mailer/placement_email.html.haml @@ -8,7 +8,7 @@ - allow_changes = !!@order.distributor.allow_order_changes? = t("email_so_edit_#{allow_changes}_html", orders_close_at: l(@order.order_cycle.orders_close_at, format: mail_long_datetime_format), - order_url: spree.order_url(@order)) + order_url: order_url(@order)) = t("email_so_contact_distributor_html", distributor: @order.distributor.name, email: @order.distributor.contact.email) - else = t("email_so_contact_distributor_to_change_order_html", diff --git a/config/initializers/compass.rb b/config/initializers/compass.rb new file mode 100644 index 0000000000..ea537f0390 --- /dev/null +++ b/config/initializers/compass.rb @@ -0,0 +1,2 @@ +require 'compass' +Sass.load_paths << Compass::Frameworks['compass'].stylesheets_directory diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 75f99d1519..92502d8433 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -2318,6 +2318,8 @@ ar: payment_processing_failed: "لا يمكن معالجة الدفع ، يرجى التحقق من التفاصيل التي أدخلتها" payment_method_not_supported: "طريقة الدفع هذه غير مدعومة. يرجى اختيار واحد آخر." payment_updated: "تم تحديث الدفع" + cannot_perform_operation: "تعذر تحديث الدفع" + action_required: "الإجراء مطلوب" inventory_settings: "إعدادات المخزون" tag_rules: "قواعد الوسم" shop_preferences: "تفضيلات المتجر" @@ -2579,6 +2581,8 @@ ar: processing: "قيد المعالجة" void: "فارغ" invalid: "غير صالحة" + quantity_adjusted: "مخزون غير كافٍ. تم تحديث البند إلى الكمية القصوى المتاحة." + quantity_unchanged: "الكمية لم تتغير عن المبلغ السابق." resend_user_email_confirmation: resend: "إعادة إرسال" sending: "إعادة إرسال..." @@ -3565,6 +3569,10 @@ ar: subject: "تعليمات إعادة تعيين كلمة المرور" confirmation_instructions: subject: "يرجى تأكيد حسابك OFN" + payment_mailer: + authorize_payment: + subject: "يرجى تفويض الدفع الخاص بك إلى %{distributor} على OFN" + instructions: "يتطلب الدفع الخاص بك من %{amount} إلى %{distributor} مصادقة إضافية. الرجاء زيارة URL التالي لتفويض الدفع الخاص بك:" shipment_mailer: shipped_email: dear_customer: "عزيزي العميل،" diff --git a/config/locales/de_DE.yml b/config/locales/de_DE.yml index a4819724fa..dbfdd458ed 100644 --- a/config/locales/de_DE.yml +++ b/config/locales/de_DE.yml @@ -55,13 +55,13 @@ de_DE: activemodel: attributes: order_management/reports/enterprise_fee_summary/parameters: - start_at: "Start" + start_at: "Von" end_at: "Ende" distributor_ids: "Hubs" - producer_ids: "Erzeuger" + producer_ids: "Produzenten" order_cycle_ids: "Bestellzyklen" enterprise_fee_ids: "Gebührennamen" - shipping_method_ids: "Lieferart" + shipping_method_ids: "Lieferoption" payment_method_ids: "Zahlungsarten" errors: messages: @@ -73,7 +73,7 @@ de_DE: at_least_one_product: "^ Bitte fügen Sie mindestens ein Produkt hinzu" not_available: "^ %{name} ist im ausgewählten Zeitplan nicht verfügbar" ends_at: - after_begins_at: "Muss nach \"beginnt um\" sein " + after_begins_at: "muss nach \"Beginnt\" sein." customer: does_not_belong_to_shop: "gehört nicht zu %{shop}" schedule: @@ -88,15 +88,15 @@ de_DE: devise: confirmations: send_instructions: "Sie erhalten in einigen Minuten eine E-Mail mit Anweisungen zur Bestätigung Ihres Kontos." - failed_to_send: "Beim Senden der Bestätigungs-E-Mail ist ein Fehler aufgetreten." - resend_confirmation_email: "Bestätigungsmail erneut senden." + failed_to_send: "Beim Senden der E-Mail-Bestätigung ist ein Fehler aufgetreten." + resend_confirmation_email: "E-Mail-Bestätigung erneut senden." confirmed: "Danke für die Bestätigung Ihrer E-Mail-Adresse! Sie können sich jetzt einloggen." not_confirmed: "Ihre E-Mail-Adresse konnte nicht bestätigt werden. Vielleicht haben Sie diesen Schritt bereits abgeschlossen?" user_confirmations: spree_user: send_instructions: "Sie erhalten in einigen Minuten eine E-Mail mit Anweisungen zur Bestätigung Ihres Kontos." confirmation_sent: "E-Mail-Bestätigung gesendet" - confirmation_not_sent: "Fehler beim Senden der Bestätigungs-E-Mail" + confirmation_not_sent: "Fehler beim Senden der E-Mail-Bestätigung" user_registrations: spree_user: signed_up_but_unconfirmed: "Eine Nachricht mit einem Bestätigungslink wurde an Ihre E-Mail-Adresse gesendet. Bitte öffnen Sie den Link, um Ihr Konto zu aktivieren." @@ -135,7 +135,7 @@ de_DE: subject: "%{enterprise} ist jetzt auf %{sitename}" email_welcome: "Willkommen" email_registered: "ist jetzt Teil von" - email_userguide_html: "Das Benutzerhandbuch mit detaillierter Unterstützung für die Einrichtung Ihres Erzeugerprofils oder Ladens finden Sie hier: %{link}" + email_userguide_html: "Das Benutzerhandbuch mit detaillierter Unterstützung für die Einrichtung Ihres Profils, Produzentenladens oder Hubs finden Sie hier: %{link}" userguide: "Open Food Network Benutzerhandbuch" email_admin_html: "Sie können Ihr Konto verwalten, indem Sie sich direkt über den Link %{link} anmelden oder indem Sie sich auf der Startseite einloggen und im Menü \"Verwaltung\" auswählen." admin_panel: "Administrationsmenü" @@ -148,11 +148,11 @@ de_DE: subject: "Bestellzyklusbericht für %{producer}" shipment_mailer: shipped_email: - dear_customer: "Sehr geehrte Kundin, sehr geehrter Kunde," - instructions: "Ihre Bestellung wurde versandt" + dear_customer: "Liebe Kundin, lieber Kunde," + instructions: "deine Bestellung wurde versandt!" shipment_summary: "Übersicht" subject: "Versandbenachrichtigung" - thanks: "Danke für Ihren Einkauf." + thanks: "Danke für deinen Einkauf!" track_information: "Tracking-Informationen: %{tracking}" track_link: "Tracking-Link: %{url}" subscription_mailer: @@ -180,7 +180,7 @@ de_DE: explainer: Diese Bestellungen konnten nicht bearbeitet werden, da für die angeforderten Artikel kein Bestand verfügbar war complete: title: Bereits verarbeitet (%{count} Bestellungen) - explainer: Diese Bestellungen wurden bereits als vollständig markiert und daher nicht verändert + explainer: Diese Bestellungen wurden bereits als vollständig markiert und daher nicht verändert. processing: title: Fehler aufgetreten (%{count} Bestellungen) explainer: Die automatische Bearbeitung dieser Bestellungen ist aufgrund eines Fehlers fehlgeschlagen. Der Fehler wurde soweit möglich aufgelistet. @@ -194,7 +194,7 @@ de_DE: title: "Open Food Network" 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, dass ihre wöchentlichen Einkaufsentscheidungen ..." - search_by_name: Suche nach Ort oder Name des Ladens/Erzeugers... + search_by_name: Suche nach Ort oder Name des Ladens/Produzents... producers_join: 'Wir laden Deutsche Produzenten ein, jetzt dem Open Food Network beizutreten. ' charges_sales_tax: Berechnet Steuern? print_invoice: "Rechnung drucken" @@ -207,7 +207,7 @@ de_DE: ship_order: "Bestellung liefern" cancel_order: "Bestellung stornieren" confirm_send_invoice: "Eine Rechnung für diese Bestellung wird an den Kunden geschickt. Sind Sie sicher, dass sie fortfahren möchten?" - confirm_resend_order_confirmation: "Sind Sie sicher, dass Sie die Bestätigungs-E-Mail erneut senden wollen?" + confirm_resend_order_confirmation: "Sind Sie sicher, dass Sie die E-Mail-Bestätigung erneut senden wollen?" must_have_valid_business_number: "%{enterprise_name} sollte eine gültige Steuer-ID-Nummer haben, bevor die Rechnung gesendet wird." invoice: "Rechnung" more: "Mehr" @@ -215,9 +215,9 @@ de_DE: say_yes: "Ja" ongoing: Laufend bill_address: Rechnungsadresse - ship_address: Lieferanschrift + ship_address: Lieferadresse sort_order_cycles_on_shopfront_by: "Sortiere die Bestellzyklen des Ladens nach" - required_fields: Die erforderlichen Felder sind mit * markiert + required_fields: Pflichtangaben sind mit * markiert select_continue: Auswählen und fortfahren remove: Entfernen or: oder @@ -230,7 +230,7 @@ de_DE: cancel: Abbrechen edit: Bearbeiten clone: Duplizieren - distributors: Verteiler + distributors: Verteilstellen bulk_order_management: Massenbearbeitung von Bestellungen enterprises: Unternehmen enterprise_groups: Gruppen @@ -292,7 +292,7 @@ de_DE: resume: "Fortsetzen" save: "Speichern" edit: "Bearbeiten" - update: "Aktualisieren" + update: "Speichern" delete: "Löschen" add: "Hinzufügen" cut: "Ausschneiden" @@ -300,12 +300,12 @@ de_DE: destroy: "Zerstören" rename: "Umbenennen" admin: - begins_at: Beginnt um + begins_at: Beginnt begins_on: Beginnt am customer: Kunde date: Datum email: E-Mail - ends_at: Endet um + ends_at: Endet ends_on: Endet am name: Name on_hand: Verfügbar @@ -316,13 +316,13 @@ de_DE: payment_method: Zahlungsart phone: Telefonnummer price: Preis - producer: Erzeuger + producer: Produzent image: Bild product: Produkt quantity: Menge schedule: Zeitplan shipping: Versand - shipping_method: Lieferart + shipping_method: Lieferoption shop: Laden sku: Artikelnummer status_state: Status @@ -343,20 +343,20 @@ de_DE: cancel: Abrechen back: Zurück show_more: Mehr zeigen - show_n_more: '%{num} mehr zeigen' + show_n_more: Zeige %{num} weitere choose: "Auswählen ..." please_select: Bitte auswählen ... column_save_as_default: Als Standard speichern columns: Spalten actions: Aktionen - viewing: "Zeigt: %{current_view_name}" + viewing: "%{current_view_name}" description: Beschreibung whats_this: Was ist das? tag_has_rules: "Vorhandene Regeln für dieses Stichwort: %{num}" has_one_rule: "hat eine Regel" has_n_rules: "hat %{num} Regel(n)" unsaved_confirm_leave: "Es gibt ungespeicherte Änderungen auf dieser Seite. Möchten Sie ohne Speichern fortfahren?" - unsaved_changes: "Sie haben ungespeicherte Änderungen" + unsaved_changes: "Sie haben ungespeicherte Änderungen!" available_units: "Verfügbare Einheiten" shopfront_settings: embedded_shopfront_settings: "Eingebettete Ladeneinstellungen" @@ -408,15 +408,15 @@ de_DE: update_address_error: "Es tut uns leid! Bitte füllen Sie alle erforderlichen Felder aus!" edit_bill_address: "Rechnungsadresse bearbeiten" edit_ship_address: "Lieferadresse bearbeiten" - required_fileds: "Die erforderlichen Felder sind mit einem Sternchen gekennzeichnet." + required_fileds: "Pflichtangaben sind mit * markiert" select_country: "Land wählen" select_state: "Bundesland wählen" edit: "Bearbeiten" update_address: "Adresse aktualisieren" confirm_delete: "Sicher zu löschen?" search_by_email: "Suche nach E-Mail/Code" - guest_label: "Gäste Kasse" - credit_owed: "Gutschrift geschuldet" + guest_label: "Gasteinkauf" + credit_owed: "Geschuldetes Guthaben" balance_due: "Restbetrag fällig" destroy: has_associated_orders: "Löschen fehlgeschlagen: Kunde hat Bestellungen mit diesem Laden" @@ -425,9 +425,9 @@ de_DE: title: Inhalt header: Header home_page: Homepage - producer_signup_page: Hersteller-Anmeldeseite + producer_signup_page: Anmeldung für Produzenten hub_signup_page: Hubregistrierseite - group_signup_page: Gruppen-Anmeldeseite + group_signup_page: Anmeldung für Gruppen main_links: Hauptmenü-Links footer_and_external_links: Fußzeile und externe Links your_content: Ihr Inhalt @@ -440,8 +440,8 @@ de_DE: fee_type: "Art der Gebühr" name: "Name" tax_category: "Steuerkategorie" - calculator: "Rechner" - calculator_values: "Werte des Rechners" + calculator: "Art der Berechnung" + calculator_values: "Werte zur Berechnung" search: "Suche" name_placeholder: "z.B. Verpackungsgebühr" enterprise_groups: @@ -453,26 +453,26 @@ de_DE: enterprise_role: manages: verwaltet products: - unit_name_placeholder: 'z.B. Bündel' + unit_name_placeholder: 'z. B. Bündel' index: unit: Einheit display_as: Angezeigt als category: Produktkategorie tax_category: Steuerkategorie - inherits_properties?: Vererbt Eigenschaften + inherits_properties?: Übernimmt Eigenschaften des Ladens? available_on: Verfügbar am av_on: "Verfüg. am" import_date: Importiert upload_an_image: Bild hochladen seo: 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." + product_search_tip: "Geben Sie Stichwörter ein, damit Ihre Produkte in den Läden besser gefunden werden. Trennen Sie mehrere Stichwörter voneinander mit Leerzeichen." + SEO_keywords: "Stichwörter für die Suche im Internet" + seo_tip: "Geben Sie Stichwörter ein, damit Ihre Produkte im Internet besser gefunden werden. Trennen Sie mehrere Stichwörter voneinander mit Leerzeichen." search: "Suche" properties: property_name: "Name der Eigenschaft" - inherited_property: "Vererbte Eigenschaft" + inherited_property: "Übernommene Eigenschaft des Ladens" variants: infinity: "Unendlichkeit" to_order_tip: "Artikel, die auf Bestellung hergestellt werden, haben keinen festgelegten Lagerbestand." @@ -506,20 +506,20 @@ de_DE: unexpected_error: "Beim Produktimport ist beim Öffnen der Datei ein unerwarteter Fehler aufgetreten: %{error_message}" malformed_csv: "Beim Produktimport ist eine fehlerhafte CSV aufgetreten: %{error_message}" index: - notice: "Beachten" + notice: "HINWEIS" beta_notice: "Diese Funktion befindet sich noch in der Beta-Phase: Während der Verwendung können Fehler auftreten. Bitte zögern Sie nicht, den Support zu kontaktieren." - select_file: Wählen Sie eine Tabelle zum Hochladen + select_file: 'Wählen Sie eine Tabelle zum Hochladen:' spreadsheet: Kalkulationstabelle - choose_import_type: Wählen Sie die Importart + choose_import_type: 'Wählen Sie die Importart:' import_into: Importart product_list: Produktliste inventories: Kataloge 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_list_template: Produktlistenvorlage herunterladen + inventory_template: Katalogvorlage herunterladen + category_values: Verfügbare Kategorien product_categories: Produktkategorien tax_categories: Steuerkategorien shipping_categories: Versandkategorien @@ -541,8 +541,8 @@ de_DE: not_found: Unternehmen konnte nicht in der Datenbank gefunden werden no_name: Kein Name blank_enterprise: Für einige Produkte ist kein Unternehmen definiert - reset_absent?: Fehlende Produkte zurücksetzen - reset_absent_tip: Den Bestand für alle nicht in der Datei vorhandenen Produkte auf Null setzen + reset_absent?: Fehlende Produkte zurücksetzen? + reset_absent_tip: Den Lagerbestand für alle nicht in der Datei vorhandenen Produkte auf Null setzen. overwrite_all: Alles überschreiben overwrite_empty: Überschreiben, wenn leer default_stock: Lagerbestand setzen @@ -584,22 +584,22 @@ de_DE: loading_inventory: KATALOG WIRD GELADEN index: 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 + description: Verwenden Sie diese Seite, um die Produktbestände Ihrer Unternehmen zu verwalten. Alle hier eingestellten Produktdetails überschreiben diejenigen, die auf der Seite "Produkte" eingestellt sind. enable_reset?: Lagerbestand zurücksetzbar? default_stock: "Standardbestand" - inherit?: Übernehmen? + inherit?: Eigenschaften übernehmen? add: Hinzufügen hide: Verbergen import_date: Importiert 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 + 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 ausgeblendet - no_matching_hidden_products: Keine ausgeblendeten 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 + no_hidden_products: In diesem Katalog wurden keine Produkte ausgeblendet. + no_matching_hidden_products: Keine ausgeblendeten Produkte entsprechen Ihren Suchkriterien. + no_new_products: Es sind keine neuen Produkte verfügbar, die in den Katalog aufgenommen werden könnten. + no_matching_new_products: Keine neuen Produkte entsprechen Ihren Suchkriterien. 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 ausgeblendet und können nicht zu 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 "Verbergen", um es aus der Ansicht auszublenden. Sie können Ihre Meinung später immer ändern! @@ -637,21 +637,21 @@ de_DE: index: title: Unternehmen new_enterprise: Neues Unternehmen - producer?: "Erzeuger?" + producer?: "Produzent?" package: Paket status: Status manage: Verwalten form: about_us: - desc_short: Kurze Beschreibung - desc_short_placeholder: Schreiben Sie etwas in ein oder zwei Sätzen über Ihr Unternehmen + desc_short: Kurzbeschreibung + desc_short_placeholder: Schreiben Sie etwas in ein oder zwei Sätzen über Ihr Unternehmen. desc_long: Über uns desc_long_placeholder: Schreiben Sie etwas über sich. Diese Information wird in Ihrem öffentlichen Profil angezeigt. business_details: abn: USt-IdNr. - abn_placeholder: z.B. DE999999999 + abn_placeholder: z. B. DE999999999 acn: St.-Nr. - acn_placeholder: z.B. 93815/08152 + acn_placeholder: z. B. 93815/08152 display_invoice_logo: Logo in Rechnungen anzeigen invoice_text: Fügen Sie benutzerdefinierten Text am Ende der Rechnungen hinzu terms_and_conditions: "Geschäftsbedingungen" @@ -659,14 +659,14 @@ de_DE: uploaded_on: "hochgeladen am" contact: name: Name - name_placeholder: z.B. Gustav Pflaume + name_placeholder: z. B. Gustav Pflaume email_address: Öffentliche E-Mail-Adresse - email_address_placeholder: z.B. anfragen@fresh-food.com - email_address_tip: "Diese E-Mail-Adresse wird in Ihrem öffentlichen Profil angezeigt" + email_address_placeholder: z. B. anfragen@fresh-food.com + email_address_tip: "Diese E-Mail-Adresse wird in Ihrem öffentlichen Profil angezeigt." phone: Telefon - phone_placeholder: z.B. 98 7654 3210 + phone_placeholder: z. B. 98 7654 3210 website: Webseite - website_placeholder: z.B. www.truffles.com + website_placeholder: z. B. www.truffles.com enterprise_fees: name: Name fee_type: Art der Gebühr @@ -675,10 +675,10 @@ de_DE: create_button: Erstelle jetzt eine images: logo: Logo - promo_image_placeholder: 'Dieses Bild wird in "Über uns" angezeigt' + promo_image_placeholder: 'Dieses Bild wird in "Über uns" angezeigt.' promo_image_note1: 'BITTE BEACHTEN SIE:' - promo_image_note2: Jedes hier hochgeladene Werbebild wird auf 1200 x 260 beschnitten. - promo_image_note3: Das Werbebild wird oben auf der Profilseite eines Unternehmens und in Pop-ups angezeigt. + promo_image_note2: Das hier hochgeladene Bild wird auf 1200 x 260 Pixel beschnitten. + promo_image_note3: Das Bild wird oben auf der Profilseite Ihres Unternehmens und in Pop-ups angezeigt. remove_logo: "Bild entfernen" remove_promo_image: "Bild entfernen" inventory_settings: @@ -691,23 +691,23 @@ de_DE: nicht zur Verwaltung Ihrer Produkte verwenden, sollten Sie die folgende "empfohlene" 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 + preferred_product_selection_from_inventory_only_no: Neue Produkte müssen zu meinem Katalog hinzugefügt werden, bevor sie in meinem Laden angeboten werden können payment_methods: name: Name - applies: Gilt? + applies: Aktiv? manage: Zahlungsarten verwalten no_method_yet: Sie haben noch keine Zahlungsarten create_button: Neue Zahlungsart create_one_button: Erstelle jetzt eine primary_details: name: Name - name_placeholder: z.B. Professor Plums biodynamische Trüffel + name_placeholder: z. B. Professor Plums biodynamische Trüffel groups: Gruppen groups_tip: Wählen Sie beliebige Gruppen oder Regionen aus, bei denen Sie Mitglied sind. Dies hilft Kunden, Ihr Unternehmen zu finden. groups_placeholder: Beginnen Sie mit der Eingabe, um nach verfügbaren Gruppen zu suchen ... - primary_producer: Erzeuger? - primary_producer_tip: Wählen Sie "Erzeuger", wenn Sie ein Erzeuger von Lebensmitteln sind. - producer: Erzeuger + primary_producer: Produzent? + primary_producer_tip: Wählen Sie "Produzent", wenn Sie eigene Produkte herstellen und diese über das Open Food Network verkaufen möchten. + producer: Produzent any: Alle none: Keine own: Eigene @@ -726,55 +726,55 @@ de_DE: shipping_methods: name: "Name" applies: "Aktiv?" - manage: "Lieferarten verwalten" - create_button: "Neue Lieferart erstellen" + manage: "Lieferoptionen verwalten" + create_button: "Neue Lieferoption" create_one_button: "Erstelle jetzt eine" - no_method_yet: "Sie haben noch keine Lieferarten angelegt." + no_method_yet: "Sie haben noch keine Lieferoptionen angelegt." shop_preferences: shopfront_requires_login: "Öffentlich sichtbarer Laden?" shopfront_requires_login_tip: "Wählen Sie aus, ob sich Kunden einloggen müssen, um den Laden zu sehen oder ob er für alle sichtbar ist." shopfront_requires_login_false: "Öffentlich" shopfront_requires_login_true: "Nur für registrierte Nutzer sichtbar" recommend_require_login: "Wenn Bestellungen nachträglich geändert werden dürfen, empfehlen wir Einkauf nur für eingeloggte Nutzer." - allow_guest_orders: "Gast Einkauf" - allow_guest_orders_tip: "Gasteinkauf erlauben oder nur für eingeloggte Nutzer" + allow_guest_orders: "Gasteinkauf" + allow_guest_orders_tip: "Wählen Sie aus, ob nich eingeloggte Kunden als Gäste einkaufen dürfen oder ob nur eingeloggten Nutzern der Einkauf möglich ist." allow_guest_orders_false: "Einkauf nur für eingeloggte Nutzer" allow_guest_orders_true: "Gasteinkauf erlauben" allow_order_changes: "Bestellungen nachträglich ändern" - allow_order_changes_tip: "Kunden erlauben, ihre Bestellung zu ändern, solange der Bestellzyklus offen ist." - allow_order_changes_false: "Bestellungen können nicht geändert/storniert werden" + allow_order_changes_tip: "Wählen Sie aus, ob Kunden ihre Bestellung ändern können, solange der Bestellzyklus geöffnet ist." + allow_order_changes_false: "Bestellungen können nicht geändert oder storniert werden" allow_order_changes_true: "Kunden können Bestellungen ändern oder stornieren, während der Bestellzyklus geöffnet ist" enable_subscriptions: "Abonnements" - enable_subscriptions_tip: "Abo-Funktionalität aktivieren?" + enable_subscriptions_tip: "Aktivieren Sie Abonnements, um Kunden eine automatische, regelmäßige Bestellung Ihrer Produkte einzurichten. Dies kann z. B. das Abonnement einer wöchentlichen Gemüsekiste sein." enable_subscriptions_false: "deaktiviert" enable_subscriptions_true: "aktiviert" customer_names_in_reports: "Kundennamen in Berichten" - customer_names_tip: "Ermöglichen Sie Ihren Lieferanten, die Namen Ihrer Kunden in Berichten anzuzeigen" + customer_names_tip: "Ermöglichen Sie Ihren Lieferanten, die Namen Ihrer Kunden in Berichten anzuzeigen." customer_names_false: "deaktiviert" customer_names_true: "aktiviert" shopfront_message: "'Willkommen'-Nachricht im Laden" shopfront_message_placeholder: > Eine optionale Nachricht, um Kunden willkommen zu heißen und zu erklären, wie Sie bei Ihnen einkaufen können. Wenn hier Text eingegeben wird, - wird dieser in einem Home-Tab in Ihrem Laden angezeigt, wenn Kunden + wird dieser auf einer Startseite in Ihrem Laden angezeigt, wenn Kunden ihn zum ersten Mal besuchen. shopfront_message_link_tooltip: "Link einfügen/bearbeiten" shopfront_message_link_prompt: "Bitte geben Sie die einzufügende URL ein:" - shopfront_closed_message: "'Laden geschlossen'-Nachricht" + shopfront_closed_message: "'Laden geschlossen'-Nachricht im Laden" shopfront_closed_message_placeholder: > Eine Nachricht, die eine detailliertere Erklärung liefert, warum Ihr 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. der Laden ist geschlossen). - shopfront_category_ordering: "Ordnung der Produktkategorien im Laden" + gerade keine aktiven Bestellzyklen haben. + shopfront_category_ordering: "Sortierung der Produktkategorien im Laden" shopfront_category_ordering_note: "(oben nach unten)" open_date: "Öffnungsdatum" - close_date: "Abschlussdatum" + close_date: "Schließdatum" social: - twitter_placeholder: "z.B. @the_prof" - instagram_placeholder: "z.B. the_prof" - facebook_placeholder: "z.B. www.facebook.com/PageNameHere" - linkedin_placeholder: "z.B. www.linkedin.com/in/IhrNameHier" + twitter_placeholder: "z. B. @the_prof" + instagram_placeholder: "z. B. the_prof" + facebook_placeholder: "z. B. www.facebook.com/PageNameHere" + linkedin_placeholder: "z. B. www.linkedin.com/in/IhrNameHier" stripe_connect: connect_with_stripe: "Stripe integrieren" stripe_connect_intro: "Um Zahlungen mit Kreditkarte zu akzeptieren, müssen Sie Ihr Stripe-Konto mit dem Open Food Network verbinden. Verwenden Sie den Knopf rechts, um loszulegen." @@ -791,28 +791,28 @@ de_DE: default_rules: by_default: Standardmäßig no_rules_yet: Es gelten noch keine Standardregeln. - add_new_button: '+ Fügen Sie eine neue Standardregel hinzu' + add_new_button: 'neue Standardregel +' no_tags_yet: Für dieses Unternehmen sind noch keine Stichwörter vorhanden. no_rules_yet: Für dieses Stichwort gelten noch keine Regeln. for_customers_tagged: 'Für Kunden mit dem Stichwort:' add_new_rule: '+ Neue Regel hinzufügen' add_new_tag: '+ Neues Stichwort hinzufügen' users: - email_confirmation_notice_html: "E-Mail-Bestätigung steht aus. Wir haben eine Bestätigungs-E-Mail an %{email} gesendet." + email_confirmation_notice_html: "E-Mail-Bestätigung steht aus. Wir haben eine E-Mail an %{email} gesendet." resend: Erneut senden owner: 'Inhaber' contact: "Kontakt" - contact_tip: "Der Manager, der Enterprise-E-Mails für Bestellungen und Benachrichtigungen erhält. Muss eine bestätigte E-Mail-Adresse haben." + contact_tip: "Der Manager, der Unternehmens-E-Mails für Bestellungen und Benachrichtigungen erhält. Er muss eine bestätigte E-Mail-Adresse haben." owner_tip: Der Hauptnutzer, der für dieses Unternehmen verantwortlich ist. notifications: Benachrichtigungen notifications_tip: Benachrichtigungen über Bestellungen werden an diese E-Mail-Adresse gesendet. - notifications_placeholder: z.B. lisa@maier.de + notifications_placeholder: z. B. lisa@maier.de notifications_note: 'Hinweis: Eine neue E-Mail-Adresse muss möglicherweise vor der Verwendung bestätigt werden' managers: Manager managers_tip: Andere Benutzer mit der Berechtigung, dieses Unternehmen zu verwalten. invite_manager: "Manager einladen" invite_manager_tip: "Laden Sie einen nicht registrierten Benutzer ein, sich anzumelden und ein Manager dieses Unternehmens zu werden." - add_unregistered_user: "Fügen Sie einen nicht registrierten Benutzer hinzu" + add_unregistered_user: "Laden Sie einen nicht registrierten Benutzer ein" email_confirmed: "E-Mail bestätigt" email_not_confirmed: "E-Mail nicht bestätigt" actions: @@ -820,35 +820,35 @@ de_DE: properties: Eigenschaften payment_methods: Zahlungsarten payment_methods_tip: Dieses Unternehmen hat keine Zahlungsarten - shipping_methods: Lieferarten - shipping_methods_tip: Dieses Unternehmen hat Lieferarten + shipping_methods: Lieferoptionen + shipping_methods_tip: Dieses Unternehmen hat Lieferoptionen enterprise_fees: Unternehmensgebühren - enterprise_fees_tip: Dieses Unternehmen hat keine Gebühren + enterprise_fees_tip: Dieses Unternehmen hat keine Gebühren. admin_index: name: Name role: Rolle sells: vertreibt visible: Sichtbar? owner: Inhaber - producer: Erzeuger + producer: Produzent change_type_form: - producer_profile: Erzeugerprofil + producer_profile: Profil connect_ofn: Stellen Sie sich und Ihre Produkte vor always_free: IMMER KOSTENLOS - producer_description_text: "Stellen Sie sich und Ihre Produkte im Open Food Network vor und vernetzen Sie sich mit anderen Erzeugern und Läden. \nFügen Sie Ihre Produkte dem Profil hinzu, damit andere Läden sie zum Verkauf anbieten können. Wenn Sie Ihre Produkte selbst verkaufen möchten, wählen Sie \"Erzeugerladen\"." - producer_shop: Erzeugerladen + producer_description_text: "Stellen Sie sich und Ihre Produkte im Open Food Network vor und vernetzen Sie sich mit anderen Produzenten und Läden. \nFügen Sie Ihre Produkte dem Profil hinzu, damit andere Läden sie zum Verkauf anbieten können. Wenn Sie Ihre Produkte selbst verkaufen möchten, wählen Sie \"Produzentenladen\"." + producer_shop: Produzentenladen sell_your_produce: Verkaufen Sie Ihre eigenen Produkte - producer_shop_description_text: Verkaufen Sie Ihre eigenen Produkte direkt an Ihre Kunden durch Ihren eigenen Erzeugerladen 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_shop_description_text: Verkaufen Sie Ihre eigenen Produkte direkt an Ihre Kunden durch Ihren eigenen Produzentenladen im Open Food Network. + producer_shop_description_text2: Ein Produzentenladen ist nur für Ihre eigenen Produkte bestimmt. Wenn Sie Produkte anderer verkaufen möchten, wählen Sie "Hub". producer_hub: Hub producer_hub_text: Verkaufen Sie eigene Produkte und Produkte anderer - producer_hub_description_text: Verkaufen Sie eigene Produkte und Produkte anderer Erzeuger oder Läden im Open Food Network. Mit Ihrem Laden sind Sie ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. - profile: Nur Profil + producer_hub_description_text: Verkaufen Sie eigene Produkte und Produkte anderer Produzenten oder Läden im Open Food Network. Mit Ihrem Laden sind Sie ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. + profile: Profil get_listing: Erstellen Sie einen Eintrag - profile_description_text: Sie können im Open Food Network gefunden und kontaktiert werden. Ihr Unternehmen wird auf der Karte und in Suchergebnissen angezeigt. + profile_description_text: Stellen Sie sich im Open Food Network vor und vernetzen Sie sich mit anderen Produzenten und Läden. Sie können im Open Food Network gefunden und kontaktiert werden. Ihr Unternehmen wird auf der Karte und in Suchergebnissen angezeigt. hub_shop: Hub hub_shop_text: Verkaufen Sie Produkte anderer - hub_shop_description_text: Verkaufen Sie Produkte anderer Erzeuger oder Läden im Open Food Network. Als Händler führen Sie die Produkte zusammen und sind mit Ihrem Laden ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. + hub_shop_description_text: Verkaufen Sie Produkte anderer Produzenten oder Läden im Open Food Network. Sie führen die Produkte zusammen und sind mit Ihrem Laden ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. choose_option: Bitte wählen Sie eine der oben aufgeführten Optionen. change_now: Jetzt ändern enterprise_user_index: @@ -857,13 +857,13 @@ de_DE: search_placeholder: Suche nach Name manage: Verwalten manage_link: Einstellungen - producer?: "Erzeuger?" + producer?: "Produzent?" package: "Paket" status: "Status" new_form: owner: Inhaber owner_tip: Der Hauptnutzer, der für dieses Unternehmen verantwortlich ist. - i_am_producer: Ich bin ein Erzeuger + i_am_producer: Ich bin ein Produzent contact_name: Kontaktname edit: editing: 'Einstellungen:' @@ -877,7 +877,7 @@ de_DE: next_step: Nächster Schritt choose_starting_point: 'Wählen Sie Ihr Paket:' profile: 'Profil' - producer_profile: 'Erzeugerprofil' + producer_profile: 'Profil' invite_manager: user_already_exists: "Benutzer existiert bereits" error: "Etwas ist schief gelaufen" @@ -902,7 +902,7 @@ de_DE: incoming: "Eingehend" supplier: "Lieferant" products: "Produkte" - receival_details: "Empfangsdetails" + receival_details: "Information an Lieferanten" fees: "Gebühren" save: "Speichern" save_and_next: "Speichern und weiter" @@ -911,7 +911,7 @@ de_DE: back_to_list: "Zurück zur Liste" outgoing: outgoing: "Ausgehend" - distributor: "Verteiler" + distributor: "Verteilstelle" products: "Produkte" tags: "Stichwörter" delivery_details: "Lieferdetails" @@ -926,20 +926,20 @@ de_DE: incoming: "2. Eingehende Produkte" outgoing: "3. Ausgehende Produkte" exchange_form: - pickup_time_tip: Wenn Bestellungen dieses Bestellzylus für den Kunden bereit sind + pickup_time_tip: Datum und Uhrzeit, ab wann Bestellungen dieses Bestellzylus für den Kunden bereit sind. pickup_instructions_placeholder: "Abholungsinformationen" - pickup_instructions_tip: Diese Informationen werden Kunden nach Abschluss einer Bestellung angezeigt - pickup_time_placeholder: "Bereit für (d.h. Datum/Uhrzeit)" + pickup_instructions_tip: Diese Informationen werden Kunden nach Abschluss einer Bestellung angezeigt. + pickup_time_placeholder: "Fertig am (d. h. Datum/Uhrzeit)" receival_instructions_placeholder: "Lieferinformation" add_fee: 'Gebühr hinzufügen' remove: 'Entfernen' selected: 'ausgewählt' add_exchange_form: add_supplier: 'Lieferant hinzufügen' - add_distributor: 'Verteiler hinzufügen' + add_distributor: 'Verteilstelle hinzufügen' advanced_settings: title: Erweiterte Einstellungen - choose_product_tip: Sie können den Wareneingang und -ausgang auf den Bestand von nur %{inventory} beschränken. + choose_product_tip: Sie können die eingehenden und ausgehenden Produkte auf den Katalog nur 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 @@ -957,7 +957,7 @@ de_DE: receival_details: Lieferinformation fees: Gebühren outgoing: Ausgehend - distributor: Verteiler + distributor: Verteilstelle products: Produkte tags: Stichwörter add_a_tag: Stichwort hinzufügen @@ -967,13 +967,13 @@ de_DE: schedules: Zeitpläne new_schedule: Neuer Zeitplan name_and_timing_form: - name: Name - orders_open: Bestellzyklus öffnet um + name: Name des Bestellzyklus + orders_open: Bestellzyklus öffnet coordinator: Koordinator - orders_close: Bestellungen schließen + orders_close: Bestellzyklus schließt row: suppliers: Lieferanten - distributors: Verteiler + distributors: Verteilstellen variants: Varianten simple_form: ready_for: Bereit am @@ -993,7 +993,7 @@ de_DE: proceed: Fortfahren producer_properties: index: - title: Erzeugereigenschaften + title: Produzenteneigenschaften proxy_orders: cancel: could_not_cancel_the_order: Die Bestellung konnte nicht storniert werden @@ -1005,22 +1005,22 @@ de_DE: enterprises_hubs_tabs: has_no_payment_methods: "%{enterprise} hat keine Zahlungsarten" has_no_shipping_methods: "%{enterprise} hat keine Versandarten" - has_no_enterprise_fees: "%{enterprise} hat keine Zuschläge" + has_no_enterprise_fees: "%{enterprise} hat keine Gebühren." enterprise_issues: create_new: Erstellen resend_email: E-Mail erneut senden - has_no_payment_methods: "%{enterprise}hat derzeit keine Zahlungsarten" - has_no_shipping_methods: "%{enterprise} hat derzeit keine Versandarten" - email_confirmation: "E-Mail-Bestätigung steht aus. Wir haben eine Bestätigungs-E-Mail an %{email} gesendet." - not_visible: "%{enterprise} ist nicht sichtbar und kann daher nicht auf der Karte oder in Suchen gefunden werden" + has_no_payment_methods: "%{enterprise}hat derzeit keine Zahlungsarten!" + has_no_shipping_methods: "%{enterprise} hat derzeit keine Versandarten!" + email_confirmation: "E-Mail-Bestätigung steht aus. Wir haben eine E-Mail an %{email} gesendet." + not_visible: "%{enterprise} ist nicht sichtbar und kann daher nicht auf der Karte oder in Suchen gefunden werden!" reports: hidden: Ausgeblendet unitsize: EINHEIT total: SUMME total_items: GESAMTANZAHL - supplier_totals: Lieferanten-Gesamtsummen - supplier_totals_by_distributor: Lieferanten-Gesamtsummen nach Verteiler - totals_by_supplier: Verteiler-Gesamtsummen nach Lieferanten + supplier_totals: Lieferantengesamtsummen + supplier_totals_by_distributor: Lieferantengesamtsummen nach Verteilstelle + totals_by_supplier: Verteilstellengesamtsummen nach Lieferanten customer_totals: Kundengesamtsummen all_products: Alle Produkte inventory: Aktueller Bestand @@ -1034,8 +1034,8 @@ de_DE: pack_by_customer: Packliste nach Kunde pack_by_supplier: Packliste nach Lieferanten orders_and_distributors: - name: Bestellungen und Verteiler - description: Bestellungen mit Verteilerdetails + name: Bestellungen und Verteilstellen + description: Bestellungen mit Verteilstellendetails bulk_coop: name: Massen-Co-Op description: Berichte für Massen-Co-Op-Bestellungen @@ -1062,7 +1062,7 @@ de_DE: name: Packberichte enterprise_fee_summary: name: "Unternehmensgebühr Zusammenfassung" - description: "Zusammenfassung der erhobenen Zuschläge" + description: "Zusammenfassung der erhobenen Gebühren" subscriptions: index: title: "Abonnements" @@ -1084,14 +1084,14 @@ de_DE: 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: Erstellen Sie %{shipping_link}und %{payment_link} + set_up_shipping_and_payment_methods_html: Erstellen Sie %{shipping_link}optionen und %{payment_link}sarten set_up_shipping_and_payment_methods_note_html: Beachten Sie, dass nur Bar- und Stripe-Zahlungsarten für Abonnements verwendet werden dürfen ensure_at_least_one_customer_html: Stellen Sie sicher, dass mindestens ein %{customer_link} vorhanden ist create_at_least_one_schedule: Erstellen Sie mindestens einen Zeitplan - create_at_least_one_schedule_step_1_html: 1. Gehen Sie auf die Seite %{order_cycles_link} - create_at_least_one_schedule_step_2: 2. Erstellen Sie einen Bestellzyklus, falls Sie dies noch nicht getan haben - create_at_least_one_schedule_step_3: 3. Klicken Sie auf "+ Neuer Zeitplan" und füllen Sie das Formular aus - once_you_are_done_you_can_html: Sobald Sie fertig sind, können Sie %{reload_this_page_link} + create_at_least_one_schedule_step_1_html: 1. Gehen Sie auf die Seite %{order_cycles_link}. + create_at_least_one_schedule_step_2: 2. Erstellen Sie einen Bestellzyklus, falls Sie dies noch nicht getan haben. + create_at_least_one_schedule_step_3: 3. Klicken Sie auf "+ Neuer Zeitplan" und füllen Sie das Formular aus. + once_you_are_done_you_can_html: Sobald Sie fertig sind, können Sie %{reload_this_page_link}. reload_this_page: diese Seite neu laden form: create: "Abonnement erstellen" @@ -1106,7 +1106,7 @@ de_DE: Wenn Sie die Preise oder Gebühren ändern, werden die Bestellungen aktualisiert, aber das Abonnement zeigt weiterhin die alten Werte an. not_in_open_and_upcoming_order_cycles_warning: "Für dieses Produkt gibt es keine offenen oder bevorstehenden Bestellzyklen." autocomplete: - name_or_sku: "NAME ODER SKU" + name_or_sku: "NAME ODER ARTIKELNUMMER" quantity: "Menge" add: "Hinzufügen" details: @@ -1130,7 +1130,7 @@ de_DE: save: "SPEICHERN" saving: "SPEICHERN" saved: "GESPEICHERT" - product_already_in_order: Dieses Produkt wurde bereits zur Bestellung hinzugefügt. Bitte änderns Sie stattdessen die Menge. + product_already_in_order: Dieses Produkt wurde bereits zur Bestellung hinzugefügt. Bitte ändern Sie stattdessen die Menge. stock: insufficient_stock: "Unzureichender Bestand verfügbar" out_of_stock: "Nicht vorrättig" @@ -1150,8 +1150,8 @@ de_DE: yes_i_am_sure: Ja, ich bin mir sicher order_update_issues_msg: Einige Bestellungen konnten nicht automatisch aktualisiert werden. Dies liegt wahrscheinlich daran, dass sie manuell bearbeitet wurden. Bitte überprüfen Sie die unten aufgeführten Punkte und nehmen Sie gegebenenfalls Anpassungen an einzelnen Bestellungen vor. no_results: - no_subscriptions: Noch keine Abonnements - why_dont_you_add_one: Vielleicht welche hinzufügen? :) + no_subscriptions: Bisher gibt es noch keine Abonnements. + why_dont_you_add_one: Warum fügen Sie nicht einige hinzu? no_matching_subscriptions: Keine passenden Abonnements gefunden schedules: destroy: @@ -1194,7 +1194,7 @@ de_DE: edit_cart: "Warenkorb bearbeiten" items_in_cart_singular: "%{num} Artikel in Ihrem Warenkorb" items_in_cart_plural: "%{num} Artikel in Ihrem Warenkorb" - close: "Abschließen" + close: "Schließen" cart_empty: "Ihr Warenkorb ist leer" take_me_shopping: "Bring mich einkaufen!" signed_in: @@ -1208,7 +1208,7 @@ de_DE: 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 Dienstleistern verarbeitet." footer_contact_headline: "In Verbindung bleiben" - footer_contact_email: "Schreiben Sie uns eine E-Mail" + footer_contact_email: "Schreiben Sie uns eine E-Mail!" footer_nav_headline: "Navigieren" footer_join_headline: "Mitmachen" footer_join_body: "Erstellen Sie einen Eintrag, einen Laden oder ein Gruppenverzeichnis im Open Food Network." @@ -1257,7 +1257,7 @@ de_DE: abn: "USt-IdNr." acn: "St.-Nr." invoice_issued_on: "Rechnung ausgestellt am:" - order_number: "Rechnungsnummer:" + order_number: "Rechnungsnummer" date_of_transaction: "Datum der Transaktion:" ticket_column_qty: "Menge" ticket_column_item: "Artikel" @@ -1267,7 +1267,7 @@ de_DE: menu_1_url: "/shops" menu_2_title: "Karte" menu_2_url: "/map" - menu_3_title: "Erzeuger" + menu_3_title: "Produzenten" menu_3_url: "/producers" menu_4_title: "Gruppen" menu_4_url: "/groups" @@ -1296,16 +1296,16 @@ de_DE: name: Name first_name: Vorname last_name: Nachname - email: 'E-Mail:' + email: E-Mail phone: Telefonnummer next: Nächste - address: Straße + Hausnummer - address_placeholder: z.B. Gartenstraße 123 - address2: Adresse (Fortsetzung) + address: Adresse + address_placeholder: z. B. Gartenstraße 123 + address2: Adresszusatz (optional) city: Ort - city_placeholder: z.B. Nordwestheim + city_placeholder: z. B. Nordwestheim postcode: Postleitzahl - postcode_placeholder: z.B. 30701 + postcode_placeholder: z. B. 30701 suburb: Vorort state: Bundesland country: Land @@ -1314,7 +1314,7 @@ de_DE: on_demand: Auf Anfrage none: Keine not_allowed: Nicht erlaubt - no_shipping: keine Lieferarten + no_shipping: keine Lieferoptionen no_payment: keine Zahlungsarten no_shipping_or_payment: keine Versand- oder Zahlungsarten unconfirmed: unbestätigt @@ -1323,8 +1323,8 @@ de_DE: label_shop: "Laden" label_shops: "Läden" label_map: "Karte" - label_producer: "Erzeuger" - label_producers: "Erzeuger" + label_producer: "Produzent" + label_producers: "Produzenten" label_groups: "Gruppen" label_about: "Über" label_connect: "Verbinde" @@ -1343,7 +1343,7 @@ de_DE: label_notices: "Bemerkungen" cart_items: "Artikel" cart_headline: "Ihr Warenkorb" - total: "Total" + total: "Summe" cart_updating: "Warenkorb wird aktualisiert ..." cart_empty: "Warenkorb leer" cart_edit: "Warenkorb bearbeiten" @@ -1409,8 +1409,8 @@ de_DE: cookies_accept_button: "Cookies akzeptieren" home_shop: Jetzt einkaufen brandstory_headline: "Lebensmittel Direktvermarktung" - brandstory_intro: "Manchmal ist der beste Weg, das System zu reparieren, ein neues aufzubauen ..." - brandstory_part1: "Wir beginnen von Grund auf. Mit Bauern und Züchtern, die bereit sind, ihre Geschichten stolz und wahrhaftig zu erzählen. Mit Händlern, die bereit sind, Menschen mit Produkten fair und ehrlich zu verbinden. Mit Käufern, die glauben, dass bessere wöchentliche Einkaufsentscheidungen die Welt ernsthaft verändern können." + brandstory_intro: "Manchmal ist der beste Weg, das System zu reparieren, einen Neuanfang zu wagen ..." + brandstory_part1: "Wir beginnen von Grund auf. Mit Bauern und Züchtern, die bereit sind, ihre Geschichten stolz und wahrhaftig zu erzählen. Mit Händlern, die bereit sind, Menschen fair und ehrlich mit Produkten zu verbinden. Mit Käufern, die glauben, dass ihr Einkaufsverhalten die Welt wirklich verändern kann." brandstory_part2: "Dann brauchen wir einen Weg, um es real zu machen. Ein Weg, jeden zu stärken, der Lebensmittel anbaut, verkauft und kauft. Ein Weg, um alle Geschichten zu erzählen, um die gesamte Logistik zu bewältigen. Eine Möglichkeit, Transaktionen jeden Tag in Transformation umzuwandeln." brandstory_part3: "Also bauen wir einen Online-Marktplatz auf, der das Spielfeld ebnet. Es ist transparent und schafft echte Beziehungen. Es ist Open Source, also gehört es allen. Es skaliert zu Regionen und Nationen, so dass Leute Versionen auf der ganzen Welt starten." brandstory_part4: "Es funktioniert überall. Es verändert alles." @@ -1418,15 +1418,15 @@ de_DE: brandstory_part6: "Wir alle lieben das Essen. Jetzt können wir unser Nahrungssystem auch lieben." learn_body: "Erkunden Sie Modelle, Geschichten und Ressourcen, um Sie bei der Entwicklung Ihres Fair-Food-Geschäfts oder Ihrer Organisation zu unterstützen. Finden Sie Schulungen, Veranstaltungen und andere Möglichkeiten, um von Gleichgesinnten zu lernen." learn_cta: "Lass dich inspirieren" - connect_body: "Durchsuchen Sie unsere vollständigen Verzeichnisse von Erzeugern, Hubs und Gruppen, um Fair-Food-Händler in Ihrer Nähe zu finden. Listen Sie Ihr Unternehmen oder Ihre Organisation auf dem OFN auf, damit Käufer Sie finden können. Treten Sie der Community bei, um Rat zu bekommen und Probleme gemeinsam zu lösen." + connect_body: "Durchsuchen Sie unsere vollständigen Verzeichnisse von Produzenten, Hubs und Gruppen, um Fair-Food-Händler in Ihrer Nähe zu finden. Präsentieren Sie Ihr Unternehmen oder Ihre Organisation im Open Food Network, damit Käufer Sie finden können. Treten Sie der Community bei, um Rat zu bekommen und Probleme gemeinsam zu lösen." connect_cta: "Erkunden" system_headline: "Einkaufen - so funktioniert es." system_step1: "1. Suche" system_step1_text: "Durchsuchen Sie unsere vielfältigen, unabhängigen Läden nach saisonal und regional erzeugten Lebensmitteln. Suchen Sie nach Region 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 Erzeugern und Hubs. Erfahren Sie die Geschichten hinter Ihrem Essen und den Menschen, die es erzeugen." + system_step2_text: "Transformieren Sie Ihre Transaktionen mit erschwinglichen lokalen Lebensmitteln von verschiedenen Produzenten und Hubs. Erfahren Sie die Geschichten hinter Ihrem Essen und den Menschen, die es erzeugen." system_step3: "3. Abholung/Lieferung" - system_step3_text: "Erhalten Sie eine Lieferung oder besuchen Sie Ihren Hersteller oder Ihr Hub für eine persönlichere Verbindung mit Ihrem Essen. Lebensmitteleinkauf so vielfältig wie die Natur es beabsichtigt hat." + system_step3_text: "Erhalten Sie eine Lieferung nach Hause oder besuchen Sie den Produzenten oder Ihren Hub für eine persönlichere Verbindung mit Ihrem Essen. Gestalten Sie Ihren Lebensmitteleinkauf so vielfältig, wie die Natur es auch ist." cta_headline: "Einkaufen, das die Welt verbessert." cta_label: "Ich bin bereit" stats_headline: "Wir schaffen ein neues Ernährungssystem." @@ -1445,7 +1445,7 @@ de_DE: checkout_billing: "Rechnungsinfo" checkout_default_bill_address: "Als Standardrechnungsadresse speichern" checkout_shipping: Versandinformation - checkout_default_ship_address: "Als Standardversandadresse speichern" + checkout_default_ship_address: "Als Standardlieferadresse speichern" checkout_method_free: kostenlos checkout_address_same: Lieferadresse wie Rechnungsadresse? checkout_ready_for: "Bereit am:" @@ -1455,7 +1455,7 @@ de_DE: checkout_your_order: Ihre Bestellung checkout_cart_total: Warenkorb insgesamt checkout_shipping_price: Versand - checkout_total_price: Total + checkout_total_price: Summe checkout_back_to_cart: "Zurück zum Warenkorb" cost_currency: "Kosten Währung" order_paid: BEZAHLT @@ -1470,7 +1470,7 @@ de_DE: order_pickup_time: abholbereit order_pickup_instructions: Abholinformationen order_produce: Produkte - order_total_price: Total + order_total_price: Summe order_includes_tax: (inkl. Steuern) order_payment_paypal_successful: Ihre Zahlung mit PayPal wurde erfolgreich abgewickelt. order_hub_info: Hub-Info @@ -1484,24 +1484,24 @@ de_DE: products_at: "bei %{distributor}" products_elsewhere: "Produkte an anderer Stelle" email_confirmed: "Vielen Dank für die Bestätigung Ihrer E-Mail-Adresse." - email_confirmation_activate_account: "Bevor wir Ihr neues Konto aktivieren, bestätigen Sie bitte Ihre E-Mail-Adresse." + email_confirmation_activate_account: "Bevor wir Ihr neues Konto aktivieren können, bestätigen Sie bitte Ihre E-Mail-Adresse." email_confirmation_greeting: "Hallo, %{contact}!" email_confirmation_profile_created: "Ein Profil für %{name} wurde erfolgreich erstellt! Um Ihr Profil zu aktivieren, müssen wir diese E-Mail-Adresse bestätigen." - email_confirmation_click_link: "Bitte klicken Sie auf den unten stehenden Link, um Ihre E-Mail-Adresse zu bestätigen und mit der Einrichtung Ihres Profils fortzufahren." + email_confirmation_click_link: "Bitte klicken Sie auf den untenstehenden Link, um Ihre E-Mail-Adresse 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 Laden zu verwenden." email_confirmation_notice_unexpected: "Sie haben diese Nachricht erhalten, weil Sie sich bei %{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: "Verbinden Sie sich mit uns:" - email_contact: "Schreiben Sie uns eine E-Mail:" + email_contact: "Schreib uns eine E-Mail:" email_signoff: "Danke" email_signature: "%{sitename} Team" email_confirm_customer_greeting: "Hallo %{name}," - email_confirm_customer_intro_html: "Vielen Dank für ihren Einkauf bei %{distributor} !" + email_confirm_customer_intro_html: "vielen Dank für deinen Einkauf bei %{distributor}!" email_confirm_customer_number_html: "Bestellbestätigung # %{number}" - email_confirm_customer_details_html: "Hier sind Ihre Bestelldaten von %{distributor}:" + email_confirm_customer_details_html: "Hier sind deine Bestelldaten bei %{distributor}:" email_confirm_customer_signoff: "Mit freundlichen Grüßen," email_confirm_shop_greeting: "Hallo %{name}," - email_confirm_shop_order_html: "Gut gemacht! Sie haben eine neue Bestellung für %{distributor}!" + email_confirm_shop_order_html: "Gut gemacht! Sie haben eine neue Bestellung bei %{distributor} erhalten!" email_confirm_shop_number_html: "Bestellbestätigung # %{number}" email_order_summary_item: "Artikel" email_order_summary_quantity: "Menge" @@ -1514,7 +1514,7 @@ de_DE: email_payment_not_paid: NICHT BEZAHLT email_payment_summary: Zahlungsübersicht email_payment_method: "Bezahlen per:" - email_so_placement_intro_html: "Sie haben eine neue Bestellung für %{distributor}" + email_so_placement_intro_html: "Sie haben eine neue Bestellung bei %{distributor} erhalten!" email_so_placement_details_html: "Hier sind die Details Ihrer Bestellung für %{distributor}:" email_so_placement_changes: "Leider waren nicht alle von Ihnen angeforderten Produkte verfügbar. Die von Ihnen angeforderten Originalmengen sind unten durchgestrichen." email_so_payment_success_intro_html: "Eine automatische Zahlung für Ihre Bestellung bei %{distributor} wurde verarbeitet." @@ -1536,14 +1536,14 @@ de_DE: email_shipping_delivery_time: "Lieferung am:" email_shipping_delivery_address: "Lieferadresse:" email_shipping_collection_details: Sammlungsdetails - email_shipping_collection_time: "Bereit zur Abholung" + email_shipping_collection_time: "Bereit zur Abholung:" email_shipping_collection_instructions: "Sammlung Anweisungen:" email_special_instructions: "Ihre Notizen:" email_signup_greeting: Hallo! email_signup_welcome: "Willkommen bei %{sitename}!" email_signup_confirmed_email: "Vielen Dank für die Bestätigung Ihrer E-Mail-Adresse." email_signup_shop_html: "Sie können sich jetzt unter %{link} anmelden." - email_signup_text: "Danke, dass Sie dem Netzwerk beigetreten sind. Wenn Sie ein Kunde sind, freuen wir uns, Ihnen viele fantastische Bauern, wunderbare Läden und leckeres Essen vorzustellen! Wenn Sie ein Produzent oder ein Lebensmittelunternehmer sind, freuen wir uns, Sie als Teil des Netzwerks zu begrüßen." + email_signup_text: "Danke, dass Sie dem Netzwerk beigetreten sind. Wenn Sie ein Kunde sind, freuen wir uns, Ihnen viele fantastische Landwirte, wunderbare Läden und leckeres Essen vorzustellen! Wenn Sie ein Produzent oder ein Lebensmittelunternehmer sind, freuen wir uns, Sie als Teil des Netzwerks zu begrüßen." email_signup_help_html: "Wir freuen und über Ihre Fragen und Rückmeldungen. Schreiben Sie uns gerne eine E-Mail an %{email}." invite_email: greeting: "Hallo!" @@ -1569,24 +1569,24 @@ de_DE: shopping_contact_web: "Kontakt" shopping_contact_social: "Folgen" shopping_groups_part_of: "ist ein Teil von:" - shopping_producers_of_hub: "Erzeuger bei %{hub}:" + shopping_producers_of_hub: "Produzenten bei %{hub}:" enterprises_next_closing: "Nächster Bestellschluss" enterprises_currently_open: "Bestellzyklus ist geöffnet" - enterprises_ready_for: "Fertig am" + enterprises_ready_for: "Bereit am" enterprises_choose: "Wählen Sie, wann Sie Ihre Bestellung wollen:" maps_open: "Offen" maps_closed: "Geschlossen" hubs_buy: "Angebot" hubs_shopping_here: "Sie kaufen hier ein" hubs_orders_closed: "Bestellzyklus geschlossen" - hubs_profile_only: "nur Profil" - hubs_delivery_options: "Lieferarten" + hubs_profile_only: "Profil" + hubs_delivery_options: "Lieferoptionen" hubs_pickup: "Abholen" hubs_delivery: "Lieferung" hubs_producers: "Unsere Produzenten" hubs_filter_by: "Filtern nach" hubs_filter_type: "Art" - hubs_filter_delivery: "Lieferarten" + hubs_filter_delivery: "Lieferoptionen" hubs_filter_property: "Eigenschaften" hubs_matches: "Meintest Du?" hubs_intro: Regional einkaufen @@ -1630,7 +1630,7 @@ de_DE: 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 Verteilern, die etwas gemeinsam haben, wie z B Standort, Bauernmarkt oder Philosophie. Dies erleichtert Ihr Einkaufserlebnis." + groups_text: "Jeder Produzent ist einzigartig. Jedes Unternehmen hat etwas anderes zu bieten. Unsere Gruppen fassen Produzenten, Hubs und Verteilstellen zusammen, die etwas gemeinsam haben, wie z. B. ihren Standort, ihre Philosophie oder den gemeinsamen Bauernmarkt . So erleichtern Gruppen Ihr Einkaufserlebnis." groups_search: "Suchen Sie nach Name oder Stichwort" groups_no_groups: "Keine Gruppen gefunden" groups_about: "Über uns" @@ -1650,7 +1650,7 @@ de_DE: groups_signup_motivation2: Deshalb sind wir jeden Tag aufgestanden. Wir sind eine globale Non-Profit-Organisation, die auf Open-Source-Code basiert. Wir spielen fair. Sie können uns immer vertrauen. groups_signup_motivation3: Wir wissen, dass Sie große Ideen haben und wir helfen wollen. Wir teilen unser Wissen, Netzwerke und Ressourcen. Wir wissen, dass Isolation keine Veränderung verursacht, also werden wir mit Ihnen zusammenarbeiten. groups_signup_motivation4: Wir treffen dich, wo du bist. - groups_signup_motivation5: Sie könnten eine Allianz von Hubs, Produzenten oder Vertailern sein, eine Industrieorganisation oder eine Lokalbehörde. + groups_signup_motivation5: Sie könnten ein Zusammenschluss von Hubs, Produzenten oder Verteilstellen sein, eine Industrieorganisation oder eine Lokalbehörde. groups_signup_motivation6: Was auch immer Ihre Rolle in Ihrer lokalen Nahrungsmittelbewegung ist, wir sind bereit zu helfen. Wie auch immer Sie sich fragen, wie Open Food Network in Ihrem Teil der Welt aussehen würde oder wird, lassen Sie uns das Gespräch beginnen. groups_signup_motivation7: Wir machen Nahrungsmittelbewegungen sinnvoller. groups_signup_motivation8: Sie müssen Ihre Netzwerke aktivieren und aktivieren, wir bieten eine Plattform für Konversation und Aktion. Sie brauchen echtes Engagement. Wir helfen, alle Akteure, alle Beteiligten, alle Sektoren zu erreichen. @@ -1688,7 +1688,7 @@ de_DE: products_available: Verfügbar? products_producer: "Produzent" products_price: "Preis" - name_or_sku: "NAME ODER SKU" + name_or_sku: "NAME ODER ARTIKELNUMMER" register_title: Anmelden sell_title: "Registrieren" sell_headline: "Steigen Sie in das Open Food Netzwerk ein!" @@ -1697,7 +1697,7 @@ de_DE: sell_hubs: "Hubs" sell_groups: "Gruppen" sell_producers_detail: "Richten Sie in wenigen Minuten für Ihr Unternehmen ein Profil im Open Food Network ein. Sie können Ihr Profil jederzeit auf einen Laden erweitern und Ihre Produkte direkt an Kunden verkaufen." - sell_hubs_detail: "Richten Sie im Open Food Network ein Profil für Ihr Lebensmittelunternehmen oder Ihre Organisation ein. Sie können Ihr Profil jederzeit auf einen Multi-Erzeugerladen erweitern." + sell_hubs_detail: "Richten Sie im Open Food Network ein Profil für Ihr Lebensmittelunternehmen oder Ihre Organisation ein. Sie können Ihr Profil jederzeit auf einen Multi-Produzentenladen erweitern." 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: "Das Aufnahme ins Open Food Network ist kostenlos. Das Eröffnen und Betreiben eines Ladens im OFN ist derzeit kostenlos." @@ -1725,7 +1725,7 @@ de_DE: orders_form_empty_cart: "Einkaufskorb leeren" orders_form_subtotal: Zwischensumme erzeugen orders_form_admin: Admin & Handhabung - orders_form_total: Total + orders_form_total: Summe orders_oc_expired_headline: Bestellungen wurden für diesen Bestellzyklus geschlossen orders_oc_expired_text: "Entschuldigung, Bestellungen für diesen Bestellzyklus wurden vor %{time} geschlossen! Bitte kontaktieren Sie Ihr Hub direkt, um zu sehen, ob sie verspätete Bestellungen annehmen können." orders_oc_expired_text_others_html: "Entschuldigung, der Bestellzyklus wurde vor %{time} geschlossen! Wenden Sie sich bitte direkt an den Laden, um zu sehen, ob er verspätete Bestellungen annehmen kann (%{link})." @@ -1734,7 +1734,7 @@ de_DE: orders_oc_expired_phone: "Telefon:" orders_show_title: Bestellbestätigung orders_show_time: Bestellung bereit am - orders_show_order_number: "Bestellung # %{number}" + orders_show_order_number: "Bestellung #%{number}" orders_show_cancelled: Storniert orders_show_confirmed: Bestätigt orders_your_order_has_been_cancelled: "Ihre Bestellung wurde storniert" @@ -1749,7 +1749,7 @@ de_DE: orders_bought_already_confirmed: "* schon bestätigt" orders_confirm_cancel: Sind Sie sicher, dass Sie diese Bestellung stornieren möchten? order_processed_successfully: "Ihre Bestellung wurde erfolgreich bearbeitet" - products_cart_distributor_choice: "Verteiler Ihrer Bestellung:" + products_cart_distributor_choice: "Verteilstelle Ihrer 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 schließen Sie Ihre Bestellung bei %{link} ab, bevor Sie bei einem anderen Händler einkaufen." @@ -1759,7 +1759,7 @@ de_DE: 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: Verteilstelle products_distributor_info: Wenn Sie einen Händler für Ihre Bestellung auswählen, werden hier ihre Adresse und Abholzeiten angezeigt. password: Passwort remember_me: Erinnere dich an mich @@ -1786,7 +1786,7 @@ de_DE: error_number: "muss nummer sein" error_email: "muss eine E-Mail-Adresse sein" error_not_found_in_database: "%{name} nicht in Datenbank gefunden" - error_not_primary_producer: "%{name} ist nicht als Erzeuger aktiviert" + error_not_primary_producer: "%{name} ist nicht als Produzent aktiviert" error_no_permission_for_enterprise: "\"%{name}\": Sie sind nicht berechtigt, Produkte für dieses Unternehmen zu verwalten" item_handling_fees: "Artikel Bearbeitungsgebühren (in den Gesamtsummen enthalten)" january: "Januar" @@ -1817,7 +1817,7 @@ de_DE: steps: introduction: registration_greeting: "Hallo!" - registration_intro: "Sie können jetzt ein Profil als Produzent oder Verteilstelle erzeugen" + registration_intro: "Sie können jetzt ein Profil als Produzent oder Hub erstellen" registration_checklist: "Was brauche ich?" registration_time: "5-10 Minuten" registration_enterprise_address: "Unternehmensadresse" @@ -1833,7 +1833,7 @@ de_DE: details: title: "Einzelheiten" headline: "Lass uns anfangen" - enterprise: "Woot! Zuerst müssen Sie ein wenig über Ihr Unternehmen wissen:" + enterprise: "Stop! Zuerst müssen wir ein wenig über Ihr Unternehmen wissen:" producer: "Woot! Zuerst müssen wir ein wenig über Ihre Farm wissen:" enterprise_name_field: "Unternehmensname:" producer_name_field: "Name des Betriebs:" @@ -1860,16 +1860,16 @@ de_DE: contact_field_placeholder: "Kontaktname" contact_field_required: "Sie müssen einen primären Kontakt eingeben." phone_field: "Telefonnummer" - phone_field_placeholder: "z.B. (03) 1234 5678" + phone_field_placeholder: "z. B. (03) 1234 5678" type: title: "Art" 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" + no_producer: "Nein, ich bin kein Produzent." producer_field_error: "Bitte wählen Sie: Sind Sie ein Produzent?" - yes_producer_help: "Die Produzenten stellen leckere Lebensmittel und/oder Getränke her. Sie sind ein Produzent, wenn Sie anbauen, brauen, backen, fermentieren, melken oder sonst wie Lebenmittel produzieren." - no_producer_help: "Wenn Sie kein Produzent sind, sind Sie wahrscheinlich jemand, der Lebensmittel verkauft und verteilt. Sie könnten ein Foodhub, eine Coop, eine Einkaufsgruppe, Einzelhändler, ein Hofladen, Großhändler oder Vergleichbares sein." + yes_producer_help: "Die Produzenten stellen leckere Lebensmittel oder Getränke her. Sie sind ein Produzent, wenn Sie anbauen, brauen, backen, fermentieren, melken oder sonst wie Lebenmittel produzieren." + no_producer_help: "Wenn Sie kein Produzent sind, sind Sie wahrscheinlich jemand, der Lebensmittel verkauft und verteilt. Sie könnten ein Foodhub, eine Lebensmittelkooperative, eine Einkaufsgemeinschaft, ein Einzelhändler, Hofladen, Großhändler oder Vergleichbares sein." create_profile: "Profil erstellen" about: title: "Über uns" @@ -1877,15 +1877,15 @@ de_DE: message: "Lassen Sie uns nun die Details überarbeiten" success: "Erfolg! %{enterprise} wurde dem Open Food Network hinzugefügt" registration_exit_message: "Wenn Sie diesen Assistenten zu einem beliebigen Zeitpunkt beenden, können Sie mit der Erstellung Ihres Profils fortfahren, indem Sie zur Administratoroberfläche gehen." - enterprise_description: "Kurze Beschreibung" + enterprise_description: "Kurzbeschreibung" enterprise_description_placeholder: "Ein kurzer Satz, der Ihr Unternehmen beschreibt" enterprise_long_desc: "Ausführliche Beschreibung" enterprise_long_desc_placeholder: "Dies ist Ihre Gelegenheit, die Geschichte Ihres Unternehmens zu erzählen - was macht Sie anders und wunderbar? Wir empfehlen, die Beschreibung unter 600 Zeichen oder 150 Wörtern zu halten." enterprise_long_desc_length: "%{num} Zeichen/bis zu 600 empfohlen" enterprise_abn: "USt-IdNr." - enterprise_abn_placeholder: "z.B. DE999999999" + enterprise_abn_placeholder: "z. B. DE999999999" enterprise_acn: "St.-Nr." - enterprise_acn_placeholder: "z.B. 93815/08152" + enterprise_acn_placeholder: "z. B. 93815/08152" enterprise_tax_required: "Sie müssen eine Auswahl treffen." images: title: "Bilder" @@ -1896,34 +1896,34 @@ de_DE: back: "Zurück" logo: select_logo: "Schritt 1. Wählen Sie Logo Image" - logo_tip: "Tipp: Am besten funktionieren quadratische Bilder, vorzugsweise mindestens 300 × 300 Pixel" + logo_tip: "Tipp: Am besten funktionieren quadratische Bilder, vorzugsweise mindestens 300 × 300 Pixel." logo_label: "Wählen Sie ein Logo aus" logo_drag: "Ziehen Sie Ihr Logo hierher" review_logo: "Schritt 2. Überprüfen Sie Ihr Logo" review_logo_tip: "Tipp: Für beste Ergebnisse sollte Ihr Logo den verfügbaren Platz ausfüllen" logo_placeholder: "Ihr Logo wird hier zur Überprüfung angezeigt, sobald es hochgeladen wurde" promo: - select_promo_image: "Schritt 3. Wählen Sie Promo Image" - promo_image_tip: "Tipp: Die als Banner dargestellte bevorzugte Größe beträgt 1200 × 260 px" - promo_image_label: "Wählen Sie ein Promobild" - promo_image_drag: "Verschieben Sie Ihre Promo hier" - review_promo_image: "Schritt 4. Überprüfen Sie Ihr Promo-Banner" - review_promo_image_tip: "Tipp: Für ein optimales Ergebnis sollte Ihr Promo-Bild den verfügbaren Platz ausfüllen" + select_promo_image: "Schritt 3. Wählen Sie ein Werbebild" + promo_image_tip: "Tipp: Die als Banner dargestellte bevorzugte Größe beträgt 1200 × 260 Pixel." + promo_image_label: "Wählen Sie ein Werbebild" + promo_image_drag: "Verschieben Sie Ihr Bild hier" + review_promo_image: "Schritt 4. Überprüfen Sie Ihr Werbebild" + review_promo_image_tip: "Tipp: Für ein optimales Ergebnis sollte Ihr Werbebild den verfügbaren Platz ausfüllen." promo_image_placeholder: "Ihr Logo wird hier zur Überprüfung angezeigt, sobald es hochgeladen wurde" social: - title: "Sozial" + title: "Soziale Medien" enterprise_final_step: "Letzter Schritt!" enterprise_social_text: "Wie kann man %{enterprise} online finden?" website: "Webseite" - website_placeholder: "z.B. openfoodnetwork.org.au" + website_placeholder: "z. B. openfoodnetwork.org.au" facebook: "Facebook" - facebook_placeholder: "z.B. www.facebook.com/PageNameHere" + facebook_placeholder: "z. B. www.facebook.com/PageNameHere" linkedin: "LinkedIn" - linkedin_placeholder: "z.B. www.linkedin.com/IhrNameHier" + linkedin_placeholder: "z. B. www.linkedin.com/IhrNameHier" twitter: "Twitter" - twitter_placeholder: "z.B. @twitter Griff" + twitter_placeholder: "z. B. @twitter Griff" instagram: "Instagram" - instagram_placeholder: "z.B. @instagram_handle" + instagram_placeholder: "z. B. @instagram_handle" limit_reached: headline: "Ach nein!" message: "Sie haben das Limit erreicht!" @@ -1938,7 +1938,7 @@ de_DE: continue: "Fortsetzen" action_or: "ODER" enterprise_limit: Enterprise Limit - shipping_method_destroy_error: "Diese Lieferart kann nicht gelöscht werden, da sie in einer Bestellung verwendet wird: %{number}." + shipping_method_destroy_error: "Diese Lieferoption kann nicht gelöscht werden, da sie in einer Bestellung verwendet wird: %{number}." fees: "Gebühren" item_cost: "Gegenstandskosten" bulk: "Bulk" @@ -1948,10 +1948,10 @@ de_DE: shop_for_products_html: "Hier erhalten Sie %{enterprise}-Produkte:" change_shop: "In diesen Laden wechseln:" shop_at: "Kaufe jetzt bei:" - admin_fee: "Gebühr Administration" - sales_fee: "Gebühr Verkauf" - packing_fee: "Gebühr Umverpackung" - transport_fee: "Gebühr Transport" + admin_fee: "Bearbeitungsgebühr" + sales_fee: "Verkaufsgebühr" + packing_fee: "Verpackungsgebühr" + transport_fee: "Versandgebühr" fundraising_fee: "Fundraising-Gebühr" price_graph: "Preisdiagramm" included_tax: "inkl. Steuer" @@ -1968,7 +1968,7 @@ de_DE: ok: OK not_visible: nicht sichtbar you_have_no_orders_yet: "Du hast noch keine Bestellungen" - show_only_complete_orders: "Nur komplette Bestellungen anzeigen" + show_only_complete_orders: "Nur abgeschlossene Bestellungen anzeigen" successfully_created: '%{resource} wurde erfolgreich erstellt!' successfully_removed: '%{resource} wurde erfolgreich entfernt!' successfully_updated: '%{resource} wurde erfolgreich aktualisiert!' @@ -1976,7 +1976,7 @@ de_DE: outstanding_balance: "Offener Betrag" admin_enterprise_relationships: "Unternehmensberechtigungen" admin_enterprise_relationships_everything: "Alles" - admin_enterprise_relationships_permits: "Genehmigungen" + admin_enterprise_relationships_permits: "erlaubt" admin_enterprise_relationships_seach_placeholder: "Suche" admin_enterprise_relationships_button_create: "Neu" admin_enterprise_relationships_to: "zu" @@ -1987,22 +1987,22 @@ de_DE: admin_enterprise_groups_enterprise: "Unternehmen" admin_enterprise_groups_data_powertip: "Der primäre Benutzer, der für diese Gruppe verantwortlich ist." admin_enterprise_groups_data_powertip_logo: "Dies ist das Logo für die Gruppe" - admin_enterprise_groups_data_powertip_promo_image: "Dieses Bild wird oben im Gruppenprofil angezeigt" + admin_enterprise_groups_data_powertip_promo_image: "Dieses Bild wird oben im Gruppenprofil angezeigt." admin_enterprise_groups_contact: "Kontakt" - admin_enterprise_groups_contact_phone_placeholder: "z.B. 98 7654 3210" - admin_enterprise_groups_contact_address1_placeholder: "z.B. Gartenstraße 123" + admin_enterprise_groups_contact_phone_placeholder: "z. B. 98 7654 3210" + admin_enterprise_groups_contact_address1_placeholder: "z. B. Gartenstraße 123" admin_enterprise_groups_contact_city: "Vorort" - admin_enterprise_groups_contact_city_placeholder: "z.B. Nordwestheim" + admin_enterprise_groups_contact_city_placeholder: "z. B. Nordwestheim" admin_enterprise_groups_contact_zipcode: "Postleitzahl" - admin_enterprise_groups_contact_zipcode_placeholder: "z.B. 30701" - admin_enterprise_groups_contact_state_id: "Status" + admin_enterprise_groups_contact_zipcode_placeholder: "z. B. 30701" + admin_enterprise_groups_contact_state_id: "Bundesland" admin_enterprise_groups_contact_country_id: "Land" admin_enterprise_groups_web: "Webressourcen" - admin_enterprise_groups_web_twitter: "z.B. @the_prof" - admin_enterprise_groups_web_website_placeholder: "z.B. www.truffles.com" - admin_order_cycles: "Admin-Bestellzyklen" + admin_enterprise_groups_web_twitter: "z. B. @the_prof" + admin_enterprise_groups_web_website_placeholder: "z. B. www.truffles.com" + admin_order_cycles: "Bestellzyklen verwalten" open: "Öffnen" - close: "Abschließen" + close: "Schließen" create: "Neu" search: "Suche" supplier: "Lieferant" @@ -2012,11 +2012,11 @@ de_DE: shipping_categories: "Versandkategorien" units: "Einheit" coordinator: "Koordinator" - distributor: "Verteiler" - enterprise_fees: "Zuschläge" + distributor: "Verteilstelle" + enterprise_fees: "Gebühren" process_my_order: "Verarbeite meine Bestellung" delivery_instructions: Lieferanleitungen - delivery_method: Lieferart + delivery_method: Lieferoption fee_type: "Art der Gebühr" tax_category: "Steuerkategorie" description: "Beschreibung" @@ -2024,17 +2024,17 @@ de_DE: tags: "Stichwörter" calculator: "Rechner" calculator_values: "Rechnerwerte" - calculator_settings_warning: "Wenn Sie den Gebühren-Typ ändern, müssen Sie zuerst speichern, bevor Sie die Gebühren-Einstellungen bearbeiten können" + calculator_settings_warning: "Wenn Sie den Gebührentyp ändern, müssen Sie zuerst speichern, bevor Sie die Gebühreneinstellungen bearbeiten können." calculator_preferred_unit_error: "muss kg oder lb sein" - flat_percent_per_item: "Flache Prozent (pro Artikel)" + flat_percent_per_item: "Fester Prozentsatz (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" + flat_rate_per_order: "Pauschale (pro Bestellung)" + flexible_rate: "Flexible Gebühr" + price_sack: "Mengenrabatt" 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" - notify_producers: 'Hersteller benachrichtigen' + notify_producers: 'Produzenten benachrichtigen' edit_order_cycle: "Bestellzyklus bearbeiten" roles: "Rollen" update: "Aktualisieren" @@ -2050,7 +2050,7 @@ de_DE: no_customers_found: "Keine Kunden gefunden" go: "Gehen" hub: "Hub" - producer: "Erzeuger" + producer: "Produzent" product: "Produkt" price: "Preis" on_hand: "Verfügbar" @@ -2062,8 +2062,8 @@ de_DE: spree_admin_overview_enterprises_footer: "VERWALTEN SIE MEINE UNTERNEHMEN" spree_admin_enterprises_hubs_name: "Name" spree_admin_enterprises_create_new: "neu erstellen" - spree_admin_enterprises_shipping_methods: "Lieferarten" - spree_admin_enterprises_fees: "Zuschläge" + spree_admin_enterprises_shipping_methods: "Lieferoptionen" + spree_admin_enterprises_fees: "Gebühren" spree_admin_enterprises_none_create_a_new_enterprise: "ERSTELLEN SIE EIN NEUES UNTERNEHMEN" spree_admin_enterprises_none_text: "Sie haben noch keine Unternehmen" spree_admin_enterprises_tabs_hubs: "HUBS" @@ -2083,11 +2083,11 @@ de_DE: unit_name: "Einheitenname" change_package: "Paket ändern" spree_admin_single_enterprise_hint: "Tipp: Damit andere Nutzer Sie finden können, aktivieren Sie Ihre Sichtbarkeit unter:" - spree_admin_eg_pickup_from_school: "z.B. \"Abholung von der Grundschule\"" - spree_admin_eg_collect_your_order: "z.B. 'Bitte sammeln Sie Ihre Bestellung von 123 Imaginary St, Northcote, 3070'" + spree_admin_eg_pickup_from_school: "z. B. \"Abholung von der Grundschule\"" + spree_admin_eg_collect_your_order: "z. B. 'Bitte sammeln Sie Ihre Bestellung von 123 Imaginary St, Northcote, 3070'" spree_classification_primary_taxon_error: "Taxon %{taxon} ist das primäre Taxon von %{product} und kann nicht gelöscht werden" spree_order_availability_error: "Distributor oder Bestellzyklus kann die Produkte in Ihrem Warenkorb nicht liefern" - spree_order_populator_error: "Dieser Verteiler oder Bestellzyklus kann nicht alle Produkte in Ihrem Einkaufswagen liefern. Bitte wählen Sie ein anderes." + spree_order_populator_error: "Diese Verteilstelle oder dieser Bestellzyklus kann nicht alle Produkte in Ihrem Einkaufswagen liefern. Bitte ändern Sie Ihre Auswahl." spree_order_cycle_error: "Bitte wählen Sie einen Bestellzyklus für diese Bestellung aus." spree_order_populator_availability_error: "Dieses Produkt ist im ausgewählten Distributor oder Bestellzyklus nicht verfügbar." spree_distributors_error: "Mindestens ein Hub muss ausgewählt sein" @@ -2108,7 +2108,7 @@ de_DE: order_cycles: "Bestellzyklen" enterprise_relationships: "Unternehmensberechtigungen" remove_tax: "Steuer entfernen" - first_name_begins_with: "Der Vorname beginnt mit" + first_name_begins_with: "Vorname beginnt mit" last_name_begins_with: "Nachname beginnt mit" shipping_method: "Versandart" new_order: "Neue Bestellung" @@ -2119,7 +2119,7 @@ de_DE: tax_settings: "Steuereinstellungen" products_require_tax_category: "Produkte benötigen eine Steuerkategorie" admin_shared_address_1: "Adresse" - admin_shared_address_2: "Adresse (Fortsetzung)" + admin_shared_address_2: "Adresszusatz (optional)" admin_share_city: "Ort" admin_share_zipcode: "Postleitzahl" admin_share_country: "Land" @@ -2131,16 +2131,16 @@ de_DE: hub_sidebar_blue: "Blau" hub_sidebar_red: "rot" order_cycles_closed_for_hub: "Der Bestellzyklus des von Ihnen ausgewählten Ladens ist derzeit geschlossen. Bitte versuchen Sie es später noch einmal." - report_customers_distributor: "Verteiler" + report_customers_distributor: "Verteilstelle" report_customers_supplier: "Lieferant" report_customers_cycle: "Bestellzyklus" report_customers_type: "Berichtsart" report_customers_csv: "Download als CSV" - report_producers: "Erzeuger:" + report_producers: "Produzenten:" report_type: "Berichtsart:" report_hubs: "Hubs:" report_payment: "Zahlungsarten:" - report_distributor: "Verteiler:" + report_distributor: "Verteilstelle:" report_payment_by: 'Zahlungen nach Art' report_itemised_payment: 'Aufgeschlüsselte Zahlung Summen' report_payment_totals: 'Zahlungssummen' @@ -2170,20 +2170,20 @@ de_DE: report_header_paid: Bezahlt? report_header_delivery: Lieferung? report_header_shipping: Lieferung - report_header_shipping_method: Lieferart + report_header_shipping_method: Lieferoption report_header_shipping_instructions: Versand-Anweisungen - report_header_ship_street: Liefer-Straße - report_header_ship_street_2: Liefer-Straße 2 - report_header_ship_city: Liefer-Stadt - report_header_ship_postcode: Liefer-Postleitzahl - report_header_ship_state: Liefer-Bundesland - report_header_billing_street: Rechnung-Straße - report_header_billing_street_2: Rechnung-Straße 2 - report_header_billing_street_3: Rechnung-Straße 3 - report_header_billing_street_4: Rechnung-Straße 4 - report_header_billing_city: Rechnung-Stadt - report_header_billing_postcode: Rechnung-Postleitzahl - report_header_billing_state: Rechnung-Bundesland + report_header_ship_street: Lieferstraße + report_header_ship_street_2: Lieferadresszusatz + report_header_ship_city: Lieferstadt + report_header_ship_postcode: Lieferpostleitzahl + report_header_ship_state: Lieferbundesland + report_header_billing_street: Rechnungsstraße + report_header_billing_street_2: Rechnungstraße 2 + report_header_billing_street_3: Rechnungsstraße 3 + report_header_billing_street_4: Rechnungsstraße 4 + report_header_billing_city: Rechnungsstadt + report_header_billing_postcode: Rechnungspostleitzahl + report_header_billing_state: Rechnungsbundesland report_header_incoming_transport: Eingehender Transport report_header_special_instructions: Besondere Anweisungen report_header_order_number: Bestellnummer @@ -2213,8 +2213,8 @@ de_DE: report_header_max_quantity_excess: Max Menge Überschuss report_header_taxons: Taxonen report_header_supplier: Lieferant - report_header_producer: Erzeuger - report_header_producer_suburb: Erzeuger Vorort + report_header_producer: Produzent + report_header_producer_suburb: Produzent Vorort report_header_unit: Einheit report_header_group_buy_unit_quantity: Gruppenkauf Einheitsmenge report_header_cost: Kosten @@ -2226,12 +2226,12 @@ de_DE: report_header_visible: öffentlich sichtbar report_header_price: Preis report_header_unit_size: Einheit - report_header_distributor: Verteiler - report_header_distributor_address: Verteileradresse - report_header_distributor_city: Verteilerstadt - report_header_distributor_postcode: Verteilerpostleitzahl + report_header_distributor: Verteilstelle + report_header_distributor_address: Verteilstellenadresse + report_header_distributor_city: Verteilstellenstadt + report_header_distributor_postcode: Verteilstellenpostleitzahl report_header_delivery_address: Lieferadresse - report_header_delivery_postcode: Liefer-Postleitzahl + report_header_delivery_postcode: Lieferpostleitzahl report_header_bulk_unit_size: Bulk-Einheit report_header_weight: Gewicht report_header_sum_total: Gesamtsumme @@ -2272,7 +2272,7 @@ de_DE: report_header_total_excl_vat: "Summe exkl. Steuern (%{currency_symbol})" report_header_total_incl_vat: "Summe inkl. Steuern (%{currency_symbol})" report_header_temp_controlled: Temperaturkontrolliert? - report_header_is_producer: Erzeuger? + report_header_is_producer: Produzent? report_header_not_confirmed: Nicht bestätigt report_header_gst_on_income: Umsatzsteuer auf Einkommen report_header_gst_free_income: Unbesteuertes Einkommen @@ -2284,7 +2284,7 @@ de_DE: report_header_transaction_fee: Transaktionsgebühr (keine Steuern) report_header_total_untaxable_admin: Summe nicht steuerpflichtiger Admin-Anpassungen (keine Steuern) report_header_total_taxable_admin: Summe steuerpflichtiger Admin-Anpassungen (inkl. Steuern) - initial_invoice_number: "Anfangsrechnungsnummer:" + initial_invoice_number: "Ursprüngliche Rechnungsnummer" invoice_date: "Rechnungsdatum:" due_date: "Geburtstermin:" account_code: "Konto Code:" @@ -2302,31 +2302,33 @@ de_DE: products_unsaved: "Änderungen an %{n} Produkten bleiben ungesichert." is_already_manager: "ist schon ein Manager!" no_change_to_save: " Keine Änderung zum Speichern" - user_invited: "%{email} wurde eingeladen, dieses Unternehmen zu verwalten" + user_invited: "%{email} wurde eingeladen, dieses Unternehmen zu verwalten." add_manager: "Fügen Sie einen vorhandenen Benutzer hinzu" users: "Benutzer" about: "Über" images: "Bilder" web: "Netz" - primary_details: "Primäre Details" + primary_details: "Unternehmen" adrdress: "Adresse" contact: "Kontakt" - social: "Sozial" + social: "Soziale Medien" business_details: "Geschäftsdetails" properties: "Eigenschaften" shipping: "Versand" - shipping_methods: "Lieferart" + shipping_methods: "Lieferoption" payment_methods: "Zahlungsarten" payment_method_fee: "Transaktionsgebühr" payment_processing_failed: "Die Zahlung konnte nicht verarbeitet werden. Bitte überprüfen Sie die eingegebenen Daten" payment_method_not_supported: "Diese Zahlungsart wird nicht unterstützt. Bitte wählen Sie eine andere." payment_updated: "Zahlung wurde aktualisiert" - inventory_settings: "Katalogeinstellungen" + cannot_perform_operation: "Die Zahlung konnte nicht aktualisiert werden." + action_required: "Handlung erforderlich" + inventory_settings: "Katalog" tag_rules: "Stichwortregeln" - shop_preferences: "Ladeneinstellungen" + shop_preferences: "Laden" 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." + validation_msg_relationship_already_established: "^ Diese Beziehung besteht bereits." validation_msg_at_least_one_hub: "^ Mindestens ein Hub muss ausgewählt sein" validation_msg_tax_category_cant_be_blank: "^ Steuerkategorie darf nicht leer sein" validation_msg_is_associated_with_an_exising_customer: "ist mit einem bestehenden Kunden verbunden" @@ -2354,7 +2356,7 @@ de_DE: Die Hubs %{distributor_names} sind in einem aktiven Bestellzyklus aufgeführt, haben jedoch keine gültigen Versand- und Zahlungsarten. Bis Sie diese einrichten, können Kunden nicht an diesen Hubs einkaufen. - enterprise_fees_update_notice: Ihre Zuschläge wurden aktualisiert. + enterprise_fees_update_notice: Ihre Gebühren wurden aktualisiert. enterprise_register_package_error: "Bitte wählen Sie ein Paket" enterprise_register_error: "Die Registrierung für %{enterprise} konnte nicht abgeschlossen werden" enterprise_register_success_notice: "Herzliche Glückwünsche! Registrierung für %{enterprise} ist abgeschlossen!" @@ -2373,11 +2375,11 @@ de_DE: no_orders_found: "Keine Bestellungen gefunden" order_information: "Bestellinformationen" date_completed: "Datum abgeschlossen" - amount: "Menge" + amount: "Summe" state_names: ready: Bereit pending: steht aus - shipped: Wird versendet + shipped: Wird versandt js: saving: 'Wird gespeichert ...' changes_saved: 'Änderungen gespeichert' @@ -2409,7 +2411,7 @@ de_DE: close: "Schließen" continue: "Fortsetzen" invite: "Einladen" - invite_title: "Laden Sie einen nicht registrierten Benutzer ein" + invite_title: "Geben Sie die E-Mail-Adresse eines nicht registrierten Benutzers ein, um dieses Unternehmen zu verwalten." tag_rule_help: title: Stichwortregeln overview: Überblick @@ -2430,7 +2432,7 @@ de_DE: überschreiben und Elemente für bestimmte Kunden wieder anzeigen. terms_and_conditions_info: title: "Allgemeine Geschäftsbedingungen hochladen" - message_1: "Allgemeine Geschäftsbedingungen sind der Vertrag zwischen Ihnen, dem Verkäufer und dem Käufer. Wenn Sie hier eine Datei hochladen, müssen Käufer Ihre Allgemeinen Geschäftsbedingungen akzeptieren, um die Kaufabwicklung abzuschließen. Für den Käufer wird dies als Kontrollkästchen an der Kasse angezeigt, das aktiviert werden muss, um mit der Bezahlung fortzufahren. Wir empfehlen Ihnen dringend, Allgemeine Geschäftsbedingungen in Übereinstimmung mit den nationalen Gesetzen hochzuladen." + message_1: "Allgemeine Geschäftsbedingungen sind der Vertrag zwischen Ihnen (dem Verkäufer) und dem Käufer. Wenn Sie hier eine Datei hochladen, müssen Käufer Ihre Allgemeinen Geschäftsbedingungen akzeptieren, um die Kaufabwicklung abzuschließen. Für den Käufer wird dies als Kontrollkästchen an der Kasse angezeigt, das aktiviert werden muss, um mit der Bezahlung fortzufahren. Wir empfehlen Ihnen dringend, Allgemeine Geschäftsbedingungen in Übereinstimmung mit den nationalen Gesetzen hochzuladen." message_2: "Käufer müssen die Allgemeinen Geschäftsbedingungen nur einmal akzeptieren. Wenn Sie jedoch Ihre Allgemeinen Geschäftsbedingungen ändern, müssen Käufer diese erneut akzeptieren, bevor sie zur Kasse gehen können." terms_and_conditions_warning: title: "Allgemeine Geschäftsbedingungen hochladen" @@ -2442,26 +2444,26 @@ de_DE: saving: SPAREN enterprise_package: hub_profile: Hubprofil - hub_profile_cost: "KOSTEN: IMMER KOSTENLOS" + hub_profile_cost: "IMMER KOSTENLOS" hub_profile_text1: > - 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. + Stellen Sie sich im Open Food Network vor und vernetzen Sie sich mit + anderen Produzenten und Läden. Sie können im Open Food Network gefunden + und kontaktiert werden. Ihr Unternehmen wird auf der Karte und in Suchergebnissen + angezeigt. hub_profile_text2: > Ein Profil zu haben und Verbindungen innerhalb Ihres lokalen Lebensmittelsystems - über das Open Food Network herzustellen, wird immer kostenlos sein. + über das Open Food Network zu pflegen, wird immer kostenlos sein. hub_shop: Hub hub_shop_text1: > - Verkaufen Sie Produkte anderer Erzeuger oder Läden im Open Food Network. - Als Händler führen Sie die Produkte zusammen und sind mit Ihrem Laden - ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. + Verkaufen Sie Produkte anderer Produzenten oder Läden im Open Food Network. + Sie führen die Produkte zusammen und sind mit Ihrem Laden ein zentraler + Bestandteil Ihres lokalen Lebensmittelsystems. 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 - handelt. + Hubs können viele Formen annehmen, sei es ein Bauernmarkt, eine Lebensmittelkooperative, + eine Einkaufsgemeinschaft, ein Gemüsekistenabo oder ein lokales Lebensmittelgeschäft. hub_shop_text3: > - Wenn Sie auch Ihre eigenen Produkte verkaufen möchten, müssen Sie dieses - Unternehmen zu einem Produzenten machen. + Wenn Sie auch Ihre eigenen Produkte verkaufen möchten, wählen Sie zunächst + in der Spalte "Produzent?" das Paket "Produzent". choose_package: Bitte wählen Sie ein Paket choose_package_text1: > Ihr Unternehmen wird nicht vollständig aktiviert, bis ein Paket aus @@ -2469,70 +2471,74 @@ de_DE: choose_package_text2: > Klicken Sie auf ein Paket, um weitere Informationen zu erhalten. Klicken Sie SPEICHERN, wenn Sie fertig sind! - profile_only: nur Profil - profile_only_cost: "KOSTEN: IMMER KOSTENLOS" + profile_only: Profil + profile_only_cost: "IMMER KOSTENLOS" profile_only_text1: > - Ein Profil macht Sie sichtbar und kontaktierbar für andere und ist eine - Möglichkeit, Ihre Geschichte zu erzählen. + Stellen Sie sich und Ihre Produkte im Open Food Network vor und vernetzen + Sie sich mit anderen Produzenten und Läden. profile_only_text2: > - 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. + Wenn Sie sich lieber auf die Lebensmittelerzeugung konzentrieren und + den Verkauf anderen überlassen möchten, benötigen Sie keinen eigenen + 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: Erzeugerladen + Fügen Sie Ihre Produkte dem Profil hinzu, damit andere Läden sie zum + Verkauf anbieten können. Wenn Sie Ihre Produkte selbst verkaufen möchten, + wählen Sie "Produzentenladen". + + Ein Profil zu haben und Verbindungen innerhalb Ihres lokalen Lebensmittelsystems + über das Open Food Network zu pflegen, wird immer kostenlos sein. + producer_shop: Produzentenladen producer_shop_text1: > - Verkaufen Sie Ihre Produkte direkt an Kunden über Ihren eigenen Laden - im Open Food Network. + Verkaufen Sie Ihre eigenen Produkte direkt an Ihre Kunden durch Ihren + eigenen Produzentenladen im Open Food Network. producer_shop_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 + Ein Produzentenladen ist nur für Ihre eigenen Produkte bestimmt. Wenn + Sie Produkte anderer verkaufen möchten, wählen Sie "Hub". + producer_hub: Hub producer_hub_text1: > - Verkaufen Sie eigene Produkte und Produkte anderer Erzeuger oder Läden - im Open Food Network. Mit Ihrem Laden sind Sie ein zentraler Bestandteil + Verkaufen Sie eigene Produkte und Produkte anderer Produzenten oder + Läden im Open Food Network. Mit Ihrem Laden sind Sie ein zentraler Bestandteil Ihres lokalen Lebensmittelsystems. producer_hub_text2: > - Erzeugerläden können viele Formen annehmen, sei es eine solidarische - Landwirtschaft, eine Gemüse-Abo oder eine Food Coop mit einem Dachgarten. + Hubs können viele Formen annehmen, sei es ein Bauernmarkt, eine Lebensmittelkooperative, + eine Einkaufsgemeinschaft, ein Gemüsekistenabo oder ein lokales Lebensmittelgeschäft. producer_hub_text3: > Das Open Food Network zielt darauf ab, so viele Hub-Modelle wie möglich zu unterstützen. Daher möchten wir Ihnen unabhängig von Ihrer Situation die Tools zur Verfügung stellen, die Sie für Ihre Organisation oder Ihr lokales Lebensmittelgeschäft benötigen. - get_listing: Holen Sie sich einen Eintrag - always_free: IMMER FREI + get_listing: Stellen Sie sich und Ihre Produkte vor + always_free: IMMER KOSTENLOS sell_produce_others: Verkaufe Produkte von anderen sell_own_produce: Verkaufen Sie Ihre eigenen Produkte sell_both: Verkaufe Produkte von dir selbst und anderen enterprise_producer: - producer: Erzeuger + producer: Produzent producer_text1: > - Produzenten machen leckere Dinge zum essen oder zum trinken. Sie sind - ein Produzent, wenn Sie Nutzpflanzen anbauen, Nutztiere aufziehen, brauen, - backen, fermentieren, melken oder etwas verarbeiten. + Die Produzenten stellen leckere Lebensmittel oder Getränke her. Sie + sind ein Produzent, wenn Sie anbauen, brauen, backen, fermentieren, + melken oder sonst wie Lebenmittel produzieren. producer_text2: > - 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. + Produzenten können auch weitere Funktionen übernehmen, wie z. B. die + Zusammenführung von Nahrungsmitteln anderer Unternehmen und den Verkauf + über einen Laden im Open Food Network. non_producer: Händler non_producer_text1: > - Händler produzieren selbst keine Lebensmittel, d.h. sie können keine + Händler produzieren selbst keine Lebensmittel, d. h. sie können keine eigenen Produkte über das Open Food Network anbieten. non_producer_text2: > Stattdessen spezialisieren sich Händler darauf, Produzenten mit dem Endverbraucher zu verbinden, sei es durch Zusammenführung, Sortierung, Verpackung, Verkauf oder Lieferung von Lebensmitteln. - producer_desc: Produzenten von Lebensmitteln - producer_example: z.B. Züchter, Bäcker, Brauer, Hersteller + producer_desc: Sie stellen selbst Lebensmittel her + producer_example: z. B. Landwirte, Gärtner, Bäcker, Brauer und mehr non_producer_desc: Alle anderen Lebensmittelunternehmen - non_producer_example: z.B. Lebensmittelgeschäfte, Essenskooperationen, Kaufgruppen + non_producer_example: z. B. Lebensmittelgeschäfte, Lebensmittelkooperativen, Einkaufsgemeinschaften enterprise_status: status_title: "%{name} ist eingerichtet und bereit zu gehen!" severity: Schwere description: Beschreibung - resolve: Entschlossenheit + resolve: Lösung exchange_products: load_more_variants: "Weitere Varianten laden" load_all_variants: "Alle Varianten laden" @@ -2552,7 +2558,7 @@ de_DE: select_rule_type: "Wählen Sie einen Regelart aus:" add_rule: "Regel hinzufügen" enterprise_fees: - inherit_from_product: "Vom Produkt erben" + inherit_from_product: "Vom Produkt übernehmen" orders: index: per_page: "%{results} pro Seite" @@ -2581,19 +2587,21 @@ de_DE: partial: "teilweise" pending: "steht aus" ready: "fertig" - shipped: "versendet" + shipped: "versandt" canceled: "abgebrochen" payment_states: balance_due: "Betrag offen" completed: "fertig gestellt" checkout: "zur Kasse" - credit_owed: "Kredit geschuldet" + credit_owed: "Geschuldetes Guthaben" failed: "misslungen" paid: "bezahlt" pending: "steht aus" processing: "Prozess läuft" void: "Angabe fehlt" invalid: "ungültig" + quantity_adjusted: "Kein ausreichender Lagerbestand vorhanden. Die Position wurde auf die maximal verfügbare Menge aktualisiert." + quantity_unchanged: "Menge wurde nicht geändert." resend_user_email_confirmation: resend: "Erneut senden" sending: "Erneut senden ..." @@ -2610,14 +2618,14 @@ de_DE: created_schedule: "Zeitplan erstellt" updated_schedule: "Zeitplan aktualisiert" deleted_schedule: "Zeitplan gelöscht" - name_required_error: "Bitte geben Sie einen Namen für diesen Zeitplan ein" - no_order_cycles_error: "Bitte wählen Sie mindestens einen Bestellzyklus aus (Drag & Drop)" + name_required_error: "Bitte geben Sie einen Namen für diesen Zeitplan ein." + no_order_cycles_error: "Bitte wählen Sie mindestens einen Bestellzyklus aus." available: "Verfügbar" selected: "Ausgewählt" customers: index: add_customer: "Kunden hinzufügen" - add_a_new_customer_for: "Neuer Kunde für %{shop_name} hinzufügen" + add_a_new_customer_for: "Neuen Kunden für %{shop_name} hinzufügen" customer_placeholder: "Kunde@beispiel.org" valid_email_error: "Bitte geben Sie eine gültige E-Mail-Adresse ein" subscriptions: @@ -2629,8 +2637,8 @@ de_DE: images: removed_logo_successfully: "Das Logo wurde erfolgreich entfernt" immediate_logo_removal_warning: "Das Logo wird sofort nach der Bestätigung entfernt." - removed_promo_image_successfully: "Werbebild wurde erfolgreich entfernt" - immediate_promo_image_removal_warning: "Das Werbebild wird sofort nach der Bestätigung entfernt." + removed_promo_image_successfully: "Bild wurde erfolgreich entfernt." + immediate_promo_image_removal_warning: "Das Bild wird sofort nach der Bestätigung entfernt." immediate_terms_and_conditions_removal_warning: "Die AGB-Datei wird sofort nach Bestätigung entfernt." removed_terms_and_conditions_successfully: "AGB-Datei erfolgreich entfernt" insufficient_stock: "Nicht genügend Lagerbestand verfügbar, nur noch %{on_hand} verfügbar" @@ -2655,27 +2663,27 @@ de_DE: 'yes': "Auf Anfrage" variant_overrides: on_demand: - use_producer_settings: "Verwenden Sie die Einstellungen des Produzentenbestands" + use_producer_settings: "Einstellungen des Produzentenbestands verwenden" 'yes': "Ja" 'no': "Nein" inventory_products: "Katalogprodukte" - hidden_products: "Ausgeblendete Produkte" + hidden_products: "Verborgene Produkte" new_products: "Neue Produkte" - reset_stock_levels: Zurücksetzen der Bestandswerte auf Standardwerte + reset_stock_levels: Lagerbestände auf Standardbestände zurücksetzen changes_to: Änderungen an one_override: ein Override overrides: überschreibt remain_unsaved: bleiben ungespeichert. no_changes_to_save: Keine Änderungen zum Speichern. - no_authorisation: "Ich konnte keine Berechtigung zum Speichern dieser Änderungen erhalten, sodass sie nicht gespeichert werden." - some_trouble: "Ich hatte Probleme beim Speichern: %{errors}" + no_authorisation: "Keine Berechtigung zum Speichern dieser Änderungen. Änderungen werden nicht gespeichert." + some_trouble: "Probleme beim Speichern: %{errors}" changing_on_hand_stock: Änderung der Lagerbestände ... - stock_reset: Aktien werden auf Standardwerte zurückgesetzt. + stock_reset: Lagerbestände werden auf Standardwerte zurückgesetzt. tag_rules: show_hide_variants: 'Produktvarianten im Laden anzeigen?' - show_hide_shipping: 'Lieferarten an der Kasse anzeigen?' + show_hide_shipping: 'Lieferoptionen an der Kasse anzeigen?' show_hide_payment: 'Zahlungsarten an der Kasse anzeigen?' - show_hide_order_cycles: 'Bestellzyklen in meinem Laden anzeigen?' + show_hide_order_cycles: 'Bestellzyklen im Laden anzeigen?' visible: SICHTBAR not_visible: NICHT SICHTBAR services: @@ -2698,15 +2706,15 @@ de_DE: update_failure: "Fehler beim Aktualisieren des Bestellzyklus" no_distributors: In diesem Bestellzyklus gibt es keine Distributoren. Dieser Bestellzyklus ist für Kunden erst sichtbar, wenn Sie einen hinzufügen. Möchten Sie diesen Bestellzyklus weiterhin speichern? enterprises: - producer: "Erzeuger" + producer: "Produzent" non_producer: "Händler" customers: - select_shop: 'Bitte wählen Sie zuerst einen Laden aus' + select_shop: 'Bitte wählen Sie zuerst einen Laden aus.' could_not_create: 'Es tut uns leid! Konnte nicht erstellt werden:' subscriptions: closes: schließt closed: geschlossen - close_date_not_set: Abschlussdatum nicht eingestellt + close_date_not_set: Schließdatum nicht eingestellt spree: users: order: "Bestellung" @@ -2805,14 +2813,14 @@ de_DE: none: "Keine" select_and_search: "Wählen Sie Filter aus und klicken Sie auf BERICHT ERSTELLEN, um auf Ihre Daten zuzugreifen." enterprise_fee_summary: - date_end_before_start_error: "muss nach dem start sein" + date_end_before_start_error: "muss nach dem Beginn sein" parameter_not_allowed_error: "Sie sind nicht berechtigt, einen oder mehrere ausgewählte Filter für diesen Bericht zu verwenden." fee_calculated_on_transfer_through_all: "Alle" fee_calculated_on_transfer_through_entire_orders: "Gesamte Bestellungen über %{distributor}" tax_category_various: "Verschiedene" fee_type: payment_method: "Zahlungsvorgang" - shipping_method: "Sendung" + shipping_method: "Versand" fee_placements: supplier: "Eingehend" distributor: "Ausgehend" @@ -2847,12 +2855,12 @@ de_DE: customer_details: "Kundendetails" adjustments: "Anpassungen" payments: "Zahlungen" - return_authorizations: "Berechtigungen zurückgeben" - credit_owed: "Gutschrift geschuldet" + return_authorizations: "Retouren" + credit_owed: "Geschuldetes Guthaben" new_adjustment: "Neue Anpassung" payment: "Zahlung" payment_method: "Zahlungsart" - shipment: "Sendung" + shipment: "Versand" shipment_inc_vat: "Versand inklusive Mehrwertsteuer" shipping_tax_rate: "Versandsteuersatz" category: "Produktkategorie" @@ -2866,21 +2874,21 @@ de_DE: date_range: "Datumsbereich" status: "Status" new: "Neu" - start: "Start" + start: "Von" end: "Ende" - stop: "Halt" + stop: "Bis" first: "Erste" previous: "Vorherige" last: "Letzte" spree: more: "Mehr" - your_order_is_empty_add_product: "Ihre Bestellung ist leer. Suchen Sie oben ein Produkt und fügen Sie es hinzu" + your_order_is_empty_add_product: "Ihre Bestellung ist leer. Suchen Sie oben ein Produkt und fügen Sie es hinzu." add_product: "Produkt hinzufügen" - name_or_sku: "Name oder SKU (geben Sie mindestens die ersten 4 Zeichen des Produktnamens ein)" + name_or_sku: "Produktname oder Artikelnummer (geben Sie mindestens die ersten 3 Zeichen des Produktnamens ein)" resend: Erneut senden back_to_orders_list: Zurück zur Bestellliste - return_authorizations: Rückgabeberechtigungen - cannot_create_returns: Retouren können nicht erstellt werden, da für diese Bestellung keine Versandeinheiten vorhanden sind. + return_authorizations: Retouren + cannot_create_returns: Retouren können nicht erstellt werden, da für diese Bestellung kein Versand bestätigt wurde. select_stock: "Bestand auswählen" location: "Ort" count_on_hand: "Zählen Sie zur Hand" @@ -2904,11 +2912,11 @@ de_DE: choose_a_customer: "Wählen Sie einen Kunden aus" account: "Konto" billing_address: "Rechnungsadresse" - shipping_address: "Lieferanschrift" + shipping_address: "Lieferadresse" first_name: "Vorname" last_name: "Nachname" - street_address: "Adresse" - street_address_2: "Straße (Fortsetzung)" + street_address: "Straße + Hausnummer" + street_address_2: "Adresszusatz (optional)" city: "Ort" zip: "Postleitzahl" country: "Land" @@ -2922,7 +2930,7 @@ de_DE: credit_card: "Kreditkarte" new_payment: "Neue Zahlung" capture: "Erfassung" - void: "Leere" + void: "Löschen" login: "Anmeldung" password: "Passwort" signature: "Unterschrift" @@ -2967,7 +2975,7 @@ de_DE: new_tax_rate: "Neuer Steuersatz" tax_category: "Steuerkategorie" rate: "Bewertung" - tax_rate_amount_explanation: "Steuersätze sind ein Dezimalbetrag zur Vereinfachung der Berechnung (d.h. wenn der Steuersatz 5 % beträgt, geben Sie 0,05 ein)." + tax_rate_amount_explanation: "Steuersätze sind ein Dezimalbetrag zur Vereinfachung der Berechnung (d. h. wenn der Steuersatz 5 % beträgt, geben Sie 0,05 ein)." included_in_price: "Im Preis inbegriffen" show_rate_in_label: "Rate im Etikett anzeigen" back_to_tax_rates_list: "Zurück zur Liste der Steuersätze" @@ -2991,8 +2999,8 @@ de_DE: taxonomies: "Taxonomien" new_taxonomy: "Neue Taxonomie" back_to_taxonomies_list: "Zurück zur Taxonomieliste" - shipping_methods: "Lieferart" - shipping_method: "Lieferart" + shipping_methods: "Lieferoption" + shipping_method: "Lieferoption" shipping_categories: "Versandkategorien" new_shipping_category: "Neue Versandkategorie" back_to_shipping_categories: "Zurück zu den Versandkategorien" @@ -3009,16 +3017,16 @@ de_DE: no_results: "Keine Ergebnisse" create: "Neu" loading: "Wird geladen ..." - flat_percent: "Flacher Prozentsatz" + flat_percent: "Fester Prozentsatz (%)" per_kg: "Pro kg" amount: "Betrag" currency: "Währung" - first_item: "Erste Artikelkosten" - additional_item: "Zusätzliche Artikelkosten" - max_items: "Max. Artikel" - minimal_amount: "Minimale Menge" - normal_amount: "Normaler Betrag" - discount_amount: "Rabattbetrag" + first_item: "Gebühr für den ersten Artikel (€)" + additional_item: "Gebühr für jeden weiteren Artikel (€)" + max_items: "Gebührenfrei ab (Anzahl Artikel)" + minimal_amount: "Mengenrabatt ab (€)" + normal_amount: "Gebühr unterhalb (€)" + discount_amount: "Gebühr oberhalb (€)" no_images_found: "Keine Bilder gefunden" new_image: "Neues Bild" filename: "Dateiname" @@ -3039,7 +3047,7 @@ de_DE: cannot_create_payment_without_payment_methods: "Sie können keine Zahlung für eine Bestellung erstellen, ohne dass Zahlungsarten definiert sind." please_define_payment_methods: "Bitte definieren Sie zunächst die Zahlungsarten." options: "Optionen" - has_no_shipped_units: "hat keine versendeten Einheiten" + has_no_shipped_units: "hat keine versandten Einheiten" successfully_created: '%{resource} wurde erfolgreich erstellt!' successfully_updated: '%{resource} wurde erfolgreich aktualisiert!' payment_method: "Zahlungsart" @@ -3093,7 +3101,7 @@ de_DE: groups: "Gruppen" product_properties: index: - inherits_properties_checkbox_hint: "Vererben Eigenschaften von %{supplier}? (außer oben aufgehoben)" + inherits_properties_checkbox_hint: "Übernahme der Eigenschaften von %{supplier} (außer oben überschrieben)?" add_product_properties: "Produkteigenschaften hinzufügen" properties: index: @@ -3112,16 +3120,16 @@ de_DE: return_authorizations: index: new_return_authorization: "Neue Rücksendegenehmigung" - return_authorizations: "Rückgabeberechtigungen" + return_authorizations: "Retouren" back_to_orders_list: "Zurück zur Bestellliste" rma_number: "RMA-Nummer" status: "Status" amount: "Betrag" - cannot_create_returns: "Retouren können nicht erstellt werden, da für diese Bestellung keine Versandeinheiten vorhanden sind." + cannot_create_returns: "Retouren können nicht erstellt werden, da für diese Bestellung kein Versand bestätigt wurde." continue: "Fortsetzen" new: new_return_authorization: "Neue Rücksendegenehmigung" - back_to_return_authorizations_list: "Zurück zur Autorisierungsliste" + back_to_return_authorizations_list: "Zurück zur Rücksendeliste" continue: "Fortsetzen" edit: receive: "erhalten" @@ -3142,9 +3150,9 @@ de_DE: canceled: "Abgesagt" orders: index: - listing_orders: "Bestellungen auflisten" + listing_orders: "Bestellungen verwalten" new_order: "Neue Bestellung" - capture: "Erfassung" + capture: "Verbuchen" ship: "Liefern" edit: "Bearbeiten" order_not_updated: "Die Bestellung konnte nicht aktualisiert werden" @@ -3175,21 +3183,21 @@ de_DE: form: distribution_fields: title: "Verteilung" - distributor: "Verteiler:" + distributor: "Verteilstelle:" order_cycle: "Bestellzyklus:" - line_item_adjustments: "Anpassungen der Werbebuchung" + line_item_adjustments: "Anpassungen der Einzelposten" order_adjustments: "Bestellanpassungen" order_total: "Bestellung insgesamt" overview: enterprises_header: - ofn_with_tip: Unternehmen sind Erzeuger und/oder Hubs und sind die grundlegende Organisationseinheit innerhalb des Open Food Network. + ofn_with_tip: Unternehmen sind Produzenten und/oder Hubs und sind die grundlegende Organisationseinheit innerhalb des Open Food Network. products: active_products: zero: "Sie haben keine aktiven Produkte." one: "Sie haben ein aktives Produkt" - few: "Sie haben %{count} aktive Produkte" - many: "Sie haben %{count} aktive Produkte" - other: "Sie haben %{count} aktive Produkte" + few: "Sie haben %{count} aktive Produkte." + many: "Sie haben %{count} aktive Produkte." + other: "Sie haben %{count} aktive Produkte." order_cycles: order_cycles: "Bestellzyklen" order_cycles_tip: "Bestellzyklen bestimmen, wann und wo Ihre Produkte für Kunden verfügbar sind." @@ -3202,35 +3210,35 @@ de_DE: manage_order_cycles: "BESTELLZYKLEN VERWALTEN" shipping_methods: index: - shipping_methods: "Lieferart" + shipping_methods: "Lieferoption" new_shipping_method: "Neue Versandart" name: "Name" - products_distributor: "Verteiler" + products_distributor: "Verteilstelle" zone: "Zone" calculator: "Rechner" display: "Anzeige" both: "Sowohl Checkout als auch Backoffice" back_end: "Nur Backoffice" - no_shipping_methods_found: "Keine Versandmethoden gefunden" + no_shipping_methods_found: "Keine Versandarten gefunden" new: new_shipping_method: "Neue Versandart" - back_to_shipping_methods_list: "Zurück zur Liste der Versandmethoden" + back_to_shipping_methods_list: "Zurück zur Liste der Versandarten" edit: editing_shipping_method: "Versandart bearbeiten" new: "Neu" - back_to_shipping_methods_list: "Zurück zur Liste der Versandmethoden" + back_to_shipping_methods_list: "Zurück zur Liste der Versandarten" form: categories: "Kategorien" zones: "Zonen" both: "Sowohl Checkout als auch Backoffice" back_end: "Nur Backoffice" - deactivation_warning: "Durch Deaktivieren einer Versandart kann die Versandart aus Ihrer Liste verschwinden. Alternativ können Sie eine Versandart auf der Checkout-Seite ausblenden, indem Sie die Option "Anzeige" auf "Nur Backoffice" setzen." + deactivation_warning: "Durch Deaktivieren einer Versandart wird die Versandart Ihren Kunden nicht mehr zur Verfügung stehen. Alternativ können Sie eine Versandart auf der Checkout-Seite ausblenden, indem Sie die Option \"Anzeige\" auf \"Nur Backoffice\" setzen." payment_methods: index: payment_methods: "Zahlungsarten" new_payment_method: "Neue Zahlungsart" name: "Name" - products_distributor: "Verteiler" + products_distributor: "Verteilstelle" provider: "Anbieter" environment: "Umgebung" display: "Anzeige" @@ -3307,10 +3315,10 @@ de_DE: product_description: "Produktbeschreibung" image: "Bild" or: "oder" - unit_name_placeholder: 'z.B. Trauben' + unit_name_placeholder: 'z. B. Trauben' index: header: - title: Massenbearbeitung von Produkten + title: Produktliste verwalten indicators: title: LADE PRODUKTE no_products: "Bisher gibt es noch keine Produkte. Warum fügen Sie nicht einige hinzu?" @@ -3321,7 +3329,7 @@ de_DE: display_as: Angezeigt als category: Kategorie tax_category: Steuerkategorie - inherits_properties?: Vererbt Eigenschaften + inherits_properties?: Übernimmt Eigenschaften des Ladens? available_on: Verfügbar am av_on: "Verfüg. am" import_date: "Importdatum" @@ -3333,7 +3341,7 @@ de_DE: product_category: Produktkategorie group_buy_form: group_buy: "Gruppenkauf?" - bulk_unit_size: Größe der Masseneinheit + bulk_unit_size: Erforderliche Menge (in Gramm, Liter oder Stück) display_as: display_as: Darstellen als reports: @@ -3365,20 +3373,20 @@ de_DE: confirm_password: "Passwort bestätigen" password: "Passwort" email_confirmation: - confirmation_pending: "E-Mail-Bestätigung steht aus. Wir haben eine Bestätigungs-E-Mail an %{address} gesendet." + confirmation_pending: "E-Mail-Bestätigung steht aus. Wir haben eine E-Mail an %{address} gesendet." variants: index: sku: "Artikelnummer" price: "Preis" - options: "Optionen" + options: "Varianten" no_results: "Keine Ergebnisse" to_add_variants_you_must_first_define: "Um Varianten hinzuzufügen, müssen Sie zuerst definieren" option_types: "Optionstypen" option_values: "Optionswerte" and: "und" new_variant: "Neue Variante" - show_active: "Aktiv anzeigen" - show_deleted: "Show gelöscht" + show_active: "Zeige Aktive" + show_deleted: "Zeige Gelöschte" new: new_variant: "Neue Variante" form: @@ -3386,12 +3394,12 @@ de_DE: sku: "Artikelnummer" price: "Preis" display_as: "Angezeigt als" - display_name: "Anzeigename" - display_as_placeholder: 'z.B. 2 kg' - display_name_placeholder: 'z.B. Tomaten' + display_name: "Variantenname" + display_as_placeholder: 'z. B. 2 kg' + display_name_placeholder: 'z. B. Tomaten' autocomplete: out_of_stock: "Nicht vorrättig" - producer_name: "Erzeuger" + producer_name: "Produzent" unit: "Einheit" shared: sortable_header: @@ -3440,17 +3448,17 @@ de_DE: shipment_states: backorder: Lieferrückstand partial: teilweise - pending: auf Bestätigung wartend + pending: wartet auf Bestätigung ready: fertig - shipped: versendet + shipped: versandt payment_states: balance_due: Betrag offen completed: fertig gestellt checkout: zur Kasse - credit_owed: Kredit geschuldet + credit_owed: Geschuldetes Guthaben failed: misslungen paid: bezahlt - pending: auf Bestätigung wartend + pending: wartet auf Bestätigung processing: Prozess läuft void: Angabe fehlt invalid: ungültig @@ -3483,13 +3491,17 @@ de_DE: subject: "Anweisungen zum Zurücksetzen des Passworts" confirmation_instructions: subject: "Bitte bestätigen Sie Ihre Anmeldung bei Open Food Network DE!" + payment_mailer: + authorize_payment: + subject: "Bitte bestätigen Sie Ihre Zahlung an %{distributor} im Open Food Network." + instructions: "Ihre Zahlung in Höhe von %{amount} an %{distributor} erfordert eine zusätzliche Authentifizierung. Bitte besuchen Sie die folgende URL, um Ihre Zahlung zu bestätigen:" shipment_mailer: shipped_email: - dear_customer: "Sehr geehrte Kundin, sehr geehrter Kunde," + dear_customer: "Liebe Kundin, lieber Kunde," instructions: "Ihre Bestellung wurde versandt" shipment_summary: "Übersicht" subject: "Versandbenachrichtigung" - thanks: "Danke für Ihren Einkauf." + thanks: "Danke für deinen Einkauf!" track_information: "Tracking-Informationen: %{tracking}" track_link: "Tracking-Link: %{url}" test_mailer: @@ -3499,18 +3511,18 @@ de_DE: subject: "Test-E-Mail" order_state: address: Adresse - adjustments: Verbesserungen - awaiting_return: Warten auf die Rückkehr + adjustments: Anpassungen + awaiting_return: wartet auf Rückkehr canceled: abgebrochen - cart: Einkaufswagen - complete: fertigstellen + cart: im Einkaufswagen + complete: abgeschlossen confirm: bestätigen delivery: Lieferung paused: pausiert payment: Bezahlung pending: steht aus - resumed: zusammengefasst - returned: zurück gegeben + resumed: wiederaufgenommen + returned: zurückgegeben skrill: Skrill subscription_state: active: aktiv @@ -3574,7 +3586,7 @@ de_DE: delete?: Löschen? cards: authorised_shops: Bevollmächtigte Läden - authorised_shops_agreement: Dies ist die Liste der Läden, in denen Ihre Standardkreditkarte für eventuelle Abonnements (d.h. wiederholte Bestellungen) belastet werden darf. Ihre Kartendaten werden sicher aufbewahrt und nicht an Ladenbesitzer weitergegeben. Sie werden immer benachrichtigt, wenn Ihre Kreditkarte belastet wird. Wenn Sie das Kontrollkästchen für einen Laden aktivieren, erklären Sie sich damit einverstanden, diesen Laden zu autorisieren, Anweisungen an das Finanzinstitut, das Ihre Kreditkarte ausgestellt hat, zu senden, um Zahlungen gemäß den Bedingungen eines Abonnements entgegenzunehmen, das Sie mit diesem Laden erstellen. + authorised_shops_agreement: Dies ist die Liste der Läden, in denen Ihre Standardkreditkarte für eventuelle Abonnements (d. h. wiederholte Bestellungen) belastet werden darf. Ihre Kartendaten werden sicher aufbewahrt und nicht an Ladenbesitzer weitergegeben. Sie werden immer benachrichtigt, wenn Ihre Kreditkarte belastet wird. Wenn Sie das Kontrollkästchen für einen Laden aktivieren, erklären Sie sich damit einverstanden, diesen Laden zu autorisieren, Anweisungen an das Finanzinstitut, das Ihre Kreditkarte ausgestellt hat, zu senden, um Zahlungen gemäß den Bedingungen eines Abonnements entgegenzunehmen, das Sie mit diesem Laden erstellen. saved_cards_popover: Dies ist die Liste der Karten, die Sie für 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). authorised_shops: shop_name: "Ladenname" diff --git a/config/locales/en.yml b/config/locales/en.yml index e24f65f92c..e3b8b3e755 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3117,6 +3117,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using tax rate: "Tax Rates" new_tax_rate: "New Tax Rate" tax_category: "Tax Category" + tax_rates: "Tax Rates" rate: "Rate" tax_rate_amount_explanation: "Tax rates are a decimal amount to aid in calculations, (i.e. if the tax rate is 5% then enter 0.05)" included_in_price: "Included in Price" diff --git a/config/locales/en_FR.yml b/config/locales/en_FR.yml index c822e98cd1..ebe38ca693 100644 --- a/config/locales/en_FR.yml +++ b/config/locales/en_FR.yml @@ -2319,6 +2319,8 @@ en_FR: payment_processing_failed: "Payment could not be processed, please check the details you entered" payment_method_not_supported: "That payment method is unsupported. Please choose another one." payment_updated: "Payment Updated" + cannot_perform_operation: "Could not update the payment" + action_required: "Action required" inventory_settings: "Inventory Settings" tag_rules: "Tag Rules" shop_preferences: "Shop Preferences" @@ -2587,6 +2589,8 @@ en_FR: processing: "processing" void: "void" invalid: "invalid" + quantity_adjusted: "Insufficient stock available. Line item updated to maximum available quantity." + quantity_unchanged: "Quantity unchanged from previous amount." resend_user_email_confirmation: resend: "Resend" sending: "Resend..." @@ -3478,6 +3482,10 @@ en_FR: subject: "Reset password instructions" confirmation_instructions: subject: "Please confirm your OFN account" + payment_mailer: + authorize_payment: + subject: "Please authorize your payment to %{distributor} on CoopCircuits" + instructions: "Your payment of %{amount} to %{distributor} requires additional authentication. Please visit the following URL to authorize your payment:" shipment_mailer: shipped_email: dear_customer: "Dear Customer," diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 4ab019d177..c1401dd28d 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -2319,6 +2319,8 @@ en_GB: payment_processing_failed: "Payment could not be processed, please check the details you entered" payment_method_not_supported: "That payment method is unsupported. Please choose another one." payment_updated: "Payment Updated" + cannot_perform_operation: "Could not update the payment" + action_required: "Action required" inventory_settings: "Inventory Settings" tag_rules: "Tag Rules" shop_preferences: "Shop Preferences" @@ -2593,6 +2595,8 @@ en_GB: processing: "processing" void: "void" invalid: "invalid" + quantity_adjusted: "Insufficient stock available. Line item updated to maximum available quantity." + quantity_unchanged: "Quantity unchanged from previous amount." resend_user_email_confirmation: resend: "Resend" sending: "Resend..." @@ -3484,6 +3488,10 @@ en_GB: subject: "Reset password instructions" confirmation_instructions: subject: "Please confirm your OFN account" + payment_mailer: + authorize_payment: + subject: "Please authorise your payment to %{distributor} on OFN" + instructions: "Your payment of %{amount} to %{distributor} requires additional authentication. Please visit the following URL to authorise your payment:" shipment_mailer: shipped_email: dear_customer: "Dear Customer," diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 09e54ca5ad..1edb7dc492 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -2321,6 +2321,8 @@ fr: payment_processing_failed: "Le paiement n'a pas pu être traité, veuillez vérifier les informations saisies" payment_method_not_supported: "Cette méthode de paiement n'est pas maintenue. Veuillez en sélectionner une autre." payment_updated: "Paiement mis à jour" + cannot_perform_operation: "Le paiement n'a pas pu être mis à jour." + action_required: "Une action est requise" inventory_settings: "Catalogue boutique" tag_rules: "Règles de tag" shop_preferences: "Préférences boutique" @@ -2615,6 +2617,8 @@ fr: processing: "en traitement" void: "faire un avoir" invalid: "invalide" + quantity_adjusted: "Le stock disponible est insuffisant. La quantité a été mise à jour en fonction du stock restant." + quantity_unchanged: "La quantité n'a pas été modifiée." resend_user_email_confirmation: resend: "Renvoyer" sending: "Renvoi...." @@ -3508,6 +3512,10 @@ fr: subject: "Instructions de mise à jour du mot de passe" confirmation_instructions: subject: "Veuillez confirmer votre compte" + payment_mailer: + authorize_payment: + subject: "Veuillez autoriser votre paiement à %{distributor} sur CoopCircuits." + instructions: "Votre paiement de %{amount} à %{distributor} demande une autorisation additionnelle. Veuillez suivre ce lien afin d'autoriser votre paiement :" shipment_mailer: shipped_email: dear_customer: "Cher Acheteur," diff --git a/config/routes/spree.rb b/config/routes/spree.rb index bc8ccf5d78..a16ccaf107 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -1,3 +1,11 @@ +Openfoodnetwork::Application.routes.draw do + scope module: 'spree' do + resources :orders do + put :cancel, on: :member + end + end +end + # Overriding Devise routes to use our own controller Spree::Core::Engine.routes.draw do devise_for :spree_user, @@ -159,12 +167,6 @@ Spree::Core::Engine.routes.draw do resources :payment_methods end - resources :orders do - get :clear, :on => :collection - get :order_cycle_expired, :on => :collection - put :cancel, on: :member - end - resources :products # Used by spree_paypal_express diff --git a/db/migrate/20210125123000_remove_enable_mail_delivery_preference.rb b/db/migrate/20210125123000_remove_enable_mail_delivery_preference.rb new file mode 100644 index 0000000000..a08642e931 --- /dev/null +++ b/db/migrate/20210125123000_remove_enable_mail_delivery_preference.rb @@ -0,0 +1,8 @@ +class RemoveEnableMailDeliveryPreference < ActiveRecord::Migration + def up + Spree::Preference.delete_all("key ilike '%enable_mail_delivery%'") + end + + def down + end +end diff --git a/db/schema.rb b/db/schema.rb index fc360b11e1..7e26c00970 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20210115143738) do +ActiveRecord::Schema.define(version: 20210125123000) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/db/seeds.rb b/db/seeds.rb index 23d907c4bf..95629e77ef 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -4,7 +4,6 @@ require 'yaml' def set_mail_configuration MailConfiguration.entries= { - enable_mail_delivery: true, mail_host: ENV.fetch('MAIL_HOST'), mail_domain: ENV.fetch('MAIL_DOMAIN'), mail_port: ENV.fetch('MAIL_PORT'), diff --git a/lib/spree/core/mail_settings.rb b/lib/spree/core/mail_settings.rb index 5fd94c8fa3..dde88bbb22 100644 --- a/lib/spree/core/mail_settings.rb +++ b/lib/spree/core/mail_settings.rb @@ -12,13 +12,9 @@ module Spree end def override! - if Config.enable_mail_delivery - ActionMailer::Base.default_url_options[:host] ||= Config.site_url - ActionMailer::Base.smtp_settings = mail_server_settings - ActionMailer::Base.perform_deliveries = true - else - ActionMailer::Base.perform_deliveries = false - end + ActionMailer::Base.default_url_options[:host] ||= Config.site_url + ActionMailer::Base.smtp_settings = mail_server_settings + ActionMailer::Base.perform_deliveries = true end private diff --git a/lib/spree/i18n.rb b/lib/spree/i18n.rb index 7780bc3ad7..39bd4590cd 100644 --- a/lib/spree/i18n.rb +++ b/lib/spree/i18n.rb @@ -6,6 +6,7 @@ require 'spree/i18n/base' module Spree extend ActionView::Helpers::TranslationHelper + extend ActionView::Helpers::TagHelper if ENV['DEPENDENCIES_NEXT'] class << self # Add spree namespace and delegate to Rails TranslationHelper for some nice diff --git a/spec/controllers/admin/bulk_line_items_controller_spec.rb b/spec/controllers/admin/bulk_line_items_controller_spec.rb index fa8f628c6c..d40e0682d2 100644 --- a/spec/controllers/admin/bulk_line_items_controller_spec.rb +++ b/spec/controllers/admin/bulk_line_items_controller_spec.rb @@ -20,7 +20,7 @@ describe Admin::BulkLineItemsController, type: :controller do before { allow(controller).to receive_messages spree_current_user: create(:user) } it "should deny me access to the index action" do - spree_get :index, format: :json + get :index, format: :json expect(response).to redirect_to unauthorized_path end end @@ -32,7 +32,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "when no ransack params are passed in" do before do - spree_get :index, format: :json + get :index, format: :json end it "retrieves a list of line_items with appropriate attributes, including line items with appropriate attributes" do @@ -56,7 +56,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "when ransack params are passed in for line items" do before do - spree_get :index, format: :json, q: { order_id_eq: order2.id } + get :index, format: :json, q: { order_id_eq: order2.id } end it "retrives a list of line items which match the criteria" do @@ -66,7 +66,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "when ransack params are passed in for orders" do before do - spree_get :index, format: :json, q: { order: { completed_at_gt: 2.hours.ago } } + get :index, format: :json, q: { order: { completed_at_gt: 2.hours.ago } } end it "retrives a list of line items whose orders match the criteria" do @@ -90,7 +90,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "producer enterprise" do before do allow(controller).to receive_messages spree_current_user: supplier.owner - spree_get :index, format: :json + get :index, format: :json end it "does not display line items for which my enterprise is a supplier" do @@ -101,7 +101,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "coordinator enterprise" do before do allow(controller).to receive_messages spree_current_user: coordinator.owner - spree_get :index, format: :json + get :index, format: :json end it "retrieves a list of line_items" do @@ -113,7 +113,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "hub enterprise" do before do allow(controller).to receive_messages spree_current_user: distributor1.owner - spree_get :index, format: :json + get :index, format: :json end it "retrieves a list of line_items" do @@ -130,7 +130,7 @@ describe Admin::BulkLineItemsController, type: :controller do context "with pagination args" do it "returns paginated results" do - spree_get :index, { page: 1, per_page: 2 }, format: :json + get :index, { page: 1, per_page: 2 }, format: :json expect(line_item_ids).to eq [line_item1.id, line_item2.id] expect(json_response['pagination']).to eq( @@ -139,7 +139,7 @@ describe Admin::BulkLineItemsController, type: :controller do end it "returns paginated results for a second page" do - spree_get :index, { page: 2, per_page: 2 }, format: :json + get :index, { page: 2, per_page: 2 }, format: :json expect(line_item_ids).to eq [line_item3.id, line_item4.id] expect(json_response['pagination']).to eq( diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index b15b5efdd8..6f289dc891 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -17,7 +17,7 @@ module Admin end it "returns an empty @collection" do - spree_get :index, format: :html + get :index, format: :html expect(assigns(:collection)).to eq [] end end @@ -34,13 +34,13 @@ module Admin let(:params) { { format: :json, enterprise_id: enterprise.id } } it "scopes @collection to customers of that enterprise" do - spree_get :index, params + get :index, params expect(assigns(:collection)).to eq [customer] end it "serializes the data" do expect(ActiveModel::ArraySerializer).to receive(:new) - spree_get :index, params + get :index, params end context 'when the customer_balance feature is enabled' do @@ -57,13 +57,13 @@ module Admin expect(customers_with_balance).to receive(:query) { Customer.none } - spree_get :index, params + get :index, params end it 'serializes using CustomerWithBalanceSerializer' do expect(Api::Admin::CustomerWithBalanceSerializer).to receive(:new) - spree_get :index, params + get :index, params end end @@ -75,20 +75,20 @@ module Admin it 'calls Customer.of' do expect(Customer).to receive(:of).twice.with(enterprise) { Customer.none } - spree_get :index, params + get :index, params end it 'serializes calling the UserBalanceCalculator' do expect(OpenFoodNetwork::UserBalanceCalculator) .to receive(:new).with(customer.email, customer.enterprise) { calculator } - spree_get :index, params + get :index, params end end context 'when the customer has no orders' do it 'includes the customer balance in the response' do - spree_get :index, params + get :index, params expect(json_response.first["balance"]).to eq("$0.00") end end @@ -103,7 +103,7 @@ module Admin end it 'includes the customer balance in the response' do - spree_get :index, params + get :index, params expect(json_response.first["balance"]).to eq("$-10.00") end end @@ -124,7 +124,7 @@ module Admin end it 'includes the customer balance in the response' do - spree_get :index, params + get :index, params expect(json_response.first["balance"]).to eq("$10.00") end end @@ -134,7 +134,7 @@ module Admin let!(:line_item) { create(:line_item, order: order, price: 10.0) } it 'includes the customer balance in the response' do - spree_get :index, params + get :index, params expect(json_response.first["balance"]).to eq("$0.00") end end @@ -156,7 +156,7 @@ module Admin it 'includes the customer balance in the response' do expect(order.payment_total).to eq(0) - spree_get :index, params + get :index, params expect(json_response.first["balance"]).to eq('$-10.00') end end @@ -164,7 +164,7 @@ module Admin context "and enterprise_id is not given in params" do it "returns an empty collection" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to eq [] end end @@ -176,7 +176,7 @@ module Admin end it "returns an empty collection" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to eq [] end end @@ -276,7 +276,7 @@ module Admin end it "renders the customer as json" do - spree_get :show, format: :json, id: customer.id + get :show, format: :json, id: customer.id expect(JSON.parse(response.body)["id"]).to eq customer.id end end @@ -287,7 +287,7 @@ module Admin end it "prevents me from updating the customer" do - spree_get :show, format: :json, id: customer.id + get :show, format: :json, id: customer.id expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb index a19cada4d4..507f840710 100644 --- a/spec/controllers/admin/enterprises_controller_spec.rb +++ b/spec/controllers/admin/enterprises_controller_spec.rb @@ -457,28 +457,28 @@ describe Admin::EnterprisesController, type: :controller do end context "when no order_cycle or coordinator is provided in params" do - before { spree_get :for_order_cycle, format: :json } + before { get :for_order_cycle, format: :json } it "initializes permissions with nil" do expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, nil) end end context "when an order_cycle_id is provided in params" do - before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1 } + before { get :for_order_cycle, format: :json, order_cycle_id: 1 } it "initializes permissions with the existing OrderCycle" do expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") end end context "when a coordinator is provided in params" do - before { spree_get :for_order_cycle, format: :json, coordinator_id: 1 } + before { get :for_order_cycle, format: :json, coordinator_id: 1 } it "initializes permissions with a new OrderCycle" do expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "new OrderCycle") end end context "when both an order cycle and a coordinator are provided in params" do - before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1, coordinator_id: 1 } + before { get :for_order_cycle, format: :json, order_cycle_id: 1, coordinator_id: 1 } it "initializes permissions with the existing OrderCycle" do expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") end @@ -500,7 +500,7 @@ describe Admin::EnterprisesController, type: :controller do it "uses permissions to determine which enterprises are visible and should be rendered" do expect(controller).to receive(:render_as_json).with([visible_enterprise], ams_prefix: 'basic', spree_current_user: user).and_call_original - spree_get :visible, format: :json + get :visible, format: :json end end @@ -518,14 +518,14 @@ describe Admin::EnterprisesController, type: :controller do context "html" do it "returns all enterprises" do - spree_get :index, format: :html + get :index, format: :html expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 end end context "json" do it "returns all enterprises" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 end end @@ -543,14 +543,14 @@ describe Admin::EnterprisesController, type: :controller do context "html" do it "returns an empty @collection" do - spree_get :index, format: :html + get :index, format: :html expect(assigns(:collection)).to eq [] end end context "json" do it "scopes @collection to enterprises editable by the user" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to include enterprise1, enterprise2 expect(assigns(:collection)).to_not include enterprise3 end diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 8321cefaa8..96eba697b0 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -20,7 +20,7 @@ module Admin context "html" do it "doesn't load any data" do - spree_get :index, format: :html + get :index, format: :html expect(assigns(:collection)).to be_empty end end @@ -28,7 +28,7 @@ module Admin context "json" do context "where ransack conditions are specified" do it "loads order cycles that closed within the past month, and orders without a close_at date" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to_not include oc1, oc2 expect(assigns(:collection)).to include oc3, oc4 end @@ -38,7 +38,7 @@ module Admin let(:q) { { orders_close_at_gt: 45.days.ago } } it "loads order cycles that closed after the specified date, and orders without a close_at date" do - spree_get :index, format: :json, q: q + get :index, format: :json, q: q expect(assigns(:collection)).to_not include oc1 expect(assigns(:collection)).to include oc2, oc3, oc4 end @@ -47,7 +47,7 @@ module Admin before { q.merge!(id_not_in: [oc2.id, oc4.id]) } it "loads order cycles that meet all conditions" do - spree_get :index, format: :json, q: q + get :index, format: :json, q: q expect(assigns(:collection)).to_not include oc1, oc2, oc4 expect(assigns(:collection)).to include oc3 end @@ -62,7 +62,7 @@ module Admin let!(:distributor) { create(:distributor_enterprise, owner: distributor_owner) } it "renders the new template" do - spree_get :new + get :new expect(response).to render_template :new end end @@ -73,21 +73,21 @@ module Admin let!(:distributor3) { create(:distributor_enterprise) } it "renders the set_coordinator template" do - spree_get :new + get :new expect(response).to render_template :set_coordinator end describe "and a coordinator_id is submitted as part of the request" do describe "when the user manages the enterprise" do it "renders the new template" do - spree_get :new, coordinator_id: distributor1.id + get :new, coordinator_id: distributor1.id expect(response).to render_template :new end end describe "when the user does not manage the enterprise" do it "renders the set_coordinator template and sets a flash error" do - spree_get :new, coordinator_id: distributor3.id + get :new, coordinator_id: distributor3.id expect(response).to render_template :set_coordinator expect(flash[:error]).to eq "You don't have permission to create an order cycle coordinated by that enterprise" end @@ -331,7 +331,7 @@ module Admin describe "when an order cycle is deleteable" do it "allows the order_cycle to be destroyed" do - spree_get :destroy, id: oc.id + get :destroy, id: oc.id expect(OrderCycle.find_by(id: oc.id)).to be nil end end @@ -340,7 +340,7 @@ module Admin let!(:order) { create(:order, order_cycle: oc) } it "displays an error message when we attempt to delete it" do - spree_get :destroy, id: oc.id + get :destroy, id: oc.id expect(response).to redirect_to admin_order_cycles_path expect(flash[:error]).to eq I18n.t('admin.order_cycles.destroy_errors.orders_present') end @@ -350,7 +350,7 @@ module Admin let!(:schedule) { create(:schedule, order_cycles: [oc]) } it "displays an error message when we attempt to delete it" do - spree_get :destroy, id: oc.id + get :destroy, id: oc.id expect(response).to redirect_to admin_order_cycles_path expect(flash[:error]).to eq I18n.t('admin.order_cycles.destroy_errors.schedule_present') end diff --git a/spec/controllers/admin/proxy_orders_controller_spec.rb b/spec/controllers/admin/proxy_orders_controller_spec.rb index 46436dedda..d98eccabeb 100644 --- a/spec/controllers/admin/proxy_orders_controller_spec.rb +++ b/spec/controllers/admin/proxy_orders_controller_spec.rb @@ -42,7 +42,7 @@ describe Admin::ProxyOrdersController, type: :controller do context "when cancellation succeeds" do it 'renders the cancelled proxy_order as json' do - spree_get :cancel, params + get :cancel, params json_response = JSON.parse(response.body) expect(json_response['state']).to eq "canceled" expect(json_response['id']).to eq proxy_order.id @@ -54,7 +54,7 @@ describe Admin::ProxyOrdersController, type: :controller do before { order_cycle.update(orders_close_at: 1.day.ago) } it "shows an error" do - spree_get :cancel, params + get :cancel, params json_response = JSON.parse(response.body) expect(json_response['errors']).to eq ['Could not cancel the order'] end @@ -111,7 +111,7 @@ describe Admin::ProxyOrdersController, type: :controller do context "when resuming succeeds" do it 'renders the resumed proxy_order as json' do - spree_get :resume, params + get :resume, params json_response = JSON.parse(response.body) expect(json_response['state']).to eq "resumed" expect(json_response['id']).to eq proxy_order.id @@ -123,7 +123,7 @@ describe Admin::ProxyOrdersController, type: :controller do before { order_cycle.update(orders_close_at: 1.day.ago) } it "shows an error" do - spree_get :resume, params + get :resume, params json_response = JSON.parse(response.body) expect(json_response['errors']).to eq ['Could not resume the order'] end diff --git a/spec/controllers/admin/schedules_controller_spec.rb b/spec/controllers/admin/schedules_controller_spec.rb index 4013f7492b..e6981bcfe6 100644 --- a/spec/controllers/admin/schedules_controller_spec.rb +++ b/spec/controllers/admin/schedules_controller_spec.rb @@ -21,13 +21,13 @@ describe Admin::SchedulesController, type: :controller do let(:params) { { format: :json } } it "scopes @collection to schedules containing order_cycles coordinated by enterprises I manage" do - spree_get :index, params + get :index, params expect(assigns(:collection)).to eq [coordinated_schedule] end it "serializes the data" do expect(ActiveModel::ArraySerializer).to receive(:new) - spree_get :index, params + get :index, params end context "and there is a schedule of an OC coordinated by _another_ enterprise I manage and the first enterprise is given" do @@ -37,7 +37,7 @@ describe Admin::SchedulesController, type: :controller do let(:params) { { format: :json, enterprise_id: managed_coordinator.id } } it "scopes @collection to schedules containing order_cycles coordinated by the first enterprise" do - spree_get :index, params + get :index, params expect(assigns(:collection)).to eq [coordinated_schedule] end end @@ -45,7 +45,7 @@ describe Admin::SchedulesController, type: :controller do context "where I dont manage an order cycle coordinator" do it "returns an empty collection" do - spree_get :index, format: :json + get :index, format: :json expect(assigns(:collection)).to be_nil end end diff --git a/spec/controllers/admin/stripe_accounts_controller_spec.rb b/spec/controllers/admin/stripe_accounts_controller_spec.rb index 3517374885..3774c47921 100644 --- a/spec/controllers/admin/stripe_accounts_controller_spec.rb +++ b/spec/controllers/admin/stripe_accounts_controller_spec.rb @@ -15,7 +15,7 @@ describe Admin::StripeAccountsController, type: :controller do end it "redirects to Stripe Authorization url constructed OAuth" do - spree_get :connect, enterprise_id: 1 # A deterministic id results in a deterministic state JWT token + get :connect, enterprise_id: 1 # A deterministic id results in a deterministic state JWT token expect(response).to redirect_to("https://connect.stripe.com/oauth/authorize?state=eyJhbGciOiJIUzI1NiJ9.eyJlbnRlcnByaXNlX2lkIjoiMSJ9.jSSFGn0bLhwuiQYK5ORmHWW7aay1l030bcfGwn1JbFg&scope=read_write&client_id=some_id&response_type=code") end @@ -98,7 +98,7 @@ describe Admin::StripeAccountsController, type: :controller do end it "redirects to unauthorized" do - spree_get :status, params + get :status, params expect(response).to redirect_to unauthorized_path end end @@ -110,7 +110,7 @@ describe Admin::StripeAccountsController, type: :controller do context "when Stripe is not enabled" do it "returns with a status of 'stripe_disabled'" do - spree_get :status, params + get :status, params json_response = JSON.parse(response.body) expect(json_response["status"]).to eq "stripe_disabled" end @@ -121,7 +121,7 @@ describe Admin::StripeAccountsController, type: :controller do context "when no stripe account is associated with the specified enterprise" do it "returns with a status of 'account_missing'" do - spree_get :status, params + get :status, params json_response = JSON.parse(response.body) expect(json_response["status"]).to eq "account_missing" end @@ -136,7 +136,7 @@ describe Admin::StripeAccountsController, type: :controller do end it "returns with a status of 'access_revoked'" do - spree_get :status, params + get :status, params json_response = JSON.parse(response.body) expect(json_response["status"]).to eq "access_revoked" end @@ -157,7 +157,7 @@ describe Admin::StripeAccountsController, type: :controller do end it "returns with a status of 'connected'" do - spree_get :status, params + get :status, params json_response = JSON.parse(response.body) expect(json_response["status"]).to eq "connected" # serializes required attrs diff --git a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb index a64bac75ba..c676cd002a 100644 --- a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb +++ b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb @@ -17,7 +17,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do before { allow(controller).to receive(:spree_current_user) { user } } it "does not allow access" do - spree_get :edit + get :edit expect(response).to redirect_to unauthorized_path end end @@ -34,7 +34,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do end it "sets the account status to :empty_api_key_error_html" do - spree_get :edit + get :edit expect(assigns(:stripe_account)[:status]).to eq :empty_api_key_error_html expect(assigns(:settings).stripe_connect_enabled).to be true end @@ -52,7 +52,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do end it "sets the account status to :auth_fail_error" do - spree_get :edit + get :edit expect(assigns(:stripe_account)[:status]).to eq :auth_fail_error expect(assigns(:settings).stripe_connect_enabled).to be true end @@ -65,7 +65,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do end it "sets the account status to :ok, loads settings into Struct" do - spree_get :edit + get :edit expect(assigns(:stripe_account)[:status]).to eq :ok expect(assigns(:obfuscated_secret_key)).to eq "sk_test_****xxxx" expect(assigns(:settings).stripe_connect_enabled).to be true @@ -82,7 +82,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do before { allow(controller).to receive(:spree_current_user) { user } } it "does not allow access" do - spree_get :update, params + get :update, params expect(response).to redirect_to unauthorized_path end end @@ -95,7 +95,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do it "sets global config to the specified values" do expect(Spree::Config.stripe_connect_enabled).to be true - spree_get :update, params + get :update, params expect(Spree::Config.stripe_connect_enabled).to be false end end diff --git a/spec/controllers/admin/subscriptions_controller_spec.rb b/spec/controllers/admin/subscriptions_controller_spec.rb index 4ef466f3e1..65a8cde0c3 100644 --- a/spec/controllers/admin/subscriptions_controller_spec.rb +++ b/spec/controllers/admin/subscriptions_controller_spec.rb @@ -19,7 +19,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do - spree_get :index, params + get :index, params expect(response).to redirect_to unauthorized_path end end @@ -32,7 +32,7 @@ describe Admin::SubscriptionsController, type: :controller do let!(:subscription) { create(:subscription, shop: shop) } it 'renders the index page with appropriate data' do - spree_get :index, params + get :index, params expect(response).to render_template 'index' expect(assigns(:collection)).to eq [] # No collection loaded expect(assigns(:shops)).to eq [shop] # Shops are loaded @@ -41,7 +41,7 @@ describe Admin::SubscriptionsController, type: :controller do context "where I don't manage a shop that is set up for subscriptions" do it 'renders the setup_explanation page' do - spree_get :index, params + get :index, params expect(response).to render_template 'setup_explanation' expect(assigns(:collection)).to eq [] # No collection loaded expect(assigns(:shop)).to eq shop # First SO enabled shop is loaded @@ -56,7 +56,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do - spree_get :index, params + get :index, params expect(response).to redirect_to unauthorized_path end end @@ -67,7 +67,7 @@ describe Admin::SubscriptionsController, type: :controller do let!(:subscription2) { create(:subscription, shop: shop2) } it 'renders the collection as json' do - spree_get :index, params + get :index, params json_response = JSON.parse(response.body) expect(json_response.count).to be 2 expect(json_response.map{ |so| so['id'] }).to include subscription.id, subscription2.id @@ -77,7 +77,7 @@ describe Admin::SubscriptionsController, type: :controller do before { params.merge!(q: { shop_id_eq: shop2.id }) } it "restricts the list of subscriptions" do - spree_get :index, params + get :index, params json_response = JSON.parse(response.body) expect(json_response.count).to be 1 ids = json_response.map{ |so| so['id'] } @@ -99,7 +99,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'loads the preloads the necessary data' do expect(controller).to receive(:load_form_data) - spree_get :new, subscription: { shop_id: shop.id } + get :new, subscription: { shop_id: shop.id } expect(assigns(:subscription)).to be_a_new Subscription expect(assigns(:subscription).shop).to eq shop end @@ -238,7 +238,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'loads the preloads the necessary data' do expect(controller).to receive(:load_form_data) - spree_get :edit, id: subscription.id + get :edit, id: subscription.id expect(assigns(:subscription)).to eq subscription end end diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb index c40f04dac7..2034d3118e 100644 --- a/spec/controllers/api/customers_controller_spec.rb +++ b/spec/controllers/api/customers_controller_spec.rb @@ -19,7 +19,7 @@ module Api end it "lists customers associated with the current user" do - spree_get :index + get :index expect(response.status).to eq 200 expect(json_response.length).to eq 1 expect(json_response.first[:id]).to eq customer1.id diff --git a/spec/controllers/api/exchange_products_controller_spec.rb b/spec/controllers/api/exchange_products_controller_spec.rb index 3fa7248198..d9aa7ce55c 100644 --- a/spec/controllers/api/exchange_products_controller_spec.rb +++ b/spec/controllers/api/exchange_products_controller_spec.rb @@ -26,7 +26,7 @@ module Api let(:products_relation) { Spree::Product.where("1=0") } it "handles it gracefully" do - spree_get :index, exchange_id: exchange.id + get :index, exchange_id: exchange.id expect(json_response["products"].length).to eq 0 end end @@ -36,7 +36,7 @@ module Api describe "when an exchange id param is provided" do it "uses exchange order_cycle, incoming and enterprise to fetch products" do - spree_get :index, exchange_id: exchange.id, order_cycle_id: 666, enterprise_id: 666, incoming: false + get :index, exchange_id: exchange.id, order_cycle_id: 666, enterprise_id: 666, incoming: false expect(json_response["products"].first["supplier_name"]).to eq exchange.variants.first.product.supplier.name end end @@ -59,7 +59,7 @@ module Api describe "when a specific page is requested" do it "returns the requested page with paginated data" do - spree_get :index, exchange_id: exchange.id, page: 1 + get :index, exchange_id: exchange.id, page: 1 expect(json_response["products"].size).to eq 1 expect(json_response["pagination"]["results"]).to eq 2 @@ -69,7 +69,7 @@ module Api describe "when no specific page is requested" do it "returns all results without paginating" do - spree_get :index, exchange_id: exchange.id + get :index, exchange_id: exchange.id expect(json_response["products"].size).to eq 2 expect(json_response["pagination"]).to be nil diff --git a/spec/controllers/api/shops_controller_spec.rb b/spec/controllers/api/shops_controller_spec.rb index 08040feea8..22b40b22db 100644 --- a/spec/controllers/api/shops_controller_spec.rb +++ b/spec/controllers/api/shops_controller_spec.rb @@ -23,7 +23,7 @@ describe Api::ShopsController, type: :controller do describe "#show" do it "returns shopfront data for an enterprise" do - spree_get :show, id: producer.id + get :show, id: producer.id expect(json_response['name']).to eq 'Shopfront Test Producer' expect(json_response['hubs'][0]['name']).to eq 'Shopfront Test Hub' @@ -33,7 +33,7 @@ describe Api::ShopsController, type: :controller do describe "#closed_shops" do it "returns data for all closed shops" do - spree_get :closed_shops, {} + get :closed_shops, {} expect(json_response).not_to match hub.name diff --git a/spec/controllers/api/statuses_controller_spec.rb b/spec/controllers/api/statuses_controller_spec.rb index b36f7511e3..40132eed5c 100644 --- a/spec/controllers/api/statuses_controller_spec.rb +++ b/spec/controllers/api/statuses_controller_spec.rb @@ -9,21 +9,21 @@ module Api describe "job queue status" do it "returns alive when up to date" do Spree::Config.last_job_queue_heartbeat_at = Time.now.in_time_zone - spree_get :job_queue + get :job_queue expect(response).to be_success expect(response.body).to eq({ alive: true }.to_json) end it "returns dead otherwise" do Spree::Config.last_job_queue_heartbeat_at = 10.minutes.ago - spree_get :job_queue + get :job_queue expect(response).to be_success expect(response.body).to eq({ alive: false }.to_json) end it "returns dead when no heartbeat recorded" do Spree::Config.last_job_queue_heartbeat_at = nil - spree_get :job_queue + get :job_queue expect(response).to be_success expect(response.body).to eq({ alive: false }.to_json) end diff --git a/spec/controllers/api/variants_controller_spec.rb b/spec/controllers/api/variants_controller_spec.rb index 6720461c56..4a26422b62 100644 --- a/spec/controllers/api/variants_controller_spec.rb +++ b/spec/controllers/api/variants_controller_spec.rb @@ -26,7 +26,7 @@ describe Api::VariantsController, type: :controller do end it "retrieves a list of variants with appropriate attributes" do - spree_get :index, format: :json + get :index, format: :json keys = json_response.first.keys.map(&:to_sym) expect(attributes.all?{ |attr| keys.include? attr }).to eq(true) diff --git a/spec/controllers/base_controller_spec.rb b/spec/controllers/base_controller_spec.rb index b3084c18f2..d0b9e54d6d 100644 --- a/spec/controllers/base_controller_spec.rb +++ b/spec/controllers/base_controller_spec.rb @@ -101,7 +101,7 @@ describe BaseController, type: :controller do end it "redirects to home with message if order cycle is expired" do - expect(controller).to receive(:current_order_cycle).and_return(oc).twice + expect(controller).to receive(:current_order_cycle).and_return(oc) expect(controller).to receive(:current_order).and_return(order).twice expect(oc).to receive(:closed?).and_return(true) expect(order).to receive(:empty!) @@ -109,7 +109,6 @@ describe BaseController, type: :controller do get :index - expect(session[:expired_order_cycle_id]).to eq oc.id expect(response).to redirect_to root_url expect(flash[:info]).to eq I18n.t('order_cycle_closed') end diff --git a/spec/controllers/checkout_controller_concurrency_spec.rb b/spec/controllers/checkout_controller_concurrency_spec.rb index 9d66c05a1f..061fd8deae 100644 --- a/spec/controllers/checkout_controller_concurrency_spec.rb +++ b/spec/controllers/checkout_controller_concurrency_spec.rb @@ -82,7 +82,7 @@ describe CheckoutController, concurrency: true, type: :controller do # see the order page. This is basically verifying a "double click" # scenario. expect(response.status).to eq(200) - expect(response.body).to eq({ path: spree.order_path(order) }.to_json) + expect(response.body).to eq({ path: order_path(order) }.to_json) expect(order.payments.count).to eq 1 expect(order.completed?).to be true end diff --git a/spec/controllers/checkout_controller_spec.rb b/spec/controllers/checkout_controller_spec.rb index d638789f6e..933348dfd7 100644 --- a/spec/controllers/checkout_controller_spec.rb +++ b/spec/controllers/checkout_controller_spec.rb @@ -110,7 +110,7 @@ describe CheckoutController, type: :controller do it "completes the order and redirects to the order confirmation page" do get :edit, { payment_intent: "pi_123" } expect(order.completed?).to be true - expect(response).to redirect_to spree.order_path(order) + expect(response).to redirect_to order_path(order) end end end @@ -242,7 +242,7 @@ describe CheckoutController, type: :controller do spree_post :update, format: :json, order: {} expect(response.status).to eq(200) - expect(response.body).to eq({ path: spree.order_path(order) }.to_json) + expect(response.body).to eq({ path: order_path(order) }.to_json) end it "returns an error on unexpected failure" do diff --git a/spec/controllers/enterprises_controller_spec.rb b/spec/controllers/enterprises_controller_spec.rb index 68ce5a8010..86ff995516 100644 --- a/spec/controllers/enterprises_controller_spec.rb +++ b/spec/controllers/enterprises_controller_spec.rb @@ -18,7 +18,7 @@ describe EnterprisesController, type: :controller do end it "sets the shop as the distributor on the order when shopping for the distributor" do - spree_get :shop, id: distributor + get :shop, id: distributor expect(controller.current_distributor).to eq(distributor) expect(controller.current_order.distributor).to eq(distributor) @@ -29,7 +29,7 @@ describe EnterprisesController, type: :controller do before { allow(controller).to receive(:spree_current_user) { user } } it "sets the shop as the distributor on the order when shopping for the distributor" do - spree_get :shop, id: distributor + get :shop, id: distributor expect(controller.current_distributor).to eq(distributor) expect(controller.current_order.distributor).to eq(distributor) @@ -39,11 +39,11 @@ describe EnterprisesController, type: :controller do it "sorts order cycles by the distributor's preferred ordering attr" do distributor.update_attribute(:preferred_shopfront_order_cycle_order, 'orders_close_at') - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to eq([order_cycle1, order_cycle2].sort_by(&:orders_close_at)) distributor.update_attribute(:preferred_shopfront_order_cycle_order, 'orders_open_at') - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to eq([order_cycle1, order_cycle2].sort_by(&:orders_open_at)) end @@ -64,23 +64,23 @@ describe EnterprisesController, type: :controller do preferred_exchange_tags: "wholesale", preferred_matched_order_cycles_visibility: 'hidden') - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to include order_cycle1, order_cycle2, order_cycle3 allow(controller).to receive(:spree_current_user) { user } - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to include order_cycle1, order_cycle2, order_cycle3 oc3_exchange.update_attribute(:tag_list, "wholesale") - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to include order_cycle1, order_cycle2 expect(assigns(:order_cycles)).not_to include order_cycle3 customer.update_attribute(:tag_list, ["wholesale"]) - spree_get :shop, id: distributor + get :shop, id: distributor expect(assigns(:order_cycles)).to include order_cycle1, order_cycle2, order_cycle3 end end @@ -89,7 +89,7 @@ describe EnterprisesController, type: :controller do line_item = create(:line_item) controller.current_order.line_items << line_item - spree_get :shop, id: distributor + get :shop, id: distributor expect(controller.current_order.distributor).to eq(distributor) expect(controller.current_order.order_cycle).to be_nil @@ -97,7 +97,7 @@ describe EnterprisesController, type: :controller do end it "should not empty an order if returning to the same distributor" do - spree_get :shop, id: current_distributor + get :shop, id: current_distributor expect(controller.current_order.distributor).to eq current_distributor expect(controller.current_order.line_items.first.variant).to eq line_item.variant @@ -117,7 +117,7 @@ describe EnterprisesController, type: :controller do end it "redirects to the cart" do - spree_get :shop, id: current_distributor + get :shop, id: current_distributor expect(response).to redirect_to cart_path end @@ -129,7 +129,7 @@ describe EnterprisesController, type: :controller do order.save order_cycle1.update_attribute :orders_close_at, Time.zone.now - spree_get :shop, id: distributor + get :shop, id: distributor expect(controller.current_order.distributor).to eq(distributor) expect(controller.current_order.order_cycle).to eq(order_cycle2) @@ -139,7 +139,7 @@ describe EnterprisesController, type: :controller do it "sets order cycle if only one is available at the chosen distributor" do order_cycle2.destroy - spree_get :shop, id: distributor + get :shop, id: distributor expect(controller.current_order.distributor).to eq(distributor) expect(controller.current_order.order_cycle).to eq(order_cycle1) @@ -155,7 +155,7 @@ describe EnterprisesController, type: :controller do end it "responds with status of 409 when the permalink matches an existing route" do - # spree_get :check_permalink, { permalink: 'enterprise_permalink', format: :js } + # get :check_permalink, { permalink: 'enterprise_permalink', format: :js } # expect(response.status).to be 409 xhr :get, :check_permalink, permalink: 'map', format: :js expect(response.status).to be 409 @@ -166,7 +166,7 @@ describe EnterprisesController, type: :controller do context "checking access on nonexistent enterprise" do before do - spree_get :shop, id: "some_nonexistent_enterprise" + get :shop, id: "some_nonexistent_enterprise" end it "redirects to shops_path" do diff --git a/spec/controllers/shop_controller_spec.rb b/spec/controllers/shop_controller_spec.rb index bbcce1bf33..6988be63a9 100644 --- a/spec/controllers/shop_controller_spec.rb +++ b/spec/controllers/shop_controller_spec.rb @@ -8,7 +8,7 @@ describe ShopController, type: :controller do let(:distributor) { create(:distributor_enterprise, payment_methods: [pm], shipping_methods: [sm]) } it "redirects to the home page if no distributor is selected" do - spree_get :show + get :show expect(response).to redirect_to root_path end @@ -20,14 +20,14 @@ describe ShopController, type: :controller do describe "selecting an order cycle" do it "should select an order cycle when only one order cycle is open" do oc1 = create(:simple_order_cycle, distributors: [distributor]) - spree_get :show + get :show expect(controller.current_order_cycle).to eq(oc1) end it "should not set an order cycle when multiple order cycles are open" do oc1 = create(:simple_order_cycle, distributors: [distributor]) oc2 = create(:simple_order_cycle, distributors: [distributor]) - spree_get :show + get :show expect(controller.current_order_cycle).to be_nil end @@ -55,7 +55,7 @@ describe ShopController, type: :controller do it "should return the current order cycle when hit with GET" do oc1 = create(:simple_order_cycle, distributors: [distributor]) allow(controller).to receive(:current_order_cycle).and_return oc1 - spree_get :order_cycle + get :order_cycle expect(response.body).to have_content oc1.id end diff --git a/spec/controllers/spree/admin/mail_methods_controller_spec.rb b/spec/controllers/spree/admin/mail_methods_controller_spec.rb index 793242d0fc..f91617e671 100644 --- a/spec/controllers/spree/admin/mail_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/mail_methods_controller_spec.rb @@ -10,7 +10,7 @@ describe Spree::Admin::MailMethodsController do context "#update" do it "should reinitialize the mail settings" do expect(Spree::Core::MailSettings).to receive(:init) - spree_put :update, enable_mail_delivery: "1", mails_from: "ofn@example.com" + spree_put :update, mails_from: "ofn@example.com" end end @@ -24,7 +24,6 @@ describe Spree::Admin::MailMethodsController do has_spree_role?: true, locale: nil) allow(controller).to receive_messages(spree_current_user: user) - Spree::Config[:enable_mail_delivery] = "1" ActionMailer::Base.perform_deliveries = true expect { diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index 982eb01bf5..64102934ad 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -22,12 +22,12 @@ describe Spree::OrdersController, type: :controller do let(:current_user) { nil } it "loads page" do - spree_get :show, id: order.number, token: order.token + get :show, id: order.number, token: order.token expect(response).to be_success end it "stores order token in session as 'access_token'" do - spree_get :show, id: order.number, token: order.token + get :show, id: order.number, token: order.token expect(session[:access_token]).to eq(order.token) end end @@ -41,7 +41,7 @@ describe Spree::OrdersController, type: :controller do end it "loads page" do - spree_get :show, id: order.number + get :show, id: order.number expect(response).to be_success end end @@ -50,7 +50,7 @@ describe Spree::OrdersController, type: :controller do let(:current_user) { order.user } it "loads page" do - spree_get :show, id: order.number + get :show, id: order.number expect(response).to be_success end end @@ -59,7 +59,7 @@ describe Spree::OrdersController, type: :controller do let(:current_user) { create(:user) } it "redirects to unauthorized" do - spree_get :show, id: order.number + get :show, id: order.number expect(response).to redirect_to unauthorized_path end end @@ -68,12 +68,12 @@ describe Spree::OrdersController, type: :controller do let(:current_user) { nil } before do - request.env["PATH_INFO"] = spree.order_path(order) + request.env["PATH_INFO"] = order_path(order) end it "redirects to unauthorized" do - spree_get :show, id: order.number - expect(response).to redirect_to(root_path(anchor: "login?after_login=#{spree.order_path(order)}")) + get :show, id: order.number + expect(response).to redirect_to(root_path(anchor: "login?after_login=#{order_path(order)}")) expect(flash[:error]).to eq("Please log in to view your order.") end end @@ -81,7 +81,7 @@ describe Spree::OrdersController, type: :controller do describe "viewing cart" do it "redirects home when no distributor is selected" do - spree_get :edit + get :edit expect(response).to redirect_to root_path end @@ -95,13 +95,13 @@ describe Spree::OrdersController, type: :controller do allow(order_cycle).to receive(:variants_distributed_by).and_return [] session[:access_token] = order.token - spree_get :edit + get :edit expect(response).to redirect_to shop_path end it "redirects to the shop when no order cycle is selected" do allow(controller).to receive(:current_distributor).and_return(distributor) - spree_get :edit + get :edit expect(response).to redirect_to shop_path end @@ -115,7 +115,7 @@ describe Spree::OrdersController, type: :controller do expect(order).to receive(:empty!) expect(order).to receive(:set_distribution!).with(nil, nil) - spree_get :edit + get :edit expect(response).to redirect_to root_url expect(flash[:info]).to eq(I18n.t('order_cycles_closed_for_hub')) @@ -144,7 +144,7 @@ describe Spree::OrdersController, type: :controller do # We fixed our view by hardcoding the link. spree_registration_path = '/signup' ofn_registration_path = '/register' - spree_get :edit + get :edit expect(response.body).to_not match spree_registration_path expect(response.body).to match ofn_registration_path end @@ -156,7 +156,7 @@ describe Spree::OrdersController, type: :controller do end it "displays a flash message when we view the cart" do - spree_get :edit + get :edit expect(response.status).to eq 200 expect(flash[:error]).to eq I18n.t('spree.orders.error_flash_for_unavailable_items') end @@ -168,7 +168,7 @@ describe Spree::OrdersController, type: :controller do end it "displays a flash message when we view the cart" do - spree_get :edit + get :edit expect(response.status).to eq 200 expect(flash[:error]).to eq I18n.t('spree.orders.error_flash_for_unavailable_items') end @@ -181,7 +181,7 @@ describe Spree::OrdersController, type: :controller do it "should silently ignore the missing line item" do order = subject.current_order(true) li = order.add_variant(create(:simple_product, on_hand: 110).variants.first) - spree_get :update, order: { line_items_attributes: { + get :update, order: { line_items_attributes: { "0" => { quantity: "0", id: "9999" }, "1" => { quantity: "99", id: li.id } } } @@ -209,7 +209,7 @@ describe Spree::OrdersController, type: :controller do line_item = order.add_variant(create(:simple_product, on_hand: 110).variants.first) adjustment = create(:adjustment, adjustable: order) - spree_get :update, order: { line_items_attributes: { + get :update, order: { line_items_attributes: { "1" => { quantity: "99", id: line_item.id } } } @@ -318,7 +318,7 @@ describe Spree::OrdersController, type: :controller do it "removes the items" do spree_post :update, params expect(flash[:error]).to be nil - expect(response).to redirect_to spree.order_path(order) + expect(response).to redirect_to order_path(order) expect(order.reload.line_items.count).to eq 1 end end @@ -329,7 +329,7 @@ describe Spree::OrdersController, type: :controller do it "does not remove items, flash suggests cancellation" do spree_post :update, params expect(flash[:error]).to eq I18n.t(:orders_cannot_remove_the_final_item) - expect(response).to redirect_to spree.order_path(order) + expect(response).to redirect_to order_path(order) expect(order.reload.line_items.count).to eq 2 end end @@ -426,7 +426,7 @@ describe Spree::OrdersController, type: :controller do context "when the order is not yet complete" do it "responds with forbidden" do spree_put :cancel, params - expect(response.status).to redirect_to spree.order_path(order) + expect(response.status).to redirect_to order_path(order) expect(flash[:error]).to eq I18n.t(:orders_could_not_cancel) end end @@ -440,7 +440,7 @@ describe Spree::OrdersController, type: :controller do it "responds with success" do spree_put :cancel, params - expect(response.status).to redirect_to spree.order_path(order) + expect(response.status).to redirect_to order_path(order) expect(flash[:success]).to eq I18n.t(:orders_your_order_has_been_cancelled) end end diff --git a/spec/controllers/spree/users_controller_spec.rb b/spec/controllers/spree/users_controller_spec.rb index 8c5c6b80b1..8f7b4257c7 100644 --- a/spec/controllers/spree/users_controller_spec.rb +++ b/spec/controllers/spree/users_controller_spec.rb @@ -40,6 +40,22 @@ describe Spree::UsersController, type: :controller do # Doesn't return uncompleted orders" do expect(orders).not_to include d1o3 end + + context 'when the customer_balance feature is enabled' do + let(:outstanding_balance) { double(:outstanding_balance) } + + before do + allow(OpenFoodNetwork::FeatureToggle) + .to receive(:enabled?).with(:customer_balance, controller.spree_current_user) { true } + end + + it 'calls OutstandingBalance' do + allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance) + expect(outstanding_balance).to receive(:query) { Spree::Order.none } + + spree_get :show + end + end end describe "registered_email" do diff --git a/spec/features/admin/shipping_methods_spec.rb b/spec/features/admin/shipping_methods_spec.rb index a2aa27b729..6e4a1c5e44 100644 --- a/spec/features/admin/shipping_methods_spec.rb +++ b/spec/features/admin/shipping_methods_spec.rb @@ -157,26 +157,35 @@ feature 'shipping methods' do expect(page).to have_selector 'td', text: 'Two', count: 1 end - pending "shows me only shipping methods for the enterprise I select" do + it "shows me only shipping methods for the enterprise I select" do shipping_method1 shipping_method2 visit admin_enterprises_path within("#e_#{distributor1.id}") { click_link 'Settings' } + within(".side_menu") do click_link "Shipping Methods" end - expect(page).to have_content shipping_method1.name - expect(page).to have_content shipping_method2.name + + expect(page).to have_content shipping_method1.name + expect(page).to have_content shipping_method2.name + + expect(page).to have_checked_field "enterprise_shipping_method_ids_#{shipping_method2.id}" + expect(page).to have_checked_field "enterprise_shipping_method_ids_#{shipping_method1.id}" click_link 'Enterprises' within("#e_#{distributor2.id}") { click_link 'Settings' } + within(".side_menu") do click_link "Shipping Methods" end - expect(page).not_to have_content shipping_method1.name + expect(page).to have_content shipping_method1.name expect(page).to have_content shipping_method2.name + + expect(page).to have_checked_field "enterprise_shipping_method_ids_#{shipping_method2.id}" + expect(page).to have_unchecked_field "enterprise_shipping_method_ids_#{shipping_method1.id}" end end end diff --git a/spec/features/consumer/account/cards_spec.rb b/spec/features/consumer/account/cards_spec.rb index fe5884e58b..d2f6b673dd 100644 --- a/spec/features/consumer/account/cards_spec.rb +++ b/spec/features/consumer/account/cards_spec.rb @@ -39,7 +39,7 @@ feature "Credit Cards", js: true do it "passes the smoke test" do visit "/account" - click_link I18n.t('spree.users.show.tabs.cards') + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.cards')}}i).click expect(page).to have_content I18n.t(:saved_cards) diff --git a/spec/features/consumer/account/settings_spec.rb b/spec/features/consumer/account/settings_spec.rb index 99abb4e52d..964a8d0fbe 100644 --- a/spec/features/consumer/account/settings_spec.rb +++ b/spec/features/consumer/account/settings_spec.rb @@ -18,7 +18,7 @@ feature "Account Settings", js: true do setup_email login_as user visit "/account" - click_link I18n.t('spree.users.show.tabs.settings') + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.settings')}}i).click expect(page).to have_content I18n.t('spree.users.form.account_settings') end @@ -37,7 +37,7 @@ feature "Account Settings", js: true do user.reload expect(user.email).to eq 'old@email.com' expect(user.unconfirmed_email).to eq 'new@email.com' - click_link I18n.t('spree.users.show.tabs.settings') + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.settings')}}i).click expect(page).to have_content I18n.t('spree.users.show.unconfirmed_email', unconfirmed_email: 'new@email.com') end diff --git a/spec/features/consumer/account_spec.rb b/spec/features/consumer/account_spec.rb index 84cb4e3731..80f57b53c5 100644 --- a/spec/features/consumer/account_spec.rb +++ b/spec/features/consumer/account_spec.rb @@ -54,7 +54,7 @@ feature ' href: "#{distributor_credit.permalink}/shop", count: 1) # Viewing transaction history - click_link I18n.t('spree.users.show.tabs.transactions') + find("a", :text => %r{#{I18n.t('spree.users.show.tabs.transactions')}}i).click # It shows all hubs that have been ordered from with balance or credit expect(page).to have_content distributor1.name @@ -85,12 +85,12 @@ feature ' visit '/account' expect(page).to have_content I18n.t('spree.users.orders.open_orders') - expect(page).to have_link d1o1.number, href: spree.order_path(d1o1) - expect(page).to have_link d1o2.number, href: spree.order_path(d1o2) + expect(page).to have_link d1o1.number, href: order_path(d1o1) + expect(page).to have_link d1o2.number, href: order_path(d1o2) expect(page).to have_link(distributor1.name, href: "#{distributor1.permalink}/shop", count: 2) - expect(page).to have_link I18n.t('spree.users.open_orders.cancel'), href: spree.cancel_order_path(d1o1) - expect(page).to have_link I18n.t('spree.users.open_orders.cancel'), href: spree.cancel_order_path(d1o2) + expect(page).to have_link I18n.t('spree.users.open_orders.cancel'), href: cancel_order_path(d1o1) + expect(page).to have_link I18n.t('spree.users.open_orders.cancel'), href: cancel_order_path(d1o2) end end end diff --git a/spec/features/consumer/shopping/orders_spec.rb b/spec/features/consumer/shopping/orders_spec.rb index 980d51893d..676914b57c 100644 --- a/spec/features/consumer/shopping/orders_spec.rb +++ b/spec/features/consumer/shopping/orders_spec.rb @@ -44,16 +44,16 @@ feature "Order Management", js: true do it "allows the user to see the details" do # Cannot load the page without token - visit spree.order_path(order) + visit order_path(order) expect(page).to_not be_confirmed_order_page # Can load the page with token - visit spree.order_path(order, token: order.token) + visit order_path(order, token: order.token) expect(page).to be_confirmed_order_page # Can load the page even without the token, after loading the page with # token. - visit spree.order_path(order) + visit order_path(order) expect(page).to be_confirmed_order_page end end @@ -66,7 +66,7 @@ feature "Order Management", js: true do end it "allows the user to see order details" do - visit spree.order_path(order) + visit order_path(order) expect(page).to be_confirmed_order_page end end @@ -76,7 +76,7 @@ feature "Order Management", js: true do it "allows the user to see order details after login" do # Cannot load the page without signing in - visit spree.order_path(order) + visit order_path(order) expect(page).to_not be_confirmed_order_page # Can load the page after signing in @@ -115,7 +115,7 @@ feature "Order Management", js: true do end it 'shows the name of the shipping method' do - visit spree.order_path(order) + visit order_path(order) expect(find('#order')).to have_content(shipping_method.name) end @@ -125,7 +125,7 @@ feature "Order Management", js: true do end it "doesn't show form elements for editing the order" do - visit spree.order_path(order) + visit order_path(order) expect(find("tr.variant-#{item1.variant.id}")).to have_content item1.product.name expect(find("tr.variant-#{item2.variant.id}")).to have_content item2.product.name expect(find("tr.variant-#{item3.variant.id}")).to have_content item3.product.name @@ -142,7 +142,7 @@ feature "Order Management", js: true do end it "allows quantity to be changed, items to be removed and the order to be cancelled" do - visit spree.order_path(order) + visit order_path(order) expect(page).to have_button I18n.t(:order_saved), disabled: true expect(page).to have_no_button I18n.t(:save_changes) diff --git a/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee b/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee index 8a2be1ee42..4576e376c7 100644 --- a/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/controllers/checkout/shop_variant_controller_spec.js.coffee @@ -4,20 +4,23 @@ describe "ShopVariantCtrl", -> beforeEach -> module 'Darkswarm' - scope = - $watchGroup: -> - variant: { + + inject ($rootScope, $controller, $modal)-> + scope = $rootScope.$new() + scope.$watchGroup = -> + scope.variant = { on_demand: true - product: {group_buy: false} + product: {group_buy: true} line_item: { - quantity: 0 - max_quantity: 0 + quantity: undefined + max_quantity: undefined } } - - inject ($controller, $modal)-> ctrl = $controller 'ShopVariantCtrl', {$scope: scope, $modal: $modal, Cart: null} + it "initializes the quantity for shop display", -> + expect(scope.variant.line_item.quantity).toEqual 0 + it "adds an item to the cart", -> scope.add 1 expect(scope.variant.line_item.quantity).toEqual 1 @@ -27,30 +30,60 @@ describe "ShopVariantCtrl", -> scope.add 5 expect(scope.variant.line_item.quantity).toEqual 6 + it "adds to an invalid quantity", -> + scope.$apply -> + scope.variant.line_item.quantity = -5 + scope.add 1 + expect(scope.variant.line_item.quantity).toEqual 1 + + it "adds to an undefined quantity", -> + scope.$apply -> + scope.variant.line_item.quantity = undefined + scope.add 1 + expect(scope.variant.line_item.quantity).toEqual 1 + it "adds to the max quantity", -> scope.addMax 5 expect(scope.variant.line_item.quantity).toEqual 0 expect(scope.variant.line_item.max_quantity).toEqual 5 - it "adds to the max quantity to be at least min quantity", -> - scope.variant.product.group_buy = true - scope.variant.line_item.max_quantity = 2 + it "adds to an undefined max quantity", -> + scope.variant.line_item.quantity = 3 + scope.variant.line_item.max_quantity = undefined + scope.addMax 1 + expect(scope.variant.line_item.max_quantity).toEqual 4 - scope.add 3 + it "adds to the max quantity to be at least min quantity", -> + scope.$apply -> + scope.variant.line_item.max_quantity = 2 + + scope.$apply -> + scope.add 3 expect(scope.variant.line_item.quantity).toEqual 3 expect(scope.variant.line_item.max_quantity).toEqual 3 it "decreases the min quantity to not exceed max quantity", -> - scope.variant.product.group_buy = true - scope.variant.line_item.quantity = 3 - scope.variant.line_item.max_quantity = 5 + scope.$apply -> + scope.variant.line_item.quantity = 3 + scope.variant.line_item.max_quantity = 5 - scope.addMax -3 + scope.$apply -> + scope.addMax -3 expect(scope.variant.line_item.quantity).toEqual 2 expect(scope.variant.line_item.max_quantity).toEqual 2 + it "caps at the available quantity", -> + scope.$apply -> + scope.variant.on_demand = false + scope.variant.on_hand = 3 + scope.variant.line_item.quantity = 5 + scope.variant.line_item.max_quantity = 7 + + expect(scope.variant.line_item.quantity).toEqual 3 + expect(scope.variant.line_item.max_quantity).toEqual 3 + it "allows adding when variant is on demand", -> expect(scope.canAdd(5000)).toEqual true @@ -72,6 +105,42 @@ describe "ShopVariantCtrl", -> expect(scope.canAdd(2)).toEqual true expect(scope.canAdd(3)).toEqual false + it "denies adding if quantity is too high", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = 7 + scope.variant.line_item.max_quantity = 7 + + expect(scope.canAdd(1)).toEqual false + expect(scope.canAddMax(1)).toEqual false + + it "allows decrease when quantity is too high", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = 7 + scope.variant.line_item.max_quantity = 7 + expect(scope.canAdd(-1)).toEqual true + expect(scope.canAddMax(-1)).toEqual true + + it "allows increase when quantity is negative", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = -3 + scope.variant.line_item.max_quantity = -3 + expect(scope.canAdd(1)).toEqual true + expect(scope.canAddMax(1)).toEqual false + + scope.variant.line_item.quantity = 1 + expect(scope.canAddMax(1)).toEqual true + + it "denies decrease when quantity is negative", -> + scope.variant.on_demand = false + scope.variant.on_hand = 5 + scope.variant.line_item.quantity = -3 + scope.variant.line_item.max_quantity = -3 + expect(scope.canAdd(-1)).toEqual false + expect(scope.canAddMax(-1)).toEqual false + it "denies declaring max quantity before item is in cart", -> expect(scope.canAddMax(1)).toEqual false diff --git a/spec/lib/spree/core/mail_settings_spec.rb b/spec/lib/spree/core/mail_settings_spec.rb index ed799f980f..4039addaf2 100644 --- a/spec/lib/spree/core/mail_settings_spec.rb +++ b/spec/lib/spree/core/mail_settings_spec.rb @@ -7,60 +7,47 @@ module Spree describe MailSettings do let!(:subject) { MailSettings.new } - context "enable delivery" do - before { Config.enable_mail_delivery = true } - - context "overrides appplication defaults" do - context "authentication method is none" do - before do - Config.mail_host = "smtp.example.com" - Config.mail_domain = "example.com" - Config.mail_port = 123 - Config.mail_auth_type = MailSettings::SECURE_CONNECTION_TYPES[0] - Config.smtp_username = "schof" - Config.smtp_password = "hellospree!" - Config.secure_connection_type = "TLS" - subject.override! - end - - it { expect(ActionMailer::Base.smtp_settings[:address]).to eq "smtp.example.com" } - it { expect(ActionMailer::Base.smtp_settings[:domain]).to eq "example.com" } - it { expect(ActionMailer::Base.smtp_settings[:port]).to eq 123 } - it { expect(ActionMailer::Base.smtp_settings[:authentication]).to eq "None" } - it { expect(ActionMailer::Base.smtp_settings[:enable_starttls_auto]).to be_truthy } - - it "doesnt touch user name config" do - expect(ActionMailer::Base.smtp_settings[:user_name]).to be_nil - end - - it "doesnt touch password config" do - expect(ActionMailer::Base.smtp_settings[:password]).to be_nil - end - end - end - - context "when mail_auth_type is other than none" do + context "overrides appplication defaults" do + context "authentication method is none" do before do - Config.mail_auth_type = "login" + Config.mail_host = "smtp.example.com" + Config.mail_domain = "example.com" + Config.mail_port = 123 + Config.mail_auth_type = MailSettings::SECURE_CONNECTION_TYPES[0] Config.smtp_username = "schof" Config.smtp_password = "hellospree!" + Config.secure_connection_type = "TLS" subject.override! end - context "overrides user credentials" do - it { expect(ActionMailer::Base.smtp_settings[:user_name]).to eq "schof" } - it { expect(ActionMailer::Base.smtp_settings[:password]).to eq "hellospree!" } + it { expect(ActionMailer::Base.smtp_settings[:address]).to eq "smtp.example.com" } + it { expect(ActionMailer::Base.smtp_settings[:domain]).to eq "example.com" } + it { expect(ActionMailer::Base.smtp_settings[:port]).to eq 123 } + it { expect(ActionMailer::Base.smtp_settings[:authentication]).to eq "None" } + it { expect(ActionMailer::Base.smtp_settings[:enable_starttls_auto]).to be_truthy } + + it "doesnt touch user name config" do + expect(ActionMailer::Base.smtp_settings[:user_name]).to be_nil + end + + it "doesnt touch password config" do + expect(ActionMailer::Base.smtp_settings[:password]).to be_nil end end end - context "do not enable delivery" do + context "when mail_auth_type is other than none" do before do - Config.enable_mail_delivery = false + Config.mail_auth_type = "login" + Config.smtp_username = "schof" + Config.smtp_password = "hellospree!" subject.override! end - it { expect(ActionMailer::Base.perform_deliveries).to be_falsy } + context "overrides user credentials" do + it { expect(ActionMailer::Base.smtp_settings[:user_name]).to eq "schof" } + it { expect(ActionMailer::Base.smtp_settings[:password]).to eq "hellospree!" } + end end end end diff --git a/spec/mailers/subscription_mailer_spec.rb b/spec/mailers/subscription_mailer_spec.rb index 2db967e603..f50f58b5e4 100644 --- a/spec/mailers/subscription_mailer_spec.rb +++ b/spec/mailers/subscription_mailer_spec.rb @@ -47,7 +47,7 @@ describe SubscriptionMailer, type: :mailer do end describe "linking to order page" do - let(:order_link_href) { "href=\"#{spree.order_url(order)}\"" } + let(:order_link_href) { "href=\"#{order_url(order)}\"" } let(:order_link_style) { "style='[^']+'" } let(:shop) { create(:enterprise, allow_order_changes: true) } @@ -113,7 +113,7 @@ describe SubscriptionMailer, type: :mailer do end describe "linking to order page" do - let(:order_link_href) { "href=\"#{spree.order_url(order)}\"" } + let(:order_link_href) { "href=\"#{order_url(order)}\"" } let(:email) { SubscriptionMailer.deliveries.last } let(:body) { email.body.encoded } @@ -179,7 +179,7 @@ describe SubscriptionMailer, type: :mailer do end describe "linking to order page" do - let(:order_link_href) { "href=\"#{spree.order_url(order)}\"" } + let(:order_link_href) { "href=\"#{order_url(order)}\"" } let(:email) { SubscriptionMailer.deliveries.last } let(:body) { email.body.encoded } diff --git a/spec/models/spree/adjustment_spec.rb b/spec/models/spree/adjustment_spec.rb index 1f77bd725b..de6bdb1f98 100644 --- a/spec/models/spree/adjustment_spec.rb +++ b/spec/models/spree/adjustment_spec.rb @@ -221,7 +221,7 @@ module Spree end it "does not crash when order data has been updated previously" do - order.price_adjustments.first.destroy + order.line_item_adjustments.first.destroy tax_rate.adjust(order) end end diff --git a/spec/queries/complete_orders_with_balance_spec.rb b/spec/queries/complete_orders_with_balance_spec.rb new file mode 100644 index 0000000000..9d46feb7da --- /dev/null +++ b/spec/queries/complete_orders_with_balance_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe CompleteOrdersWithBalance do + let(:complete_orders_with_balance) { described_class.new(user) } + + describe '#query' do + let(:user) { order.user } + let(:outstanding_balance) { instance_double(OutstandingBalance) } + + context 'when the user has complete orders' do + let(:order) do + create(:order, state: 'complete', total: 2.0, payment_total: 1.0, completed_at: 2.day.ago) + end + let!(:other_order) do + create( + :order, + user: user, + state: 'complete', + total: 2.0, + payment_total: 1.0, + completed_at: 1.days.ago + ) + end + + it 'calls OutstandingBalance#query' do + allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance) + expect(outstanding_balance).to receive(:query) + + complete_orders_with_balance.query + end + + it 'returns complete orders including their balance' do + order = complete_orders_with_balance.query.first + expect(order[:balance_value]).to eq(-1.0) + end + + it 'sorts them by their completed_at with the most recent first' do + orders = complete_orders_with_balance.query + expect(orders.pluck(:id)).to eq([other_order.id, order.id]) + end + end + + context 'when the user has no complete orders' do + let(:order) { create(:order) } + + it 'calls OutstandingBalance' do + allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance) + expect(outstanding_balance).to receive(:query) + + complete_orders_with_balance.query + end + + it 'returns an empty array' do + order = complete_orders_with_balance.query + expect(order).to be_empty + end + end + end +end diff --git a/spec/services/customers_with_balance_spec.rb b/spec/queries/customers_with_balance_spec.rb similarity index 88% rename from spec/services/customers_with_balance_spec.rb rename to spec/queries/customers_with_balance_spec.rb index fefd1d9090..479be6b410 100644 --- a/spec/services/customers_with_balance_spec.rb +++ b/spec/queries/customers_with_balance_spec.rb @@ -9,6 +9,14 @@ describe CustomersWithBalance do let(:customer) { create(:customer) } let(:total) { 200.00 } let(:order_total) { 100.00 } + let(:outstanding_balance) { instance_double(OutstandingBalance) } + + it 'calls CustomersWithBalance#statement' do + allow(OutstandingBalance).to receive(:new).and_return(outstanding_balance) + expect(outstanding_balance).to receive(:statement) + + customers_with_balance.query + end context 'when orders are in cart state' do before do @@ -61,9 +69,9 @@ describe CustomersWithBalance do context 'when no orders where paid' do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') end it 'returns the customer balance' do @@ -77,9 +85,9 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: payment_total) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') end it 'returns the customer balance' do @@ -94,7 +102,7 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') create( :order, customer: customer, @@ -115,7 +123,7 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: payment_total) order.update_attribute(:state, 'resumed') end @@ -131,7 +139,7 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: payment_total) order.update_attribute(:state, 'payment') end @@ -147,7 +155,7 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: payment_total) order.update_attribute(:state, 'awaiting_return') end @@ -164,7 +172,7 @@ describe CustomersWithBalance do before do order = create(:order, customer: customer, total: order_total, payment_total: 0) - order.update_attribute(:state, 'checkout') + order.update_attribute(:state, 'complete') order = create(:order, customer: customer, total: order_total, payment_total: payment_total) order.update_attribute(:state, 'returned') end diff --git a/spec/queries/outstanding_balance_spec.rb b/spec/queries/outstanding_balance_spec.rb new file mode 100644 index 0000000000..af880528f7 --- /dev/null +++ b/spec/queries/outstanding_balance_spec.rb @@ -0,0 +1,197 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe OutstandingBalance do + let(:outstanding_balance) { described_class.new(relation) } + + describe '#statement' do + let(:relation) { Spree::Order.none } + + it 'returns the CASE statement necessary to compute the order balance' do + normalized_sql_statement = normalize(outstanding_balance.statement) + + expect(normalized_sql_statement).to eq(normalize(<<-SQL)) + CASE WHEN state IN ('canceled', 'returned') THEN payment_total + WHEN state IS NOT NULL THEN payment_total - total + ELSE 0 END + SQL + end + + def normalize(sql) + sql.strip_heredoc.gsub("\n", '').squeeze(' ') + end + end + + describe '#query' do + let(:relation) { Spree::Order.all } + let(:total) { 200.00 } + let(:order_total) { 100.00 } + + context 'when orders are in cart state' do + before do + create(:order, total: order_total, payment_total: 0, state: 'cart') + create(:order, total: order_total, payment_total: 0, state: 'cart') + end + + it 'returns the order balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(-order_total) + end + end + + context 'when orders are in address state' do + before do + create(:order, total: order_total, payment_total: 0, state: 'address') + create(:order, total: order_total, payment_total: 50, state: 'address') + end + + it 'returns the order balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(-order_total) + end + end + + context 'when orders are in delivery state' do + before do + create(:order, total: order_total, payment_total: 0, state: 'delivery') + create(:order, total: order_total, payment_total: 50, state: 'delivery') + end + + it 'returns the order balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(-order_total) + end + end + + context 'when orders are in payment state' do + before do + create(:order, total: order_total, payment_total: 0, state: 'payment') + create(:order, total: order_total, payment_total: 50, state: 'payment') + end + + it 'returns the order balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(-order_total) + end + end + + context 'when no orders where paid' do + before do + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(-order_total) + end + end + + context 'when an order was paid' do + let(:payment_total) { order_total } + + before do + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + order = create(:order, total: order_total, payment_total: payment_total) + order.update_attribute(:state, 'complete') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total - 200.0) + end + end + + context 'when an order is canceled' do + let(:payment_total) { order_total } + let(:non_canceled_orders_total) { order_total } + + before do + create(:order, total: order_total, payment_total: order_total, state: 'canceled') + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total) + end + end + + context 'when an order is resumed' do + let(:payment_total) { order_total } + + before do + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + order = create(:order, total: order_total, payment_total: payment_total) + order.update_attribute(:state, 'resumed') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total - 200.0) + end + end + + context 'when an order is in payment' do + let(:payment_total) { order_total } + + before do + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + order = create(:order, total: order_total, payment_total: payment_total) + order.update_attribute(:state, 'payment') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total - 200.0) + end + end + + context 'when an order is awaiting_return' do + let(:payment_total) { order_total } + + before do + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + order = create(:order, total: order_total, payment_total: payment_total) + order.update_attribute(:state, 'awaiting_return') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total - 200.0) + end + end + + context 'when an order is returned' do + let(:payment_total) { order_total } + let(:non_returned_orders_total) { order_total } + + before do + order = create(:order, total: order_total, payment_total: payment_total) + order.update_attribute(:state, 'returned') + order = create(:order, total: order_total, payment_total: 0) + order.update_attribute(:state, 'complete') + end + + it 'returns the customer balance' do + order = outstanding_balance.query.first + expect(order.balance_value).to eq(payment_total) + end + end + + context 'when there are no orders' do + it 'returns the order balance' do + orders = outstanding_balance.query + expect(orders).to be_empty + end + end + end +end diff --git a/spec/requests/checkout/paypal_spec.rb b/spec/requests/checkout/paypal_spec.rb index e61bdb813c..a6436d4347 100644 --- a/spec/requests/checkout/paypal_spec.rb +++ b/spec/requests/checkout/paypal_spec.rb @@ -58,7 +58,7 @@ describe "checking out an order with a paypal express payment method", type: :re get spree.confirm_paypal_path, params # Processing was successful, order is complete - expect(response).to redirect_to spree.order_path(order, token: order.token) + expect(response).to redirect_to order_path(order, token: order.token) expect(order.reload.complete?).to be true # We have only one payment, and one transaction fee diff --git a/spec/requests/checkout/stripe_connect_spec.rb b/spec/requests/checkout/stripe_connect_spec.rb index 50af6b975c..63eea0e5c8 100644 --- a/spec/requests/checkout/stripe_connect_spec.rb +++ b/spec/requests/checkout/stripe_connect_spec.rb @@ -104,7 +104,7 @@ describe "checking out an order with a Stripe Connect payment method", type: :re it "should process the payment without storing card details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source @@ -161,7 +161,7 @@ describe "checking out an order with a Stripe Connect payment method", type: :re it "should process the payment, and stores the card/customer details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source @@ -263,7 +263,7 @@ describe "checking out an order with a Stripe Connect payment method", type: :re it "should process the payment, and keep the profile ids and other card details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index d1d959ff5f..49c99b7ce0 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -130,7 +130,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques it "should process the payment without storing card details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source @@ -218,7 +218,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques it "should process the payment, and store the card/customer details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source @@ -303,7 +303,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques it "should process the payment, and keep the profile ids and other card details" do put update_checkout_path, params - expect(json_response["path"]).to eq spree.order_path(order) + expect(json_response["path"]).to eq order_path(order) expect(order.payments.completed.count).to be 1 card = order.payments.completed.first.source diff --git a/spec/serializers/api/order_serializer_spec.rb b/spec/serializers/api/order_serializer_spec.rb index 04ef728d59..d635cf0ada 100644 --- a/spec/serializers/api/order_serializer_spec.rb +++ b/spec/serializers/api/order_serializer_spec.rb @@ -6,21 +6,55 @@ describe Api::OrderSerializer do let(:serializer) { Api::OrderSerializer.new order } let(:order) { create(:completed_order_with_totals) } - let!(:completed_payment) { create(:payment, order: order, state: 'completed', amount: order.total - 1) } - let!(:payment) { create(:payment, order: order, state: 'checkout', amount: 123.45) } + describe '#serializable_hash' do + let!(:completed_payment) do + create(:payment, order: order, state: 'completed', amount: order.total - 1) + end + let!(:payment) { create(:payment, order: order, state: 'checkout', amount: 123.45) } - it "serializes an order" do - expect(serializer.to_json).to match order.number.to_s + it "serializes an order" do + expect(serializer.serializable_hash[:number]).to eq(order.number) + end + + it "convert the state attributes to translatable keys" do + hash = serializer.serializable_hash + + expect(hash[:state]).to eq("complete") + expect(hash[:payment_state]).to eq("balance_due") + end + + it "only serializes completed payments" do + hash = serializer.serializable_hash + + expect(hash[:payments].first[:amount]).to eq(completed_payment.amount) + end end - it "convert the state attributes to translatable keys" do - # byebug if serializer.to_json =~ /balance_due/ - expect(serializer.to_json).to match "complete" - expect(serializer.to_json).to match "balance_due" - end + describe '#outstanding_balance' do + context 'when the customer_balance feature is enabled' do + before do + allow(OpenFoodNetwork::FeatureToggle) + .to receive(:enabled?).with(:customer_balance, order.user) { true } - it "only serializes completed payments" do - expect(serializer.to_json).to match completed_payment.amount.to_s - expect(serializer.to_json).to_not match payment.amount.to_s + allow(order).to receive(:balance_value).and_return(-1.23) + end + + it "returns the object's balance_value from the users perspective" do + expect(serializer.serializable_hash[:outstanding_balance]).to eq(1.23) + end + end + + context 'when the customer_balance is not enabled' do + before do + allow(OpenFoodNetwork::FeatureToggle) + .to receive(:enabled?).with(:customer_balance, order.user) { false } + + allow(order).to receive(:outstanding_balance).and_return(123.0) + end + + it 'calls #outstanding_balance on the object' do + expect(serializer.serializable_hash[:outstanding_balance]).to eq(123.0) + end + end end end diff --git a/vendor/assets/javascripts/jquery.adaptivemenu.js b/vendor/assets/javascripts/jquery.adaptivemenu.js deleted file mode 100644 index b9a611a8fb..0000000000 --- a/vendor/assets/javascripts/jquery.adaptivemenu.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Original from spree/core/vendor/assets/javascripts/jquery.adaptivemenu.js - */ - -/* - * Used for the spree admin tab bar (Orders, Products, Reports etc.). - * Using parent's width instead of window width. - */ -jQuery.fn.AdaptiveMenu = function(options){ - - var options = jQuery.extend({ - text: "More...", - accuracy:0, // originally 70, but not needed anymore - 'class':null, - 'classLinckMore':null - },options); - - var menu = this; - var li = $(menu).find("li"); - - var width = 0; - var widthLi = []; - $.each( li , function(i, l){ - width += $(l).width(); - widthLi.push( width ); - }); - - var buildingMenu = function(){ - // Using parent width instead of given window width - var windowWidth = $(menu.parent()).width() - options.accuracy; - for(var i = 0; i windowWidth ) - $( li[i] ).hide(); - else - $( li[i] ).show(); - } - $(menu).find('#more').remove(); - var hideLi = $(li).filter(':not(:visible)'); - var lastLi = $(li).filter(':visible').last(); - if ( hideLi.length > 0 ){ - var more = $("
  • ") - .css({"display":"inline-block","white-space":"nowrap"}) - .addClass(options.classLinckMore) - .attr({"id":"more"}) - .html(options.text) - .click(function(){$(this).find('li').toggle()}); - - var ul = $("