mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-17 19:26:48 +00:00
Compare commits
174 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
917079931e | ||
|
|
46e54f48c9 | ||
|
|
059dceb304 | ||
|
|
f0abe650f6 | ||
|
|
282df9859e | ||
|
|
3474c60f4c | ||
|
|
503148b13b | ||
|
|
8442c7d334 | ||
|
|
b14cd08990 | ||
|
|
50ebfe412c | ||
|
|
e59ab6b2d9 | ||
|
|
417d39f684 | ||
|
|
35169f66dc | ||
|
|
64568f4aa4 | ||
|
|
734aebbaaa | ||
|
|
8a2be468fc | ||
|
|
feb429fee7 | ||
|
|
b75101f24f | ||
|
|
1e71db9315 | ||
|
|
82b742608d | ||
|
|
49aa9e0768 | ||
|
|
a85cfab506 | ||
|
|
e2e3aa9281 | ||
|
|
6bd0f2c088 | ||
|
|
ab2968ffd2 | ||
|
|
83bf19084b | ||
|
|
40a59c988b | ||
|
|
43d983cac2 | ||
|
|
ad3e772944 | ||
|
|
6a438a07fe | ||
|
|
ea238829a8 | ||
|
|
91fddeaa8b | ||
|
|
0de8a90b14 | ||
|
|
9fe128d494 | ||
|
|
193e17b625 | ||
|
|
6ad03e6d5c | ||
|
|
1f55ff4b72 | ||
|
|
be13d43e0c | ||
|
|
af7b663334 | ||
|
|
da24638079 | ||
|
|
8ab1cbe600 | ||
|
|
cad0245510 | ||
|
|
93edf4e3ad | ||
|
|
caa2764317 | ||
|
|
4f1e6382c9 | ||
|
|
54d33ca103 | ||
|
|
787205dcca | ||
|
|
fcb0996a76 | ||
|
|
76d874d5f9 | ||
|
|
81711e4c43 | ||
|
|
e64f60a166 | ||
|
|
24bc56781b | ||
|
|
6757c8df74 | ||
|
|
647a384561 | ||
|
|
ec828c335d | ||
|
|
6d03a8ddf3 | ||
|
|
05878fcbb8 | ||
|
|
fd8973862e | ||
|
|
40c77948b9 | ||
|
|
a95aa1b3e9 | ||
|
|
706eb737b1 | ||
|
|
c31758d347 | ||
|
|
6139ba3015 | ||
|
|
256d5ba61c | ||
|
|
cb42e7e119 | ||
|
|
566d310880 | ||
|
|
5cdce35ee8 | ||
|
|
ffe3f12a23 | ||
|
|
bd48a982fb | ||
|
|
5d732d80a6 | ||
|
|
254e11aa36 | ||
|
|
4223b36bc3 | ||
|
|
fcea437d7e | ||
|
|
8716b75d3d | ||
|
|
e055b8b16c | ||
|
|
f5875e4c0b | ||
|
|
56d23c172c | ||
|
|
19bb40d1d3 | ||
|
|
4169a956c9 | ||
|
|
d54dbdfe2d | ||
|
|
fed2ae9a93 | ||
|
|
f00b2f0397 | ||
|
|
c101c4e42f | ||
|
|
11ba33d7f4 | ||
|
|
8e663dac3f | ||
|
|
df0795acf1 | ||
|
|
7e1af9e04b | ||
|
|
4805adec42 | ||
|
|
7939bf8038 | ||
|
|
d4e0b2ab51 | ||
|
|
1014a50aff | ||
|
|
0afbdf157e | ||
|
|
5012c52438 | ||
|
|
615a81c55d | ||
|
|
99b31d05cb | ||
|
|
1a72b5b227 | ||
|
|
a1aea54405 | ||
|
|
e01354e863 | ||
|
|
ffe4603f2f | ||
|
|
ebc794194f | ||
|
|
287f65ec8e | ||
|
|
1288592d58 | ||
|
|
0836d844a6 | ||
|
|
96355a1ed4 | ||
|
|
ce44f19b4a | ||
|
|
6c214543ad | ||
|
|
8b1713d169 | ||
|
|
587ce5ad9d | ||
|
|
f51705cb57 | ||
|
|
55df9416cc | ||
|
|
0376c04ad5 | ||
|
|
2709479bf2 | ||
|
|
c5fc621aa4 | ||
|
|
bfd0e7f784 | ||
|
|
ec3c157f1e | ||
|
|
32aacbd2b0 | ||
|
|
655dc92246 | ||
|
|
fece8beef5 | ||
|
|
53e3621e04 | ||
|
|
1949839056 | ||
|
|
00a0006ff2 | ||
|
|
325f9aa6f3 | ||
|
|
95ec5c3c58 | ||
|
|
ef87cdb167 | ||
|
|
65d4596f3b | ||
|
|
a9e295bc11 | ||
|
|
ac8caf7710 | ||
|
|
8a1e61fd60 | ||
|
|
baf38b6b30 | ||
|
|
3507405dae | ||
|
|
c25fe6ae57 | ||
|
|
7bcf3206d8 | ||
|
|
e808c7fb2b | ||
|
|
df81e8ed35 | ||
|
|
e9d7a0b099 | ||
|
|
da7bbcf82f | ||
|
|
1742d2807f | ||
|
|
d3c5e2365a | ||
|
|
27e53f9dcc | ||
|
|
5d0f55b8c3 | ||
|
|
9d89b4726b | ||
|
|
9b37eacb8d | ||
|
|
bbe22bbfeb | ||
|
|
85d5e2ee70 | ||
|
|
9a4051f37b | ||
|
|
05ed4639b2 | ||
|
|
2bcf84d9a9 | ||
|
|
99acf752f4 | ||
|
|
5086f2d8b5 | ||
|
|
0b46c41ffd | ||
|
|
4fe3f60009 | ||
|
|
dfea0cd805 | ||
|
|
0f04b2fb10 | ||
|
|
a6efad73a8 | ||
|
|
29d63b0f0f | ||
|
|
25e9fd22d8 | ||
|
|
bb427db66a | ||
|
|
1165b00600 | ||
|
|
2d45952611 | ||
|
|
1af811cf51 | ||
|
|
1850f298a6 | ||
|
|
80ade22bd6 | ||
|
|
4fb458afe0 | ||
|
|
2baf7c0250 | ||
|
|
29aa3a8059 | ||
|
|
718e6765e1 | ||
|
|
31d49ee99e | ||
|
|
1e08f2713e | ||
|
|
8955972b05 | ||
|
|
5fe5804b56 | ||
|
|
9d12e55bd7 | ||
|
|
b3570991f4 | ||
|
|
e2aca63fff | ||
|
|
e537bda9b7 |
17
.github/workflows/build.yml
vendored
17
.github/workflows/build.yml
vendored
@@ -216,9 +216,9 @@ jobs:
|
||||
|
||||
- name: Archive failed tests screenshots
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: failed-tests-screenshots
|
||||
name: failed-admin-tests-screenshots
|
||||
path: tmp/capybara/screenshots/*.png
|
||||
retention-days: 7
|
||||
if-no-files-found: ignore
|
||||
@@ -294,9 +294,9 @@ jobs:
|
||||
|
||||
- name: Archive failed tests screenshots
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: failed-tests-screenshots
|
||||
name: failed-consumer-tests-screenshots
|
||||
path: tmp/capybara/screenshots/*.png
|
||||
retention-days: 7
|
||||
if-no-files-found: ignore
|
||||
@@ -371,15 +371,6 @@ jobs:
|
||||
run: |
|
||||
bin/rake knapsack_pro:rspec
|
||||
|
||||
- name: Archive failed tests screenshots
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: failed-tests-screenshots
|
||||
path: tmp/capybara/screenshots/*.png
|
||||
retention-days: 7
|
||||
if-no-files-found: ignore
|
||||
|
||||
test_the_rest:
|
||||
runs-on: ubuntu-22.04
|
||||
services:
|
||||
|
||||
@@ -12,22 +12,6 @@ Layout/EmptyLines:
|
||||
Exclude:
|
||||
- 'app/services/products_renderer.rb'
|
||||
|
||||
# Offense count: 6
|
||||
# This cop supports safe autocorrection (--autocorrect).
|
||||
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
||||
# SupportedStyles: aligned, indented, indented_relative_to_receiver
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Exclude:
|
||||
- 'app/services/products_renderer.rb'
|
||||
|
||||
# Offense count: 2
|
||||
# This cop supports safe autocorrection (--autocorrect).
|
||||
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
||||
# SupportedStyles: aligned, indented
|
||||
Layout/MultilineOperationIndentation:
|
||||
Exclude:
|
||||
- 'app/services/products_renderer.rb'
|
||||
|
||||
# Offense count: 16
|
||||
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
||||
Lint/EmptyBlock:
|
||||
@@ -101,7 +85,7 @@ Lint/UselessMethodDefinition:
|
||||
Exclude:
|
||||
- 'app/models/spree/gateway.rb'
|
||||
|
||||
# Offense count: 23
|
||||
# Offense count: 24
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
||||
Metrics/AbcSize:
|
||||
Exclude:
|
||||
@@ -114,6 +98,7 @@ Metrics/AbcSize:
|
||||
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||
- 'app/models/enterprise_group.rb'
|
||||
- 'app/models/enterprise_relationship.rb'
|
||||
- 'app/models/product_import/entry_processor.rb'
|
||||
- 'app/models/spree/ability.rb'
|
||||
- 'app/models/spree/address.rb'
|
||||
- 'app/models/spree/order/checkout.rb'
|
||||
@@ -142,7 +127,7 @@ Metrics/BlockNesting:
|
||||
Exclude:
|
||||
- 'app/models/spree/payment/processing.rb'
|
||||
|
||||
# Offense count: 47
|
||||
# Offense count: 46
|
||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||
Metrics/ClassLength:
|
||||
Exclude:
|
||||
@@ -178,7 +163,6 @@ Metrics/ClassLength:
|
||||
- 'app/models/spree/variant.rb'
|
||||
- 'app/models/spree/zone.rb'
|
||||
- 'app/reflexes/admin/orders_reflex.rb'
|
||||
- 'app/reflexes/products_reflex.rb'
|
||||
- 'app/serializers/api/cached_enterprise_serializer.rb'
|
||||
- 'app/serializers/api/enterprise_shopfront_serializer.rb'
|
||||
- 'app/services/cart_service.rb'
|
||||
@@ -408,7 +392,6 @@ RSpecRails/HaveHttpStatus:
|
||||
- 'spec/controllers/stripe/webhooks_controller_spec.rb'
|
||||
- 'spec/controllers/user_passwords_controller_spec.rb'
|
||||
- 'spec/controllers/user_registrations_controller_spec.rb'
|
||||
- 'spec/requests/admin/images_spec.rb'
|
||||
- 'spec/requests/api/routes_spec.rb'
|
||||
- 'spec/requests/checkout/stripe_sca_spec.rb'
|
||||
- 'spec/requests/home_controller_spec.rb'
|
||||
@@ -638,12 +621,6 @@ Rails/ResponseParsedBody:
|
||||
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
|
||||
- 'spec/controllers/user_registrations_controller_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
Rails/RootPathnameMethods:
|
||||
Exclude:
|
||||
- 'spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb'
|
||||
|
||||
# Offense count: 7
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
@@ -725,7 +702,7 @@ Style/ClassAndModuleChildren:
|
||||
- 'lib/open_food_network/locking.rb'
|
||||
- 'spec/models/spree/payment_method_spec.rb'
|
||||
|
||||
# Offense count: 2
|
||||
# Offense count: 1
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
# SupportedStyles: always, always_true, never
|
||||
@@ -872,39 +849,6 @@ Style/ReturnNilInPredicateMethodDefinition:
|
||||
- 'app/serializers/api/admin/customer_serializer.rb'
|
||||
- 'engines/order_management/app/services/order_management/subscriptions/validator.rb'
|
||||
|
||||
# Offense count: 207
|
||||
Style/Send:
|
||||
Exclude:
|
||||
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||
- 'spec/controllers/payment_gateways/paypal_controller_spec.rb'
|
||||
- 'spec/controllers/spree/admin/base_controller_spec.rb'
|
||||
- 'spec/controllers/spree/orders_controller_spec.rb'
|
||||
- 'spec/helpers/order_cycles_helper_spec.rb'
|
||||
- 'spec/jobs/subscription_confirm_job_spec.rb'
|
||||
- 'spec/jobs/subscription_placement_job_spec.rb'
|
||||
- 'spec/lib/open_food_network/address_finder_spec.rb'
|
||||
- 'spec/lib/open_food_network/enterprise_fee_applicator_spec.rb'
|
||||
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
|
||||
- 'spec/lib/open_food_network/order_cycle_form_applicator_spec.rb'
|
||||
- 'spec/lib/open_food_network/permissions_spec.rb'
|
||||
- 'spec/lib/open_food_network/tag_rule_applicator_spec.rb'
|
||||
- 'spec/lib/reports/xero_invoices_report_spec.rb'
|
||||
- 'spec/lib/stripe/webhook_handler_spec.rb'
|
||||
- 'spec/models/calculator/weight_spec.rb'
|
||||
- 'spec/models/enterprise_spec.rb'
|
||||
- 'spec/models/exchange_spec.rb'
|
||||
- 'spec/models/spree/order_inventory_spec.rb'
|
||||
- 'spec/models/spree/payment_spec.rb'
|
||||
- 'spec/models/spree/return_authorization_spec.rb'
|
||||
- 'spec/models/tag_rule/filter_order_cycles_spec.rb'
|
||||
- 'spec/models/tag_rule/filter_payment_methods_spec.rb'
|
||||
- 'spec/models/tag_rule/filter_products_spec.rb'
|
||||
- 'spec/models/tag_rule/filter_shipping_methods_spec.rb'
|
||||
- 'spec/services/cart_service_spec.rb'
|
||||
- 'spec/services/products_renderer_spec.rb'
|
||||
- 'spec/services/variant_units/option_value_namer_spec.rb'
|
||||
- 'spec/support/localized_number_helper.rb'
|
||||
|
||||
# Offense count: 3
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
Style/SlicingWithRange:
|
||||
|
||||
1
Gemfile
1
Gemfile
@@ -16,7 +16,6 @@ gem "image_processing"
|
||||
|
||||
gem 'activemerchant', '>= 1.78.0'
|
||||
gem 'angular-rails-templates', '>= 0.3.0'
|
||||
gem 'awesome_nested_set'
|
||||
gem 'ransack', '~> 4.1.0'
|
||||
gem 'responders'
|
||||
gem 'webpacker', '~> 5'
|
||||
|
||||
@@ -161,8 +161,6 @@ GEM
|
||||
activerecord (>= 3.1.0, < 8)
|
||||
ast (2.4.2)
|
||||
attr_required (1.0.2)
|
||||
awesome_nested_set (3.6.0)
|
||||
activerecord (>= 4.0.0, < 7.2)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.929.0)
|
||||
aws-sdk-core (3.196.1)
|
||||
@@ -358,7 +356,7 @@ GEM
|
||||
ruby-vips (>= 2.0.17, < 3)
|
||||
immigrant (0.3.6)
|
||||
activerecord (>= 3.0)
|
||||
invisible_captcha (2.2.0)
|
||||
invisible_captcha (2.3.0)
|
||||
rails (>= 5.2)
|
||||
io-console (0.7.2)
|
||||
ipaddress (0.8.3)
|
||||
@@ -417,7 +415,7 @@ GEM
|
||||
net-imap
|
||||
net-pop
|
||||
net-smtp
|
||||
marcel (1.0.2)
|
||||
marcel (1.0.4)
|
||||
matrix (0.4.2)
|
||||
method_source (1.1.0)
|
||||
mime-types (3.5.2)
|
||||
@@ -449,7 +447,7 @@ GEM
|
||||
net-smtp (0.5.0)
|
||||
net-protocol
|
||||
newrelic_rpm (9.9.0)
|
||||
nio4r (2.7.0)
|
||||
nio4r (2.7.1)
|
||||
nokogiri (1.16.5)
|
||||
mini_portile2 (~> 2.8.2)
|
||||
racc (~> 1.4)
|
||||
@@ -863,7 +861,6 @@ DEPENDENCIES
|
||||
angularjs-file-upload-rails (~> 2.4.1)
|
||||
angularjs-rails (= 1.8.0)
|
||||
arel-helpers (~> 2.12)
|
||||
awesome_nested_set
|
||||
aws-sdk-s3
|
||||
bigdecimal (= 3.0.2)
|
||||
bootsnap
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
//= require jquery.ui.all
|
||||
//= require jquery.powertip
|
||||
//= require jquery.cookie
|
||||
//= require jquery.jstree/jquery.jstree
|
||||
//= require jquery.vAlign
|
||||
//= require angular
|
||||
//= require angular-resource
|
||||
|
||||
@@ -126,8 +126,11 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
|
||||
$scope.addVariant = (product) ->
|
||||
# Set new variant category to same as last product variant category to keep compactibility with deleted variant callback to set new variant category
|
||||
newVariantId = $scope.nextVariantId();
|
||||
newVariantCategoryId = product.variants[product.variants.length - 1]?.category_id
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
id: newVariantId
|
||||
unit_value: null
|
||||
unit_description: null
|
||||
on_demand: false
|
||||
@@ -136,8 +139,9 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
on_hand: null
|
||||
price: null
|
||||
tax_category_id: null
|
||||
category_id: null
|
||||
category_id: newVariantCategoryId
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
DirtyProducts.addVariantProperty(product.id, newVariantId, 'category_id', newVariantCategoryId)
|
||||
|
||||
|
||||
$scope.nextVariantId = ->
|
||||
|
||||
@@ -3,6 +3,7 @@ angular.module('admin.orderCycles')
|
||||
$controller('AdminOrderCycleBasicCtrl', {$scope: $scope, ocInstance: ocInstance})
|
||||
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.order_cycle_id = order_cycle_id
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id)
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: order_cycle_id)
|
||||
@@ -18,6 +19,8 @@ angular.module('admin.orderCycles')
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
$scope.order_cycle?.trigger_action = $($event.target).data('trigger-action');
|
||||
$scope.order_cycle?.confirm = $($event.target).data('confirm');
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.update(destination, $scope.order_cycle_form)
|
||||
|
||||
@@ -25,4 +28,4 @@ angular.module('admin.orderCycles')
|
||||
if $scope.order_cycle_form?.$dirty
|
||||
t('admin.unsaved_confirm_leave')
|
||||
|
||||
NavigationCheck.register(warnAboutUnsavedChanges)
|
||||
NavigationCheck.register(warnAboutUnsavedChanges)
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $rootScope, $controller, $location, Enterprise, OrderCycle, ExchangeProduct, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller 'AdminOrderCycleIncomingCtrl', ($scope, $rootScope, $controller, $location, Enterprise, EnterpriseFee, OrderCycle, ExchangeProduct, ocInstance) ->
|
||||
$controller('AdminOrderCycleExchangesCtrl', {$scope: $scope, ocInstance: ocInstance, $location: $location})
|
||||
|
||||
$scope.view = 'incoming'
|
||||
|
||||
# NB: weirdly at this next line $scope.order_cycle.id comes out undefined so we use $scope.order_cycle_id instead
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.order_cycle_id, per_item: true)
|
||||
$scope.exchangeTotalVariants = (exchange) ->
|
||||
return unless $scope.enterprises? && $scope.enterprises[exchange.enterprise_id]?
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
|
||||
$scope.submit = ($event, destination) ->
|
||||
$event.preventDefault()
|
||||
$scope.order_cycle?.trigger_action = $($event.target).data('trigger-action');
|
||||
$scope.order_cycle?.confirm = $($event.target).data('confirm');
|
||||
StatusMessage.display 'progress', t('js.saving')
|
||||
OrderCycle.mirrorIncomingToOutgoingProducts()
|
||||
OrderCycle.update(destination, $scope.order_cycle_form) if OrderCycle.confirmNoDistributors()
|
||||
|
||||
@@ -6,6 +6,8 @@ angular.module('admin.orderCycles').factory('EnterpriseFee', ($resource) ->
|
||||
params:
|
||||
order_cycle_id: '@order_cycle_id'
|
||||
coordinator_id: '@coordinator_id'
|
||||
per_item: '@per_item'
|
||||
per_order: '@per_order'
|
||||
})
|
||||
|
||||
{
|
||||
|
||||
@@ -161,7 +161,11 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, $
|
||||
StatusMessage.display('failure', t('js.order_cycles.create_failure'))
|
||||
|
||||
update: (destination, form) ->
|
||||
oc = new OrderCycleResource({order_cycle: this.dataForSubmit()})
|
||||
oc = new OrderCycleResource({
|
||||
order_cycle: this.dataForSubmit(),
|
||||
confirm: this.order_cycle.confirm,
|
||||
trigger_action: this.order_cycle.trigger_action
|
||||
})
|
||||
oc.$update {order_cycle_id: this.order_cycle.id, reloading: (if destination? then 1 else 0)}, (data) =>
|
||||
form.$setPristine() if form
|
||||
if destination?
|
||||
@@ -171,6 +175,8 @@ angular.module('admin.orderCycles').factory 'OrderCycle', ($resource, $window, $
|
||||
, (response) ->
|
||||
if response.data.errors?
|
||||
StatusMessage.display('failure', response.data.errors[0])
|
||||
else if (response.data.trigger_action)
|
||||
StatusMessage.display('notice', t('js.order_cycles.unsaved_changes'), response.data.trigger_action)
|
||||
else
|
||||
StatusMessage.display('failure', t('js.order_cycles.update_failure'))
|
||||
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
root = exports ? this
|
||||
|
||||
root.taxon_tree_menu = (obj, context) ->
|
||||
|
||||
base_url = Spree.url(Spree.routes.taxonomy_taxons)
|
||||
admin_base_url = Spree.url(Spree.routes.admin_taxonomy_taxons)
|
||||
edit_url = Spree.url(Spree.routes.admin_taxonomy_taxons + '/' + obj.attr("id") + "/edit");
|
||||
|
||||
create:
|
||||
label: "<i class='icon-plus'></i> " + Spree.translations.add,
|
||||
action: (obj) -> context.create(obj)
|
||||
rename:
|
||||
label: "<i class='icon-pencil'></i> " + Spree.translations.rename,
|
||||
action: (obj) -> context.rename(obj)
|
||||
remove:
|
||||
label: "<i class='icon-trash'></i> " + Spree.translations.remove,
|
||||
action: (obj) -> context.remove(obj)
|
||||
edit:
|
||||
separator_before: true,
|
||||
label: "<i class='icon-edit'></i> " + Spree.translations.edit,
|
||||
action: (obj) -> window.location = edit_url.toString()
|
||||
@@ -1,139 +0,0 @@
|
||||
handle_ajax_error = (XMLHttpRequest, textStatus, errorThrown) ->
|
||||
$.jstree.rollback(last_rollback)
|
||||
$("#ajax_error").show().html("<strong>" + server_error + "</strong><br />" + taxonomy_tree_error)
|
||||
|
||||
handle_move = (e, data) ->
|
||||
last_rollback = data.rlbk
|
||||
position = data.rslt.cp
|
||||
node = data.rslt.o
|
||||
new_parent = data.rslt.np
|
||||
|
||||
url = new URL(Spree.routes.admin_taxonomy_taxons)
|
||||
url.pathname = url.pathname + '/' + node.attr("id")
|
||||
data = {
|
||||
_method: "put",
|
||||
"taxon[position]": position,
|
||||
"taxon[parent_id]": if !isNaN(new_parent.attr("id")) then new_parent.attr("id") else undefined
|
||||
}
|
||||
$.ajax
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: url.toString(),
|
||||
data: data,
|
||||
error: handle_ajax_error
|
||||
|
||||
true
|
||||
|
||||
handle_create = (e, data) ->
|
||||
last_rollback = data.rlbk
|
||||
node = data.rslt.obj
|
||||
name = data.rslt.name
|
||||
position = data.rslt.position
|
||||
new_parent = data.rslt.parent
|
||||
|
||||
data = {
|
||||
"taxon[name]": name,
|
||||
"taxon[position]": position
|
||||
"taxon[parent_id]": if !isNaN(new_parent.attr("id")) then new_parent.attr("id") else undefined
|
||||
}
|
||||
$.ajax
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: base_url.toString(),
|
||||
data: data,
|
||||
error: handle_ajax_error,
|
||||
success: (data,result) ->
|
||||
node.attr('id', data.id)
|
||||
|
||||
handle_rename = (e, data) ->
|
||||
last_rollback = data.rlbk
|
||||
node = data.rslt.obj
|
||||
name = data.rslt.new_name
|
||||
# change the name inside the main input field as well if taxon is the root one
|
||||
document.getElementById("taxonomy_name").value = name if node.parents("[id]").attr("id") == "taxonomy_tree"
|
||||
|
||||
url = new URL(base_url)
|
||||
url.pathname = url.pathname + '/' + node.attr("id")
|
||||
|
||||
$.ajax
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: url.toString(),
|
||||
data: {_method: "put", "taxon[name]": name },
|
||||
error: handle_ajax_error
|
||||
|
||||
handle_delete = (e, data) ->
|
||||
last_rollback = data.rlbk
|
||||
node = data.rslt.obj
|
||||
delete_url = new URL(base_url)
|
||||
delete_url.pathname = delete_url.pathname + '/' + node.attr("id")
|
||||
if confirm(Spree.translations.are_you_sure_delete)
|
||||
$.ajax
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
url: delete_url.toString(),
|
||||
data: {_method: "delete"},
|
||||
error: handle_ajax_error
|
||||
else
|
||||
$.jstree.rollback(last_rollback)
|
||||
last_rollback = null
|
||||
|
||||
root = exports ? this
|
||||
root.setup_taxonomy_tree = (taxonomy_id) ->
|
||||
if taxonomy_id != undefined
|
||||
# this is defined within admin/taxonomies/edit
|
||||
root.base_url = Spree.url(Spree.routes.taxonomy_taxons)
|
||||
|
||||
$.ajax
|
||||
url: base_url.pathname.replace("/taxons", "/jstree"),
|
||||
success: (taxonomy) ->
|
||||
last_rollback = null
|
||||
|
||||
conf =
|
||||
json_data:
|
||||
data: taxonomy,
|
||||
ajax:
|
||||
url: (e) ->
|
||||
base_url.pathname + '/' + e.attr('id') + '/jstree'
|
||||
themes:
|
||||
theme: "apple",
|
||||
url: "/assets/jquery.jstree/themes/apple/style.css"
|
||||
strings:
|
||||
new_node: new_taxon,
|
||||
loading: Spree.translations.loading + "..."
|
||||
crrm:
|
||||
move:
|
||||
check_move: (m) ->
|
||||
position = m.cp
|
||||
node = m.o
|
||||
new_parent = m.np
|
||||
|
||||
# no parent or cant drag and drop
|
||||
if !new_parent || node.attr("rel") == "root"
|
||||
return false
|
||||
|
||||
# can't drop before root
|
||||
if new_parent.attr("id") == "taxonomy_tree" && position == 0
|
||||
return false
|
||||
|
||||
true
|
||||
contextmenu:
|
||||
items: (obj) ->
|
||||
taxon_tree_menu(obj, this)
|
||||
plugins: ["themes", "json_data", "dnd", "crrm", "contextmenu"]
|
||||
|
||||
$("#taxonomy_tree").jstree(conf)
|
||||
.bind("move_node.jstree", handle_move)
|
||||
.bind("remove.jstree", handle_delete)
|
||||
.bind("create.jstree", handle_create)
|
||||
.bind("rename.jstree", handle_rename)
|
||||
.bind "loaded.jstree", ->
|
||||
$(this).jstree("core").toggle_node($('.jstree-icon').first())
|
||||
|
||||
$("#taxonomy_tree a").on "dblclick", (e) ->
|
||||
$("#taxonomy_tree").jstree("rename", this)
|
||||
|
||||
# surpress form submit on enter/return
|
||||
$(document).keypress (e) ->
|
||||
if e.keyCode == 13
|
||||
e.preventDefault()
|
||||
@@ -10,7 +10,9 @@ angular.module("admin.utils").factory "StatusMessage", ->
|
||||
|
||||
statusMessage:
|
||||
text: ""
|
||||
style: {}
|
||||
style: {},
|
||||
type: null,
|
||||
actionName: null
|
||||
|
||||
invalidMessage: ""
|
||||
|
||||
@@ -23,11 +25,15 @@ angular.module("admin.utils").factory "StatusMessage", ->
|
||||
active: ->
|
||||
@statusMessage.text != ''
|
||||
|
||||
display: (type, text) ->
|
||||
display: (type, text, actionName = null) ->
|
||||
@statusMessage.text = text
|
||||
@statusMessage.type = type
|
||||
@statusMessage.actionName = actionName
|
||||
@statusMessage.style = @types[type].style
|
||||
null
|
||||
|
||||
clear: ->
|
||||
@statusMessage.text = ''
|
||||
@statusMessage.style = {}
|
||||
@statusMessage.type = null
|
||||
@statusMessage.actionName = null
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#save-bar.animate-show{ "ng-show": 'dirty || persist || StatusMessage.active()' }
|
||||
.container
|
||||
.seven.columns.alpha
|
||||
%h5#status-message{ "ng-show": "StatusMessage.invalidMessage == ''", "ng-style": 'StatusMessage.statusMessage.style' }
|
||||
%h5#status-message{ "ng-show": "StatusMessage.invalidMessage == ''", "ng-style": 'StatusMessage.statusMessage.style', data: { 'order-cycle-form-target': 'statusMessage' }, "ng-attr-data-type": "{{StatusMessage.statusMessage.type}}", "ng-attr-data-action-name": "{{StatusMessage.statusMessage.actionName}}" }
|
||||
{{ StatusMessage.statusMessage.text || " " }}
|
||||
%h5#status-message{ style: 'color: #C85136', "ng-show": "StatusMessage.invalidMessage !== ''" }
|
||||
{{ StatusMessage.invalidMessage || " " }}
|
||||
|
||||
@@ -24,6 +24,19 @@
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.flex-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.gap-1 {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.gap-2 {
|
||||
gap: 2rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* prevent arrow on selected admin menu item appearing above modal */
|
||||
|
||||
22
app/controllers/admin/connected_app_settings_controller.rb
Normal file
22
app/controllers/admin/connected_app_settings_controller.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
class ConnectedAppSettingsController < Spree::Admin::BaseController
|
||||
def update
|
||||
Spree::Config.set(connected_apps_enabled:)
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:success] = t(:successfully_updated, resource: t('.resource'))
|
||||
redirect_to main_app.edit_admin_connected_app_settings_path
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def connected_apps_enabled
|
||||
params.require(:preferences).require(:connected_apps_enabled).compact_blank.join(",")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,12 +5,12 @@ module Admin
|
||||
def create
|
||||
authorize! :admin, enterprise
|
||||
|
||||
app = ConnectedApp.create!(enterprise_id: enterprise.id)
|
||||
attributes = {}
|
||||
attributes[:type] = connected_app_params[:type] if connected_app_params[:type]
|
||||
|
||||
ConnectAppJob.perform_later(
|
||||
app, spree_current_user.spree_api_key,
|
||||
channel: SessionChannel.for_request(request),
|
||||
)
|
||||
app = ConnectedApp.create!(enterprise_id: enterprise.id, **attributes)
|
||||
app.connect(api_key: spree_current_user.spree_api_key,
|
||||
channel: SessionChannel.for_request(request))
|
||||
|
||||
render_panel
|
||||
end
|
||||
@@ -18,15 +18,9 @@ module Admin
|
||||
def destroy
|
||||
authorize! :admin, enterprise
|
||||
|
||||
app = enterprise.connected_apps.first
|
||||
app = enterprise.connected_apps.find(params.require(:id))
|
||||
app.destroy
|
||||
|
||||
WebhookDeliveryJob.perform_later(
|
||||
app.data["destroy"],
|
||||
"disconnect-app",
|
||||
nil
|
||||
)
|
||||
|
||||
render_panel
|
||||
end
|
||||
|
||||
@@ -39,5 +33,9 @@ module Admin
|
||||
def render_panel
|
||||
redirect_to "#{edit_admin_enterprise_path(enterprise)}#/connected_apps_panel"
|
||||
end
|
||||
|
||||
def connected_app_params
|
||||
params.permit(:type)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,13 +35,7 @@ module Admin
|
||||
private
|
||||
|
||||
def fetch_catalog(url)
|
||||
if url =~ /food-data-collaboration/
|
||||
fdc_json = FdcRequest.new(spree_current_user).call(url)
|
||||
fdc_message = JSON.parse(fdc_json)
|
||||
fdc_message["products"]
|
||||
else
|
||||
DfcRequest.new(spree_current_user).call(url)
|
||||
end
|
||||
DfcRequest.new(spree_current_user).call(url)
|
||||
end
|
||||
|
||||
# Most of this code is the same as in the DfcProvider::SuppliedProductsController.
|
||||
|
||||
@@ -65,7 +65,9 @@ module Admin
|
||||
order_cycle ||= OrderCycle.new(coordinator:) if coordinator.present?
|
||||
enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user,
|
||||
order_cycle).visible_enterprises
|
||||
EnterpriseFee.for_enterprises(enterprises).order('enterprise_id', 'fee_type', 'name')
|
||||
|
||||
fees = EnterpriseFee.for_enterprises(enterprises).order('enterprise_id', 'fee_type', 'name')
|
||||
filter_fees(fees)
|
||||
else
|
||||
collection = EnterpriseFee.managed_by(spree_current_user).order('enterprise_id',
|
||||
'fee_type', 'name')
|
||||
@@ -74,6 +76,12 @@ module Admin
|
||||
end
|
||||
end
|
||||
|
||||
def filter_fees(fees)
|
||||
fees = fees.per_item if params[:per_item]
|
||||
fees = fees.per_order if params[:per_order]
|
||||
fees
|
||||
end
|
||||
|
||||
def collection_actions
|
||||
[:index, :for_order_cycle, :bulk_update]
|
||||
end
|
||||
|
||||
@@ -11,6 +11,7 @@ module Admin
|
||||
before_action :remove_protected_attrs, only: [:update]
|
||||
before_action :require_order_cycle_set_params, only: [:bulk_update]
|
||||
around_action :protect_invalid_destroy, only: :destroy
|
||||
before_action :verify_datetime_change, only: :update
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
@@ -235,7 +236,7 @@ module Admin
|
||||
else
|
||||
begin
|
||||
yield
|
||||
rescue ActiveRecord::InvalidForeignKey
|
||||
rescue ActiveRecord::InvalidForeignKey, ActiveRecord::DeleteRestrictionError
|
||||
redirect_to main_app.admin_order_cycles_url
|
||||
flash[:error] = I18n.t('admin.order_cycles.destroy_errors.orders_present')
|
||||
end
|
||||
@@ -294,5 +295,22 @@ module Admin
|
||||
collection_attributes: [:id] + PermittedAttributes::OrderCycle.basic_attributes
|
||||
).to_h.with_indifferent_access
|
||||
end
|
||||
|
||||
# Check that order cycle datetime values changed if it has existing orders
|
||||
def verify_datetime_change
|
||||
return unless params[:order_cycle][:confirm]
|
||||
return unless @order_cycle.orders.exists?
|
||||
return if same_dates(@order_cycle.orders_open_at, order_cycle_params[:orders_open_at]) &&
|
||||
same_dates(@order_cycle.orders_close_at, order_cycle_params[:orders_close_at])
|
||||
|
||||
render json: { trigger_action: params[:order_cycle][:trigger_action] },
|
||||
status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def same_dates(date, string)
|
||||
false unless date && string
|
||||
|
||||
DateTime.parse(string).to_fs(:short) == date.to_fs(:short)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,6 +11,8 @@ module Admin
|
||||
def index
|
||||
fetch_products
|
||||
render "index", locals: { producers:, categories:, tax_category_options:, flash: }
|
||||
|
||||
session[:products_return_to_url] = request.url
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V0
|
||||
class TaxonomiesController < Api::V0::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: :jstree
|
||||
|
||||
def jstree
|
||||
@taxonomy = Spree::Taxonomy.find(params[:id])
|
||||
render json: @taxonomy.root, serializer: Api::TaxonJstreeSerializer
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -5,12 +5,10 @@ module Api
|
||||
class TaxonsController < Api::V0::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: [:index, :show, :jstree]
|
||||
skip_authorization_check only: [:index, :show]
|
||||
|
||||
def index
|
||||
@taxons = if taxonomy
|
||||
taxonomy.root.children
|
||||
elsif params[:ids]
|
||||
@taxons = if params[:ids]
|
||||
Spree::Taxon.where(id: raw_params[:ids].split(","))
|
||||
else
|
||||
Spree::Taxon.ransack(raw_params[:q]).result
|
||||
@@ -18,23 +16,9 @@ module Api
|
||||
render json: @taxons, each_serializer: Api::TaxonSerializer
|
||||
end
|
||||
|
||||
def jstree
|
||||
@taxon = taxon
|
||||
render json: @taxon.children, each_serializer: Api::TaxonJstreeSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Taxon
|
||||
@taxon = Spree::Taxon.new(taxon_params)
|
||||
@taxon.taxonomy_id = params[:taxonomy_id]
|
||||
taxonomy = Spree::Taxonomy.find_by(id: params[:taxonomy_id])
|
||||
|
||||
if taxonomy.nil?
|
||||
@taxon.errors.add(:taxonomy_id, I18n.t(:invalid_taxonomy_id, scope: 'spree.api'))
|
||||
invalid_resource!(@taxon) && return
|
||||
end
|
||||
|
||||
@taxon.parent_id = taxonomy.root.id unless params.dig(:taxon, :parent_id)
|
||||
|
||||
if @taxon.save
|
||||
render json: @taxon, serializer: Api::TaxonSerializer, status: :created
|
||||
@@ -60,20 +44,14 @@ module Api
|
||||
|
||||
private
|
||||
|
||||
def taxonomy
|
||||
return if params[:taxonomy_id].blank?
|
||||
|
||||
@taxonomy ||= Spree::Taxonomy.find(params[:taxonomy_id])
|
||||
end
|
||||
|
||||
def taxon
|
||||
@taxon ||= taxonomy.taxons.find(params[:id])
|
||||
@taxon = Spree::Taxon.find(params[:id])
|
||||
end
|
||||
|
||||
def taxon_params
|
||||
return if params[:taxon].blank?
|
||||
|
||||
params.require(:taxon).permit([:name, :parent_id, :position])
|
||||
params.require(:taxon).permit([:name, :position])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,15 +19,18 @@ module Spree
|
||||
|
||||
before_action :authorize_admin
|
||||
before_action :set_locale
|
||||
before_action :warn_invalid_order_cycles, if: :html_request?
|
||||
before_action :warn_invalid_order_cycles, if: :page_load_request?
|
||||
|
||||
# Warn the user when they have an active order cycle with hubs that are not ready
|
||||
# for checkout (ie. does not have valid shipping and payment methods).
|
||||
def warn_invalid_order_cycles
|
||||
return if flash[:notice].present?
|
||||
return if flash[:notice].present? || session[:displayed_order_cycle_warning]
|
||||
|
||||
warning = OrderCycles::WarningService.new(spree_current_user).call
|
||||
flash[:notice] = warning if warning.present?
|
||||
return if warning.blank?
|
||||
|
||||
flash.now[:notice] = warning
|
||||
session[:displayed_order_cycle_warning] = true
|
||||
end
|
||||
|
||||
protected
|
||||
@@ -81,6 +84,12 @@ module Spree
|
||||
|
||||
private
|
||||
|
||||
def page_load_request?
|
||||
return false if request.format.include?('turbo')
|
||||
|
||||
html_request?
|
||||
end
|
||||
|
||||
def html_request?
|
||||
request.format.html?
|
||||
end
|
||||
|
||||
@@ -10,6 +10,7 @@ module Spree
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
include OrderCyclesHelper
|
||||
include EnterprisesHelper
|
||||
helper ::Admin::ProductsHelper
|
||||
|
||||
before_action :load_data
|
||||
before_action :load_producers, only: [:index, :new]
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxonomiesController < ::Admin::ResourceController
|
||||
respond_to :json, only: [:get_children]
|
||||
|
||||
def get_children
|
||||
@taxons = Taxon.find(params[:parent_id]).children
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def location_after_save
|
||||
if @taxonomy.created_at == @taxonomy.updated_at
|
||||
spree.edit_admin_taxonomy_url(@taxonomy)
|
||||
else
|
||||
spree.admin_taxonomies_url
|
||||
end
|
||||
end
|
||||
|
||||
def permitted_resource_params
|
||||
params.require(:taxonomy).permit(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -2,122 +2,70 @@
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxonsController < Spree::Admin::BaseController
|
||||
respond_to :html, :json, :js
|
||||
class TaxonsController < ::Admin::ResourceController
|
||||
before_action :set_taxon, except: %i[create index new]
|
||||
|
||||
def edit
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
@permalink_part = @taxon.permalink.split("/").last
|
||||
def index
|
||||
@taxons = Taxon.order(:name)
|
||||
end
|
||||
|
||||
def new
|
||||
@taxon = Taxon.new
|
||||
end
|
||||
|
||||
def edit; end
|
||||
|
||||
def create
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.build(params[:taxon])
|
||||
@taxon = Spree::Taxon.new(taxon_params)
|
||||
if @taxon.save
|
||||
respond_with(@taxon) do |format|
|
||||
format.json { render json: @taxon.to_json }
|
||||
end
|
||||
flash[:success] = flash_message_for(@taxon, :successfully_created)
|
||||
redirect_to edit_admin_taxon_path(@taxon.id)
|
||||
else
|
||||
flash[:error] = Spree.t('errors.messages.could_not_create_taxon')
|
||||
respond_with(@taxon) do |format|
|
||||
format.html do
|
||||
if redirect_to @taxonomy
|
||||
spree.edit_admin_taxonomy_url(@taxonomy)
|
||||
else
|
||||
spree.admin_taxonomies_url
|
||||
end
|
||||
end
|
||||
end
|
||||
render :new, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
parent_id = params[:taxon][:parent_id]
|
||||
new_position = params[:taxon][:position]
|
||||
|
||||
if parent_id || new_position # taxon is being moved
|
||||
new_parent = parent_id.nil? ? @taxon.parent : Taxon.find(parent_id.to_i)
|
||||
new_position = new_position.nil? ? -1 : new_position.to_i
|
||||
|
||||
# Bellow is a very complicated way of finding where in nested set we
|
||||
# should actually move the taxon to achieve sane results,
|
||||
# JS is giving us the desired position, which was awesome for previous setup,
|
||||
# but now it's quite complicated to find where we should put it as we have
|
||||
# to differenciate between moving to the same branch, up down and into
|
||||
# first position.
|
||||
new_siblings = new_parent.children
|
||||
if new_position <= 0 && new_siblings.empty?
|
||||
@taxon.move_to_child_of(new_parent)
|
||||
elsif new_parent.id != @taxon.parent_id
|
||||
if new_position.zero?
|
||||
@taxon.move_to_left_of(new_siblings.first)
|
||||
else
|
||||
@taxon.move_to_right_of(new_siblings[new_position - 1])
|
||||
end
|
||||
elsif new_position < new_siblings.index(@taxon)
|
||||
@taxon.move_to_left_of(new_siblings[new_position]) # we move up
|
||||
else
|
||||
@taxon.move_to_right_of(new_siblings[new_position - 1]) # we move down
|
||||
end
|
||||
# Reset legacy position, if any extensions still rely on it
|
||||
new_parent.children.reload.each do |t|
|
||||
t.update_columns(
|
||||
position: t.position,
|
||||
updated_at: Time.zone.now
|
||||
)
|
||||
end
|
||||
|
||||
if parent_id
|
||||
@taxon.reload
|
||||
@taxon.set_permalink
|
||||
@taxon.save!
|
||||
@update_children = true
|
||||
end
|
||||
end
|
||||
|
||||
if params.key? "permalink_part"
|
||||
parent_permalink = @taxon.permalink.split("/")[0...-1].join("/")
|
||||
parent_permalink += "/" if parent_permalink.present?
|
||||
params[:taxon][:permalink] = parent_permalink + params[:permalink_part]
|
||||
end
|
||||
# check if we need to rename child taxons if parent name or permalink changes
|
||||
if params[:taxon][:name] != @taxon.name || params[:taxon][:permalink] != @taxon.permalink
|
||||
@update_children = true
|
||||
end
|
||||
|
||||
if @taxon.update(taxon_params)
|
||||
flash[:success] = flash_message_for(@taxon, :successfully_updated)
|
||||
end
|
||||
|
||||
# rename child taxons
|
||||
if @update_children
|
||||
@taxon.descendants.each do |taxon|
|
||||
taxon.reload
|
||||
taxon.set_permalink
|
||||
taxon.save!
|
||||
end
|
||||
end
|
||||
|
||||
respond_with(@taxon) do |format|
|
||||
format.html { redirect_to spree.edit_admin_taxonomy_url(@taxonomy) }
|
||||
format.json { render json: @taxon.to_json }
|
||||
redirect_to edit_admin_taxon_path(@taxon.id)
|
||||
else
|
||||
render :edit, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@taxon = Taxon.find(params[:id])
|
||||
@taxon.destroy
|
||||
respond_with(@taxon) { |format| format.json { render json: '' } }
|
||||
status = if @taxon.destroy
|
||||
flash_message = t('.delete_taxon.success')
|
||||
status = :ok
|
||||
else
|
||||
flash_message = t('.delete_taxon.error')
|
||||
status = :unprocessable_entity
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:success] = flash_message if status == :ok
|
||||
flash[:error] = flash_message if status == :unprocessable_entity
|
||||
redirect_to admin_taxons_path
|
||||
}
|
||||
format.turbo_stream {
|
||||
flash[:success] = flash_message if status == :ok
|
||||
flash[:error] = flash_message if status == :unprocessable_entity
|
||||
render :destroy_taxon, status:
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_taxon
|
||||
@taxon = Taxon.find(params[:id])
|
||||
end
|
||||
|
||||
def taxon_params
|
||||
params.require(:taxon).permit(
|
||||
:name, :parent_id, :position, :icon, :description, :permalink, :taxonomy_id,
|
||||
:name, :position, :icon, :description, :permalink,
|
||||
:meta_description, :meta_keywords, :meta_title, :dfc_id
|
||||
)
|
||||
end
|
||||
|
||||
@@ -26,7 +26,8 @@ module Admin
|
||||
show_enterprise_fees = can?(:manage_enterprise_fees,
|
||||
enterprise) && (is_shop || enterprise.is_primary_producer)
|
||||
show_connected_apps = can?(:manage_connected_apps, enterprise) &&
|
||||
feature?(:connected_apps, spree_current_user, enterprise)
|
||||
feature?(:connected_apps, spree_current_user, enterprise) &&
|
||||
Spree::Config.connected_apps_enabled.present?
|
||||
|
||||
build_enterprise_side_menu_items(
|
||||
is_shop:,
|
||||
@@ -38,6 +39,11 @@ module Admin
|
||||
)
|
||||
end
|
||||
|
||||
def connected_apps_enabled
|
||||
connected_apps_enabled = Spree::Config.connected_apps_enabled&.split(',') || []
|
||||
ConnectedApp::TYPES & connected_apps_enabled
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build_enterprise_side_menu_items(
|
||||
|
||||
@@ -11,21 +11,31 @@ module Admin
|
||||
end
|
||||
|
||||
def prepare_new_variant(product)
|
||||
product.variants.build do |variant|
|
||||
variant.unit_value = 1.0 * (product.variant_unit_scale || 1)
|
||||
variant.unit_presentation = VariantUnits::OptionValueNamer.new(variant).name
|
||||
end
|
||||
product.variants.build
|
||||
end
|
||||
|
||||
def unit_value_with_description(variant)
|
||||
scaled_unit_value = variant.unit_value / (variant.product.variant_unit_scale || 1)
|
||||
precised_unit_value = number_with_precision(
|
||||
scaled_unit_value,
|
||||
precision: nil,
|
||||
strip_insignificant_zeros: true
|
||||
)
|
||||
precised_unit_value = nil
|
||||
|
||||
if variant.unit_value
|
||||
scaled_unit_value = variant.unit_value / (variant.product.variant_unit_scale || 1)
|
||||
precised_unit_value = number_with_precision(
|
||||
scaled_unit_value,
|
||||
precision: nil,
|
||||
strip_insignificant_zeros: true,
|
||||
significant: false,
|
||||
)
|
||||
end
|
||||
|
||||
[precised_unit_value, variant.unit_description].compact_blank.join(" ")
|
||||
end
|
||||
|
||||
def products_return_to_url(url_filters)
|
||||
if feature?(:admin_style_v3, spree_current_user)
|
||||
return session[:products_return_to_url] || admin_products_url
|
||||
end
|
||||
|
||||
"#{admin_products_path}#{url_filters.empty? ? '' : "#?#{url_filters.to_query}"}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
module I18nHelper
|
||||
def locale_options
|
||||
OpenFoodNetwork::I18nConfig.available_locales.map do |locale|
|
||||
OpenFoodNetwork::I18nConfig.selectable_locales.map do |locale|
|
||||
[t('language_name', locale:), locale]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,4 +10,8 @@ module MailerHelper
|
||||
link_to ofn, "https://www.openfoodnetwork.org"
|
||||
end
|
||||
end
|
||||
|
||||
def order_reply_email(order)
|
||||
order.distributor.email_address.presence || order.distributor.contact.email
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module Admin
|
||||
module TaxonsHelper
|
||||
def taxon_path(taxon)
|
||||
taxon.ancestors.reverse.collect(&:name).join( " >> ")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -19,8 +19,8 @@ class ConnectAppJob < ApplicationJob
|
||||
|
||||
selector = "#connected-app-discover-regen.enterprise_#{enterprise.id}"
|
||||
html = ApplicationController.render(
|
||||
partial: "admin/enterprises/form/connected_apps",
|
||||
locals: { enterprise: },
|
||||
partial: "admin/enterprises/form/connected_apps/discover_regen",
|
||||
locals: { enterprise:, connected_app: enterprise.connected_apps.discover_regen.first },
|
||||
)
|
||||
|
||||
cable_ready[channel].morph(selector:, html:).broadcast
|
||||
|
||||
@@ -4,8 +4,34 @@
|
||||
#
|
||||
# Here we store keys and links to access the app.
|
||||
class ConnectedApp < ApplicationRecord
|
||||
TYPES = ['discover_regen', 'affiliate_sales_data'].freeze
|
||||
|
||||
belongs_to :enterprise
|
||||
after_destroy :disconnect
|
||||
|
||||
scope :discover_regen, -> { where(type: "ConnectedApp") }
|
||||
scope :affiliate_sales_data, -> { where(type: "ConnectedApps::AffiliateSalesData") }
|
||||
|
||||
scope :connecting, -> { where(data: nil) }
|
||||
scope :ready, -> { where.not(data: nil) }
|
||||
|
||||
def connecting?
|
||||
data.nil?
|
||||
end
|
||||
|
||||
def ready?
|
||||
!connecting?
|
||||
end
|
||||
|
||||
def connect(api_key:, channel:)
|
||||
ConnectAppJob.perform_later(self, api_key, channel:)
|
||||
end
|
||||
|
||||
def disconnect
|
||||
WebhookDeliveryJob.perform_later(
|
||||
data["destroy"],
|
||||
"disconnect-app",
|
||||
nil
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
13
app/models/connected_apps/affiliate_sales_data.rb
Normal file
13
app/models/connected_apps/affiliate_sales_data.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# An enterprise can opt-in for their data to be included in the affiliate_sales_data endpoint
|
||||
#
|
||||
module ConnectedApps
|
||||
class AffiliateSalesData < ConnectedApp
|
||||
def connect(_opts)
|
||||
update! data: true # not-nil value indicates it is ready
|
||||
end
|
||||
|
||||
def disconnect; end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,7 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
require "mini_magick"
|
||||
|
||||
class Enterprise < ApplicationRecord
|
||||
SELLS = %w(unspecified none own any).freeze
|
||||
ENTERPRISE_SEARCH_RADIUS = 100
|
||||
|
||||
@@ -24,6 +24,7 @@ class OrderCycle < ApplicationRecord
|
||||
where incoming: false
|
||||
}, class_name: "Exchange", dependent: :destroy
|
||||
|
||||
has_many :orders, class_name: 'Spree::Order', dependent: :restrict_with_exception
|
||||
has_many :suppliers, -> { distinct }, source: :sender, through: :cached_incoming_exchanges
|
||||
has_many :distributors, -> { distinct }, source: :receiver, through: :cached_outgoing_exchanges
|
||||
has_many :order_cycle_schedules, dependent: :destroy
|
||||
|
||||
@@ -162,7 +162,7 @@ module ProductImport
|
||||
return
|
||||
end
|
||||
|
||||
product = Spree::Product.new
|
||||
product = Spree::Product.new(supplier_id: entry.enterprise_id)
|
||||
product.assign_attributes(
|
||||
entry.assignable_attributes.except('id', 'on_hand', 'on_demand', 'display_name')
|
||||
)
|
||||
|
||||
@@ -377,7 +377,7 @@ module ProductImport
|
||||
end
|
||||
|
||||
def mark_as_new_product(entry)
|
||||
new_product = Spree::Product.new
|
||||
new_product = Spree::Product.new(supplier_id: entry.enterprise_id)
|
||||
new_product.assign_attributes(
|
||||
entry.assignable_attributes.except('id', 'on_hand', 'on_demand', 'display_name')
|
||||
)
|
||||
|
||||
@@ -39,7 +39,6 @@ module Spree
|
||||
can [:index, :read], StockLocation
|
||||
can [:index, :read], StockMovement
|
||||
can [:index, :read], Taxon
|
||||
can [:index, :read], Taxonomy
|
||||
can [:index, :read], Variant
|
||||
can [:index, :read], Zone
|
||||
end
|
||||
|
||||
@@ -139,5 +139,8 @@ module Spree
|
||||
|
||||
# Available units
|
||||
preference :available_units, :string, default: "g,kg,T,mL,L,kL"
|
||||
|
||||
# Connected Apps
|
||||
preference :connected_apps_enabled, :string, default: nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "mini_magick"
|
||||
|
||||
module Spree
|
||||
class Image < Asset
|
||||
has_one_attached :attachment, service: image_service do |attachment|
|
||||
|
||||
@@ -69,6 +69,7 @@ module Spree
|
||||
attr_accessor :price, :display_as, :unit_value, :unit_description, :tax_category_id,
|
||||
:shipping_category_id, :primary_taxon_id, :supplier_id
|
||||
|
||||
after_validation :validate_variant_attrs, on: :create
|
||||
after_create :ensure_standard_variant
|
||||
after_update :touch_supplier, if: :saved_change_to_primary_taxon_id?
|
||||
around_destroy :destruction
|
||||
@@ -264,6 +265,7 @@ module Spree
|
||||
def variant_unit_with_scale
|
||||
scale_clean = ActiveSupport::NumberHelper.number_to_rounded(variant_unit_scale,
|
||||
precision: nil,
|
||||
significant: false,
|
||||
strip_insignificant_zeros: true)
|
||||
[variant_unit, scale_clean].compact_blank.join("_")
|
||||
end
|
||||
@@ -288,6 +290,21 @@ module Spree
|
||||
|
||||
private
|
||||
|
||||
def validate_variant_attrs
|
||||
# Avoid running validation when we can't set variant attrs
|
||||
# eg clone product. Will raise error if clonning a product with no variant
|
||||
return if variants.first&.valid?
|
||||
|
||||
unless Spree::Taxon.find_by(id: primary_taxon_id)
|
||||
errors.add(:primary_taxon_id,
|
||||
I18n.t('activerecord.errors.models.spree/product.must_exist'))
|
||||
end
|
||||
return if Enterprise.find_by(id: supplier_id)
|
||||
|
||||
errors.add(:supplier_id,
|
||||
I18n.t('activerecord.errors.models.spree/product.must_exist'))
|
||||
end
|
||||
|
||||
def update_units
|
||||
return unless saved_change_to_variant_unit? || saved_change_to_variant_unit_name?
|
||||
|
||||
|
||||
@@ -2,19 +2,11 @@
|
||||
|
||||
module Spree
|
||||
class Taxon < ApplicationRecord
|
||||
self.belongs_to_required_by_default = false
|
||||
|
||||
acts_as_nested_set dependent: :destroy
|
||||
|
||||
belongs_to :taxonomy, class_name: 'Spree::Taxonomy', touch: true
|
||||
|
||||
has_many :variants, class_name: "Spree::Variant", foreign_key: "primary_taxon_id",
|
||||
inverse_of: :primary_taxon, dependent: :restrict_with_error
|
||||
|
||||
has_many :products, through: :variants, dependent: nil
|
||||
|
||||
before_create :set_permalink
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
# Indicate which filters should be used for this taxon
|
||||
@@ -31,26 +23,6 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
def set_permalink
|
||||
if parent.present?
|
||||
self.permalink = [parent.permalink, permalink_end].join('/')
|
||||
elsif permalink.blank?
|
||||
self.permalink = UrlGenerator.to_url(name)
|
||||
end
|
||||
end
|
||||
|
||||
# For #2759
|
||||
def to_param
|
||||
permalink
|
||||
end
|
||||
|
||||
def pretty_name
|
||||
ancestor_chain = ancestors.inject("") do |name, ancestor|
|
||||
name + "#{ancestor.name} -> "
|
||||
end
|
||||
ancestor_chain + name.to_s
|
||||
end
|
||||
|
||||
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.supplied_taxons
|
||||
@@ -90,13 +62,5 @@ module Spree
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def permalink_end
|
||||
return UrlGenerator.to_url(name) if permalink.blank?
|
||||
|
||||
permalink.split('/').last
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Taxonomy < ApplicationRecord
|
||||
validates :name, presence: true
|
||||
|
||||
has_many :taxons, dependent: :nullify
|
||||
has_one :root, -> { where parent_id: nil }, class_name: "Spree::Taxon", dependent: :destroy
|
||||
|
||||
after_save :set_name
|
||||
|
||||
default_scope -> { order("#{table_name}.position") }
|
||||
|
||||
private
|
||||
|
||||
def set_name
|
||||
if root
|
||||
root.update_columns(
|
||||
name:,
|
||||
updated_at: Time.zone.now
|
||||
)
|
||||
else
|
||||
self.root = Taxon.create!(taxonomy_id: id, name:)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -156,6 +156,12 @@ module Spree
|
||||
self.disabled_at = value == '1' ? Time.zone.now : nil
|
||||
end
|
||||
|
||||
def affiliate_enterprises
|
||||
return [] unless Flipper.enabled?(:affiliate_sales_data, self)
|
||||
|
||||
Enterprise.joins(:connected_apps).merge(ConnectedApps::AffiliateSalesData.ready)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def password_required?
|
||||
|
||||
@@ -87,7 +87,6 @@ module Spree
|
||||
before_validation :ensure_unit_value
|
||||
before_validation :update_weight_from_unit_value, if: ->(v) { v.product.present? }
|
||||
before_validation :convert_variant_weight_to_decimal
|
||||
before_validation :assign_related_taxon, if: ->(v) { v.primary_taxon.blank? }
|
||||
|
||||
before_save :assign_units, if: ->(variant) {
|
||||
variant.new_record? || variant.changed_attributes.keys.intersection(NAME_FIELDS).any?
|
||||
@@ -217,10 +216,6 @@ module Spree
|
||||
|
||||
private
|
||||
|
||||
def assign_related_taxon
|
||||
self.primary_taxon ||= product.variants.last&.primary_taxon
|
||||
end
|
||||
|
||||
def check_currency
|
||||
return unless currency.nil?
|
||||
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ProductsReflex < ApplicationReflex
|
||||
include Pagy::Backend
|
||||
|
||||
before_reflex :init_filters_params, :init_pagination_params
|
||||
|
||||
def change_per_page
|
||||
@per_page = element.value.to_i
|
||||
@page = 1
|
||||
|
||||
fetch_and_render_products_with_flash
|
||||
end
|
||||
|
||||
def clear_search
|
||||
@search_term = nil
|
||||
@producer_id = nil
|
||||
@category_id = nil
|
||||
@page = 1
|
||||
|
||||
fetch_and_render_products_with_flash
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def init_filters_params
|
||||
# params comes from the form
|
||||
# _params comes from the url
|
||||
# priority is given to params from the form (if present) over url params
|
||||
@search_term = params[:search_term] || params[:_search_term]
|
||||
@producer_id = params[:producer_id] || params[:_producer_id]
|
||||
@category_id = params[:category_id] || params[:_category_id]
|
||||
end
|
||||
|
||||
def init_pagination_params
|
||||
# prority is given to element dataset (if present) over url params
|
||||
@page = element.dataset.page || params[:_page] || 1
|
||||
@per_page = element.dataset.perpage || params[:_per_page] || 15
|
||||
end
|
||||
|
||||
def fetch_and_render_products_with_flash
|
||||
fetch_products
|
||||
render_products
|
||||
end
|
||||
|
||||
def render_products
|
||||
cable_ready.replace(
|
||||
selector: "#products-content",
|
||||
html: render(partial: "admin/products_v3/content",
|
||||
locals: { products: @products, pagy: @pagy, search_term: @search_term,
|
||||
producer_options: producers, producer_id: @producer_id,
|
||||
category_options: categories, tax_category_options:,
|
||||
category_id: @category_id, flashes: flash })
|
||||
)
|
||||
|
||||
cable_ready.replace_state(
|
||||
url: current_url,
|
||||
)
|
||||
|
||||
morph :nothing
|
||||
end
|
||||
|
||||
def render_products_form_with_flash
|
||||
locals = { products: @products }
|
||||
locals[:error_counts] = @error_counts if @error_counts.present?
|
||||
locals[:flashes] = flash if flash.any?
|
||||
|
||||
cable_ready.replace(
|
||||
selector: "#products-form",
|
||||
html: render(partial: "admin/products_v3/table", locals:)
|
||||
)
|
||||
morph :nothing
|
||||
|
||||
# dunno why this doesn't work. The HTML stops after the first `<col>` element, wtf?!
|
||||
# morph "#products-form", render(partial: "admin/products_v3/table", locals:)
|
||||
end
|
||||
|
||||
def producers
|
||||
producers = OpenFoodNetwork::Permissions.new(current_user)
|
||||
.managed_product_enterprises.is_primary_producer.by_name
|
||||
producers.map { |p| [p.name, p.id] }
|
||||
end
|
||||
|
||||
def categories
|
||||
Spree::Taxon.order(:name).map { |c| [c.name, c.id] }
|
||||
end
|
||||
|
||||
def tax_category_options
|
||||
Spree::TaxCategory.order(:name).pluck(:name, :id)
|
||||
end
|
||||
|
||||
def fetch_products
|
||||
product_query = OpenFoodNetwork::Permissions.new(current_user)
|
||||
.editable_products.merge(product_scope).ransack(ransack_query).result(distinct: true)
|
||||
@pagy, @products = pagy(product_query.order(:name), items: @per_page, page: @page,
|
||||
size: [1, 2, 2, 1])
|
||||
end
|
||||
|
||||
def product_scope
|
||||
scope = if current_user.has_spree_role?("admin") || current_user.enterprises.present?
|
||||
Spree::Product
|
||||
else
|
||||
Spree::Product.active
|
||||
end
|
||||
|
||||
scope.includes(product_query_includes)
|
||||
end
|
||||
|
||||
def ransack_query
|
||||
query = {}
|
||||
query.merge!(variants_supplier_id_in: @producer_id) if @producer_id.present?
|
||||
if @search_term.present?
|
||||
query.merge!(Spree::Variant::SEARCH_KEY => @search_term)
|
||||
end
|
||||
query.merge!(variants_primary_taxon_id_in: @category_id) if @category_id.present?
|
||||
query
|
||||
end
|
||||
|
||||
# Optimise by pre-loading required columns
|
||||
def product_query_includes
|
||||
# TODO: add other fields used in columns? (eg supplier: [:name])
|
||||
[
|
||||
# variants: [
|
||||
# :default_price,
|
||||
# :stock_locations,
|
||||
# :stock_items,
|
||||
# :variant_overrides
|
||||
# ]
|
||||
]
|
||||
end
|
||||
|
||||
def current_url
|
||||
url = URI(request.original_url)
|
||||
url.query = url.query.present? ? "#{url.query}&" : ""
|
||||
# add params with _ to avoid conflicts with params from the form
|
||||
url.query += "_page=#{@page}"
|
||||
url.query += "&_per_page=#{@per_page}"
|
||||
url.query += "&_search_term=#{@search_term}" if @search_term.present?
|
||||
url.query += "&_producer_id=#{@producer_id}" if @producer_id.present?
|
||||
url.query += "&_category_id=#{@category_id}" if @category_id.present?
|
||||
url.to_s
|
||||
end
|
||||
|
||||
# Similar to spree/admin/products_controller
|
||||
def product_set_from_params
|
||||
# Form field names:
|
||||
# '[products][0][id]' (hidden field)
|
||||
# '[products][0][name]'
|
||||
# '[products][0][variants_attributes][0][id]' (hidden field)
|
||||
# '[products][0][variants_attributes][0][display_name]'
|
||||
#
|
||||
# Resulting in params:
|
||||
# "products" => {
|
||||
# "0" => {
|
||||
# "id" => "123"
|
||||
# "name" => "Pommes",
|
||||
# "variants_attributes" => {
|
||||
# "0" => {
|
||||
# "id" => "1234",
|
||||
# "display_name" => "Large box",
|
||||
# }
|
||||
# }
|
||||
# }
|
||||
collection_hash = products_bulk_params[:products]
|
||||
.transform_values { |product|
|
||||
# Convert variants_attributes form hash to an array if present
|
||||
product[:variants_attributes] &&= product[:variants_attributes].values
|
||||
product
|
||||
}.with_indifferent_access
|
||||
Sets::ProductSet.new(collection_attributes: collection_hash)
|
||||
end
|
||||
|
||||
def products_bulk_params
|
||||
params.permit(products: ::PermittedAttributes::Product.attributes)
|
||||
.to_h.with_indifferent_access
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,7 @@
|
||||
module Api
|
||||
module Admin
|
||||
class TaxonSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :pretty_name
|
||||
attributes :id, :name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,5 +4,5 @@ class Api::TaxonSerializer < ActiveModel::Serializer
|
||||
cached
|
||||
delegate :cache_key, to: :object
|
||||
|
||||
attributes :id, :name, :permalink, :pretty_name, :position, :parent_id, :taxonomy_id
|
||||
attributes :id, :name, :permalink, :position
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ module OrderCycles
|
||||
end
|
||||
|
||||
def products_relation_incl_supplier_properties
|
||||
query = relation_by_sorting(supplier_properties: true)
|
||||
query = relation_by_sorting
|
||||
|
||||
query = supplier_property_join(query)
|
||||
|
||||
@@ -34,10 +34,10 @@ module OrderCycles
|
||||
|
||||
attr_reader :distributor, :order_cycle, :customer
|
||||
|
||||
def relation_by_sorting(supplier_properties: false)
|
||||
def relation_by_sorting
|
||||
query = Spree::Product.where(id: stocked_products)
|
||||
|
||||
if sorting == "by_producer" || supplier_properties
|
||||
if sorting == "by_producer"
|
||||
# Joins on the first product variant to allow us to filter product by supplier. This is so
|
||||
# enterprise can display product sorted by supplier in a custom order on their shopfront.
|
||||
#
|
||||
@@ -57,7 +57,8 @@ module OrderCycles
|
||||
# different category for a given product.
|
||||
query.
|
||||
joins("LEFT JOIN (
|
||||
SELECT DISTINCT ON(product_id) id, product_id, primary_taxon_id
|
||||
SELECT DISTINCT ON(product_id) id, product_id, primary_taxon_id,
|
||||
supplier_id
|
||||
FROM spree_variants WHERE deleted_at IS NULL
|
||||
) first_variant ON spree_products.id = first_variant.product_id").
|
||||
select("spree_products.*, first_variant.primary_taxon_id").
|
||||
@@ -71,6 +72,16 @@ module OrderCycles
|
||||
distributor.preferred_shopfront_product_sorting_method
|
||||
end
|
||||
|
||||
def sorting_by_producer?
|
||||
sorting == "by_producer" &&
|
||||
distributor.preferred_shopfront_producer_order.present?
|
||||
end
|
||||
|
||||
def sorting_by_category?
|
||||
sorting == "by_category" &&
|
||||
distributor.preferred_shopfront_taxon_order.present?
|
||||
end
|
||||
|
||||
def supplier_property_join(query)
|
||||
query.joins("
|
||||
JOIN enterprises ON enterprises.id = first_variant.supplier_id
|
||||
@@ -79,16 +90,14 @@ module OrderCycles
|
||||
end
|
||||
|
||||
def order
|
||||
if distributor.preferred_shopfront_product_sorting_method == "by_producer" &&
|
||||
distributor.preferred_shopfront_producer_order.present?
|
||||
if sorting_by_producer?
|
||||
order_by_producer = distributor
|
||||
.preferred_shopfront_producer_order
|
||||
.split(",").map { |id| "first_variant.supplier_id=#{id} DESC" }
|
||||
.join(", ")
|
||||
|
||||
"#{order_by_producer}, spree_products.name ASC, spree_products.id ASC"
|
||||
elsif distributor.preferred_shopfront_product_sorting_method == "by_category" &&
|
||||
distributor.preferred_shopfront_taxon_order.present?
|
||||
elsif sorting_by_category?
|
||||
order_by_category = distributor
|
||||
.preferred_shopfront_taxon_order
|
||||
.split(",").map { |id| "first_variant.primary_taxon_id=#{id} DESC" }
|
||||
|
||||
@@ -19,5 +19,7 @@ class ShopsListService
|
||||
.includes(address: [:state, :country])
|
||||
.includes(:properties)
|
||||
.includes(supplied_products: :properties)
|
||||
.with_attached_promo_image
|
||||
.with_attached_logo
|
||||
end
|
||||
end
|
||||
|
||||
25
app/views/admin/connected_app_settings/edit.html.haml
Normal file
25
app/views/admin/connected_app_settings/edit.html.haml
Normal file
@@ -0,0 +1,25 @@
|
||||
= render :partial => 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t('.title')
|
||||
|
||||
= form_tag main_app.admin_connected_app_settings_path, :method => :put do
|
||||
|
||||
%fieldset
|
||||
%legend= t('.enabled_legend')
|
||||
|
||||
= t('.info_html')
|
||||
|
||||
.field
|
||||
-# Blank value in case nothing is selected
|
||||
= hidden_field_tag("preferences[connected_apps_enabled][]", "")
|
||||
|
||||
- ConnectedApp::TYPES.each do |type|
|
||||
%label
|
||||
= check_box_tag("preferences[connected_apps_enabled][]", type,
|
||||
Spree::Config.connected_apps_enabled&.split(',')&.include?(type))
|
||||
= t('.connected_apps_enabled.' + type)
|
||||
%br
|
||||
|
||||
.form-buttons
|
||||
= button t(:update), 'icon-refresh'
|
||||
@@ -1,30 +1,3 @@
|
||||
%div{ id: "connected-app-discover-regen", class: "enterprise_#{enterprise.id}" }
|
||||
.connected-app__head
|
||||
%div
|
||||
%h3= t ".title"
|
||||
%p= t ".tagline"
|
||||
%div
|
||||
- if enterprise.connected_apps.empty?
|
||||
= button_to t(".enable"), admin_enterprise_connected_apps_path(enterprise.id), method: :post, disabled: !managed_by_user?(enterprise)
|
||||
-# This is only seen by super-admins:
|
||||
%em= t(".need_to_be_manager") unless managed_by_user?(enterprise)
|
||||
- elsif enterprise.connected_apps.connecting.present?
|
||||
%button{ disabled: true }
|
||||
%i.spinner.fa.fa-spin.fa-circle-o-notch
|
||||
|
||||
= t ".loading"
|
||||
- else
|
||||
= button_to t(".disable"), admin_enterprise_connected_app_path(0, enterprise_id: enterprise.id), method: :delete
|
||||
|
||||
.connected-app__connection
|
||||
- if enterprise.connected_apps.ready.present?
|
||||
.connected-app__note
|
||||
- link = enterprise.connected_apps[0].data["link"]
|
||||
%p= t ".note"
|
||||
%div
|
||||
%a{ href: link, target: "_blank", class: "button secondary" }
|
||||
= t ".link_label"
|
||||
|
||||
%hr
|
||||
.connected-app__description
|
||||
= t ".description_html"
|
||||
- connected_apps_enabled.each do |type|
|
||||
= render partial: "/admin/enterprises/form/connected_apps/#{type}",
|
||||
locals: { enterprise:, connected_app: enterprise.connected_apps.public_send(type).first }
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
%section.connected_app
|
||||
.connected-app__head
|
||||
%div
|
||||
%h3= t ".title"
|
||||
%p= t ".tagline"
|
||||
%div
|
||||
- if connected_app.nil?
|
||||
= button_to t(".enable"), admin_enterprise_connected_apps_path(enterprise.id, type: "ConnectedApps::AffiliateSalesData"), method: :post, disabled: !managed_by_user?(enterprise)
|
||||
-# This is only seen by super-admins:
|
||||
%em= t(".need_to_be_manager") unless managed_by_user?(enterprise)
|
||||
- else
|
||||
= button_to t(".disable"), admin_enterprise_connected_app_path(connected_app.id, enterprise_id: enterprise.id), method: :delete
|
||||
%hr
|
||||
.connected-app__description
|
||||
= t ".description_html"
|
||||
@@ -0,0 +1,30 @@
|
||||
%section.connected_app{ id: "connected-app-discover-regen", class: "enterprise_#{enterprise.id}" }
|
||||
.connected-app__head
|
||||
%div
|
||||
%h3= t ".title"
|
||||
%p= t ".tagline"
|
||||
%div
|
||||
- if connected_app.nil?
|
||||
= button_to t(".enable"), admin_enterprise_connected_apps_path(enterprise.id), method: :post, disabled: !managed_by_user?(enterprise)
|
||||
-# This is only seen by super-admins:
|
||||
%em= t(".need_to_be_manager") unless managed_by_user?(enterprise)
|
||||
- elsif connected_app&.connecting?
|
||||
%button{ disabled: true }
|
||||
%i.spinner.fa.fa-spin.fa-circle-o-notch
|
||||
|
||||
= t ".loading"
|
||||
- else
|
||||
= button_to t(".disable"), admin_enterprise_connected_app_path(connected_app.id, enterprise_id: enterprise.id), method: :delete
|
||||
|
||||
.connected-app__connection
|
||||
- if connected_app&.ready?
|
||||
.connected-app__note
|
||||
- link = connected_app.data["link"]
|
||||
%p= t ".note"
|
||||
%div
|
||||
%a{ href: link, target: "_blank", class: "button secondary" }
|
||||
= t ".link_label"
|
||||
|
||||
%hr
|
||||
.connected-app__description
|
||||
= t ".description_html"
|
||||
@@ -0,0 +1,14 @@
|
||||
.flex-column-gap-1
|
||||
%h6
|
||||
= t('.title')
|
||||
%div{ style: 'font-size: 1rem;' }
|
||||
= t('.content')
|
||||
%p.modal-actions.justify-end.gap-1
|
||||
%button.button.secondary{ "ng-click": "submit($event, null)", type: "button", style: "display: none;", data: { action: 'click->modal#close', 'trigger-action': 'save' } }
|
||||
= t('.proceed')
|
||||
%button.button.secondary{ "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", type: "button", style: "display: none;", data: { action: 'click->modal#close', 'trigger-action': 'saveAndNext' } }
|
||||
= t('.proceed')
|
||||
%button.button.secondary{ "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')", type: "button", style: "display: none;", data: { action: 'click->modal#close', 'trigger-action': 'saveAndBack' } }
|
||||
= t('.proceed')
|
||||
%button.button.primary{ type: "button", 'data-action': 'click->modal#close' }
|
||||
= t('.cancel')
|
||||
@@ -16,18 +16,25 @@
|
||||
|
||||
- ng_controller = @order_cycle.simple? ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl'
|
||||
= admin_inject_order_cycle_instance(@order_cycle)
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f|
|
||||
%div{ data: { controller: 'order-cycle-form' } }
|
||||
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f|
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input.red{ type: "button", value: t('.save'), "ng-click": "submit($event, null)", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { confirm: "true", 'trigger-action': 'save' } }
|
||||
- if @order_cycle.simple?
|
||||
%input.red{ type: "button", value: t('.save_and_back_to_list'), "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { confirm: "true", 'trigger-action': 'saveAndBack' } }
|
||||
- else
|
||||
%input.red{ type: "button", value: t('.save_and_next'), "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid", data: { confirm: "true", 'trigger-action': 'saveAndNext' } }
|
||||
%input{ type: "button", value: t('.next'), "ng-click": "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "order_cycle_form.$dirty" }
|
||||
%input{ type: "button", "ng-value": "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", "ng-click": "cancel('#{main_app.admin_order_cycles_path}')" }
|
||||
|
||||
%save-bar{ dirty: "order_cycle_form.$dirty", persist: "true" }
|
||||
%input.red{ type: "button", value: t('.save'), "ng-click": "submit($event, null)", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
|
||||
- if @order_cycle.simple?
|
||||
%input.red{ type: "button", value: t('.save_and_back_to_list'), "ng-click": "submit($event, '#{main_app.admin_order_cycles_path}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
|
||||
= render 'simple_form', f: f
|
||||
- else
|
||||
%input.red{ type: "button", value: t('.save_and_next'), "ng-click": "submit($event, '#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "!order_cycle_form.$dirty || order_cycle_form.$invalid" }
|
||||
%input{ type: "button", value: t('.next'), "ng-click": "cancel('#{main_app.admin_order_cycle_incoming_path(@order_cycle)}')", "ng-disabled": "order_cycle_form.$dirty" }
|
||||
%input{ type: "button", "ng-value": "order_cycle_form.$dirty ? '#{t('.cancel')}' : '#{t('.back_to_list')}'", "ng-click": "cancel('#{main_app.admin_order_cycles_path}')" }
|
||||
= render 'form', f: f
|
||||
|
||||
- if @order_cycle.simple?
|
||||
= render 'simple_form', f: f
|
||||
- else
|
||||
= render 'form', f: f
|
||||
%div.warning-modal{ data: { controller: 'modal modal-link', 'modal-link-target-value': "linked-order-warning-modal" } }
|
||||
%button.modal-target-trigger{ type: 'button', data: { 'action': 'modal-link#open' }, style: 'display: none;' }
|
||||
= render ModalComponent.new(id: "linked-order-warning-modal", close_button: false) do
|
||||
.content.flex-column.gap-2
|
||||
= render 'date_time_warning_modal_content'
|
||||
@@ -1,6 +1,6 @@
|
||||
= form_with url: admin_products_path, id: "filters", method: :get, data: { "search-target": "form", 'turbo-frame': "_self" } do
|
||||
= form_with url: admin_products_path, id: "filters", method: :get, data: { "search-target": "form", 'turbo-frame': "_self", 'turbo-action': "advance" } do
|
||||
= hidden_field_tag :page, nil, class: "page"
|
||||
= hidden_field_tag :per_page, nil, class: "per-page"
|
||||
= hidden_field_tag :per_page, params[:per_page], class: "per-page"
|
||||
= hidden_field_tag '[q][s]', params.dig(:q, :s) || 'name asc', class: 'sort', 'data-default': 'name asc'
|
||||
|
||||
.query
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
- if search_term.present? || producer_id.present? || category_id.present?
|
||||
= t('.no_products_found_for_search')
|
||||
%a{ href: "#", class: "button disruptive relaxed", data: { reflex: "click->products#clear_search" } }
|
||||
%a{ href: admin_products_path, class: "button disruptive relaxed", 'data-turbo-frame': "_self" }
|
||||
= t("admin.products_v3.sort.pagination.clear_search")
|
||||
- else
|
||||
= t('.no_products_found')
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
= t(".pagination.total_html", total: pagy.count, from: pagy.from, to: pagy.to)
|
||||
|
||||
- if search_term.present? || producer_id.present? || category_id.present?
|
||||
%a{ href: url_for(page: 1), class: "button disruptive", 'data-turbo-frame': "_self" }
|
||||
%a{ href: url_for(page: 1), class: "button disruptive", data: { 'turbo-frame': "_self", 'turbo-action': "advance" } }
|
||||
= t(".pagination.clear_search")
|
||||
|
||||
%form.with-dropdown
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
= f.hidden_field :unit_value
|
||||
= f.hidden_field :unit_description
|
||||
= f.text_field :unit_value_with_description,
|
||||
value: unit_value_with_description(variant), 'aria-label': t('admin.products_page.columns.unit_value'), required: true
|
||||
value: unit_value_with_description(variant), 'aria-label': t('admin.products_page.columns.unit_value')
|
||||
.field
|
||||
= f.label :display_as, t('admin.products_page.columns.display_as')
|
||||
= f.text_field :display_as, placeholder: VariantUnits::OptionValueNamer.new(variant).name
|
||||
@@ -37,20 +37,24 @@
|
||||
= f.label :on_demand do
|
||||
= f.check_box :on_demand, 'data-action': 'change->toggle-control#disableIfPresent change->popout#closeIfChecked'
|
||||
= t(:on_demand)
|
||||
%td.col-producer.naked_inputs
|
||||
%td.col-producer.field.naked_inputs
|
||||
= render(SearchableDropdownComponent.new(form: f,
|
||||
name: :supplier_id,
|
||||
aria_label: t('.producer_field_name'),
|
||||
options: producer_options,
|
||||
selected_option: variant.supplier_id,
|
||||
placeholder_value: t('admin.products_v3.filters.search_for_producers')))
|
||||
include_blank: t('admin.products_v3.filters.select_producer'),
|
||||
placeholder_value: t('admin.products_v3.filters.select_producer')))
|
||||
= error_message_on variant, :supplier
|
||||
%td.col-category.field.naked_inputs
|
||||
= render(SearchableDropdownComponent.new(form: f,
|
||||
name: :primary_taxon_id,
|
||||
options: category_options,
|
||||
selected_option: variant.primary_taxon_id,
|
||||
aria_label: t('.category_field_name'),
|
||||
placeholder_value: t('admin.products_v3.filters.search_for_categories')))
|
||||
include_blank: t('admin.products_v3.filters.select_category'),
|
||||
placeholder_value: t('admin.products_v3.filters.select_category')))
|
||||
= error_message_on variant, :primary_taxon
|
||||
%td.col-tax_category.field.naked_inputs
|
||||
= render(SearchableDropdownComponent.new(form: f,
|
||||
name: :tax_category_id,
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
%tr
|
||||
%th{:align => "left"}
|
||||
%h5= t(:invoice_column_item)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%th{:align => "right", :width => "6%" }
|
||||
%h5= t(:invoice_column_qty)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%h5= t(:invoice_column_weight_volume)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%h5= t(:invoice_column_price_per_unit_without_taxes)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%th{:align => "right", :width => "12%"}
|
||||
%h5= t(:invoice_column_price_without_taxes)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%th{:align => "right", :width => "9%" }
|
||||
%h5= t(:invoice_column_tax_rate)
|
||||
%th{:align => "right", :width => "15%"}
|
||||
%th{:align => "right", :width => "12%" }
|
||||
%h5= t(:invoice_column_price_with_taxes)
|
||||
%tbody
|
||||
- @order.sorted_line_items.each do |item|
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
= admin_inject_available_units
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to t('admin.products.back_to_products_list'), "#{admin_products_path}#{(@url_filters.empty? ? "" : "#?#{@url_filters.to_query}")}", :icon => 'icon-arrow-left'
|
||||
%li= button_link_to t('admin.products.back_to_products_list'), products_return_to_url(@url_filters), :icon => 'icon-arrow-left'
|
||||
%li#new_product_link
|
||||
= button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' }
|
||||
|
||||
@@ -16,4 +16,4 @@
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t(:update), 'icon-refresh'
|
||||
|
||||
= button_link_to t(:cancel), "#{collection_url}#{(@url_filters.empty? ? "" : "#?#{@url_filters.to_query}")}", icon: 'icon-remove'
|
||||
= button_link_to t(:cancel), products_return_to_url(@url_filters), icon: 'icon-remove'
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
= f.label :supplier, t(".supplier")
|
||||
%span.required *
|
||||
= f.select :supplier_id, options_from_collection_for_select(@producers, :id, :name, @product.supplier_id), { include_blank: t("spree.admin.products.new.supplier_select_placeholder") }, { "data-controller": "tom-select", class: "primary" }
|
||||
= f.error_message_on :supplier
|
||||
= f.error_message_on :supplier_id
|
||||
.eight.columns.omega
|
||||
= f.field_container :name do
|
||||
= f.label :name, t(".product_name")
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
- if DefaultCountry.id
|
||||
= configurations_sidebar_menu_item Spree.t(:states), admin_country_states_path(DefaultCountry.id)
|
||||
= configurations_sidebar_menu_item Spree.t(:payment_methods), admin_payment_methods_path
|
||||
= configurations_sidebar_menu_item Spree.t(:taxonomies), admin_taxonomies_path
|
||||
= configurations_sidebar_menu_item Spree.t(:taxons), admin_taxons_path
|
||||
= configurations_sidebar_menu_item Spree.t(:shipping_methods), admin_shipping_methods_path
|
||||
= configurations_sidebar_menu_item Spree.t(:shipping_categories), admin_shipping_categories_path
|
||||
= configurations_sidebar_menu_item t(:enterprise_fees), main_app.admin_enterprise_fees_path
|
||||
@@ -23,3 +23,4 @@
|
||||
= configurations_sidebar_menu_item t('admin.invoice_settings.edit.title'), main_app.edit_admin_invoice_settings_path
|
||||
= configurations_sidebar_menu_item t('admin.matomo_settings.edit.title'), main_app.edit_admin_matomo_settings_path
|
||||
= configurations_sidebar_menu_item t('admin.stripe_connect_settings.edit.title'), main_app.edit_admin_stripe_connect_settings_path
|
||||
= configurations_sidebar_menu_item t('admin.connected_app_settings.edit.title'), main_app.edit_admin_connected_app_settings_path
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
%meta{:content => "text/html; charset=UTF-8", "http-equiv" => "Content-Type"}
|
||||
%meta{ name: "turbo-cache-control", content: "no-cache" }
|
||||
|
||||
= csrf_meta_tags
|
||||
= action_cable_meta_tag
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
= tab :order_cycles, url: main_app.admin_order_cycles_path, icon: 'icon-refresh'
|
||||
= tab :orders, :subscriptions, :customer_details, :adjustments, :payments, :return_authorizations, url: admin_orders_path, icon: 'icon-shopping-cart'
|
||||
= tab :reports, url: main_app.admin_reports_path, icon: 'icon-file'
|
||||
= tab :general_settings, :terms_of_service_files, :mail_methods, :tax_categories, :tax_rates, :tax_settings, :zones, :countries, :states, :payment_methods, :taxonomies, :shipping_methods, :shipping_categories, :enterprise_fees, :contents, :invoice_settings, :matomo_settings, :stripe_connect_settings, label: 'configuration', icon: 'icon-wrench', url: edit_admin_general_settings_path
|
||||
= tab :general_settings, :terms_of_service_files, :mail_methods, :tax_categories, :tax_rates, :tax_settings, :zones, :countries, :states, :payment_methods, :taxons, :shipping_methods, :shipping_categories, :enterprise_fees, :contents, :invoice_settings, :matomo_settings, :stripe_connect_settings, :connected_app_settings, label: 'configuration', icon: 'icon-wrench', url: edit_admin_general_settings_path
|
||||
= tab :enterprises, :enterprise_relationships, :vouchers, :oidc_settings, url: main_app.admin_enterprises_path
|
||||
= tab :customers, url: main_app.admin_customers_path
|
||||
= tab :enterprise_groups, url: main_app.admin_enterprise_groups_path, label: 'groups'
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
.field.align-center
|
||||
= f.field_container :name do
|
||||
= f.label :name, t("spree.name")
|
||||
%span.required *
|
||||
%br/
|
||||
= error_message_on :taxonomy, :name
|
||||
= text_field :taxonomy, :name
|
||||
@@ -1,13 +0,0 @@
|
||||
<% content_for :head do %>
|
||||
<%= javascript_tag "var taxonomy_id = #{@taxonomy.id};
|
||||
var loading = '#{escape_javascript t("spree.loading")}';
|
||||
var new_taxon = '#{escape_javascript t("spree.new_taxon")}';
|
||||
var server_error = '#{escape_javascript t("spree.server_error")}';
|
||||
var taxonomy_tree_error = '#{escape_javascript t("spree.taxonomy_tree_error")}';
|
||||
|
||||
$(document).ready(function(){
|
||||
setup_taxonomy_tree(taxonomy_id);
|
||||
});
|
||||
"
|
||||
%>
|
||||
<% end %>
|
||||
@@ -1,19 +0,0 @@
|
||||
%table#listing_taxonomies.index.sortable{"data-sortable-link" => update_positions_admin_taxonomies_url}
|
||||
%colgroup
|
||||
%col{style: "width: 85%"}/
|
||||
%col{style: "width: 15%"}/
|
||||
%thead
|
||||
%tr
|
||||
%th= t("spree.name")
|
||||
%th.actions
|
||||
%tbody
|
||||
- @taxonomies.each do |taxonomy|
|
||||
- tr_class = cycle('odd', 'even')
|
||||
- tr_id = spree_dom_id(taxonomy)
|
||||
%tr{class: tr_class, id: tr_id}
|
||||
%td
|
||||
%span.handle
|
||||
= taxonomy.name
|
||||
%td.actions
|
||||
= link_to_edit taxonomy.id, no_text: true
|
||||
= link_to_delete taxonomy, no_text: true
|
||||
@@ -1,7 +0,0 @@
|
||||
- if taxon.children.length != 0
|
||||
%ul
|
||||
- taxon.children.each do |child|
|
||||
%li{id: "#{child.id}", rel: "taxon"}
|
||||
%a{href: "#"}= child.name
|
||||
- if child.children.length > 0
|
||||
= render partial: 'taxon', locals: { taxon: child }
|
||||
@@ -1,27 +0,0 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
= render partial: 'js_head'
|
||||
|
||||
- content_for :page_title do
|
||||
= t("spree.taxonomy_edit")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t("spree.back_to_taxonomies_list"), spree.admin_taxonomies_path, icon: 'icon-arrow-left'
|
||||
|
||||
#ajax_error.errorExplanation{style: "display:none;"}
|
||||
= form_for [:admin, @taxonomy] do |f|
|
||||
%fieldset.no-border-top
|
||||
= render partial: 'form', locals: { f: f }
|
||||
%div
|
||||
= label_tag nil, t("spree.tree")
|
||||
%br/
|
||||
:javascript
|
||||
Spree.routes.taxonomy_taxons = "#{main_app.api_v0_taxonomy_taxons_url(@taxonomy)}";
|
||||
Spree.routes.admin_taxonomy_taxons = "#{spree.admin_taxonomy_taxons_url(@taxonomy)}";
|
||||
#taxonomy_tree.tree
|
||||
.info= t("spree.taxonomy_tree_instruction")
|
||||
%br/
|
||||
.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
= button_link_to t('spree.actions.cancel'), admin_taxonomies_path, icon: 'icon-remove'
|
||||
@@ -1,11 +0,0 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t("spree.taxonomies")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t("spree.new_taxonomy"), spree.new_admin_taxonomy_url, icon: 'icon-plus', id: 'admin_new_taxonomy_link'
|
||||
|
||||
#list-taxonomies
|
||||
= render partial: 'list'
|
||||
@@ -1,15 +0,0 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t("spree.new_taxonomy")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t("spree.back_to_taxonomies_list"), spree.admin_taxonomies_path, icon: 'icon-arrow-left'
|
||||
|
||||
= form_for [:admin, @taxonomy] do |f|
|
||||
= render partial: 'form', locals: { f: f }
|
||||
%fieldset.no-border-top
|
||||
%br/
|
||||
.filter-actions.actions
|
||||
= button t("spree.create"), 'icon-ok'
|
||||
@@ -6,12 +6,6 @@
|
||||
%br/
|
||||
= error_message_on :taxon, :name
|
||||
= text_field :taxon, :name, class: 'fullwidth'
|
||||
= f.field_container :permalink_part do
|
||||
= f.label :permalink_part, t(".permalink")
|
||||
%span.required *
|
||||
%br/
|
||||
= @taxon.permalink.split("/")[0...-1].join("/") + "/"
|
||||
= text_field_tag :permalink_part, @permalink_part
|
||||
= f.field_container :meta_title do
|
||||
= f.label :meta_title, t(".meta_title")
|
||||
%br/
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
- unless flash[:error]
|
||||
= turbo_stream.remove(spree_dom_id(@taxon))
|
||||
= turbo_stream.append "flashes" do
|
||||
= render(partial: 'admin/shared/flashes', locals: { flashes: flash })
|
||||
@@ -1,16 +1,16 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t("spree.taxonomy_edit")
|
||||
= t(".title")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t("spree.back_to_taxonomies_list"), spree.admin_taxonomies_path, icon: 'icon-arrow-left'
|
||||
= button_link_to t("spree.admin.taxons.back_to_list"), admin_taxons_path, icon: 'icon-arrow-left'
|
||||
|
||||
- # Because otherwise the form would attempt to use to_param of @taxon
|
||||
- form_url = admin_taxonomy_taxon_path(@taxonomy.id, @taxon.id)
|
||||
= form_for [:admin, @taxonomy, @taxon], method: :put, url: form_url, html: { multipart: true } do |f|
|
||||
= form_with model: @taxon, url: admin_taxon_path(@taxon.id),
|
||||
data: { turbo: true }, id: "edit-taxon-#{@taxon.id}",
|
||||
method: :put, html: { multipart: true } do |f|
|
||||
= render partial: 'form', locals: { f: f }
|
||||
.form-buttons
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
= button_link_to t('spree.actions.cancel'), edit_admin_taxonomy_url(@taxonomy), icon: "icon-remove"
|
||||
= button_link_to t('spree.actions.cancel'), admin_taxons_url, icon: "icon-remove"
|
||||
|
||||
27
app/views/spree/admin/taxons/index.html.haml
Normal file
27
app/views/spree/admin/taxons/index.html.haml
Normal file
@@ -0,0 +1,27 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t(".title")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t(".new_taxon"), spree.new_admin_taxon_url, icon: 'icon-plus', id: 'admin_new_taxon_link'
|
||||
|
||||
%table#listing_taxons.index
|
||||
%colgroup
|
||||
%col{style: "width: 85%"}/
|
||||
%col{style: "width: 15%"}/
|
||||
%thead
|
||||
%tr
|
||||
%th= t("spree.name")
|
||||
%th.actions
|
||||
%tbody
|
||||
- @taxons.each do |taxon|
|
||||
%tr{class: cycle('odd', 'even'), id: spree_dom_id(taxon)}
|
||||
%td
|
||||
= taxon.name
|
||||
%td.actions
|
||||
= link_to_edit taxon.id, no_text: true
|
||||
= link_to '', admin_taxon_path(taxon.id), method: :delete,
|
||||
class: "icon_link with-tip icon-trash no-text",
|
||||
data: { turbo: true, turbo_method: :delete, turbo_confirm: t(:are_you_sure) }
|
||||
14
app/views/spree/admin/taxons/new.html.haml
Normal file
14
app/views/spree/admin/taxons/new.html.haml
Normal file
@@ -0,0 +1,14 @@
|
||||
= render partial: 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t(".title")
|
||||
|
||||
- content_for :page_actions do
|
||||
%li
|
||||
= button_link_to t("spree.admin.taxons.back_to_list"), spree.admin_taxons_path, icon: 'icon-arrow-left'
|
||||
|
||||
= form_with model: @taxon, url: admin_taxons_path, data: { turbo: true }, html: { multipart: true } do |f|
|
||||
= render partial: 'form', locals: { f: f }
|
||||
.form-buttons
|
||||
= button t('actions.create'), 'icon-ok'
|
||||
= button_link_to t('actions.cancel'), admin_taxons_url, icon: "icon-remove"
|
||||
@@ -9,8 +9,8 @@
|
||||
%br
|
||||
= @order.distributor.phone || ""
|
||||
%br
|
||||
%a{:href => "mailto:#{@order.distributor.contact.email}", :target => "_blank"}
|
||||
= @order.distributor.contact.email
|
||||
%a{:href => "mailto:#{order_reply_email(@order)}", :target => "_blank"}
|
||||
= order_reply_email(@order)
|
||||
%br
|
||||
= @order.distributor.website || ""
|
||||
%br
|
||||
|
||||
@@ -12,6 +12,9 @@ export const useOpenAndCloseAsAModal = (controller) => {
|
||||
}.bind(controller),
|
||||
|
||||
close: function (_event, remove = false) {
|
||||
// Only execute close if there is an open modal
|
||||
if (!document.querySelector("body").classList.contains('modal-open')) return;
|
||||
|
||||
this.modalTarget.classList.remove("in");
|
||||
this.backgroundTarget.classList.remove("in");
|
||||
document.querySelector("body").classList.remove("modal-open");
|
||||
|
||||
44
app/webpacker/controllers/order_cycle_form_controller.js
Normal file
44
app/webpacker/controllers/order_cycle_form_controller.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import { Controller } from "stimulus";
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ['statusMessage']
|
||||
connect() {
|
||||
this.observer = new MutationObserver(this.updateCallback);
|
||||
this.observer.observe(
|
||||
this.statusMessageTarget,
|
||||
{ attributes: true, attributeOldValue: true, attributeFilter: ['data-type'] }
|
||||
);
|
||||
}
|
||||
|
||||
// Callback to trigger warning modal
|
||||
updateCallback(mutationsList) {
|
||||
const newDataType = document.getElementById('status-message').getAttribute('data-type');
|
||||
const actionName = document.getElementById('status-message').getAttribute('data-action-name');
|
||||
if(!actionName) return;
|
||||
|
||||
for(let mutation of mutationsList) {
|
||||
if (mutation.type === 'attributes' && mutation.attributeName === 'data-type') {
|
||||
// Only trigger warning modal when notice display (notice) is preceeded by progress display (progress)
|
||||
if(mutation.oldValue === 'progress' && newDataType === 'notice') {
|
||||
// Hide all confirmation buttons in warning modal
|
||||
document.querySelectorAll(
|
||||
'#linked-order-warning-modal .modal-actions button.secondary'
|
||||
).forEach((node) => {
|
||||
node.style.display = 'none';
|
||||
});
|
||||
// Show the appropriate confirmation button, open warning modal, and return
|
||||
document.querySelectorAll(
|
||||
`#linked-order-warning-modal button[data-trigger-action=${actionName}]`
|
||||
).forEach((node) => {
|
||||
node.style.display = 'block';
|
||||
})
|
||||
document.querySelector('.warning-modal button.modal-target-trigger').click();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,6 @@
|
||||
|
||||
@import "plugins/flatpickr-customization";
|
||||
@import "plugins/powertip";
|
||||
@import "plugins/jstree";
|
||||
@import "plugins/select2";
|
||||
|
||||
@import "sections/orders";
|
||||
|
||||
@@ -2,10 +2,18 @@
|
||||
max-width: 615px;
|
||||
}
|
||||
|
||||
.connected_app {
|
||||
margin-bottom: 2rem;
|
||||
|
||||
&:not(:first-of-type) {
|
||||
border-top: 1px solid $color-border;
|
||||
}
|
||||
}
|
||||
|
||||
.connected-app__head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 1em;
|
||||
margin: 1em 0;
|
||||
|
||||
h3 {
|
||||
margin-bottom: 1em;
|
||||
|
||||
@@ -62,3 +62,7 @@ form.order_cycle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#linked-order-warning-modal .reveal-modal{
|
||||
width: 28rem;
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
#taxonomy_tree {
|
||||
> ul,
|
||||
.jstree-icon {
|
||||
background-image: none;
|
||||
}
|
||||
|
||||
.jstree-icon {
|
||||
@extend [class^="icon-"], :before;
|
||||
}
|
||||
|
||||
.jstree-open > .jstree-icon {
|
||||
@extend .icon-caret-down;
|
||||
}
|
||||
.jstree-closed > .jstree-icon {
|
||||
@extend .icon-caret-right;
|
||||
}
|
||||
|
||||
li {
|
||||
background-image: none;
|
||||
|
||||
a {
|
||||
background-color: very-light($color-3);
|
||||
border: 1px solid $color-border;
|
||||
color: $color-body-text;
|
||||
font-weight: $font-weight-bold;
|
||||
text-shadow: none;
|
||||
width: 90%;
|
||||
height: auto;
|
||||
line-height: inherit;
|
||||
padding: 5px 0 5px 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
.jstree-icon {
|
||||
padding-left: 0px;
|
||||
@extend .icon-move;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#vakata-dragged.jstree-apple .jstree-invalid,
|
||||
#vakata-dragged.jstree-apple .jstree-ok,
|
||||
#jstree-marker {
|
||||
background-image: none !important;
|
||||
background-color: transparent !important;
|
||||
@extend [class^="icon-"], :before;
|
||||
}
|
||||
#vakata-dragged.jstree-apple .jstree-invalid {
|
||||
@extend .icon-remove;
|
||||
color: $color-5;
|
||||
}
|
||||
#vakata-dragged.jstree-apple .jstree-ok {
|
||||
@extend .icon-ok;
|
||||
color: $color-2;
|
||||
}
|
||||
|
||||
#jstree-marker {
|
||||
@extend .icon-caret-right;
|
||||
color: $color-body-text !important;
|
||||
width: 4px !important;
|
||||
}
|
||||
|
||||
#jstree-marker-line {
|
||||
@include border-radius($border-radius !important);
|
||||
height: 0px !important;
|
||||
margin-left: 5px !important;
|
||||
margin-top: -2px !important;
|
||||
border: none !important;
|
||||
border-bottom: 1px solid $color-body-text !important;
|
||||
background-color: very-light($color-3) !important;
|
||||
|
||||
-webkit-box-shadow: none !important;
|
||||
-moz-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
#vakata-contextmenu {
|
||||
background-color: $color-3 !important;
|
||||
-moz-box-shadow: none !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
box-shadow: none !important;
|
||||
border: none !important;
|
||||
@include border-radius($border-radius !important);
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-left: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid $color-3;
|
||||
top: 0px;
|
||||
margin-top: -10px;
|
||||
left: 25px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $color-1 !important;
|
||||
line-height: inherit !important;
|
||||
padding: 5px 10px !important;
|
||||
margin: 0 !important;
|
||||
font-size: 90% !important;
|
||||
|
||||
&:hover {
|
||||
@include border-radius($border-radius !important);
|
||||
background-color: $color-2 !important;
|
||||
border: none !important;
|
||||
-moz-box-shadow: none !important;
|
||||
-webkit-box-shadow: none !important;
|
||||
line-height: inherit !important;
|
||||
padding: 5px 10px !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
li:first-child a:hover:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border-left: 10px solid transparent;
|
||||
border-right: 10px solid transparent;
|
||||
border-bottom: 10px solid $color-2;
|
||||
top: 0px;
|
||||
margin-top: -10px;
|
||||
left: 25px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
li.vakata-separator {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -220,15 +220,13 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
|
||||
line-height: $btn-relaxed-height;
|
||||
height: $btn-relaxed-height;
|
||||
|
||||
&.disabled-section {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pagination-description {
|
||||
flex-grow: 1; // Grow to fill space
|
||||
margin-right: 1em; // TODO: cleanup and use flex gap
|
||||
}
|
||||
|
||||
.with-dropdown {
|
||||
@@ -257,31 +255,20 @@
|
||||
min-width: 15em;
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background-color: $lighter-grey;
|
||||
border: 1px solid $lighter-grey;
|
||||
border-radius: 4px;
|
||||
height: $btn-relaxed-height;
|
||||
line-height: $btn-relaxed-height;
|
||||
|
||||
&:has(input:focus),
|
||||
&:has(input:active) {
|
||||
border: 1px solid $dark-blue;
|
||||
}
|
||||
|
||||
> input {
|
||||
// Totally hide the input from its container
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
width: calc(100% - 30px); // 30px is the width of the search icon + padding
|
||||
padding-left: 33px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
font-family: FontAwesome;
|
||||
content: "\f002";
|
||||
color: $near-black;
|
||||
font-size: 16px;
|
||||
margin-top: 0.7rem;
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
@@ -435,33 +422,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideOutLeft {
|
||||
@keyframes slideOutTop {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
to {
|
||||
transform: translateX(-100%);
|
||||
opacity: 0;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.slide-out {
|
||||
animation: slideOutLeft 0.5s forwards;
|
||||
transform-origin: top;
|
||||
animation: slideOutTop 0.5s forwards;
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
@keyframes slideInTop {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
transform: scaleY(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.slide-in {
|
||||
animation: slideInRight 0.5s forwards;
|
||||
transform-origin: top;
|
||||
animation: slideInTop 0.5s forwards;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
|
||||
@import "plugins/flatpickr-customization"; // admin_v3
|
||||
@import "plugins/powertip"; // admin_v3
|
||||
@import "../admin/plugins/jstree";
|
||||
|
||||
@import "sections/orders"; // admin_v3
|
||||
@import "../admin/sections/products";
|
||||
|
||||
@@ -40,6 +40,7 @@ Openfoodnetwork::Application.configure do
|
||||
|
||||
# Configure logging:
|
||||
config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
|
||||
config.log_tags = [:request_id]
|
||||
|
||||
# Use a different cache store in production
|
||||
config.cache_store = :redis_cache_store, {
|
||||
|
||||
@@ -40,6 +40,7 @@ Openfoodnetwork::Application.configure do
|
||||
|
||||
# Configure logging:
|
||||
config.log_formatter = Logger::Formatter.new.tap { |f| f.datetime_format = "%Y-%m-%d %H:%M:%S" }
|
||||
config.log_tags = [:request_id]
|
||||
|
||||
# Use a different cache store in production
|
||||
config.cache_store = :redis_cache_store, {
|
||||
|
||||
@@ -44,7 +44,7 @@ ar:
|
||||
spree/product:
|
||||
name: "اسم المنتج"
|
||||
price: "السعر"
|
||||
primary_taxon: "نوع المنتج "
|
||||
primary_taxon_id: "نوع المنتج "
|
||||
shipping_category_id: "نوع الشحن"
|
||||
variant_unit: "وحدة النوع"
|
||||
variant_unit_name: "اسم وحدة النوع"
|
||||
@@ -1133,16 +1133,19 @@ ar:
|
||||
add_new: اضف جديد
|
||||
no_voucher_yet: لا قسائم حتى الآن
|
||||
connected_apps:
|
||||
tagline: "By clicking ‘Allow data sharing’, you are sharing data between Open Food Network and the Discover Regenerative Portal, and agreeing to make specific data public on the Portal, which will also be publicly available on the API.\nIMPORTANT: Before you stop sharing and remove your listing, please first contact hello@regenerative.org.au to request a copy of your Discover Regenerative data."
|
||||
loading: "جار التحميل"
|
||||
description_html: |
|
||||
<p>
|
||||
Discover Regenerative is a showcase of Australia’s Regenerative Farmers, their produce/products, outcomes and achievements. It simplifies how business-to-business (B2B) / wholesale buyers can find regenerative produce and directly connect with Producers.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://regenerative.org.au/" target="_blank"><b>Visit Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
affiliate_sales_data:
|
||||
loading: "جار التحميل"
|
||||
discover_regen:
|
||||
tagline: "By clicking ‘Allow data sharing’, you are sharing data between Open Food Network and the Discover Regenerative Portal, and agreeing to make specific data public on the Portal, which will also be publicly available on the API.\nIMPORTANT: Before you stop sharing and remove your listing, please first contact hello@regenerative.org.au to request a copy of your Discover Regenerative data."
|
||||
loading: "جار التحميل"
|
||||
description_html: |
|
||||
<p>
|
||||
Discover Regenerative is a showcase of Australia’s Regenerative Farmers, their produce/products, outcomes and achievements. It simplifies how business-to-business (B2B) / wholesale buyers can find regenerative produce and directly connect with Producers.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://regenerative.org.au/" target="_blank"><b>Visit Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
actions:
|
||||
edit_profile: الإعدادات
|
||||
properties: الخصائص
|
||||
@@ -1235,6 +1238,8 @@ ar:
|
||||
choose_products_from: "اختر المنتجات من:"
|
||||
re_notify_producers: إعادة إخطار المنتجين
|
||||
notify_producers_tip: سيؤدي هذا إلى إرسال بريد إلكتروني إلى كل منتج مع قائمة طلباتهم.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'إلغاء'
|
||||
incoming:
|
||||
incoming: "الوارد"
|
||||
supplier: "المورد"
|
||||
@@ -3297,6 +3302,7 @@ ar:
|
||||
سيؤدي ذلك إلى ضبط مستوى المخزون لصفر على جميع المنتجات
|
||||
المؤسسة غير موجودة في الملف الذي تم تحميله.
|
||||
order_cycles:
|
||||
unsaved_changes: "لم تحفظ التغييرات"
|
||||
create_failure: "فشل في تكوين دورة الطلب"
|
||||
update_success: 'تم تحديث دورة الطلب.'
|
||||
update_failure: "فشل في تحديث دورة الطلب"
|
||||
@@ -3633,8 +3639,6 @@ ar:
|
||||
delivery: "موقعة ومختومة وتم التسليم"
|
||||
start_date: "تاريخ البدء"
|
||||
successfully_removed: "تمت الإزالة بنجاح"
|
||||
taxonomy_edit: "التصنيف"
|
||||
tree: "شجرة"
|
||||
updating: "تحديث"
|
||||
your_order_is_empty_add_product: "طلبك فارغ ، يرجى البحث عن المنتج أعلاه وإضافته"
|
||||
add_product: "أضف منتج"
|
||||
@@ -3748,9 +3752,7 @@ ar:
|
||||
abbreviation: "الاختصار"
|
||||
new_state: "محافظة جديدة"
|
||||
payment_methods: "طرق الدفع"
|
||||
taxonomies: "التصنيفات"
|
||||
new_taxonomy: "تصنيف جديد"
|
||||
back_to_taxonomies_list: "العودة إلى قائمة التصنيفات"
|
||||
taxons: "فئات المنتجات"
|
||||
shipping_methods: "طرق الشحن"
|
||||
shipping_method: "طريقة الشحن"
|
||||
shipment: "الشحنة"
|
||||
@@ -4215,9 +4217,10 @@ ar:
|
||||
total: "المجموع"
|
||||
billing_address_name: "الاسم"
|
||||
taxons:
|
||||
index:
|
||||
title: "فئات المنتجات"
|
||||
form:
|
||||
name: الاسم
|
||||
permalink: الرابط الثابت
|
||||
description: وصف
|
||||
general_settings:
|
||||
edit:
|
||||
|
||||
@@ -44,7 +44,7 @@ ca:
|
||||
spree/product:
|
||||
name: "Nom del producte"
|
||||
price: "Preu"
|
||||
primary_taxon: "Categoria del producte"
|
||||
primary_taxon_id: "Categoria del producte"
|
||||
shipping_category_id: "Categoria d'enviament"
|
||||
variant_unit: "Unitat de la variant"
|
||||
variant_unit_name: "Nom de la unitat de la variant"
|
||||
@@ -1197,7 +1197,10 @@ ca:
|
||||
remove_logo_success: "Logo eliminat"
|
||||
white_label_logo_link_label: "Enllaç del logotip utilitzat a botiga"
|
||||
connected_apps:
|
||||
loading: "S'està carregant"
|
||||
affiliate_sales_data:
|
||||
loading: "S'està carregant"
|
||||
discover_regen:
|
||||
loading: "S'està carregant"
|
||||
actions:
|
||||
edit_profile: Configuració
|
||||
properties: Propietats
|
||||
@@ -1289,6 +1292,8 @@ ca:
|
||||
save_and_back_to_list: "Desa i torna a la llista"
|
||||
choose_products_from: "Trieu Productes des de:"
|
||||
notify_producers_tip: Això enviarà un correu electrònic a cada productor amb la llista dels seus productes demanats a les comandes.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Cancel·lar'
|
||||
incoming:
|
||||
incoming: "Entrant"
|
||||
supplier: "Proveïdora"
|
||||
@@ -3278,6 +3283,7 @@ ca:
|
||||
Això establirà el nivell d'estoc a zero en tots els productes per aquesta
|
||||
organització que no estan presents al fitxer carregat.
|
||||
order_cycles:
|
||||
unsaved_changes: "Teniu canvis sense desar"
|
||||
create_failure: "No s'ha pogut crear el cicle de comanda"
|
||||
update_success: 'S''ha actualitzat el cicle de comanda.'
|
||||
update_failure: "No s'ha pogut actualitzar el cicle de comanda"
|
||||
@@ -3510,8 +3516,6 @@ ca:
|
||||
delivery: "Signat, segellat, lliurat"
|
||||
start_date: "Data d'inici"
|
||||
successfully_removed: "S'ha suprimit correctament"
|
||||
taxonomy_edit: "Edició de taxonomia"
|
||||
tree: "Arbre"
|
||||
updating: "Actualitzant"
|
||||
your_order_is_empty_add_product: "La comanda està buida, si us plau cerca i afegeix un producte a dalt"
|
||||
add_product: "Afegeix un producte"
|
||||
@@ -3626,9 +3630,7 @@ ca:
|
||||
abbreviation: "Abreviatura"
|
||||
new_state: "Nou estat"
|
||||
payment_methods: "Mètodes de Pagament"
|
||||
taxonomies: "Taxonomies"
|
||||
new_taxonomy: "Nova taxonomia"
|
||||
back_to_taxonomies_list: "Torna a la llista de taxonomies"
|
||||
taxons: "Tipus de productes"
|
||||
shipping_methods: "Mètodes d'enviament"
|
||||
shipping_method: "Mètode d'enviament"
|
||||
shipment: "Enviament"
|
||||
@@ -4093,9 +4095,10 @@ ca:
|
||||
total: "Total"
|
||||
billing_address_name: "Nom"
|
||||
taxons:
|
||||
index:
|
||||
title: "Tipus de productes"
|
||||
form:
|
||||
name: Nom
|
||||
permalink: Enllaç permanent
|
||||
description: Descripció
|
||||
general_settings:
|
||||
edit:
|
||||
|
||||
@@ -47,7 +47,7 @@ cy:
|
||||
spree/product:
|
||||
name: "Enw Cynnyrch"
|
||||
price: "Pris"
|
||||
primary_taxon: "Categori Cynnyrch"
|
||||
primary_taxon_id: "Categori Cynnyrch"
|
||||
shipping_category_id: "Categori dosbarthu."
|
||||
variant_unit: "Uned Amrywiol"
|
||||
variant_unit_name: "Enw Uned Amrywiol"
|
||||
@@ -1254,10 +1254,15 @@ cy:
|
||||
custom_tab_content: "Cynnwys y tab pwrpasol"
|
||||
connected_apps:
|
||||
legend: "Apiau cysylltiedig"
|
||||
enable: "Caniatáu rhannu data"
|
||||
disable: "Rhoi’r gorau i rannu"
|
||||
loading: "Yn llwytho"
|
||||
link_label: "Rheoli’r rhestru"
|
||||
affiliate_sales_data:
|
||||
enable: "Caniatáu rhannu data"
|
||||
disable: "Rhoi’r gorau i rannu"
|
||||
loading: "Yn llwytho"
|
||||
discover_regen:
|
||||
enable: "Caniatáu rhannu data"
|
||||
disable: "Rhoi’r gorau i rannu"
|
||||
loading: "Yn llwytho"
|
||||
link_label: "Rheoli’r rhestru"
|
||||
actions:
|
||||
edit_profile: Gosodiadau
|
||||
properties: Manylion
|
||||
@@ -1350,6 +1355,8 @@ cy:
|
||||
choose_products_from: "Dewis Cynnyrch gan:"
|
||||
re_notify_producers: Ail-hysbysu cynhyrchwyr.
|
||||
notify_producers_tip: Trwy hyn anfonir ebost at bob cynhyrchydd gyda rhestr o'r archebion.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Canslo'
|
||||
incoming:
|
||||
incoming: "Yn dod i mewn"
|
||||
supplier: "Cyflenwr"
|
||||
@@ -3457,6 +3464,7 @@ cy:
|
||||
This will set stock level to zero on all products for this
|
||||
enterprise that are not present in the uploaded file.
|
||||
order_cycles:
|
||||
unsaved_changes: "Mae gennych chi newidiadau heb eu cadw"
|
||||
create_failure: "Wedi methu creu cylch archebu"
|
||||
update_success: 'Diweddarwyd eich cylch archebu'
|
||||
update_failure: "Wedi methu diweddaru'r cylch archebu"
|
||||
@@ -3746,8 +3754,6 @@ cy:
|
||||
delivery: "Llofnodwyd, cadarnhawyd a chyflenwyd"
|
||||
start_date: "Dyddiad cychwyn"
|
||||
successfully_removed: "Llwyddwyd i ddileu"
|
||||
taxonomy_edit: "Golygu tacsonomi"
|
||||
tree: "Coeden"
|
||||
updating: "Yn diweddaru"
|
||||
your_order_is_empty_add_product: "Mae eich archeb yn wag, chwiliwch am ac ychwanegwch gynnyrch uchod"
|
||||
add_product: "Ychwanegu Cynnyrch"
|
||||
@@ -3862,9 +3868,7 @@ cy:
|
||||
abbreviation: "Talfyriad"
|
||||
new_state: "Sir Newydd"
|
||||
payment_methods: "Dulliau Talu"
|
||||
taxonomies: "Tacsonomeg"
|
||||
new_taxonomy: "Tacsonomeg Newydd"
|
||||
back_to_taxonomies_list: "Yn ôl i'r Rhestr Tacsonomeg"
|
||||
taxons: "Categorïau Cynnyrch"
|
||||
shipping_methods: "Dulliau Anfon"
|
||||
shipping_method: "Dull Anfon"
|
||||
shipment: "Llwyth"
|
||||
@@ -4345,9 +4349,10 @@ cy:
|
||||
total: "Cyfanswm"
|
||||
billing_address_name: "Enw"
|
||||
taxons:
|
||||
index:
|
||||
title: "Categorïau Cynnyrch"
|
||||
form:
|
||||
name: Enw
|
||||
permalink: Permalink
|
||||
meta_title: Meta Title
|
||||
meta_description: Meta Description
|
||||
meta_keywords: Meta Keywords
|
||||
|
||||
@@ -33,7 +33,7 @@ de_CH:
|
||||
spree/product:
|
||||
name: "Produktname"
|
||||
price: "Preis"
|
||||
primary_taxon: "Produktkategorie"
|
||||
primary_taxon_id: "Produktkategorie"
|
||||
shipping_category_id: "Lieferkategorie"
|
||||
variant_unit: "Varianteneinheit"
|
||||
variant_unit_name: "Name der Varianteneinheit"
|
||||
@@ -1108,7 +1108,10 @@ de_CH:
|
||||
customers: Kunde
|
||||
active: Aktiv?
|
||||
connected_apps:
|
||||
loading: "Wird geladen ..."
|
||||
affiliate_sales_data:
|
||||
loading: "Wird geladen ..."
|
||||
discover_regen:
|
||||
loading: "Wird geladen ..."
|
||||
actions:
|
||||
edit_profile: Einstellungen
|
||||
properties: Eigenschaften
|
||||
@@ -1201,6 +1204,8 @@ de_CH:
|
||||
choose_products_from: "Wählen Sie Produkte von:"
|
||||
re_notify_producers: Produzenten erneut benachrichtigen
|
||||
notify_producers_tip: Benachrichtigen Sie die Produzenten per E-Mail über in diesem Bestellzyklus erhaltene Bestellungen.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Stornieren'
|
||||
incoming:
|
||||
incoming: "Eingehend"
|
||||
supplier: "Lieferant"
|
||||
@@ -3207,6 +3212,7 @@ de_CH:
|
||||
Dadurch wird der Lagerbestand für alle Produkte dieses Unternehmens,
|
||||
die in der hochgeladenen Datei nicht vorhanden sind, auf Null gesetzt.
|
||||
order_cycles:
|
||||
unsaved_changes: "Sie haben nicht gespeicherte Änderungen."
|
||||
create_failure: "Fehler beim Erstellen des Bestellzyklus."
|
||||
update_success: 'Ihr Bestellzyklus wurde aktualisiert.'
|
||||
update_failure: "Fehler beim Aktualisieren des Bestellzyklus."
|
||||
@@ -3437,8 +3443,6 @@ de_CH:
|
||||
UPS Ground: "UPS Ground"
|
||||
start_date: "Anfangsdatum"
|
||||
successfully_removed: "Erfolgreich gelöscht"
|
||||
taxonomy_edit: "Kategorien bearbeiten"
|
||||
tree: "Struktur"
|
||||
updating: "Aktualisierung"
|
||||
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"
|
||||
@@ -3551,9 +3555,7 @@ de_CH:
|
||||
abbreviation: "Abkürzung"
|
||||
new_state: "Neuer Kanton"
|
||||
payment_methods: "Zahlungsarten"
|
||||
taxonomies: "Kategorien"
|
||||
new_taxonomy: "Neue Kategorie"
|
||||
back_to_taxonomies_list: "Zurück zur Kategorieliste"
|
||||
taxons: "Produktkategorien"
|
||||
shipping_methods: "Lieferoptionen"
|
||||
shipping_method: "Lieferoption"
|
||||
shipment: "Lieferung"
|
||||
@@ -3999,9 +4001,10 @@ de_CH:
|
||||
total: "Gesamt"
|
||||
billing_address_name: "Name"
|
||||
taxons:
|
||||
index:
|
||||
title: "Produktkategorien"
|
||||
form:
|
||||
name: Name
|
||||
permalink: Permalink
|
||||
description: Beschreibung
|
||||
general_settings:
|
||||
edit:
|
||||
|
||||
@@ -47,7 +47,7 @@ de_DE:
|
||||
spree/product:
|
||||
name: "Produktname"
|
||||
price: "Preis"
|
||||
primary_taxon: "Produktkategorie"
|
||||
primary_taxon_id: "Produktkategorie"
|
||||
shipping_category_id: "Lieferkategorie"
|
||||
variant_unit: "Varianteneinheit"
|
||||
variant_unit_name: "Name der Varianteneinheit"
|
||||
@@ -1239,7 +1239,10 @@ de_DE:
|
||||
custom_tab_content: "Inhalt des Reiters"
|
||||
connected_apps:
|
||||
legend: "Verknüpfte Apps"
|
||||
loading: "Wird geladen ..."
|
||||
affiliate_sales_data:
|
||||
loading: "Wird geladen ..."
|
||||
discover_regen:
|
||||
loading: "Wird geladen ..."
|
||||
actions:
|
||||
edit_profile: Einstellungen
|
||||
properties: Eigenschaften
|
||||
@@ -1332,6 +1335,8 @@ de_DE:
|
||||
choose_products_from: "Wählen Sie Produkte von:"
|
||||
re_notify_producers: Produzenten erneut benachrichtigen
|
||||
notify_producers_tip: Benachrichtigen Sie die Produzenten per E-Mail über in diesem Bestellzyklus erhaltene Bestellungen.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Abbrechen'
|
||||
incoming:
|
||||
incoming: "Eingehend"
|
||||
supplier: "Lieferant"
|
||||
@@ -3447,6 +3452,7 @@ de_DE:
|
||||
Dadurch wird der Lagerbestand für alle Produkte dieses Unternehmens,
|
||||
die in der hochgeladenen Datei nicht vorhanden sind, auf Null gesetzt.
|
||||
order_cycles:
|
||||
unsaved_changes: "Sie haben nicht gespeicherte Änderungen."
|
||||
create_failure: "Fehler beim Erstellen des Bestellzyklus."
|
||||
update_success: 'Ihr Bestellzyklus wurde aktualisiert.'
|
||||
update_failure: "Fehler beim Aktualisieren des Bestellzyklus."
|
||||
@@ -3687,8 +3693,6 @@ de_DE:
|
||||
delivery: "Lieferung"
|
||||
start_date: "Anfangsdatum"
|
||||
successfully_removed: "Erfolgreich gelöscht"
|
||||
taxonomy_edit: "Kategorien bearbeiten"
|
||||
tree: "Struktur"
|
||||
updating: "Aktualisierung"
|
||||
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"
|
||||
@@ -3803,9 +3807,7 @@ de_DE:
|
||||
abbreviation: "Abkürzung"
|
||||
new_state: "Neues Bundesland"
|
||||
payment_methods: "Zahlungsarten"
|
||||
taxonomies: "Kategorien"
|
||||
new_taxonomy: "Neue Kategorie"
|
||||
back_to_taxonomies_list: "Zurück zur Kategorieliste"
|
||||
taxons: "Produktkategorien"
|
||||
shipping_methods: "Lieferoptionen"
|
||||
shipping_method: "Lieferoption"
|
||||
shipment: "Lieferung"
|
||||
@@ -4278,9 +4280,10 @@ de_DE:
|
||||
total: "Gesamt"
|
||||
billing_address_name: "Name"
|
||||
taxons:
|
||||
index:
|
||||
title: "Produktkategorien"
|
||||
form:
|
||||
name: Name
|
||||
permalink: Permalink
|
||||
description: Beschreibung
|
||||
general_settings:
|
||||
edit:
|
||||
|
||||
@@ -44,7 +44,7 @@ el:
|
||||
spree/product:
|
||||
name: "Όνομα Προϊόντος"
|
||||
price: "Τιμή"
|
||||
primary_taxon: "Κατηγορία προϊόντος"
|
||||
primary_taxon_id: "Κατηγορία προϊόντος"
|
||||
shipping_category_id: "Κατηγορία μεταφορικών"
|
||||
variant_unit: "Μονάδα μέτρησης μεταβλητής"
|
||||
variant_unit_name: "Όνομα μεταβλητής"
|
||||
@@ -454,7 +454,7 @@ el:
|
||||
admin_and_handling: Διαχείριση
|
||||
profile: Προφίλ
|
||||
supplier_only: Μόνο Προμηθευτής
|
||||
has_shopfront: Διαθέτει σελίδα καταστήματος
|
||||
has_shopfront: Ενεργό κατάστημα
|
||||
weight: Βάρος
|
||||
volume: Όγκος
|
||||
items: Αντικείμενα
|
||||
@@ -570,7 +570,7 @@ el:
|
||||
email: Email
|
||||
ends_at: Ολοκληρώνεται σε
|
||||
ends_on: Ολοκληρώνεται στις
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
first_name: Όνομα
|
||||
last_name: Επίθετο
|
||||
on_hand: Στο χέρι
|
||||
@@ -725,7 +725,7 @@ el:
|
||||
title: "Χρεώσεις επιχείρησης"
|
||||
enterprise: "Επιχείρηση"
|
||||
fee_type: "Κατηγορίες αμοιβών"
|
||||
name: "Όνονα"
|
||||
name: "Όνομα"
|
||||
tax_category: "Φορολογική Κατηγορία"
|
||||
calculator: "Υπολογισμός"
|
||||
calculator_values: "Υπολογισμός Αξίας"
|
||||
@@ -875,7 +875,7 @@ el:
|
||||
index:
|
||||
notice: "Ειδοποίηση"
|
||||
beta_notice: "Αυτή η λειτουργία είναι ακόμα σε δοκιμαστική έκδοση beta: ενδέχεται να αντιμετωπίσετε ορισμένα σφάλματα κατά τη χρήση της. Μη διστάσετε να επικοινωνήσετε με την υποστήριξη."
|
||||
select_file: Επιλέξτε φύλλο εργασίας προς ανέβασμα
|
||||
select_file: Επιλέξτε αρχείο CSV
|
||||
spreadsheet: Φύλλο Εργασίας
|
||||
choose_import_type: Επιλογή τύπου εισαγωγής
|
||||
import_into: Τύπος εισαγωγής
|
||||
@@ -886,7 +886,7 @@ el:
|
||||
csv_templates: Πρότυπο CSV
|
||||
product_list_template: Λήψη προτύπου λίστας προϊόντων
|
||||
inventory_template: Λήψη προτύπου κατάλογου προϊόντων
|
||||
category_values: Διαθέσιμες παραλλαγές Κατηγορίας
|
||||
category_values: Διαθέσιμες κατηγορίες
|
||||
product_categories: Κατηγορίες προϊόντος
|
||||
tax_categories: Κατηγορίες Φορολόγησης
|
||||
shipping_categories: Κατηγορίες Μεταφορικών
|
||||
@@ -913,8 +913,8 @@ el:
|
||||
not_found: δεν ήταν δυνατή η εύρεση της επιχείρησης στη βάση δεδομένων
|
||||
no_name: Δεν υπάρχει όνομα
|
||||
blank_enterprise: ορισμένα προϊόντα δεν έχουν συσχετιστεί με κάποια επιχείρηση
|
||||
reset_absent?: Επαναφέρετε τα προϊόντα που λείπουν
|
||||
reset_absent_tip: Ορίστε μηδενικό απόθεμα για όλα τα εξερχόμενα προϊόντα που δεν υπάρχουν στο αρχείο
|
||||
reset_absent?: Σχετικά με τα υπόλοιπα προϊόντα
|
||||
reset_absent_tip: Ορίστε μηδενικό απόθεμα για όλα τα προϊόντα που δεν υπάρχουν στο αρχείο
|
||||
overwrite_all: Αντικατάσταση Όλων
|
||||
overwrite_empty: Αντικατάσταση αν είναι κενό
|
||||
default_stock: Ορισμός επιπέδου αποθέματος
|
||||
@@ -1075,7 +1075,7 @@ el:
|
||||
select_state: "Επέλεξε πόλη"
|
||||
contact:
|
||||
legend: "επικοινωνία"
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
name_placeholder: π.χ Gustav Plum
|
||||
email_address: Δημόσια Διεύθυνση Ηλεκτρονικού Ταχυδρομείου
|
||||
email_address_placeholder: π.χ. inquiries@fresh-food.com
|
||||
@@ -1089,9 +1089,9 @@ el:
|
||||
website_placeholder: π.χ. www.truffles.com
|
||||
enterprise_fees:
|
||||
legend: "Χρεώσεις επιχείρησης"
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
fee_type: Κατηγορίες αμοιβών
|
||||
manage_fees: Διαχείρηση Αμοιβών Επιχειρήσεων
|
||||
manage_fees: Διαχείριση αμοιβών επιχειρήσεων
|
||||
no_fees_yet: Δεν έχετε τέλη επιχείρησης ακόμα.
|
||||
create_button: Δημιούργησε έναν τώρα
|
||||
enterprise_permissions:
|
||||
@@ -1121,7 +1121,7 @@ el:
|
||||
preferred_product_selection_from_inventory_only_no: Νέα προϊόντα πρέπει να προστεθούν στο απόθεμά μου πριν μπορέσουν να τοποθετηθούν στη βιτρίνα μου
|
||||
payment_methods:
|
||||
legend: "Τρόποι πληρωμής"
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
applies: Ισχύει?
|
||||
manage: Διαχείριση Τρόπων Πληρωμής
|
||||
no_method_yet: Δεν έχετε επιλέξει κανέναν τρόπο πληρωμής.
|
||||
@@ -1129,7 +1129,7 @@ el:
|
||||
create_one_button: Δημιούργησε έναν τώρα
|
||||
primary_details:
|
||||
legend: "Βασικές λεπτομέρειες"
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
name_placeholder: π.χ. Βιοδυναμικές τρούφες του καθηγητή Plum
|
||||
groups: Ομάδες
|
||||
groups_tip: Επέλεξε κάποια ομάδα ή περιοχή. Αυτό θα βοηθήσει τους καταναλωτές να βρίσκουν την επιχείρησή σου.
|
||||
@@ -1158,7 +1158,7 @@ el:
|
||||
ofn_uid_tip: Το μοναδικό αναγνωριστικό που χρησιμοποιείται για την ταυτοποίηση της επιχείρησης στο Open Food Network.
|
||||
shipping_methods:
|
||||
legend: "Τρόποι αποστολής"
|
||||
name: "Όνονα"
|
||||
name: "Όνομα"
|
||||
applies: "Ενεργό;"
|
||||
manage: "Διαχείριση Τρόπων Αποστολής"
|
||||
create_button: "Δημιουργία Νέου Τρόπου Αποστολής"
|
||||
@@ -1216,6 +1216,7 @@ el:
|
||||
enabled: "Ενεργό"
|
||||
disabled: "Απενεργοποιημένο"
|
||||
social:
|
||||
legend: "Κοινωνικός"
|
||||
twitter_placeholder: "π.χ. @the_prof"
|
||||
instagram_placeholder: "π.χ. the_prof"
|
||||
facebook_placeholder: "π.χ. www.facebook.com/PageNameHere"
|
||||
@@ -1288,28 +1289,34 @@ el:
|
||||
custom_tab_content: "Περιεχόμενο για την προσαρμοσμένη καρτέλα"
|
||||
connected_apps:
|
||||
legend: "Μόνο οι διαχειριστές μπορούν να συνδέσουν εφαρμογές"
|
||||
title: "Discover Regenerative"
|
||||
tagline: "Να επιτρέψετε στο Discover Regenerative να δημοσιεύσει τις πληροφορίες της επιχείρησής σας."
|
||||
enable: "Να επιτρέπεται η κοινοποίηση δεδομένων."
|
||||
disable: "Διακοπή κοινοποίησης"
|
||||
loading: "Φόρτωση"
|
||||
need_to_be_manager: "Μόνο οι διαχειριστές μπορούν να συνδέουν εφαρμογές."
|
||||
note: |
|
||||
Ο λογαριασμός σας στο Open Food Network είναι συνδεδεμένος με το Discover Regenerative.
|
||||
Προσθέστε ή ενημερώστε πληροφορίες για τη λίστα σας στο Discover Regenerative εδώ.
|
||||
link_label: "Διαχείριση λίστας"
|
||||
description_html: |
|
||||
<p>
|
||||
Οι επιλέξιμοι παραγωγοί μπορούν να παρουσιάσουν τις αναγεννητικές πιστοποιήσεις τους,
|
||||
τις πρακτικές γεωργίας και άλλες πληροφορίες μέσω μιας καταχώρισης προφίλ.
|
||||
Αυτό απλοποιεί τον τρόπο με τον οποίο οι αγοραστές μπορούν να βρουν αναγεννητικά προϊόντα και να συνδεθούν
|
||||
με παραγωγούς που τους ενδιαφέρουν.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://about.openfoodnetwork.org.au/regen-produce-portal/"
|
||||
target="_blank"><b>Μάθετε περισσότερα για το Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
affiliate_sales_data:
|
||||
enable: "Να επιτρέπεται η κοινοποίηση δεδομένων."
|
||||
disable: "Διακοπή κοινοποίησης"
|
||||
loading: "Φόρτωση"
|
||||
need_to_be_manager: "Μόνο οι διαχειριστές μπορούν να συνδέουν εφαρμογές."
|
||||
discover_regen:
|
||||
title: "Discover Regenerative"
|
||||
tagline: "Να επιτρέψετε στο Discover Regenerative να δημοσιεύσει τις πληροφορίες της επιχείρησής σας."
|
||||
enable: "Να επιτρέπεται η κοινοποίηση δεδομένων."
|
||||
disable: "Διακοπή κοινοποίησης"
|
||||
loading: "Φόρτωση"
|
||||
need_to_be_manager: "Μόνο οι διαχειριστές μπορούν να συνδέουν εφαρμογές."
|
||||
note: |
|
||||
Ο λογαριασμός σας στο Open Food Network είναι συνδεδεμένος με το Discover Regenerative.
|
||||
Προσθέστε ή ενημερώστε πληροφορίες για τη λίστα σας στο Discover Regenerative εδώ.
|
||||
link_label: "Διαχείριση λίστας"
|
||||
description_html: |
|
||||
<p>
|
||||
Οι επιλέξιμοι παραγωγοί μπορούν να παρουσιάσουν τις αναγεννητικές πιστοποιήσεις τους,
|
||||
τις πρακτικές γεωργίας και άλλες πληροφορίες μέσω μιας καταχώρισης προφίλ.
|
||||
Αυτό απλοποιεί τον τρόπο με τον οποίο οι αγοραστές μπορούν να βρουν αναγεννητικά προϊόντα και να συνδεθούν
|
||||
με παραγωγούς που τους ενδιαφέρουν.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://about.openfoodnetwork.org.au/regen-produce-portal/"
|
||||
target="_blank"><b>Μάθετε περισσότερα για το Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
actions:
|
||||
edit_profile: Ρυθμήσεις
|
||||
properties: Ιδιότητες
|
||||
@@ -1350,7 +1357,7 @@ el:
|
||||
loading_enterprises: ΦΌΡΤΩΣΕ ΤΙΣ ΕΠΙΧΕΙΡΉΣΕΙΣ
|
||||
no_enterprises_found: Δεν βρέθηκε επιχείρηση.
|
||||
search_placeholder: Αναζήτηση Με Όνομα
|
||||
manage: Διαχείρηση
|
||||
manage: Διαχείριση
|
||||
manage_link: Ρυθμήσεις
|
||||
producer?: "Παραγωγός?"
|
||||
package: "Πακέτο"
|
||||
@@ -1402,6 +1409,8 @@ el:
|
||||
choose_products_from: "Επιλογή προϊόντων Από:"
|
||||
re_notify_producers: Επαναλάβετε την ειδοποίηση προς τους παραγωγούς
|
||||
notify_producers_tip: Αυτό θα στείλει ένα email σε κάθε παραγωγό με τη λίστα των παραγγελιών τους.
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Ακύρωση'
|
||||
incoming:
|
||||
incoming: "Εισερχόμενο"
|
||||
supplier: "Προμηθευτής"
|
||||
@@ -1469,7 +1478,7 @@ el:
|
||||
add: Προσθήκη κομίστρου συντονιστή
|
||||
filters:
|
||||
search_by_order_cycle_name: "Αναζήτηση με όνομα Κύκλου Παραγγελίας ..."
|
||||
involving: "Συμμετοχή"
|
||||
involving: "Αφορά"
|
||||
any_enterprise: "Οποιαδήποτε Επιχείρηση"
|
||||
any_schedule: "Οποιοδήποτε Πρόγραμμα"
|
||||
form:
|
||||
@@ -1490,7 +1499,7 @@ el:
|
||||
new_schedule: Νέο Πρόγραμμα
|
||||
new_schedule_tooltip: Η συχνότητα με την οποία πραγματοποιείται μια συνδρομή
|
||||
name_and_timing_form:
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
orders_open: Οι παραγγελίες ανοιγούν στις
|
||||
coordinator: Συντονιστής
|
||||
orders_close: Οι παραγγελίες είναι κλείστες
|
||||
@@ -1546,6 +1555,7 @@ el:
|
||||
primary_details: "Βασικές λεπτομέρειες"
|
||||
address: "Διεύθυνση"
|
||||
contact: "επικοινωνία"
|
||||
social: "Κοινωνικός"
|
||||
about: "Σχετικά"
|
||||
business_details: "Λεπτομέρειες επιχείρησης "
|
||||
images: "Εικόνες"
|
||||
@@ -1654,6 +1664,7 @@ el:
|
||||
table:
|
||||
select_and_search: "Επιλέξτε φίλτρα και κάντε κλικ στο %{option} για να αποκτήσετε πρόσβαση στα δεδομένα σας."
|
||||
headings:
|
||||
hub: "Κεντρικό σημείο"
|
||||
customer_code: "Κωδικός"
|
||||
first_name: "Όνομα"
|
||||
last_name: "Επίθετο"
|
||||
@@ -2009,15 +2020,15 @@ el:
|
||||
invoice_issued_on: "Το τιμολόγιο εκδόθηκε στις:"
|
||||
order_number: "Αριθμός παραγγελίας:"
|
||||
date_of_transaction: "Ημερομηνία συναλλαγής"
|
||||
menu_1_title: "Καταστήματα"
|
||||
menu_1_title: "Καταστηματα"
|
||||
menu_1_url: "/shops"
|
||||
menu_2_title: "Χάρτης"
|
||||
menu_2_title: "Χαρτης"
|
||||
menu_2_url: "/map"
|
||||
menu_3_title: "Παραγωγοί"
|
||||
menu_3_title: "Παραγωγοι"
|
||||
menu_3_url: "/producers"
|
||||
menu_4_title: "Ομάδες"
|
||||
menu_4_title: "Ομαδες"
|
||||
menu_4_url: "/groups"
|
||||
menu_5_title: "Σχετικά"
|
||||
menu_5_title: "Σχετικα"
|
||||
menu_5_url: "https://about.openfoodnetwork.org.au/"
|
||||
menu_6_title: "Σύνδεση"
|
||||
menu_6_url: "https://openfoodnetwork.org/au/connect/"
|
||||
@@ -2039,7 +2050,7 @@ el:
|
||||
footer_links_md: "Σύνδεσμοι"
|
||||
footer_about_url: "Σχετικά με τη διεύθυνση URL"
|
||||
user_guide_link: "Σύνδεσμος οδηγού χρήστη"
|
||||
name: Όνονα
|
||||
name: Όνομα
|
||||
first_name: Όνομα
|
||||
last_name: Επίθετο
|
||||
email: Email
|
||||
@@ -2150,7 +2161,7 @@ el:
|
||||
cookies_policy_link_desc: "Αν θέλετε να μάθετε περισσότερα, ελέγξτε το"
|
||||
cookies_policy_link: "πολιτική cookies"
|
||||
cookies_accept_button: "Αποδοχή Cookies"
|
||||
home_shop: Αγόρασε Τώρα
|
||||
home_shop: Αγορασε Τωρα
|
||||
brandstory_headline: "Τροφή απευθείας από τον αγρό στο πιάτο μας"
|
||||
brandstory_intro: "Κάποιες φορές ο καλύτερος τρόπος για να διορθώσεις το σύστημα είναι να ξεκινήσεις ένα νέο..."
|
||||
brandstory_part1: "Ξεκινάμε από τη βάση. Με αγρότες και καλλιεργητές έτοιμους να πουν τις ιστορίες τους περήφανα και αληθινά. Με διανομείς έτοιμους να συνδέσουν τους ανθρώπους με προϊόντα δίκαια και ειλικρινά. Με αγοραστές που πιστεύουν ότι οι καλύτερες εβδομαδιαίες αποφάσεις αγορών μπορούν να αλλάξουν σοβαρά τον κόσμο."
|
||||
@@ -2167,12 +2178,12 @@ el:
|
||||
system_step3: "3. Παραλαβή / Αποστολή"
|
||||
system_step3_text: "Περίμενε την παράδοση του φαγητού σου, ή επισκέψου τον παραγωγό ή το κατάστημα της περιοχής σου για μια πιο προσωπική επαφή. Η αγορά των τροφίμων είναι τόσο ποικιλόμορφη όσο η φύση ορίζει."
|
||||
cta_headline: "Αγορές που κάνουν τον κόσμο καλύτερο."
|
||||
cta_label: "είμαι έτοιμος"
|
||||
cta_label: "ειμαι ετοιμος"
|
||||
stats_headline: "Δημιουργούμε ένα νέο σύστημα διατροφής."
|
||||
stats_producers: "Παραγωγοί τροφίμων"
|
||||
stats_shops: "Καταστήματα τροφίμων"
|
||||
stats_shoppers: "Αγοραστές τροφίμων"
|
||||
stats_orders: "Παραγγελίες τροφίμων"
|
||||
stats_producers: "Παραγωγοι τροφιμων"
|
||||
stats_shops: "Καταστηματα τροφιμων"
|
||||
stats_shoppers: "Καταναλωτες τροφιμων"
|
||||
stats_orders: "Παραγγελιες τροφιμων"
|
||||
checkout_title: Ολοκλήρωση
|
||||
checkout_now: Ολοκλήρωση τώρα
|
||||
checkout_order_ready: Παραγγελία έτοιμη για
|
||||
@@ -2324,7 +2335,7 @@ el:
|
||||
enterprises_currently_open: "Οι παραγγελίες είναι προς το παρόν ανοιχτές"
|
||||
enterprises_ready_for: "Έτοιμος για"
|
||||
enterprises_choose: "Επιλέξτε πότε θέλετε την παραγγελία σας:"
|
||||
maps_open: "Ανοιξε"
|
||||
maps_open: "Άνοιγμα"
|
||||
maps_closed: "Κλειστό"
|
||||
map_title: "Χάρτης"
|
||||
hubs_buy: "Ψώνια για:"
|
||||
@@ -2764,9 +2775,9 @@ el:
|
||||
admin_enterprise_groups_contact_country_id: "Χώρα"
|
||||
admin_enterprise_groups_web_twitter: "π.χ. @the_prof"
|
||||
admin_enterprise_groups_web_website_placeholder: "π.χ. www.fresh-food-supplier.gr"
|
||||
admin_order_cycles: "Κύκλοι παραγγελίας διαχειριστή"
|
||||
open: "Ανοιξε"
|
||||
close: "Κλείσιμο"
|
||||
admin_order_cycles: "Κύκλοι παραγγελιών διαχειριστή"
|
||||
open: "Έναρξη"
|
||||
close: "Λήξη"
|
||||
create: "Δημιουργία"
|
||||
search: "Αναζήτηση"
|
||||
supplier: "Προμηθευτής"
|
||||
@@ -2796,7 +2807,7 @@ el:
|
||||
flexible_rate: "Ευέλικτο ποσοστό"
|
||||
price_sack: "Price Sack"
|
||||
new_order_cycles: "Κύκλοι νέας παραγγελίας"
|
||||
new_order_cycle: "Κύκλος νέας παραγγελίας"
|
||||
new_order_cycle: "Νέος κύκλος παραγγελίας"
|
||||
new_order_cycle_tooltip: "Ανοίξτε το κατάστημα για μια ορισμένη χρονική περίοδο"
|
||||
select_a_coordinator_for_your_order_cycle: "Επιλέξτε έναν συντονιστή για τον κύκλο παραγγελιών σας"
|
||||
notify_producers: 'Ειδοποιήστε τους παραγωγούς'
|
||||
@@ -2823,14 +2834,14 @@ el:
|
||||
no_products: Χωρίς Προϊόντα
|
||||
spree_admin_overview_enterprises_header: "Οι Επιχειρήσεις μου"
|
||||
spree_admin_overview_enterprises_footer: "ΔΙΑΧΕΙΡΙΣΤΕ ΤΙΣ ΕΠΙΧΕΙΡΗΣΕΙΣ ΜΟΥ"
|
||||
spree_admin_enterprises_hubs_name: "Όνονα"
|
||||
spree_admin_enterprises_hubs_name: "Όνομα"
|
||||
spree_admin_enterprises_create_new: "ΔΗΜΙΟΥΡΓΗΣΤΕ ΝΕΟ"
|
||||
spree_admin_enterprises_shipping_methods: "Τρόποι αποστολής"
|
||||
spree_admin_enterprises_fees: "Αμοιβή επιχείρησης"
|
||||
spree_admin_enterprises_none_create_a_new_enterprise: "ΔΗΜΙΟΥΡΓΗΣΤΕ ΝΕΑ ΕΠΙΧΕΙΡΗΣΗ"
|
||||
spree_admin_enterprises_none_text: "Δεν έχετε ακόμη επιχειρήσεις"
|
||||
spree_admin_enterprises_tabs_hubs: "HUBS"
|
||||
spree_admin_enterprises_producers_manage_products: "ΔΙΑΧΕΙΡΙΣΗ ΠΡΟDΟΝΤΩΝ"
|
||||
spree_admin_enterprises_producers_manage_products: "Διαχείριση προϊόντων"
|
||||
spree_admin_enterprises_create_new_product: "ΔΗΜΙΟΥΡΓΗΣΤΕ ΝΕΟ ΠΡΟDΟΝ"
|
||||
spree_admin_single_enterprise_alert_mail_confirmation: "Παρακαλώ επιβεβαιώστε τη διεύθυνση email για"
|
||||
spree_admin_single_enterprise_alert_mail_sent: "Έχουμε στείλει ένα email στο"
|
||||
@@ -2856,17 +2867,17 @@ el:
|
||||
spree_distributors_error: "Πρέπει να επιλεγεί τουλάχιστον ένας κόμβος"
|
||||
spree_user_enterprise_limit_error: "^%{email} δεν επιτρέπεται να κατέχει άλλες επιχειρήσεις (το όριο είναι %{enterprise_limit})."
|
||||
spree_variant_product_error: πρέπει να έχει τουλάχιστον μία παραλλαγή
|
||||
your_profil_live: "Το προφίλ σας ζωντανά"
|
||||
see: "Βλέπω"
|
||||
live: "ζω"
|
||||
manage: "Διαχείρηση"
|
||||
your_profil_live: "Προφίλ καταστήματος"
|
||||
see: "ΕΜΦΑΝΙΣΗ"
|
||||
live: " "
|
||||
manage: "Διαχείριση"
|
||||
resend: "Ξαναστείλτε"
|
||||
add_and_manage_products: "Προσθήκη και διαχείριση προϊόντων"
|
||||
add_and_manage_order_cycles: "Προσθήκη & διαχείριση κύκλων παραγγελίας"
|
||||
add_and_manage_order_cycles: "Προσθήκη & διαχείριση κύκλων παραγγελίας"
|
||||
manage_order_cycles: "Διαχείριση κύκλων παραγγελίας"
|
||||
manage_products: "Διαχειριστείτε προϊόντα"
|
||||
manage_products: "Διαχείριση προϊόντων"
|
||||
edit_profile_details: "Επεξεργασία στοιχείων προφίλ"
|
||||
edit_profile_details_etc: "Αλλάξτε την περιγραφή του προφίλ σας, εικόνες κ.λπ."
|
||||
edit_profile_details_etc: "Αλλάξτε την περιγραφή του καταστήματός σας, εικόνες κ.λ.π."
|
||||
order_cycle: "Κύκλος Παραγγελειών"
|
||||
enterprise_relationships: "Δικαιώματα επιχείρησης"
|
||||
first_name_begins_with: "Το όνομα αρχίζει με"
|
||||
@@ -2886,12 +2897,13 @@ el:
|
||||
admin_share_state: "Πόλη"
|
||||
hub_sidebar_hubs: "Σημείο Συλλογής "
|
||||
hub_sidebar_none_available: "Κανένα διαθέσιμο"
|
||||
hub_sidebar_manage: "Διαχείρηση"
|
||||
hub_sidebar_manage: "Διαχείριση"
|
||||
hub_sidebar_at_least: "Πρέπει να επιλεγεί τουλάχιστον ένας κόμβος"
|
||||
hub_sidebar_blue: "μπλε"
|
||||
hub_sidebar_red: "το κόκκινο"
|
||||
order_cycles_closed_for_hub: "Ο κόμβος που επιλέξατε είναι προσωρινά κλειστός για παραγγελίες. Παρακαλώ προσπαθήστε ξανά αργότερα."
|
||||
report_customers_distributor: "Διανομέας"
|
||||
report_customers_hub: "Κεντρικό σημείο"
|
||||
report_customers_supplier: "Προμηθευτής"
|
||||
report_customers_cycle: "Κύκλος Παραγγελειών"
|
||||
report_customers_type: "Τύπος αναφοράς"
|
||||
@@ -3502,6 +3514,7 @@ el:
|
||||
Αυτό θα θέσει το επίπεδο αποθέματος σε μηδέν για όλα τα προϊόντα αυτής της
|
||||
επιχείρησης που δεν υπάρχουν στο ανεβασμένο αρχείο.
|
||||
order_cycles:
|
||||
unsaved_changes: "Έχετε μη αποθηκευμένες αλλαγές"
|
||||
create_failure: "Η δημιουργία κύκλου παραγγελίας απέτυχε"
|
||||
update_success: 'Ο κύκλος παραγγελιών σας ενημερώθηκε.'
|
||||
update_failure: "Η ενημέρωση του κύκλου παραγγελίας απέτυχε"
|
||||
@@ -3677,7 +3690,7 @@ el:
|
||||
import_date: "Ημερομηνία εισαγωγής"
|
||||
delivery: "Διανομή"
|
||||
temperature_controlled: "Ελεγχόμενη θερμοκρασία"
|
||||
new_product: "Καινουργιο ΠΡΟΪΟΝ"
|
||||
new_product: "Καινούργιο προϊόν"
|
||||
administration: "Διαχείριση"
|
||||
logged_in_as: "Συνδεδεμένος ως"
|
||||
account: "Λογαριασμός"
|
||||
@@ -3744,10 +3757,6 @@ el:
|
||||
delivery: "Υπογράφηκε, σφραγίστηκε, παραδόθηκε"
|
||||
start_date: "Ημερομηνία έναρξης"
|
||||
successfully_removed: "Καταργήθηκε επιτυχώς"
|
||||
taxonomy_edit: "Επεξεργασία ταξινόμησης"
|
||||
taxonomy_tree_error: "Παρουσιάστηκε σφάλμα κατά την ενημέρωση του δέντρου ταξονομίας. "
|
||||
taxonomy_tree_instruction: "Κάντε δεξί κλικ σε ένα αντικείμενο για να προσθέσετε, μετονομάσετε, αφαιρέσετε ή επεξεργαστείτε."
|
||||
tree: "Δέντρο"
|
||||
updating: "Ενημέρωση"
|
||||
your_order_is_empty_add_product: "Η παραγγελία σας είναι κενή, αναζητήστε και προσθέστε ένα προϊόν παραπάνω"
|
||||
add_product: "Προσθήκη Προϊόντος"
|
||||
@@ -3863,9 +3872,7 @@ el:
|
||||
abbreviation: "Συντομογραφία"
|
||||
new_state: "Νέα Πολιτεία"
|
||||
payment_methods: "τρόποι πληρωμής"
|
||||
taxonomies: "Ταξινομίες"
|
||||
new_taxonomy: "Νέα Ταξινομία"
|
||||
back_to_taxonomies_list: "Επιστροφή στη λίστα ταξινομιών"
|
||||
taxons: "Κατηγορίες προϊόντος"
|
||||
shipping_methods: "Τρόποι αποστολής"
|
||||
shipping_method: "Τρόπος Αποστολής"
|
||||
shipment: "Αποστολή"
|
||||
@@ -4234,8 +4241,8 @@ el:
|
||||
image_upload_error: "Παρακαλώ ανεβάστε την εικόνα σε τύπο αρχείου JPG, PNG, GIF, SVG ή WEBP."
|
||||
image_not_processable: "Η συνημμένη εικόνα δεν υποστηρίζεται."
|
||||
new:
|
||||
title: "Καινουργιο ΠΡΟΪΟΝ"
|
||||
new_product: "Καινουργιο ΠΡΟΪΟΝ"
|
||||
title: "Καινούργιο προϊόν"
|
||||
new_product: "Καινούργιο προϊόν"
|
||||
supplier: "Προμηθευτής"
|
||||
supplier_select_placeholder: "Διαλέξτε ένα προμηθευτή"
|
||||
product_name: "Ονομασία προϊόντος"
|
||||
@@ -4348,9 +4355,10 @@ el:
|
||||
total: "Σύνολο"
|
||||
billing_address_name: "Όνομα"
|
||||
taxons:
|
||||
index:
|
||||
title: "Κατηγορίες προϊόντος"
|
||||
form:
|
||||
name: Όνομα
|
||||
permalink: Permalink
|
||||
meta_title: Τίτλος Meta
|
||||
meta_description: Περιγραφή Meta
|
||||
meta_keywords: Λέξεις-κλειδιά Meta
|
||||
|
||||
@@ -68,7 +68,7 @@ en:
|
||||
spree/product:
|
||||
name: "Product Name"
|
||||
price: "Price"
|
||||
primary_taxon: "Product Category"
|
||||
primary_taxon_id: "Product Category"
|
||||
shipping_category_id: "Shipping Category"
|
||||
variant_unit: "Variant Unit"
|
||||
variant_unit_name: "Variant Unit Name"
|
||||
@@ -120,6 +120,8 @@ en:
|
||||
attributes:
|
||||
base:
|
||||
card_expired: "has expired"
|
||||
spree/product:
|
||||
must_exist: 'must exist'
|
||||
order_cycle:
|
||||
attributes:
|
||||
orders_close_at:
|
||||
@@ -683,6 +685,8 @@ en:
|
||||
terms_of_service_have_been_updated_html: "Open Food Network's Terms of Service have been updated: %{tos_link}"
|
||||
terms_of_service: Read Terms of Service
|
||||
accept_terms_of_service: Accept Terms of Service
|
||||
|
||||
# Pages
|
||||
shopfront_settings:
|
||||
embedded_shopfront_settings: "Embedded Shopfront Settings"
|
||||
enable_embedded_shopfronts: "Enable Embedded Shopfronts"
|
||||
@@ -739,6 +743,17 @@ en:
|
||||
config_instructions_html: "Here you can configure the OFN Matomo integration. The Matomo URL below should point to the Matomo instance where the user tracking information will be sent to; if it is left empty, Matomo user tracking will be disabled. The Site ID field is not mandatory but useful if you are tracking more than one website on a single Matomo instance; it can be found on the Matomo instance console."
|
||||
config_instructions_tag_manager_html: "Setting the Matomo Tag Manager URL enables Matomo Tag Manager. This tool allows you to set up analytics events. The Matomo Tag Manager URL is copied from the Install Code section of Matomo Tag Manager. Ensure you select the right container and environment as these options change the URL."
|
||||
|
||||
connected_app_settings:
|
||||
edit:
|
||||
title: "Connected app settings"
|
||||
info_html: "Enabled apps will appear under Enterprise Settings > Connected Apps."
|
||||
enabled_legend: "Enabled connected apps"
|
||||
connected_apps_enabled:
|
||||
discover_regen: Discover Regenerative portal
|
||||
affiliate_sales_data: DFC anonymised orders API for research purposes
|
||||
update:
|
||||
resource: Connected app settings
|
||||
|
||||
customers:
|
||||
index:
|
||||
new_customer: "New Customer"
|
||||
@@ -868,8 +883,10 @@ en:
|
||||
filters:
|
||||
search_products: Search for products
|
||||
search_for_producers: Search for producers
|
||||
select_producer: Select producer
|
||||
all_producers: All producers
|
||||
search_for_categories: Search for categories
|
||||
select_category: Select category
|
||||
all_categories: All categories
|
||||
producers:
|
||||
label: Producers
|
||||
@@ -1358,28 +1375,45 @@ en:
|
||||
custom_tab_content: "Content for custom tab"
|
||||
connected_apps:
|
||||
legend: "Connected apps"
|
||||
title: "Discover Regenerative"
|
||||
tagline: "Allow Discover Regenerative to publish your enterprise information."
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
loading: "Loading"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
note: |
|
||||
Your Open Food Network account is connected to Discover Regenerative.
|
||||
Add or update information on your Discover Regenerative listing here.
|
||||
link_label: "Manage listing"
|
||||
description_html: |
|
||||
<p>
|
||||
Eligible producers can showcase their regenerative credentials,
|
||||
farming practices and more through a profile listing.
|
||||
Simplifying how buyers can find regenerative produce and connect
|
||||
with producers of interest.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://about.openfoodnetwork.org.au/regen-produce-portal/"
|
||||
target="_blank"><b>Learn more about Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
affiliate_sales_data:
|
||||
title: "INRAE / UFC QUE CHOISIR Research"
|
||||
tagline: "Allow this research project to access your orders data anonymously"
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
loading: "Loading"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
description_html: |
|
||||
<p>
|
||||
INRAE and UFC QUE CHOISIR are teaming up to study food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://apropos.coopcircuits.fr/"
|
||||
target="_blank"><b>Learn more about this research project</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
discover_regen:
|
||||
title: "Discover Regenerative"
|
||||
tagline: "Allow Discover Regenerative to publish your enterprise information."
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
loading: "Loading"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
note: |
|
||||
Your Open Food Network account is connected to Discover Regenerative.
|
||||
Add or update information on your Discover Regenerative listing here.
|
||||
link_label: "Manage listing"
|
||||
description_html: |
|
||||
<p>
|
||||
Eligible producers can showcase their regenerative credentials,
|
||||
farming practices and more through a profile listing.
|
||||
Simplifying how buyers can find regenerative produce and connect
|
||||
with producers of interest.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://about.openfoodnetwork.org.au/regen-produce-portal/"
|
||||
target="_blank"><b>Learn more about Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
actions:
|
||||
edit_profile: Settings
|
||||
properties: Properties
|
||||
@@ -1472,6 +1506,11 @@ en:
|
||||
choose_products_from: "Choose Products From:"
|
||||
re_notify_producers: Re notify producers
|
||||
notify_producers_tip: This will send an email to each producer with the list of their orders.
|
||||
date_time_warning_modal_content:
|
||||
title: 'Orders are linked to this order cycle.'
|
||||
content: 'If you wish to create a new order cycle, it is recommended to duplicate the order cycle first and then change the dates.'
|
||||
proceed: 'Proceed anyway'
|
||||
cancel: 'Cancel'
|
||||
incoming:
|
||||
incoming: "Incoming"
|
||||
supplier: "Supplier"
|
||||
@@ -3664,6 +3703,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
This will set stock level to zero on all products for this
|
||||
enterprise that are not present in the uploaded file.
|
||||
order_cycles:
|
||||
unsaved_changes: "You have unsaved changes"
|
||||
create_failure: "Failed to create order cycle"
|
||||
update_success: 'Your order cycle has been updated.'
|
||||
update_failure: "Failed to update order cycle"
|
||||
@@ -3925,10 +3965,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
delivery: "Signed, sealed, delivered"
|
||||
start_date: "Start date"
|
||||
successfully_removed: "Successfully Removed"
|
||||
taxonomy_edit: "Taxonomy edit"
|
||||
taxonomy_tree_error: "There was an error updating the taxonomy tree."
|
||||
taxonomy_tree_instruction: "Right-click on an item to add, rename, remove or edit."
|
||||
tree: "Tree"
|
||||
updating: "Updating"
|
||||
your_order_is_empty_add_product: "Your order is empty, please search for and add a product above"
|
||||
add_product: "Add Product"
|
||||
@@ -4052,10 +4088,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
new_state: "New State"
|
||||
|
||||
payment_methods: "Payment Methods"
|
||||
|
||||
taxonomies: "Taxonomies"
|
||||
new_taxonomy: "New Taxonomy"
|
||||
back_to_taxonomies_list: "Back to Taxonomies List"
|
||||
taxons: "Product Categories"
|
||||
|
||||
shipping_methods: "Shipping Methods"
|
||||
shipping_method: "Shipping Method"
|
||||
@@ -4548,9 +4581,20 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
total: "Total"
|
||||
billing_address_name: "Name"
|
||||
taxons:
|
||||
back_to_list: "Back to Product Categeory List"
|
||||
index:
|
||||
title: "Product Categories"
|
||||
new_taxon: 'New product category'
|
||||
new:
|
||||
title: "New Product Category"
|
||||
edit:
|
||||
title: "Edit Product Category"
|
||||
destroy:
|
||||
delete_taxon:
|
||||
success: "Successfully deleted the product category"
|
||||
error: "Unable to delete the product category"
|
||||
form:
|
||||
name: Name
|
||||
permalink: Permalink
|
||||
meta_title: Meta Title
|
||||
meta_description: Meta Description
|
||||
meta_keywords: Meta Keywords
|
||||
|
||||
@@ -28,7 +28,7 @@ en_AU:
|
||||
spree/product:
|
||||
name: "Product Name"
|
||||
price: "Price"
|
||||
primary_taxon: "Product Category"
|
||||
primary_taxon_id: "Product Category"
|
||||
shipping_category_id: "Shipping Category"
|
||||
variant_unit: "Variant Unit"
|
||||
variant_unit_name: "Variant Unit Name"
|
||||
@@ -943,16 +943,19 @@ en_AU:
|
||||
customers: Customer
|
||||
active: Active?
|
||||
connected_apps:
|
||||
tagline: "By clicking ‘Allow data sharing’, you are sharing data between Open Food Network and the Discover Regenerative Portal, and agreeing to make specific data public on the Portal, which will also be publicly available on the API.\nIMPORTANT: Before you stop sharing and remove your listing, please first contact hello@regenerative.org.au to request a copy of your Discover Regenerative data."
|
||||
loading: "Loading"
|
||||
description_html: |
|
||||
<p>
|
||||
Discover Regenerative is a showcase of Australia’s Regenerative Farmers, their produce/products, outcomes and achievements. It simplifies how business-to-business (B2B) / wholesale buyers can find regenerative produce and directly connect with Producers.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://regenerative.org.au/" target="_blank"><b>Visit Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
affiliate_sales_data:
|
||||
loading: "Loading"
|
||||
discover_regen:
|
||||
tagline: "By clicking ‘Allow data sharing’, you are sharing data between Open Food Network and the Discover Regenerative Portal, and agreeing to make specific data public on the Portal, which will also be publicly available on the API.\nIMPORTANT: Before you stop sharing and remove your listing, please first contact hello@regenerative.org.au to request a copy of your Discover Regenerative data."
|
||||
loading: "Loading"
|
||||
description_html: |
|
||||
<p>
|
||||
Discover Regenerative is a showcase of Australia’s Regenerative Farmers, their produce/products, outcomes and achievements. It simplifies how business-to-business (B2B) / wholesale buyers can find regenerative produce and directly connect with Producers.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://regenerative.org.au/" target="_blank"><b>Visit Discover Regenerative</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
actions:
|
||||
edit_profile: Settings
|
||||
properties: Properties
|
||||
@@ -1050,6 +1053,8 @@ en_AU:
|
||||
back_to_list: "Back To List"
|
||||
save_and_back_to_list: "Save and Back to List"
|
||||
choose_products_from: "Choose Products From:"
|
||||
date_time_warning_modal_content:
|
||||
cancel: 'Cancel'
|
||||
incoming:
|
||||
incoming: "Incoming"
|
||||
supplier: "Supplier"
|
||||
@@ -2929,6 +2934,7 @@ en_AU:
|
||||
This will set stock level to zero on all products for this
|
||||
enterprise that are not present in the uploaded file.
|
||||
order_cycles:
|
||||
unsaved_changes: "You have unsaved changes"
|
||||
create_failure: "Failed to create order cycle"
|
||||
update_success: 'Your order cycle has been updated.'
|
||||
update_failure: "Failed to update order cycle"
|
||||
@@ -3230,9 +3236,7 @@ en_AU:
|
||||
abbreviation: "Abbreviation"
|
||||
new_state: "New State"
|
||||
payment_methods: "Payment Methods"
|
||||
taxonomies: "Taxonomies"
|
||||
new_taxonomy: "New Taxonomy"
|
||||
back_to_taxonomies_list: "Back to Taxonomies List"
|
||||
taxons: "Product Categories"
|
||||
shipping_methods: "Shipping Methods"
|
||||
shipping_method: "Shipping Method"
|
||||
shipment: "Shipment"
|
||||
@@ -3651,9 +3655,10 @@ en_AU:
|
||||
total: "Total"
|
||||
billing_address_name: "Name"
|
||||
taxons:
|
||||
index:
|
||||
title: "Product Categories"
|
||||
form:
|
||||
name: Name
|
||||
permalink: Permalink
|
||||
description: Description
|
||||
general_settings:
|
||||
edit:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user