mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-16 19:16:49 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6a1021d6e |
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -38,5 +38,6 @@ Add the link or remove this section. -->
|
||||
|
||||
|
||||
#### Documentation updates
|
||||
<!-- Are there any wiki pages that need updating after merging this PR?
|
||||
<!-- Are their any wiki pages that need updating after merging this PR?
|
||||
List them here or remove this section. -->
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ RUN git clone --depth 1 --branch v1.1.2 https://github.com/rbenv/rbenv.git ${RBE
|
||||
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh && \
|
||||
rbenv install $(cat .ruby-version) && \
|
||||
rbenv global $(cat .ruby-version) && \
|
||||
gem install bundler --version=1.17.3
|
||||
gem install bundler --version=1.17.2
|
||||
|
||||
# Install Postgres
|
||||
RUN sh -c "echo 'deb https://apt.postgresql.org/pub/repos/apt/ bionic-pgdg main' > /etc/apt/sources.list.d/pgdg.list" && \
|
||||
|
||||
@@ -509,7 +509,7 @@ GEM
|
||||
pry-byebug (3.7.0)
|
||||
byebug (~> 11.0)
|
||||
pry (~> 0.10)
|
||||
public_suffix (4.0.6)
|
||||
public_suffix (4.0.5)
|
||||
rack (1.5.5)
|
||||
rack-mini-profiler (2.0.2)
|
||||
rack (>= 1.2.0)
|
||||
@@ -658,7 +658,7 @@ GEM
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (5.25.0)
|
||||
stripe (5.22.0)
|
||||
temple (0.8.2)
|
||||
test-unit (3.3.6)
|
||||
power_assert
|
||||
@@ -671,7 +671,7 @@ GEM
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.7.0)
|
||||
unicorn (5.7.0)
|
||||
unicorn (5.6.0)
|
||||
kgio (~> 2.6)
|
||||
raindrops (~> 0.7)
|
||||
unicorn-rails (2.2.1)
|
||||
@@ -687,7 +687,7 @@ GEM
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (>= 1.3.0)
|
||||
selenium-webdriver (>= 3.0, < 4.0)
|
||||
webmock (3.9.1)
|
||||
webmock (3.8.3)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser, ProductFiltersUrl) ->
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
@@ -13,29 +13,37 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
{id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
|
||||
]
|
||||
|
||||
$scope.q = {
|
||||
producerFilter: ""
|
||||
categoryFilter: ""
|
||||
importDateFilter: ""
|
||||
query: ""
|
||||
sorting: ""
|
||||
}
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.producerFilter = ""
|
||||
$scope.categoryFilter = ""
|
||||
$scope.importDateFilter = ""
|
||||
$scope.page = 1
|
||||
$scope.per_page = 15
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.sortOptions = SortOptions
|
||||
|
||||
$scope.initialise = ->
|
||||
$scope.q = ProductFiltersUrl.loadFromUrl($location.search())
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.$watchCollection '[q.query, q.producerFilter, q.categoryFilter, q.importDateFilter, per_page]', ->
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter, per_page]', ->
|
||||
$scope.page = 1 # Reset page when changing filters for new search
|
||||
|
||||
$scope.changePage = (newPage) ->
|
||||
@@ -45,27 +53,25 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.fetchProducts = ->
|
||||
removeClearedValues()
|
||||
params = {
|
||||
'q[name_cont]': $scope.q.query,
|
||||
'q[supplier_id_eq]': $scope.q.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.q.categoryFilter,
|
||||
'q[s]': $scope.q.sorting,
|
||||
import_date: $scope.q.importDateFilter,
|
||||
'q[name_cont]': $scope.query,
|
||||
'q[supplier_id_eq]': $scope.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter,
|
||||
'q[s]': $scope.sorting,
|
||||
import_date: $scope.importDateFilter,
|
||||
page: $scope.page,
|
||||
per_page: $scope.per_page
|
||||
}
|
||||
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
|
||||
# update url with the filters used
|
||||
$location.search(ProductFiltersUrl.generate($scope.q))
|
||||
$scope.resetProducts()
|
||||
|
||||
removeClearedValues = ->
|
||||
delete $scope.q.producerFilter if $scope.q.producerFilter == "0"
|
||||
delete $scope.q.categoryFilter if $scope.q.categoryFilter == "0"
|
||||
delete $scope.q.importDateFilter if $scope.q.importDateFilter == "0"
|
||||
delete $scope.producerFilter if $scope.producerFilter == "0"
|
||||
delete $scope.categoryFilter if $scope.categoryFilter == "0"
|
||||
delete $scope.importDateFilter if $scope.importDateFilter == "0"
|
||||
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.q.importDateFilter = $scope.importDates[1].id
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
@@ -95,10 +101,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.q.query = ""
|
||||
$scope.q.producerFilter = "0"
|
||||
$scope.q.categoryFilter = "0"
|
||||
$scope.q.importDateFilter = "0"
|
||||
$scope.query = ""
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.$watch 'sortOptions', (sort) ->
|
||||
@@ -116,7 +122,8 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if confirm_unsaved_changes()
|
||||
$window.location.href = ProductFiltersUrl.buildUrl(editProductUrl(product, variant), $scope.q)
|
||||
window.open(editProductUrl(product, variant), "_blank")
|
||||
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
@@ -213,10 +220,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters:
|
||||
'q[name_cont]': $scope.q.query
|
||||
'q[supplier_id_eq]': $scope.q.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.q.categoryFilter
|
||||
import_date: $scope.q.importDateFilter
|
||||
'q[name_cont]': $scope.query
|
||||
'q[supplier_id_eq]': $scope.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter
|
||||
import_date: $scope.importDateFilter
|
||||
page: $scope.page
|
||||
per_page: $scope.per_page
|
||||
).success((data) ->
|
||||
|
||||
@@ -5,10 +5,5 @@ angular.module("ofn.admin").directive "ofnSelect2MinSearch", ->
|
||||
minimumResultsForSearch: attrs.ofnSelect2MinSearch
|
||||
|
||||
ngModel.$formatters.push (value) ->
|
||||
# select2 populates options with a value like "number:3" or "string:category" but
|
||||
# select2('val', value) doesn't do the type conversion for us as one would expect
|
||||
if isNaN(value)
|
||||
element.select2('val', "string:#{value}")
|
||||
else
|
||||
element.select2('val', "number:#{value}")
|
||||
|
||||
if (value)
|
||||
element.select2('val', value);
|
||||
@@ -69,24 +69,25 @@ angular.module("admin.enterprises")
|
||||
$scope.newUser = $scope.invite_errors = $scope.invite_success = null
|
||||
|
||||
$scope.removeLogo = ->
|
||||
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")
|
||||
return unless confirm(t("admin.enterprises.remove_logo.immediate_removal_warning"))
|
||||
|
||||
$scope.removePromoImage = ->
|
||||
$scope.performEnterpriseAction("removePromoImage", "immediate_promo_image_removal_warning", "removed_promo_image_successfully")
|
||||
|
||||
$scope.removeTermsAndConditions = ->
|
||||
$scope.performEnterpriseAction("removeTermsAndConditions", "immediate_terms_and_conditions_removal_warning", "removed_terms_and_conditions_successfully")
|
||||
|
||||
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
|
||||
return unless confirm($scope.translation(warning_message_key))
|
||||
|
||||
Enterprises[enterpriseActionName]($scope.Enterprise).then (data) ->
|
||||
Enterprises.removeLogo($scope.Enterprise).then (data) ->
|
||||
$scope.Enterprise = angular.copy(data)
|
||||
$scope.$emit("enterprise:updated", $scope.Enterprise)
|
||||
StatusMessage.display("success", $scope.translation(success_message_key))
|
||||
|
||||
StatusMessage.display("success", t("admin.enterprises.remove_logo.removed_successfully"))
|
||||
, (response) ->
|
||||
if response.data.error?
|
||||
StatusMessage.display("failure", response.data.error)
|
||||
|
||||
$scope.translation = (key) ->
|
||||
t('js.admin.enterprises.form.images.' + key)
|
||||
$scope.removePromoImage = ->
|
||||
return unless confirm(t("admin.enterprises.remove_promo_image.immediate_removal_warning"))
|
||||
|
||||
Enterprises.removePromoImage($scope.Enterprise).then (data) ->
|
||||
$scope.Enterprise = angular.copy(data)
|
||||
$scope.$emit("enterprise:updated", $scope.Enterprise)
|
||||
|
||||
StatusMessage.display("success", t("admin.enterprises.remove_promo_image.removed_successfully"))
|
||||
, (response) ->
|
||||
if response.data.error?
|
||||
StatusMessage.display("failure", response.data.error)
|
||||
|
||||
@@ -9,19 +9,22 @@ angular.module('admin.orderCycles', ['ngTagsInput', 'admin.indexUtils', 'admin.e
|
||||
$timeout ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
# where attrs.datetimepicker is 'foo.bar.lol'
|
||||
$(element).datetimepicker(
|
||||
Object.assign(
|
||||
window.JQUERY_UI_DATETIME_PICKER_DEFAULTS,
|
||||
{
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply(->
|
||||
element.val(dateText)
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
$(element).datetimepicker
|
||||
dateFormat: 'yy-mm-dd'
|
||||
timeFormat: 'HH:mm'
|
||||
showOn: 'button'
|
||||
controlType: 'select'
|
||||
oneLine: true
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>"
|
||||
buttonImageOnly: true
|
||||
stepMinute: 15
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply(->
|
||||
element.val(dateText)
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
)
|
||||
|
||||
|
||||
.directive 'ofnOnChange', ->
|
||||
(scope, element, attrs) ->
|
||||
|
||||
@@ -53,18 +53,17 @@ angular.module("admin.products").factory "OptionValueNamer", (VariantUnitManager
|
||||
[value, unit_name]
|
||||
|
||||
scale_for_unit_value: ->
|
||||
# Find the largest available and compatible unit where unit_value comes
|
||||
# to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest
|
||||
# available unit.
|
||||
product = @variant.product
|
||||
scales = VariantUnitManager.compatibleUnitScales(product.variant_unit_scale, product.variant_unit)
|
||||
variantUnitValue = @variant.unit_value
|
||||
# Find the largest available unit where unit_value comes to >= 1 when expressed in it.
|
||||
# If there is none available where this is true, use the smallest available unit.
|
||||
unit = ([scale, unit_name] for scale, unit_name of VariantUnitManager.unitNames[@variant.product.variant_unit] when @variant.unit_value / scale >= 1).reduce (unit, [scale, unit_name]) ->
|
||||
if (unit && scale > unit[0]) || !unit?
|
||||
[scale, unit_name]
|
||||
else
|
||||
unit
|
||||
, null
|
||||
if !unit?
|
||||
unit = ([scale, unit_name] for scale, unit_name of VariantUnitManager.unitNames[@variant.product.variant_unit]).reduce (unit, [scale, unit_name]) ->
|
||||
if scale < unit[0] then [scale, unit_name] else unit
|
||||
, [Infinity,""]
|
||||
|
||||
# sets largestScale = last element in filtered scales array
|
||||
[_, ..., largestScale] = (scales.filter (s) -> variantUnitValue / s >= 1)
|
||||
|
||||
if (largestScale)
|
||||
[largestScale, VariantUnitManager.getUnitName(largestScale, product.variant_unit)]
|
||||
else
|
||||
[scales[0], VariantUnitManager.getUnitName(scales[0], product.variant_unit)]
|
||||
unit
|
||||
|
||||
@@ -1,35 +1,17 @@
|
||||
angular.module("admin.products").factory "VariantUnitManager", ->
|
||||
class VariantUnitManager
|
||||
@units:
|
||||
@unitNames:
|
||||
'weight':
|
||||
1.0:
|
||||
name: 'g'
|
||||
system: 'metric'
|
||||
1000.0:
|
||||
name: 'kg'
|
||||
system: 'metric'
|
||||
1000000.0:
|
||||
name: 'T'
|
||||
system: 'metric'
|
||||
453.6:
|
||||
name: 'lb'
|
||||
system: 'imperial'
|
||||
28.35:
|
||||
name: 'oz'
|
||||
system: 'imperial'
|
||||
1.0: 'g'
|
||||
1000.0: 'kg'
|
||||
1000000.0: 'T'
|
||||
'volume':
|
||||
0.001:
|
||||
name: 'mL'
|
||||
system: 'metric'
|
||||
1.0:
|
||||
name: 'L'
|
||||
system: 'metric'
|
||||
1000.0:
|
||||
name: 'kL'
|
||||
system: 'metric'
|
||||
0.001: 'mL'
|
||||
1.0: 'L'
|
||||
1000.0: 'kL'
|
||||
|
||||
@variantUnitOptions: ->
|
||||
options = for unit_type, _ of @units
|
||||
options = for unit_type, scale_with_name of @unitNames
|
||||
for scale in @unitScales(unit_type)
|
||||
name = @getUnitName(scale, unit_type)
|
||||
["#{I18n.t(unit_type)} (#{name})", "#{unit_type}_#{scale}"]
|
||||
@@ -48,16 +30,7 @@ angular.module("admin.products").factory "VariantUnitManager", ->
|
||||
unitScales[0]
|
||||
|
||||
@getUnitName: (scale, unitType) ->
|
||||
if @units[unitType][scale]
|
||||
@units[unitType][scale]['name']
|
||||
else
|
||||
''
|
||||
@unitNames[unitType][scale]
|
||||
|
||||
@unitScales: (unitType) ->
|
||||
(parseFloat(scale) for scale in Object.keys(@units[unitType])).sort (a, b) ->
|
||||
a - b
|
||||
|
||||
@compatibleUnitScales: (scale, unitType) ->
|
||||
scaleSystem = @units[unitType][scale]['system']
|
||||
(parseFloat(scale) for scale, scaleInfo of @units[unitType] when scaleInfo['system'] == scaleSystem).sort (a, b) ->
|
||||
a - b
|
||||
(parseFloat(scale) for scale in Object.keys(@unitNames[unitType])).sort()
|
||||
|
||||
@@ -14,7 +14,4 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
|
||||
'removePromoImage':
|
||||
url: '/api/enterprises/:id/promo_image.json'
|
||||
method: 'DELETE'
|
||||
'removeTermsAndConditions':
|
||||
url: '/api/enterprises/:id/terms_and_conditions.json'
|
||||
method: 'DELETE'
|
||||
})
|
||||
|
||||
@@ -52,4 +52,3 @@ angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource
|
||||
|
||||
removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo)
|
||||
removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage)
|
||||
removeTermsAndConditions: performActionOnEnterpriseResource(EnterpriseResource.removeTermsAndConditions)
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
angular.module("ofn.admin").factory "ProductFiltersUrl", ($httpParamSerializer) ->
|
||||
new class ProductFiltersUrl
|
||||
productFilters: ['producerFilter', 'categoryFilter', 'query', 'sorting', 'importDateFilter']
|
||||
|
||||
loadFromUrl: (filters) ->
|
||||
loadedFilters = {}
|
||||
for filter in @productFilters
|
||||
loadedFilters[filter] = if filters[filter] then filters[filter] else ""
|
||||
|
||||
loadedFilters
|
||||
|
||||
generate: (ctrlFilters) ->
|
||||
filters = {}
|
||||
for filter in @productFilters
|
||||
filters[filter] = ctrlFilters[filter] if ctrlFilters[filter]
|
||||
|
||||
filters
|
||||
|
||||
buildUrl: (baseUrl, ctrlFilters) ->
|
||||
filterUrl = $httpParamSerializer(@generate(ctrlFilters))
|
||||
filterUrl = "?#{filterUrl}" if filterUrl isnt ""
|
||||
|
||||
"#{baseUrl}#{filterUrl}"
|
||||
@@ -1,17 +1,27 @@
|
||||
var update_state = function(region) {
|
||||
var country = $('span#' + region + 'country .select2').select2('val');
|
||||
var state_select = $('span#' + region + 'state select.select2');
|
||||
|
||||
$.get(Spree.routes.states_search + "?country_id=" + country, function(states) {
|
||||
state_select.html('');
|
||||
var states_with_blank = [{name: '', id: ''}].concat(states);
|
||||
$.each(states_with_blank, function(pos,state) {
|
||||
var opt = $(document.createElement('option'))
|
||||
.attr('value', state.id)
|
||||
.html(state.name);
|
||||
state_select.append(opt);
|
||||
});
|
||||
state_select.prop("disabled", false).show();
|
||||
state_select.select2();
|
||||
var state_select = $('span#' + region + 'state select.select2');
|
||||
var state_input = $('span#' + region + 'state input.state_name');
|
||||
|
||||
$.get(Spree.routes.states_search + "?country_id=" + country, function(data) {
|
||||
var states = data["states"]
|
||||
if (states.length > 0) {
|
||||
state_select.html('');
|
||||
var states_with_blank = [{name: '', id: ''}].concat(states);
|
||||
$.each(states_with_blank, function(pos,state) {
|
||||
var opt = $(document.createElement('option'))
|
||||
.attr('value', state.id)
|
||||
.html(state.name);
|
||||
state_select.append(opt);
|
||||
});
|
||||
state_select.prop("disabled", false).show();
|
||||
state_select.select2();
|
||||
state_input.hide().prop("disabled", true);
|
||||
|
||||
} else {
|
||||
state_input.prop("disabled", false).show();
|
||||
state_select.select2('destroy').hide();
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
$(document).ready(function() {
|
||||
var order_use_billing_input = $('input#order_use_billing');
|
||||
|
||||
var order_use_billing = function () {
|
||||
if (!order_use_billing_input.is(':checked')) {
|
||||
$('#shipping').show();
|
||||
} else {
|
||||
$('#shipping').hide();
|
||||
}
|
||||
};
|
||||
|
||||
order_use_billing_input.click(function() {
|
||||
order_use_billing();
|
||||
});
|
||||
|
||||
order_use_billing();
|
||||
});
|
||||
@@ -1,30 +1,22 @@
|
||||
$(document).ready(function(){
|
||||
window.JQUERY_UI_DATE_PICKER_DEFAULTS = {
|
||||
dateFormat: Spree.translations.date_picker,
|
||||
$(document).ready(function() {
|
||||
$('.datetimepicker').datetimepicker({
|
||||
dateFormat: 'yy-mm-dd',
|
||||
timeFormat: 'HH:mm',
|
||||
dayNames: Spree.translations.abbr_day_names,
|
||||
dayNamesMin: Spree.translations.abbr_day_names,
|
||||
monthNames: Spree.translations.month_names,
|
||||
prevText: Spree.translations.previous,
|
||||
nextText: Spree.translations.next,
|
||||
oneLine: true,
|
||||
showOn: 'button',
|
||||
controlType: 'select',
|
||||
oneLine: true,
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>",
|
||||
buttonImageOnly: true
|
||||
}
|
||||
buttonImageOnly: true,
|
||||
stepMinute: 15
|
||||
});
|
||||
});
|
||||
|
||||
window.JQUERY_UI_DATETIME_PICKER_DEFAULTS = Object.assign(
|
||||
{},
|
||||
window.JQUERY_UI_DATE_PICKER_DEFAULTS,
|
||||
{
|
||||
currentText: Spree.translations.datetime_ui_current_text,
|
||||
closeText: Spree.translations.datetime_ui_close_text,
|
||||
timeText: Spree.translations.datetime_ui_time_text,
|
||||
timeFormat: 'HH:mm',
|
||||
controlType: 'select',
|
||||
stepMinute: 15
|
||||
}
|
||||
);
|
||||
$('.datetimepicker').datetimepicker(window.JQUERY_UI_DATETIME_PICKER_DEFAULTS);
|
||||
$(document).ready(function(){
|
||||
$('a.close').click(function(event){
|
||||
event.preventDefault();
|
||||
$(this).parent().slideUp(250);
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
@import "../variables";
|
||||
@import "variables";
|
||||
|
||||
span.unavailable,
|
||||
span.available {
|
||||
span.unavailable, span.available {
|
||||
font-weight: bold;
|
||||
|
||||
i {
|
||||
font-size: 150%;
|
||||
}
|
||||
@@ -15,4 +13,4 @@ span.available {
|
||||
|
||||
span.unavailable {
|
||||
color: $warning-red;
|
||||
}
|
||||
}
|
||||
@@ -132,25 +132,3 @@ dl {
|
||||
padding: 40px 0px;
|
||||
color: lighten($color-body-text, 15);
|
||||
}
|
||||
|
||||
.text-normal {
|
||||
font-size: 1rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-big {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: $warning-red;
|
||||
}
|
||||
|
||||
input.text-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.pad-top {
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
20
app/assets/stylesheets/admin/typography.scss
Normal file
20
app/assets/stylesheets/admin/typography.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
@import "variables";
|
||||
|
||||
.text-normal {
|
||||
font-size: 1.0rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-big {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: $warning-red;
|
||||
}
|
||||
|
||||
|
||||
input.text-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
@@ -212,7 +212,7 @@ nav.top-bar {
|
||||
}
|
||||
|
||||
.off-canvas-wrap {
|
||||
overflow: initial;
|
||||
overflow: inherit;
|
||||
}
|
||||
|
||||
.off-canvas-list li.language-switcher ul li {
|
||||
|
||||
@@ -33,6 +33,12 @@ module Api
|
||||
use_renderers :json
|
||||
check_authorization
|
||||
|
||||
# Temporary measure to help debugging strong_parameters
|
||||
rescue_from ActiveModel::ForbiddenAttributesError, with: :print_params
|
||||
def print_params
|
||||
raise ActiveModel::ForbiddenAttributesError, params.to_s
|
||||
end
|
||||
|
||||
def set_jsonp_format
|
||||
return unless params[:callback] && request.get?
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
class StatesController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check
|
||||
|
||||
def index
|
||||
render json: states, each_serializer: Api::StateSerializer, status: :ok
|
||||
end
|
||||
|
||||
def show
|
||||
@state = scope.find(params[:id])
|
||||
render json: @state, serializer: Api::StateSerializer, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scope
|
||||
if params[:country_id]
|
||||
@country = Spree::Country.find(params[:country_id])
|
||||
@country.states
|
||||
else
|
||||
Spree::State.all
|
||||
end
|
||||
end
|
||||
|
||||
def states
|
||||
states = scope.ransack(params[:q]).result.
|
||||
includes(:country).order('name ASC')
|
||||
|
||||
if pagination?
|
||||
states = states.page(params[:page]).per(params[:per_page])
|
||||
end
|
||||
|
||||
states
|
||||
end
|
||||
|
||||
def pagination?
|
||||
params[:page] || params[:per_page]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,18 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
class TermsAndConditionsController < Api::EnterpriseAttachmentController
|
||||
private
|
||||
|
||||
def attachment_name
|
||||
:terms_and_conditions
|
||||
end
|
||||
|
||||
def enterprise_authorize_action
|
||||
case action_name.to_sym
|
||||
when :destroy
|
||||
:remove_terms_and_conditions
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,6 +10,12 @@ class ApplicationController < ActionController::Base
|
||||
include EnterprisesHelper
|
||||
include Spree::AuthenticationHelpers
|
||||
|
||||
# Temporary measure to help debugging strong_parameters
|
||||
rescue_from ActiveModel::ForbiddenAttributesError, with: :print_params
|
||||
def print_params
|
||||
raise ActiveModel::ForbiddenAttributesError, params.to_s
|
||||
end
|
||||
|
||||
def redirect_to(options = {}, response_status = {})
|
||||
::Rails.logger.error("Redirected by #{begin
|
||||
caller(1).first
|
||||
|
||||
@@ -8,55 +8,9 @@ module Spree
|
||||
|
||||
before_action :load_data
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def new
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
render layout: !request.xhr?
|
||||
end
|
||||
|
||||
def create
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
set_viewable
|
||||
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
else
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
set_viewable
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
else
|
||||
respond_with(@object)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
destroy_before
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
end
|
||||
|
||||
redirect_to admin_product_images_url(params[:product_id], @url_filters)
|
||||
end
|
||||
create.before :set_viewable
|
||||
update.before :set_viewable
|
||||
destroy.before :destroy_before
|
||||
|
||||
private
|
||||
|
||||
|
||||
@@ -5,20 +5,6 @@ module Spree
|
||||
before_action :find_properties
|
||||
before_action :setup_property, only: [:index]
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
end
|
||||
# if destroy fails it won't show any errors to the user
|
||||
redirect_to admin_product_product_properties_url(params[:product_id], @url_filters)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_properties
|
||||
|
||||
@@ -10,32 +10,35 @@ module Spree
|
||||
include OrderCyclesHelper
|
||||
include EnterprisesHelper
|
||||
|
||||
create.before :create_before
|
||||
update.before :update_before
|
||||
|
||||
before_action :load_data
|
||||
before_action :load_form_data, only: [:index, :new, :create, :edit, :update]
|
||||
before_action :load_spree_api_key, only: [:index, :variant_overrides]
|
||||
before_action :strip_new_properties, only: [:create, :update]
|
||||
|
||||
respond_override create: { html: {
|
||||
success: lambda {
|
||||
if params[:button] == "add_another"
|
||||
redirect_to new_admin_product_path
|
||||
else
|
||||
redirect_to admin_products_path
|
||||
end
|
||||
},
|
||||
failure: lambda {
|
||||
render :new
|
||||
}
|
||||
} }
|
||||
|
||||
def new
|
||||
@object.shipping_category = DefaultShippingCategory.find_or_create
|
||||
super
|
||||
end
|
||||
|
||||
def create
|
||||
delete_stock_params_and_set_after do
|
||||
if params[:product][:prototype_id].present?
|
||||
@prototype = Spree::Prototype.find(params[:product][:prototype_id])
|
||||
end
|
||||
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
if params[:button] == "add_another"
|
||||
redirect_to new_admin_product_path
|
||||
else
|
||||
redirect_to admin_products_path
|
||||
end
|
||||
else
|
||||
render :new
|
||||
end
|
||||
super
|
||||
end
|
||||
rescue Paperclip::Errors::NotIdentifiedByImageMagickError
|
||||
invoke_callbacks(:create, :fails)
|
||||
@@ -53,24 +56,14 @@ module Spree
|
||||
@show_latest_import = params[:latest_import] || false
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(params)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
original_supplier_id = @product.supplier_id
|
||||
delete_stock_params_and_set_after do
|
||||
params[:product] ||= {} if params[:clear_product_properties]
|
||||
if @object.update(permitted_resource_params)
|
||||
if original_supplier_id != @product.supplier_id
|
||||
ExchangeVariantDeleter.new.delete(@product)
|
||||
end
|
||||
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
if original_supplier_id != @product.supplier_id
|
||||
ExchangeVariantDeleter.new.delete(@product)
|
||||
end
|
||||
redirect_to edit_admin_product_url(@object, @url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,14 +93,6 @@ module Spree
|
||||
redirect_to edit_admin_product_url(@new)
|
||||
end
|
||||
|
||||
def group_buy_options
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def seo
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def find_resource
|
||||
@@ -150,6 +135,19 @@ module Spree
|
||||
@collection
|
||||
end
|
||||
|
||||
def create_before
|
||||
return if params[:product][:prototype_id].blank?
|
||||
|
||||
@prototype = Spree::Prototype.find(params[:product][:prototype_id])
|
||||
end
|
||||
|
||||
def update_before
|
||||
# We only reset the product properties if we're receiving a post from the form on that tab
|
||||
return unless params[:clear_product_properties]
|
||||
|
||||
params[:product] ||= {}
|
||||
end
|
||||
|
||||
def product_includes
|
||||
[{ variants: [:images, { option_values: :option_type }] },
|
||||
{ master: [:images, :default_price] }]
|
||||
|
||||
@@ -4,46 +4,14 @@ module Spree
|
||||
module Admin
|
||||
class VariantsController < ResourceController
|
||||
helper 'spree/products'
|
||||
|
||||
belongs_to 'spree/product', find_by: :permalink
|
||||
new_action.before :new_before
|
||||
|
||||
def index
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def edit
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def update
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
if @object.update(permitted_resource_params)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to edit_admin_product_variant_url(params[:product_id], @object, @url_filters)
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
end
|
||||
|
||||
def create
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
on_demand = params[:variant].delete(:on_demand)
|
||||
on_hand = params[:variant].delete(:on_hand)
|
||||
|
||||
@object.attributes = permitted_resource_params
|
||||
if @object.save
|
||||
flash[:success] = flash_message_for(@object, :successfully_created)
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
else
|
||||
redirect_to new_admin_product_variant_url(params[:product_id], @url_filters)
|
||||
end
|
||||
super
|
||||
|
||||
return unless @object.present? && @object.valid?
|
||||
|
||||
@@ -58,8 +26,6 @@ module Spree
|
||||
end
|
||||
|
||||
def destroy
|
||||
@url_filters = ::ProductFilters.new.extract(request.query_parameters)
|
||||
|
||||
@variant = Spree::Variant.find(params[:id])
|
||||
flash[:success] = if VariantDeleter.new.delete(@variant)
|
||||
Spree.t('notice_messages.variant_deleted')
|
||||
@@ -67,7 +33,9 @@ module Spree
|
||||
Spree.t('notice_messages.variant_not_deleted')
|
||||
end
|
||||
|
||||
redirect_to admin_product_variants_url(params[:product_id], @url_filters)
|
||||
respond_with(@variant) do |format|
|
||||
format.html { redirect_to admin_product_variants_url(params[:product_id]) }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
module BaseHelper
|
||||
# human readable list of variant options
|
||||
# Override: Do not show out of stock text
|
||||
def variant_options(variant, _options = {})
|
||||
variant.options_text
|
||||
end
|
||||
|
||||
# Overriden to eager-load :states
|
||||
def available_countries
|
||||
checkout_zone = Zone.find_by(name: Spree::Config[:checkout_zone])
|
||||
|
||||
@@ -16,10 +21,5 @@ module Spree
|
||||
country
|
||||
end.sort { |a, b| a.name <=> b.name }
|
||||
end
|
||||
|
||||
def pretty_time(time)
|
||||
[I18n.l(time.to_date, format: :long),
|
||||
time.strftime("%l:%M %p")].join(" ")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,19 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'active_support/concern'
|
||||
|
||||
# This concern is used to duplicate the associations distributors and distributor_ids
|
||||
# across payment method and gateway
|
||||
# this fixes the inheritance problem https://github.com/openfoodfoundation/openfoodnetwork/issues/2781
|
||||
module PaymentMethodDistributors
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods',
|
||||
class_name: 'Enterprise',
|
||||
foreign_key: 'payment_method_id',
|
||||
association_foreign_key: 'distributor_id'
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,7 +12,10 @@ class Enterprise < ActiveRecord::Base
|
||||
preference :shopfront_order_cycle_order, :string, default: "orders_close_at"
|
||||
preference :show_customer_names_to_suppliers, :boolean, default: false
|
||||
|
||||
# Allow hubs to restrict visible variants to only those in their inventory
|
||||
# This is hopefully a temporary measure, pending the arrival of multiple named inventories
|
||||
# for shops. We need this here to allow hubs to restrict visible variants to only those in
|
||||
# their inventory if they so choose
|
||||
# TODO: delegate this to a separate model instead of abusing Preferences.
|
||||
preference :product_selection_from_inventory_only, :boolean, default: false
|
||||
|
||||
has_paper_trail only: [:owner_id, :sells], on: [:update]
|
||||
@@ -75,16 +78,10 @@ class Enterprise < ActiveRecord::Base
|
||||
},
|
||||
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
|
||||
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
|
||||
|
||||
validates_attachment_content_type :logo, content_type: %r{\Aimage/.*\Z}
|
||||
validates_attachment_content_type :promo_image, content_type: %r{\Aimage/.*\Z}
|
||||
|
||||
has_attached_file :terms_and_conditions,
|
||||
url: '/files/enterprises/terms_and_conditions/:id/:basename.:extension',
|
||||
path: 'public/files/enterprises/terms_and_conditions/:id/:basename.:extension'
|
||||
validates_attachment_content_type :terms_and_conditions,
|
||||
content_type: "application/pdf",
|
||||
message: I18n.t(:enterprise_terms_and_conditions_type_error)
|
||||
|
||||
include Spree::Core::S3Support
|
||||
supports_s3 :logo
|
||||
supports_s3 :promo_image
|
||||
|
||||
@@ -159,7 +159,7 @@ module ProductImport
|
||||
end
|
||||
|
||||
def unit_fields_validation(entry)
|
||||
unit_types = ['g', 'oz', 'lb', 'kg', 't', 'ml', 'l', 'kl', '']
|
||||
unit_types = ['g', 'kg', 't', 'ml', 'l', 'kl', '']
|
||||
|
||||
unless entry.units&.present?
|
||||
mark_as_invalid(entry, attribute: 'units',
|
||||
|
||||
@@ -32,8 +32,6 @@ module ProductImport
|
||||
{
|
||||
'g' => { scale: 1, unit: 'weight' },
|
||||
'kg' => { scale: 1000, unit: 'weight' },
|
||||
'oz' => { scale: 28.35, unit: 'weight' },
|
||||
'lb' => { scale: 453.6, unit: 'weight' },
|
||||
't' => { scale: 1_000_000, unit: 'weight' },
|
||||
'ml' => { scale: 0.001, unit: 'volume' },
|
||||
'l' => { scale: 1, unit: 'volume' },
|
||||
|
||||
@@ -97,9 +97,7 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
can [:admin, :index, :create], Enterprise
|
||||
can [:read, :edit, :update,
|
||||
:remove_logo, :remove_promo_image, :remove_terms_and_conditions,
|
||||
:bulk_update, :resend_confirmation], Enterprise do |enterprise|
|
||||
can [:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], Enterprise do |enterprise|
|
||||
OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise
|
||||
end
|
||||
can [:welcome, :register], Enterprise do |enterprise|
|
||||
|
||||
@@ -1,162 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Address < ActiveRecord::Base
|
||||
include AddressDisplay
|
||||
|
||||
belongs_to :country, class_name: "Spree::Country"
|
||||
belongs_to :state, class_name: "Spree::State"
|
||||
|
||||
has_one :enterprise, dependent: :restrict_with_exception
|
||||
has_many :shipments
|
||||
|
||||
validates :firstname, :lastname, :address1, :city, :country, presence: true
|
||||
validates :zipcode, presence: true, if: :require_zipcode?
|
||||
validates :phone, presence: true, if: :require_phone?
|
||||
|
||||
validate :state_validate
|
||||
|
||||
after_save :touch_enterprise
|
||||
|
||||
alias_attribute :first_name, :firstname
|
||||
alias_attribute :last_name, :lastname
|
||||
delegate :name, to: :state, prefix: true, allow_nil: true
|
||||
|
||||
geocoded_by :geocode_address
|
||||
|
||||
def self.default
|
||||
country = begin
|
||||
Spree::Country.find(Spree::Config[:default_country_id])
|
||||
rescue StandardError
|
||||
Spree::Country.first
|
||||
end
|
||||
new(country: country)
|
||||
end
|
||||
|
||||
def full_name
|
||||
"#{firstname} #{lastname}".strip
|
||||
end
|
||||
|
||||
def state_text
|
||||
state.try(:abbr) || state.try(:name) || state_name
|
||||
end
|
||||
|
||||
def same_as?(other)
|
||||
return false if other.nil?
|
||||
|
||||
attributes.except('id', 'updated_at', 'created_at') ==
|
||||
other.attributes.except('id', 'updated_at', 'created_at')
|
||||
end
|
||||
|
||||
alias same_as same_as?
|
||||
|
||||
def to_s
|
||||
"#{full_name}: #{address1}"
|
||||
end
|
||||
|
||||
def clone
|
||||
self.class.new(attributes.except('id', 'updated_at', 'created_at'))
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self_attrs = attributes
|
||||
other_attrs = other.respond_to?(:attributes) ? other.attributes : {}
|
||||
|
||||
[self_attrs, other_attrs].each { |attrs|
|
||||
attrs.except!('id', 'created_at', 'updated_at', 'order_id')
|
||||
}
|
||||
|
||||
self_attrs == other_attrs
|
||||
end
|
||||
|
||||
def empty?
|
||||
attributes.except('id', 'created_at', 'updated_at', 'order_id', 'country_id').all? { |_, v|
|
||||
v.nil?
|
||||
}
|
||||
end
|
||||
|
||||
# Generates an ActiveMerchant compatible address hash
|
||||
def active_merchant_hash
|
||||
{
|
||||
name: full_name,
|
||||
address1: address1,
|
||||
address2: address2,
|
||||
city: city,
|
||||
state: state_text,
|
||||
zip: zipcode,
|
||||
country: country.try(:iso),
|
||||
phone: phone
|
||||
}
|
||||
end
|
||||
|
||||
def geocode_address
|
||||
render_address([address1, address2, zipcode, city, country.andand.name, state.andand.name])
|
||||
end
|
||||
|
||||
def full_address
|
||||
render_address([address1, address2, city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
def address_part1
|
||||
render_address([address1, address2])
|
||||
end
|
||||
|
||||
def address_part2
|
||||
render_address([city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def require_phone?
|
||||
true
|
||||
end
|
||||
|
||||
def require_zipcode?
|
||||
true
|
||||
end
|
||||
|
||||
def state_validate
|
||||
# Skip state validation without country (also required)
|
||||
# or when disabled by preference
|
||||
return if country.blank? || !Spree::Config[:address_requires_state]
|
||||
return unless country.states_required
|
||||
|
||||
# Ensure associated state belongs to country
|
||||
if state.present?
|
||||
if state.country == country
|
||||
self.state_name = nil # not required as we have a valid state and country combo
|
||||
elsif state_name.present?
|
||||
self.state = nil
|
||||
else
|
||||
errors.add(:state, :invalid)
|
||||
end
|
||||
end
|
||||
|
||||
# Ensure state_name belongs to country without states,
|
||||
# or that it matches a predefined state name/abbr
|
||||
if state_name.present?
|
||||
if country.states.present?
|
||||
states = country.states.find_all_by_name_or_abbr(state_name)
|
||||
|
||||
if states.size == 1
|
||||
self.state = states.first
|
||||
self.state_name = nil
|
||||
else
|
||||
errors.add(:state, :invalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# ensure at least one state field is populated
|
||||
errors.add :state, :blank if state.blank? && state_name.blank?
|
||||
end
|
||||
|
||||
def touch_enterprise
|
||||
enterprise.andand.touch
|
||||
end
|
||||
|
||||
def render_address(parts)
|
||||
parts.select(&:present?).join(', ')
|
||||
end
|
||||
end
|
||||
end
|
||||
38
app/models/spree/address_decorator.rb
Normal file
38
app/models/spree/address_decorator.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
Spree::Address.class_eval do
|
||||
include AddressDisplay
|
||||
|
||||
has_one :enterprise, dependent: :restrict_with_exception
|
||||
belongs_to :country, class_name: "Spree::Country"
|
||||
|
||||
after_save :touch_enterprise
|
||||
|
||||
geocoded_by :geocode_address
|
||||
|
||||
delegate :name, to: :state, prefix: true, allow_nil: true
|
||||
|
||||
def geocode_address
|
||||
render_address([address1, address2, zipcode, city, country.andand.name, state.andand.name])
|
||||
end
|
||||
|
||||
def full_address
|
||||
render_address([address1, address2, city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
def address_part1
|
||||
render_address([address1, address2])
|
||||
end
|
||||
|
||||
def address_part2
|
||||
render_address([city, zipcode, state.andand.name])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def touch_enterprise
|
||||
enterprise.andand.touch
|
||||
end
|
||||
|
||||
def render_address(parts)
|
||||
parts.select(&:present?).join(', ')
|
||||
end
|
||||
end
|
||||
@@ -1,21 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Classification < ActiveRecord::Base
|
||||
self.table_name = 'spree_products_taxons'
|
||||
belongs_to :product, class_name: "Spree::Product", touch: true
|
||||
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
|
||||
|
||||
before_destroy :dont_destroy_if_primary_taxon
|
||||
|
||||
private
|
||||
|
||||
def dont_destroy_if_primary_taxon
|
||||
return unless product.primary_taxon == taxon
|
||||
|
||||
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name,
|
||||
product: product.name)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/models/spree/classification_decorator.rb
Normal file
15
app/models/spree/classification_decorator.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
Spree::Classification.class_eval do
|
||||
belongs_to :product, class_name: "Spree::Product", touch: true
|
||||
belongs_to :taxon, class_name: "Spree::Taxon", touch: true
|
||||
|
||||
before_destroy :dont_destroy_if_primary_taxon
|
||||
|
||||
private
|
||||
|
||||
def dont_destroy_if_primary_taxon
|
||||
if product.primary_taxon == taxon
|
||||
errors.add :base, I18n.t(:spree_classification_primary_taxon_error, taxon: taxon.name, product: product.name)
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
16
app/models/spree/concerns/payment_method_distributors.rb
Normal file
16
app/models/spree/concerns/payment_method_distributors.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
require 'active_support/concern'
|
||||
|
||||
# This concern is used to duplicate the associations distributors and distributor_ids
|
||||
# across payment method and gateway
|
||||
# this fixes the inheritance problem https://github.com/openfoodfoundation/openfoodnetwork/issues/2781
|
||||
module Spree
|
||||
module PaymentMethodDistributors
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def self.included(base)
|
||||
base.class_eval do
|
||||
has_and_belongs_to_many :distributors, join_table: 'distributors_payment_methods', class_name: 'Enterprise', foreign_key: 'payment_method_id', association_foreign_key: 'distributor_id'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,10 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spree/concerns/payment_method_distributors'
|
||||
|
||||
module Spree
|
||||
class Gateway < PaymentMethod
|
||||
include PaymentMethodDistributors
|
||||
include Spree::PaymentMethodDistributors
|
||||
|
||||
delegate_belongs_to :provider, :authorize, :purchase, :capture, :void, :credit
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
require 'variant_units/variant_and_line_item_naming'
|
||||
require 'open_food_network/variant_and_line_item_naming'
|
||||
|
||||
Spree::LineItem.class_eval do
|
||||
include VariantUnits::VariantAndLineItemNaming
|
||||
include OpenFoodNetwork::VariantAndLineItemNaming
|
||||
include LineItemBasedAdjustmentHandling
|
||||
has_and_belongs_to_many :option_values, join_table: 'spree_option_values_line_items', class_name: 'Spree::OptionValue'
|
||||
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class LogEntry < ActiveRecord::Base
|
||||
belongs_to :source, polymorphic: true
|
||||
|
||||
# Fix for Spree #1767
|
||||
# If a payment fails, we want to make sure we keep the record of it failing
|
||||
after_rollback :save_anyway
|
||||
|
||||
def save_anyway
|
||||
log = Spree::LogEntry.new
|
||||
log.source = source
|
||||
log.details = details
|
||||
log.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -194,6 +194,8 @@ Spree::Order.class_eval do
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
# TODO: perhaps this should be triggered from a controller
|
||||
# rather than an after_save callback?
|
||||
def update_shipping_fees!
|
||||
shipments.each do |shipment|
|
||||
next if shipment.shipped?
|
||||
@@ -220,6 +222,8 @@ Spree::Order.class_eval do
|
||||
end
|
||||
|
||||
# After changing line items of a completed order
|
||||
# TODO: perhaps this should be triggered from a controller
|
||||
# rather than an after_save callback?
|
||||
def update_payment_fees!
|
||||
payments.each do |payment|
|
||||
next if payment.completed?
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spree/concerns/payment_method_distributors'
|
||||
|
||||
module Spree
|
||||
class PaymentMethod < ActiveRecord::Base
|
||||
include Spree::Core::CalculatedAdjustments
|
||||
include PaymentMethodDistributors
|
||||
include Spree::PaymentMethodDistributors
|
||||
|
||||
acts_as_taggable
|
||||
acts_as_paranoid
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Role < ActiveRecord::Base
|
||||
has_and_belongs_to_many :users, join_table: 'spree_roles_users',
|
||||
class_name: Spree.user_class.to_s
|
||||
end
|
||||
end
|
||||
@@ -90,7 +90,7 @@ module Spree
|
||||
end
|
||||
|
||||
def selected_shipping_rate
|
||||
shipping_rates.find_by(selected: true)
|
||||
shipping_rates.where(selected: true).first
|
||||
end
|
||||
|
||||
def selected_shipping_rate_id
|
||||
@@ -294,7 +294,7 @@ module Spree
|
||||
record = true
|
||||
while record
|
||||
random = "H#{Array.new(11) { rand(9) }.join}"
|
||||
record = self.class.find_by(number: random)
|
||||
record = self.class.where(number: random).first
|
||||
end
|
||||
self.number = random
|
||||
end
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingCategory < ActiveRecord::Base
|
||||
validates :name, presence: true
|
||||
has_many :products
|
||||
has_many :shipping_method_categories
|
||||
has_many :shipping_methods, through: :shipping_method_categories
|
||||
end
|
||||
end
|
||||
@@ -1,132 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingMethod < ActiveRecord::Base
|
||||
include Spree::Core::CalculatedAdjustments
|
||||
DISPLAY = [:both, :front_end, :back_end].freeze
|
||||
|
||||
acts_as_taggable
|
||||
|
||||
default_scope -> { where(deleted_at: nil) }
|
||||
|
||||
has_many :shipments
|
||||
has_many :shipping_method_categories
|
||||
has_many :shipping_categories, through: :shipping_method_categories
|
||||
has_many :shipping_rates
|
||||
has_many :distributor_shipping_methods
|
||||
has_many :distributors, through: :distributor_shipping_methods,
|
||||
class_name: 'Enterprise',
|
||||
foreign_key: 'distributor_id'
|
||||
|
||||
has_and_belongs_to_many :zones, join_table: 'spree_shipping_methods_zones',
|
||||
class_name: 'Spree::Zone',
|
||||
foreign_key: 'shipping_method_id'
|
||||
|
||||
validates :name, presence: true
|
||||
validate :distributor_validation
|
||||
validate :at_least_one_shipping_category
|
||||
|
||||
after_save :touch_distributors
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
where(nil)
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)',
|
||||
user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_shipping_methods.*')
|
||||
end
|
||||
}
|
||||
|
||||
scope :for_distributors, ->(distributors) {
|
||||
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
|
||||
where(id: non_unique_matches.map(&:id))
|
||||
}
|
||||
scope :for_distributor, lambda { |distributor|
|
||||
joins(:distributors).
|
||||
where('enterprises.id = ?', distributor)
|
||||
}
|
||||
|
||||
scope :by_name, -> { order('spree_shipping_methods.name ASC') }
|
||||
scope :display_on_checkout, -> {
|
||||
where("spree_shipping_methods.display_on is null OR spree_shipping_methods.display_on = ''")
|
||||
}
|
||||
|
||||
def adjustment_label
|
||||
I18n.t('shipping')
|
||||
end
|
||||
|
||||
# Here we allow checkout with shipping methods without zones (see issue #3928 for details)
|
||||
# and also checkout with addresses outside of the zones of the selected shipping method
|
||||
# This method could be used, like in Spree, to validate shipping method zones on checkout.
|
||||
def include?(address)
|
||||
address.present?
|
||||
end
|
||||
|
||||
def build_tracking_url(tracking)
|
||||
tracking_url.gsub(/:tracking/, tracking) unless tracking.blank? || tracking_url.blank?
|
||||
end
|
||||
|
||||
def self.calculators
|
||||
spree_calculators.__send__ model_name_without_spree_namespace
|
||||
end
|
||||
|
||||
# Some shipping methods are only meant to be set via backend
|
||||
def frontend?
|
||||
display_on != "back_end"
|
||||
end
|
||||
|
||||
def has_distributor?(distributor)
|
||||
distributors.include?(distributor)
|
||||
end
|
||||
|
||||
# Checks whether the shipping method is of delivery type, meaning that it
|
||||
# requires the user to specify a ship address at checkout.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def delivery?
|
||||
require_ship_address
|
||||
end
|
||||
|
||||
# Return the services (pickup, delivery) that different distributors provide, in the format:
|
||||
# {distributor_id => {pickup: true, delivery: false}, ...}
|
||||
def self.services
|
||||
Hash[
|
||||
Spree::ShippingMethod.
|
||||
joins(:distributor_shipping_methods).
|
||||
group('distributor_id').
|
||||
select("distributor_id").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
|
||||
map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] }
|
||||
]
|
||||
end
|
||||
|
||||
def self.on_backend_query
|
||||
"#{table_name}.display_on != 'front_end' OR #{table_name}.display_on IS NULL"
|
||||
end
|
||||
|
||||
def self.on_frontend_query
|
||||
"#{table_name}.display_on != 'back_end' OR #{table_name}.display_on IS NULL"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def at_least_one_shipping_category
|
||||
return unless shipping_categories.empty?
|
||||
|
||||
errors[:base] << "You need to select at least one shipping category"
|
||||
end
|
||||
|
||||
def touch_distributors
|
||||
distributors.each do |distributor|
|
||||
distributor.touch if distributor.persisted?
|
||||
end
|
||||
end
|
||||
|
||||
def distributor_validation
|
||||
validates_with DistributorsValidator
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,8 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingMethodCategory < ActiveRecord::Base
|
||||
belongs_to :shipping_method, class_name: 'Spree::ShippingMethod'
|
||||
belongs_to :shipping_category, class_name: 'Spree::ShippingCategory'
|
||||
end
|
||||
end
|
||||
90
app/models/spree/shipping_method_decorator.rb
Normal file
90
app/models/spree/shipping_method_decorator.rb
Normal file
@@ -0,0 +1,90 @@
|
||||
Spree::ShippingMethod.class_eval do
|
||||
acts_as_taggable
|
||||
|
||||
has_many :distributor_shipping_methods
|
||||
has_many :distributors, through: :distributor_shipping_methods, class_name: 'Enterprise', foreign_key: 'distributor_id'
|
||||
|
||||
after_save :touch_distributors
|
||||
|
||||
validate :distributor_validation
|
||||
|
||||
scope :managed_by, lambda { |user|
|
||||
if user.has_spree_role?('admin')
|
||||
where(nil)
|
||||
else
|
||||
joins(:distributors).
|
||||
where('distributors_shipping_methods.distributor_id IN (?)', user.enterprises.select(&:id)).
|
||||
select('DISTINCT spree_shipping_methods.*')
|
||||
end
|
||||
}
|
||||
|
||||
scope :for_distributors, ->(distributors) {
|
||||
non_unique_matches = unscoped.joins(:distributors).where(enterprises: { id: distributors })
|
||||
where(id: non_unique_matches.map(&:id))
|
||||
}
|
||||
scope :for_distributor, lambda { |distributor|
|
||||
joins(:distributors).
|
||||
where('enterprises.id = ?', distributor)
|
||||
}
|
||||
|
||||
scope :by_name, -> { order('spree_shipping_methods.name ASC') }
|
||||
scope :display_on_checkout, -> { where("spree_shipping_methods.display_on is null OR spree_shipping_methods.display_on = ''") }
|
||||
|
||||
# Return the services (pickup, delivery) that different distributors provide, in the format:
|
||||
# {distributor_id => {pickup: true, delivery: false}, ...}
|
||||
def self.services
|
||||
Hash[
|
||||
Spree::ShippingMethod.
|
||||
joins(:distributor_shipping_methods).
|
||||
group('distributor_id').
|
||||
select("distributor_id").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 'f') AS pickup").
|
||||
select("BOOL_OR(spree_shipping_methods.require_ship_address = 't') AS delivery").
|
||||
map { |sm| [sm.distributor_id.to_i, { pickup: sm.pickup, delivery: sm.delivery }] }
|
||||
]
|
||||
end
|
||||
|
||||
# This method is overriden so that we can remove the restriction added in Spree
|
||||
# Spree restricts shipping method calculators to the ones that inherit from Spree::Shipping::ShippingCalculator
|
||||
# Spree::Shipping::ShippingCalculator makes sure that calculators are able to handle packages and not orders as input
|
||||
# This is not necessary in OFN because calculators in OFN are already customized to work with different types of input
|
||||
def self.calculators
|
||||
spree_calculators.send model_name_without_spree_namespace
|
||||
end
|
||||
|
||||
# This is bypassing the validation of shipping method zones on checkout
|
||||
# It allows checkout using shipping methods without zones (see issue #3928 for details)
|
||||
# and it allows checkout with addresses outside of the zones of the selected shipping method
|
||||
def include?(address)
|
||||
address.present?
|
||||
end
|
||||
|
||||
def has_distributor?(distributor)
|
||||
distributors.include?(distributor)
|
||||
end
|
||||
|
||||
def adjustment_label
|
||||
I18n.t('shipping')
|
||||
end
|
||||
|
||||
# Checks whether the shipping method is of delivery type, meaning that it
|
||||
# requires the user to specify a ship address at checkout. Note this is
|
||||
# a setting we added onto the +spree_shipping_methods+ table.
|
||||
#
|
||||
# @return [Boolean]
|
||||
def delivery?
|
||||
require_ship_address
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def touch_distributors
|
||||
distributors.each do |distributor|
|
||||
distributor.touch if distributor.persisted?
|
||||
end
|
||||
end
|
||||
|
||||
def distributor_validation
|
||||
validates_with DistributorsValidator
|
||||
end
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class ShippingRate < ActiveRecord::Base
|
||||
belongs_to :shipment, class_name: 'Spree::Shipment'
|
||||
belongs_to :shipping_method, class_name: 'Spree::ShippingMethod'
|
||||
|
||||
scope :frontend,
|
||||
-> {
|
||||
includes(:shipping_method).
|
||||
where(ShippingMethod.on_frontend_query).
|
||||
references(:shipping_method).
|
||||
order("cost ASC")
|
||||
}
|
||||
scope :backend,
|
||||
-> {
|
||||
includes(:shipping_method).
|
||||
where(ShippingMethod.on_backend_query).
|
||||
references(:shipping_method).
|
||||
order("cost ASC")
|
||||
}
|
||||
|
||||
delegate :order, :currency, to: :shipment
|
||||
delegate :name, to: :shipping_method
|
||||
|
||||
def display_price
|
||||
price = if Spree::Config[:shipment_inc_vat]
|
||||
(1 + Spree::TaxRate.default) * cost
|
||||
else
|
||||
cost
|
||||
end
|
||||
|
||||
Spree::Money.new(price, { currency: currency })
|
||||
end
|
||||
|
||||
alias_method :display_cost, :display_price
|
||||
end
|
||||
end
|
||||
@@ -1,113 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Taxon < ActiveRecord::Base
|
||||
acts_as_nested_set dependent: :destroy
|
||||
|
||||
belongs_to :taxonomy, class_name: 'Spree::Taxonomy', touch: true
|
||||
has_many :classifications, dependent: :destroy
|
||||
has_many :products, through: :classifications
|
||||
|
||||
before_create :set_permalink
|
||||
|
||||
validates :name, presence: true
|
||||
|
||||
has_attached_file :icon,
|
||||
styles: { mini: '32x32>', normal: '128x128>' },
|
||||
default_style: :mini,
|
||||
url: '/spree/taxons/:id/:style/:basename.:extension',
|
||||
path: ':rails_root/public/spree/taxons/:id/:style/:basename.:extension',
|
||||
default_url: '/assets/default_taxon.png'
|
||||
|
||||
include Spree::Core::S3Support
|
||||
supports_s3 :icon
|
||||
|
||||
# Indicate which filters should be used for this taxon
|
||||
def applicable_filters
|
||||
[]
|
||||
end
|
||||
|
||||
# Return meta_title if set otherwise generates from root name and/or taxon name
|
||||
def seo_title
|
||||
if meta_title
|
||||
meta_title
|
||||
else
|
||||
root? ? name : "#{root.name} - #{name}"
|
||||
end
|
||||
end
|
||||
|
||||
# Creates permalink based on Stringex's .to_url method
|
||||
def set_permalink
|
||||
if parent.present?
|
||||
self.permalink = [parent.permalink, permalink_end].join('/')
|
||||
elsif permalink.blank?
|
||||
self.permalink = name.to_url
|
||||
end
|
||||
end
|
||||
|
||||
# For #2759
|
||||
def to_param
|
||||
permalink
|
||||
end
|
||||
|
||||
def active_products
|
||||
scope = products.active
|
||||
scope
|
||||
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
|
||||
taxons = {}
|
||||
|
||||
Spree::Taxon.
|
||||
joins(products: :supplier).
|
||||
select('spree_taxons.*, enterprises.id AS enterprise_id').
|
||||
each do |t|
|
||||
taxons[t.enterprise_id.to_i] ||= Set.new
|
||||
taxons[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
|
||||
taxons
|
||||
end
|
||||
|
||||
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
|
||||
# May return :all taxons (distributed in open and closed order cycles),
|
||||
# or :current taxons (distributed in an open order cycle).
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons(which_taxons = :all)
|
||||
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
|
||||
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
|
||||
|
||||
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons = Spree::Taxon
|
||||
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id")
|
||||
.joins(products: :variants_including_master)
|
||||
.joins("
|
||||
INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars
|
||||
ON spree_variants.id = ents_and_vars.variant_id")
|
||||
|
||||
taxons.each_with_object({}) do |t, ts|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def permalink_end
|
||||
return name.to_url if permalink.blank?
|
||||
|
||||
permalink.split('/').last
|
||||
end
|
||||
end
|
||||
end
|
||||
47
app/models/spree/taxon_decorator.rb
Normal file
47
app/models/spree/taxon_decorator.rb
Normal file
@@ -0,0 +1,47 @@
|
||||
Spree::Taxon.class_eval do
|
||||
has_many :classifications, dependent: :destroy
|
||||
|
||||
# Indicate which filters should be used for this taxon
|
||||
def applicable_filters
|
||||
fs = []
|
||||
# fs << Spree::ProductFilters.distributor_filter if Spree::ProductFilters.respond_to? :distributor_filter
|
||||
fs
|
||||
end
|
||||
|
||||
# Find all the taxons of supplied products for each enterprise, indexed by enterprise.
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.supplied_taxons
|
||||
taxons = {}
|
||||
|
||||
Spree::Taxon.
|
||||
joins(products: :supplier).
|
||||
select('spree_taxons.*, enterprises.id AS enterprise_id').
|
||||
each do |t|
|
||||
taxons[t.enterprise_id.to_i] ||= Set.new
|
||||
taxons[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
|
||||
taxons
|
||||
end
|
||||
|
||||
# Find all the taxons of distributed products for each enterprise, indexed by enterprise.
|
||||
# May return :all taxons (distributed in open and closed order cycles),
|
||||
# or :current taxons (distributed in an open order cycle).
|
||||
#
|
||||
# Format: {enterprise_id => [taxon_id, ...]}
|
||||
def self.distributed_taxons(which_taxons = :all)
|
||||
ents_and_vars = ExchangeVariant.joins(exchange: :order_cycle).merge(Exchange.outgoing)
|
||||
.select("DISTINCT variant_id, receiver_id AS enterprise_id")
|
||||
|
||||
ents_and_vars = ents_and_vars.merge(OrderCycle.active) if which_taxons == :current
|
||||
|
||||
taxons = Spree::Taxon
|
||||
.select("DISTINCT spree_taxons.id, ents_and_vars.enterprise_id").joins(products: :variants_including_master)
|
||||
.joins("INNER JOIN (#{ents_and_vars.to_sql}) AS ents_and_vars ON spree_variants.id = ents_and_vars.variant_id")
|
||||
|
||||
taxons.each_with_object({}) do |t, ts|
|
||||
ts[t.enterprise_id.to_i] ||= Set.new
|
||||
ts[t.enterprise_id.to_i] << t.id
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,24 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Spree
|
||||
class Taxonomy < ActiveRecord::Base
|
||||
validates :name, presence: true
|
||||
|
||||
has_many :taxons
|
||||
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_column(:name, name)
|
||||
else
|
||||
self.root = Taxon.create!(taxonomy_id: id, name: name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -7,13 +7,6 @@ module Spree
|
||||
belongs_to :ship_address, foreign_key: 'ship_address_id', class_name: 'Spree::Address'
|
||||
belongs_to :bill_address, foreign_key: 'bill_address_id', class_name: 'Spree::Address'
|
||||
|
||||
has_and_belongs_to_many :spree_roles,
|
||||
join_table: 'spree_roles_users',
|
||||
foreign_key: "user_id",
|
||||
class_name: "Spree::Role"
|
||||
|
||||
has_many :spree_orders, foreign_key: "user_id", class_name: "Spree::Order"
|
||||
|
||||
before_validation :set_login
|
||||
before_destroy :check_completed_orders
|
||||
|
||||
@@ -48,12 +41,6 @@ module Spree
|
||||
User.admin.count > 0
|
||||
end
|
||||
|
||||
# Whether a user has a role or not.
|
||||
def has_spree_role?(role_in_question)
|
||||
spree_roles.where(name: role_in_question.to_s).any?
|
||||
end
|
||||
|
||||
# Checks whether the specified user is a superadmin, with full control of the instance
|
||||
def admin?
|
||||
has_spree_role?('admin')
|
||||
end
|
||||
@@ -120,6 +107,14 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
# Checks whether the specified user is a superadmin, with full control of the
|
||||
# instance
|
||||
#
|
||||
# @return [Boolean]
|
||||
def superadmin?
|
||||
has_spree_role?('admin')
|
||||
end
|
||||
|
||||
def generate_spree_api_key!
|
||||
self.spree_api_key = SecureRandom.hex(24)
|
||||
save!
|
||||
@@ -130,10 +125,6 @@ module Spree
|
||||
save!
|
||||
end
|
||||
|
||||
def last_incomplete_spree_order
|
||||
spree_orders.incomplete.where(created_by_id: id).order('created_at DESC').first
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def password_required?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
require 'open_food_network/enterprise_fee_calculator'
|
||||
require 'variant_units/variant_and_line_item_naming'
|
||||
require 'open_food_network/variant_and_line_item_naming'
|
||||
require 'concerns/variant_stock'
|
||||
|
||||
Spree::Variant.class_eval do
|
||||
@@ -8,7 +8,7 @@ Spree::Variant.class_eval do
|
||||
# This file may be double-loaded in delayed job environment, so we check before
|
||||
# removing the Spree method to prevent error.
|
||||
remove_method :options_text if instance_methods(false).include? :options_text
|
||||
include VariantUnits::VariantAndLineItemNaming
|
||||
include OpenFoodNetwork::VariantAndLineItemNaming
|
||||
include VariantStock
|
||||
|
||||
has_many :exchange_variants
|
||||
|
||||
@@ -6,7 +6,7 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
:preferred_product_selection_from_inventory_only,
|
||||
:preferred_show_customer_names_to_suppliers, :owner, :contact, :users, :tag_groups,
|
||||
:default_tag_group, :require_login, :allow_guest_orders, :allow_order_changes,
|
||||
:logo, :promo_image, :terms_and_conditions, :terms_and_conditions_file_name
|
||||
:logo, :promo_image
|
||||
|
||||
has_one :owner, serializer: Api::Admin::UserSerializer
|
||||
has_many :users, serializer: Api::Admin::UserSerializer
|
||||
@@ -20,12 +20,6 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attachment_urls(object.promo_image, [:thumb, :medium, :large])
|
||||
end
|
||||
|
||||
def terms_and_conditions
|
||||
return unless @object.terms_and_conditions.file?
|
||||
|
||||
@object.terms_and_conditions.url
|
||||
end
|
||||
|
||||
def tag_groups
|
||||
object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
|
||||
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
class Api::StateSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :abbr, :country_id
|
||||
attributes :id, :name, :abbr
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ class OrderTaxAdjustmentsFetcher
|
||||
end
|
||||
|
||||
def line_item_adjustments
|
||||
table[:adjustable_id].eq_any(order.line_item_ids)
|
||||
table[:adjustable_id].eq(order.line_item_ids.join(','))
|
||||
.and(table[:adjustable_type].eq('Spree::LineItem'))
|
||||
end
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ module PermittedAttributes
|
||||
[
|
||||
:id, :name, :visible, :permalink, :owner_id, :contact_name, :email_address, :phone,
|
||||
:is_primary_producer, :sells, :website, :facebook, :instagram, :linkedin, :twitter,
|
||||
:description, :long_description, :logo, :promo_image, :terms_and_conditions,
|
||||
:description, :long_description, :logo, :promo_image,
|
||||
:allow_guest_orders, :allow_order_changes, :require_login, :enable_subscriptions,
|
||||
:abn, :acn, :charges_sales_tax, :display_invoice_logo, :invoice_text,
|
||||
:preferred_product_selection_from_inventory_only, :preferred_shopfront_message,
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ProductFilters
|
||||
PRODUCT_FILTERS = [
|
||||
'query', 'producerFilter', 'categoryFilter', 'sorting', 'importDateFilter'
|
||||
].freeze
|
||||
|
||||
def extract(params)
|
||||
params.select { |key, _value| PRODUCT_FILTERS.include?(key) }
|
||||
end
|
||||
end
|
||||
@@ -31,16 +31,3 @@
|
||||
= f.label :invoice_text, t('.invoice_text')
|
||||
.omega.eight.columns
|
||||
= f.text_area :invoice_text, style: "width: 100%; height: 100px;"
|
||||
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :terms_and_conditions, t('.terms_and_conditions')
|
||||
|
||||
.omega.eight.columns
|
||||
%a{ href: '{{ Enterprise.terms_and_conditions }}', ng: { if: 'Enterprise.terms_and_conditions' } }
|
||||
= '{{ Enterprise.terms_and_conditions_file_name }}'
|
||||
.pad-top
|
||||
= f.file_field :terms_and_conditions
|
||||
.pad-top
|
||||
%a.button.red{ href: '', ng: {click: 'removeTermsAndConditions()', if: 'Enterprise.terms_and_conditions'} }
|
||||
= t('.remove_terms_and_conditions')
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.logo.medium }}', if: 'Enterprise.logo' } }
|
||||
= f.file_field :logo
|
||||
%a.button.red{ href: '', ng: {click: 'removeLogo()', if: 'Enterprise.logo'} }
|
||||
= t('.remove_logo')
|
||||
= t('admin.enterprises.remove_logo.remove')
|
||||
|
||||
.row.page-admin-enterprises-form__promo-image-field-group.image-field-group
|
||||
.alpha.three.columns
|
||||
@@ -23,4 +23,4 @@
|
||||
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.promo_image.large }}', if: 'Enterprise.promo_image' } }
|
||||
= f.file_field :promo_image
|
||||
%a.button.red{ href: '', ng: {click: 'removePromoImage()', if: 'Enterprise.promo_image'} }
|
||||
= t('.remove_promo_image')
|
||||
= t('admin.enterprises.remove_promo_image.remove')
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
= render "checkout/shipping", f: f
|
||||
= render "checkout/payment", f: f
|
||||
= render "checkout/already_ordered", f: f if show_bought_items?
|
||||
= render "checkout/terms_and_conditions", f: f
|
||||
%p
|
||||
%button.button.primary{type: :submit}
|
||||
= t :checkout_send
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"ng-class" => "{valid: payment.$valid, open: accordion.payment}"}
|
||||
= render 'checkout/accordion_heading'
|
||||
|
||||
-# TODO render this in Angular instead of server-side
|
||||
-# The problem being how to render the partials
|
||||
.row
|
||||
.small-12.medium-12.large-6.columns
|
||||
- available_payment_methods.each do |method|
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
%p.small
|
||||
= t('.message_html', terms_and_conditions_link: link_to( t( '.link_text' ), current_order.distributor.terms_and_conditions.url, target: '_blank')) if current_order.distributor.terms_and_conditions.file?
|
||||
@@ -2,6 +2,7 @@
|
||||
.row
|
||||
.small-12.text-center.columns
|
||||
%h1
|
||||
/ TODO: Rohan - logo asset & width is content manageable:
|
||||
%img{src: image_path("logo-white-notext.png"), title: Spree::Config.site_name}
|
||||
%br/
|
||||
%a.button.transparent{href: "/shops"}
|
||||
|
||||
@@ -1,34 +1,29 @@
|
||||
:javascript
|
||||
var isInIframe = function(){
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
$(document).ready(function() {
|
||||
var in_iframe = function(){
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var embedded_styles_active = $('body.off-canvas').hasClass('embedded');
|
||||
|
||||
var set_shopfront_styles = function(state) {
|
||||
$.ajax({
|
||||
url: '/embedded_shopfront/'+state,
|
||||
type: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
if (in_iframe() && !embedded_styles_active){
|
||||
$('body.off-canvas').addClass('embedded');
|
||||
set_shopfront_styles('enable');
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener(
|
||||
'DOMContentLoaded',
|
||||
function() {
|
||||
var inIframe = isInIframe();
|
||||
var embedded_styles_active = $('body.off-canvas').hasClass('embedded');
|
||||
|
||||
var set_shopfront_styles = function (state) {
|
||||
$.ajax({
|
||||
url: '/embedded_shopfront/' + state,
|
||||
type: 'POST'
|
||||
});
|
||||
};
|
||||
|
||||
if (inIframe && !embedded_styles_active){
|
||||
$('body.off-canvas').addClass('embedded');
|
||||
set_shopfront_styles('enable');
|
||||
}
|
||||
|
||||
if (!inIframe && embedded_styles_active) {
|
||||
$('body.off-canvas').removeClass('embedded');
|
||||
set_shopfront_styles('disable');
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
if (!in_iframe() && embedded_styles_active) {
|
||||
$('body.off-canvas').removeClass('embedded');
|
||||
set_shopfront_styles('disable');
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,14 +18,14 @@
|
||||
= stylesheet_link_tag "darkswarm/all"
|
||||
= csrf_meta_tags
|
||||
|
||||
%body{ class: body_classes, "body-scroll" => true , ng: { app: 'Darkswarm' }}
|
||||
%body{class: body_classes, "body-scroll" => true , ng: {app: "Darkswarm"}}
|
||||
/ [if lte IE 8]
|
||||
= render partial: "shared/ie_warning"
|
||||
= javascript_include_tag "iehack"
|
||||
|
||||
= render "layouts/shopfront_script" if @shopfront_layout
|
||||
|
||||
.off-canvas-wrap{ offcanvas: true }
|
||||
.off-canvas-wrap{offcanvas: true}
|
||||
.fixed.off-canvas-fixed
|
||||
= render "shared/menu/menu" unless @hide_menu
|
||||
= yield :page_alert
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
= render partial: 'spree/shared/error_messages', locals: { target: @image }
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to t('spree.back_to_images_list'), admin_product_images_url(@product, @url_filters), icon: 'icon-arrow-left'
|
||||
%li= button_link_to t('spree.back_to_images_list'), admin_product_images_url(@product), icon: 'icon-arrow-left'
|
||||
|
||||
= form_for [:admin, @product, @image], url: admin_product_image_path(@product, @image, @url_filters), html: { multipart: true } do |f|
|
||||
= form_for [:admin, @product, @image], html: { multipart: true } do |f|
|
||||
%fieldset
|
||||
%legend{align: "center"}= @image.attachment_file_name
|
||||
.field.alpha.three.columns.align-center
|
||||
@@ -18,4 +18,4 @@
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), admin_product_images_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
= link_to t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button icon-remove'
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
= render partial: 'spree/admin/shared/product_tabs', locals: { current: 'Images'}
|
||||
|
||||
- content_for :page_actions do
|
||||
%li= link_to_with_icon('icon-plus', t('spree.new_image'), new_admin_product_image_url(@product, @url_filters), id: 'new_image_link', class: 'button')
|
||||
%li= link_to_with_icon('icon-plus', t('spree.new_image'), new_admin_product_image_url(@product), id: 'new_image_link', class: 'button')
|
||||
|
||||
#images
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
= t('spree.no_images_found')
|
||||
\.
|
||||
- else
|
||||
%table.index.sortable{ "data-sortable-link" => "#{update_positions_admin_product_images_url(@product, @url_filters)}" }
|
||||
%table.index.sortable{ "data-sortable-link" => "#{update_positions_admin_product_images_url(@product)}" }
|
||||
%colgroup
|
||||
%col{ style: "width: 5%" }/
|
||||
%col{ style: "width: 10%" }/
|
||||
@@ -36,5 +36,5 @@
|
||||
%td= options_text_for(image)
|
||||
%td= image.alt
|
||||
%td.actions
|
||||
= link_to_with_icon 'icon-edit', t('spree.edit'), edit_admin_product_image_url(@product, image, @url_filters), no_text: true, data: { action: 'edit'}
|
||||
= link_to_delete image, { url: admin_product_image_url(@product, image, @url_filters), no_text: true }
|
||||
= link_to_with_icon 'icon-edit', t('spree.edit'), edit_admin_product_image_url(@product, image), no_text: true, data: { action: 'edit'}
|
||||
= link_to_delete image, { url: admin_product_image_url(@product, image), no_text: true }
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
= form_for [:admin, @product, @image], url: admin_product_images_path(@product, @image, @url_filters), html: { multipart: true } do |f|
|
||||
= form_for [:admin, @product, @image], html: { multipart: true } do |f|
|
||||
%fieldset
|
||||
%legend{ align: "center" }= t('spree.new_image')
|
||||
= render partial: 'form', locals: { f: f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product, @url_filters), id: 'cancel_link', class: 'button'
|
||||
= link_to_with_icon 'icon-remove', t('spree.actions.cancel'), admin_product_images_url(@product), id: 'cancel_link', class: 'button'
|
||||
|
||||
= javascript_include_tag 'admin/spree/images/new.js'
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
- if use_billing
|
||||
.field{style: "position: absolute;margin-top: -15px;right: 0;"}
|
||||
%span
|
||||
= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address))
|
||||
= label_tag 'order[use_billing]', Spree.t(:use_billing_address)
|
||||
|
||||
- is_shipping_address = name == Spree.t(:shipping_address)
|
||||
- s_or_b = is_shipping_address ? 's' : 'b'
|
||||
|
||||
- display_style = (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address == @order.ship_address)) ? 'none' : 'block'
|
||||
|
||||
%div{id: "#{is_shipping_address ? 'shipping' : 'billing'}", style: "display: #{display_style}"}
|
||||
%div{class: "field"}
|
||||
= f.label :firstname, Spree.t(:first_name) + ':'
|
||||
= f.text_field :firstname, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :lastname, Spree.t(:last_name) + ':'
|
||||
= f.text_field :lastname, class: 'fullwidth'
|
||||
- if Spree::Config[:company]
|
||||
%div{class: "field"}
|
||||
= f.label :company, Spree.t(:company) + ':'
|
||||
= f.text_field :company, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :address1, Spree.t(:street_address) + ':'
|
||||
= f.text_field :address1, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :address2, Spree.t(:street_address_2) + ':'
|
||||
= f.text_field :address2, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :city, Spree.t(:city) + ':'
|
||||
= f.text_field :city, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :zipcode, Spree.t(:zip) + ':'
|
||||
= f.text_field :zipcode, class: 'fullwidth'
|
||||
%div{class: "field"}
|
||||
= f.label :country_id, Spree.t(:country) + ':'
|
||||
%span{id: "#{s_or_b}country"}
|
||||
= f.collection_select :country_id, available_countries, :id, :name, {}, {class: 'select2 fullwidth', onchange: "update_state('#{s_or_b}')"}
|
||||
%div{class: "field"}
|
||||
= f.label :state_id, Spree.t(:state) + ':'
|
||||
%span{id: "#{s_or_b}state"}
|
||||
= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {include_blank: true}, {class: 'select2 fullwidth', disabled: f.object.country.states.empty?}
|
||||
%div{class: "field"}
|
||||
= f.label :phone, Spree.t(:phone) + ':'
|
||||
= f.phone_field :phone, class: 'fullwidth'
|
||||
@@ -11,13 +11,13 @@
|
||||
%fieldset.no-border-bottom
|
||||
%legend{:align => "center"}= Spree.t(:billing_address)
|
||||
= f.fields_for :bill_address do |ba_form|
|
||||
= render :partial => 'address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
|
||||
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
|
||||
|
||||
.omega.six.columns{"data-hook" => "ship_address_wrapper"}
|
||||
%fieldset.no-border-bottom
|
||||
%legend{:align => "center"}= Spree.t(:shipping_address)
|
||||
= f.fields_for :ship_address do |sa_form|
|
||||
= render :partial => 'address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
|
||||
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
|
||||
|
||||
.clear
|
||||
|
||||
@@ -26,4 +26,3 @@
|
||||
|
||||
- content_for :head do
|
||||
= javascript_include_tag 'admin/spree/orders/address_states.js'
|
||||
= javascript_include_tag 'admin/spree/orders/use_billing.js'
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
%col{style: "width: 13%"}
|
||||
%col{style: "width: 14%"}
|
||||
%col{style: "width: 32%"}
|
||||
- if spree_current_user.admin?
|
||||
%col{style: "width: 14%"}
|
||||
%col{style: "width: 14%"}
|
||||
%col{style: "width: 8%"}
|
||||
%col{style: "width: 8%"}
|
||||
%col{style: "width: 11%"}
|
||||
@@ -21,8 +20,7 @@
|
||||
%th= t('.name')
|
||||
%th= t('.products_distributor')
|
||||
%th= t('.provider')
|
||||
- if spree_current_user.admin?
|
||||
%th= t('.environment')
|
||||
%th= t('.environment')
|
||||
%th= t('.display')
|
||||
%th= t('.active')
|
||||
%th.actions
|
||||
@@ -35,8 +33,7 @@
|
||||
= distributor.name
|
||||
%br/
|
||||
%td= method.class.clean_name
|
||||
- if spree_current_user.admin?
|
||||
%td.align-center= method.environment.to_s.titleize
|
||||
%td.align-center= method.environment.to_s.titleize
|
||||
%td.align-center= method.display_on.blank? ? t('.both') : t('.' + method.display_on.to_s)
|
||||
%td.align-center= method.active ? t('.active_yes') : t('.active_no')
|
||||
%td.actions
|
||||
|
||||
@@ -11,4 +11,4 @@
|
||||
= f.text_field :value, class: 'autocomplete'
|
||||
%td.actions
|
||||
- if f.object.persisted?
|
||||
= link_to_delete f.object, { url: admin_product_product_property_url(@product, f.object, @url_filters), no_text: true }
|
||||
= link_to_delete f.object, no_text: true
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
%li
|
||||
= link_to_add_fields t('.add_product_properties'), 'tbody#product_properties', class: 'icon-plus button'
|
||||
|
||||
= form_for @product, url: admin_product_url(@product, @url_filters), method: :put do |f|
|
||||
= form_for @product, url: admin_product_url(@product), method: :put do |f|
|
||||
%fieldset.no-border-top
|
||||
.add_product_properties
|
||||
= image_tag 'select2-spinner.gif', plugin: 'spree', style: 'display:none;', id: 'busy_indicator'
|
||||
@@ -46,10 +46,7 @@
|
||||
%td.actions
|
||||
|
||||
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), admin_product_product_properties_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
= render partial: 'spree/admin/shared/edit_resource_links'
|
||||
|
||||
= hidden_field_tag 'clear_product_properties', 'true'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
- 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'), admin_products_path, :icon => 'icon-arrow-left'
|
||||
%li#new_product_link
|
||||
= button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' }
|
||||
|
||||
@@ -8,10 +8,7 @@
|
||||
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Product Details' }
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
|
||||
|
||||
= form_for [:admin, @product], :url => admin_product_path(@product, @url_filters), :method => :put, :html => { :multipart => true } do |f|
|
||||
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
|
||||
%fieldset.no-border-top{'ng-app' => 'admin.products'}
|
||||
= render :partial => 'form', :locals => { :f => f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t(:update), 'icon-refresh'
|
||||
%span.or= t(:or)
|
||||
= button_link_to t(:cancel), "#{collection_url}#{(@url_filters.empty? ? "" : "#?#{@url_filters.to_query}")}", icon: 'icon-remove'
|
||||
= render :partial => 'spree/admin/shared/edit_resource_links'
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
= render partial: 'spree/admin/shared/product_sub_menu'
|
||||
= render partial: 'spree/admin/shared/product_tabs', locals: { :current => 'Group Buy Options' }
|
||||
= render partial: 'spree/shared/error_messages', locals: { :target => @product }
|
||||
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => 'Group Buy Options' }
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
|
||||
|
||||
= form_for [:admin, @product], url: admin_product_url(@product, @url_filters), method: :put, html: { :multipart => true } do |f|
|
||||
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
|
||||
%fieldset.no-border-top
|
||||
= render partial: 'group_buy_form', locals: { f: f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), edit_admin_product_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
= render :partial => 'group_buy_form', :locals => { :f => f }
|
||||
= render :partial => 'spree/admin/shared/edit_resource_links'
|
||||
|
||||
@@ -5,20 +5,22 @@
|
||||
.quick_search.three.columns.alpha
|
||||
%label{ for: 'quick_filter' }
|
||||
%br
|
||||
%input.quick-search.fullwidth{ ng: {model: 'q.query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
|
||||
%input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" }
|
||||
.one.columns
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'producer_filter' }= t 'producer'
|
||||
%br
|
||||
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.producerFilter', options: 'producer.id as producer.name for producer in producers'} }
|
||||
%select.fullwidth{ id: 'producer_filter', 'ofn-select2-min-search' => 5, ng: {model: 'producerFilter', options: 'producer.id as producer.name for producer in producers'} }
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'category_filter' }= t 'category'
|
||||
%br
|
||||
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
|
||||
%select.fullwidth{ id: 'category_filter', 'ofn-select2-min-search' => 5, ng: {model: 'categoryFilter', options: 'taxon.id as taxon.name for taxon in taxons'} }
|
||||
.filter_select.three.columns
|
||||
%label{ for: 'import_filter' } Import Date
|
||||
%br
|
||||
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'q.importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}", options: 'date.id as date.name for date in importDates'} }
|
||||
%select.fullwidth{ id: 'import_date_filter', 'ofn-select2-min-search' => 5, ng: {model: 'importDateFilter', init: "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}"}}
|
||||
%option{value: "{{date.id}}", ng: {repeat: "date in importDates" }}
|
||||
{{date.name}}
|
||||
|
||||
.filter_clear.three.columns.omega
|
||||
%label{ for: 'clear_all_filters' }
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
%img.spinner{ src: image_path("spinning-circles.svg") }
|
||||
%h1= t('.title')
|
||||
|
||||
%div.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && q.query.length == 0' }
|
||||
%div.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && query.length==0' }
|
||||
%h1#no_results= t('.no_products')
|
||||
|
||||
%div.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && q.query.length != 0' }
|
||||
%div.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && query.length!=0' }
|
||||
%h1#no_results
|
||||
= t('.no_results')
|
||||
'
|
||||
{{q.query}}
|
||||
'
|
||||
{{query}}
|
||||
'
|
||||
@@ -1,12 +1,9 @@
|
||||
= render partial: 'spree/admin/shared/product_sub_menu'
|
||||
= render partial: 'spree/admin/shared/product_tabs', locals: { current: t(:search) }
|
||||
= render partial: 'spree/shared/error_messages', locals: { target: @product }
|
||||
= render :partial => 'spree/admin/shared/product_tabs', :locals => { :current => t(:search) }
|
||||
= render :partial => 'spree/shared/error_messages', :locals => { :target => @product }
|
||||
|
||||
%div{ 'ng-app' => 'ofn.admin' }
|
||||
= form_for [:admin, @product], url: admin_product_url(@product, @url_filters), method: :put, html: { :multipart => true } do |f|
|
||||
= form_for [:admin, @product], :method => :put, :html => { :multipart => true } do |f|
|
||||
%fieldset.no-border-top
|
||||
= render :partial => 'seo_form', :locals => { :f => f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('spree.actions.update'), 'icon-refresh'
|
||||
%span.or= t('spree.or')
|
||||
= link_to t('spree.actions.cancel'), edit_admin_product_url(@product, @url_filters), id: 'cancel_link', class: 'button icon-remove'
|
||||
= render :partial => 'spree/admin/shared/edit_resource_links'
|
||||
|
||||
72
app/views/spree/admin/shared/_address_form.html.erb
Normal file
72
app/views/spree/admin/shared/_address_form.html.erb
Normal file
@@ -0,0 +1,72 @@
|
||||
<% if use_billing %>
|
||||
<div class="field" style="position: absolute;margin-top: -15px;right: 0;">
|
||||
<span data-hook="use_billing">
|
||||
<%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address)) %>
|
||||
<%= label_tag 'order[use_billing]', Spree.t(:use_billing_address) %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% is_shipping_address = name == Spree.t(:shipping_address) %>
|
||||
<% shipping_or_billing = is_shipping_address ? 'shipping' : 'billing' %>
|
||||
<% s_or_b = is_shipping_address ? 's' : 'b' %>
|
||||
|
||||
<div id="<%= is_shipping_address ? 'shipping' : 'billing' %>" style="display: <%= (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.eql?(@order.ship_address))) ? 'none' : 'block' %>" data-hook="address_fields">
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :firstname, Spree.t(:first_name) + ':' %>
|
||||
<%= f.text_field :firstname, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :lastname, Spree.t(:last_name) + ':' %>
|
||||
<%= f.text_field :lastname, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<% if Spree::Config[:company] %>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :company, Spree.t(:company) + ':' %>
|
||||
<%= f.text_field :company, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :address1, Spree.t(:street_address) + ':' %>
|
||||
<%= f.text_field :address1, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :address2, Spree.t(:street_address_2) + ':' %>
|
||||
<%= f.text_field :address2, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :city, Spree.t(:city) + ':' %>
|
||||
<%= f.text_field :city, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :zipcode, Spree.t(:zip) + ':' %>
|
||||
<%= f.text_field :zipcode, :class => 'fullwidth' %>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :country_id, Spree.t(:country) + ':' %>
|
||||
<span id="<%= s_or_b %>country">
|
||||
<%= f.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'select2 fullwidth'} %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :state_id, Spree.t(:state) + ':' %>
|
||||
<span id="<%= s_or_b %>state">
|
||||
<%= f.text_field :state_name,
|
||||
:style => "display: #{f.object.country.states.empty? ? 'block' : 'none' };",
|
||||
:disabled => !f.object.country.states.empty?, :class => 'fullwidth state_name' %>
|
||||
<%= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {:include_blank => true}, {:class => 'select2 fullwidth', :style => "display: #{f.object.country.states.empty? ? 'none' : 'block' };", :disabled => f.object.country.states.empty?} %>
|
||||
</span>
|
||||
</div>
|
||||
<div class="field <%= "#{shipping_or_billing}-row" %>">
|
||||
<%= f.label :phone, Spree.t(:phone) + ':' %>
|
||||
<%= f.phone_field :phone, :class => 'fullwidth' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% content_for :head do %>
|
||||
<%= javascript_tag do -%>
|
||||
$(document).ready(function(){
|
||||
$('span#<%= s_or_b %>country .select2').on('change', function() { update_state('<%= s_or_b %>'); });
|
||||
});
|
||||
<% end -%>
|
||||
<% end %>
|
||||
@@ -12,22 +12,22 @@
|
||||
- if can?(:admin, Spree::Product)
|
||||
- klass = current == 'Product Details' ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-edit', t('admin.products.tabs.product_details'), edit_admin_product_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-edit', t('admin.products.tabs.product_details'), edit_admin_product_url(@product)
|
||||
- if can?(:admin, Spree::Image)
|
||||
- klass = current == 'Images' ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-picture', t('admin.products.tabs.images'), admin_product_images_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-picture', t('admin.products.tabs.images'), admin_product_images_url(@product)
|
||||
- if can?(:admin, Spree::Variant)
|
||||
- klass = current == 'Variants' ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-th-large', t('admin.products.tabs.variants'), admin_product_variants_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-th-large', t('admin.products.tabs.variants'), admin_product_variants_url(@product)
|
||||
- if can?(:admin, Spree::ProductProperty)
|
||||
- klass = current == 'Product Properties' ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-tasks', t('admin.products.tabs.product_properties'), admin_product_product_properties_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-tasks', t('admin.products.tabs.product_properties'), admin_product_product_properties_url(@product)
|
||||
- klass = current == 'Group Buy Options' ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-tasks', t('admin.products.tabs.group_buy_options'), group_buy_options_admin_product_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-tasks', t('admin.products.tabs.group_buy_options'), group_buy_options_admin_product_url(@product)
|
||||
- klass = current == t(:search) ? 'active' : ''
|
||||
%li{:class => klass}
|
||||
= link_to_with_icon 'icon-tasks', t(:search), seo_admin_product_url(@product, @url_filters)
|
||||
= link_to_with_icon 'icon-tasks', t(:search), seo_admin_product_url(@product)
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
Spree.routes = <%== {
|
||||
:variants_search => spree.admin_search_variants_path(:format => 'json'),
|
||||
:taxons_search => main_app.api_taxons_path(:format => 'json'),
|
||||
:orders_api => main_app.api_orders_path,
|
||||
:states_search => main_app.api_states_path(:format => 'json')
|
||||
:orders_api => main_app.api_orders_path
|
||||
}.to_json %>;
|
||||
</script>
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
:loading => Spree.t(:loading),
|
||||
:month_names => I18n.t(:month_names, :scope => :date).reject(&:blank?),
|
||||
:more => Spree.t(:more),
|
||||
:datetime_ui_current_text => I18n.t('datetime_picker_ui.current_text'),
|
||||
:datetime_ui_close_text => I18n.t('datetime_picker_ui.close_text'),
|
||||
:datetime_ui_time_text => I18n.t('datetime_picker_ui.time_text'),
|
||||
:name => Spree.t(:name),
|
||||
:next => Spree.t(:next),
|
||||
:no_results => Spree.t(:no_results),
|
||||
|
||||
@@ -4,11 +4,8 @@
|
||||
|
||||
= render partial: 'spree/shared/error_messages', locals: { target: @variant }
|
||||
|
||||
= form_for [:admin, @product, @variant], :url => admin_product_variant_path(@product, @variant, @url_filters) do |f|
|
||||
= form_for [:admin, @product, @variant] do |f|
|
||||
%fieldset.no-border-top
|
||||
%div
|
||||
= render partial: 'form', locals: { f: f }
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t(:update), 'icon-refresh'
|
||||
%span.or= t(:or)
|
||||
= button_link_to t(:cancel), collection_url(@url_filters), icon: 'icon-remove'
|
||||
= render partial: 'spree/admin/shared/edit_resource_links'
|
||||
|
||||
@@ -27,8 +27,8 @@
|
||||
%td.align-center= variant.display_price.to_html
|
||||
%td.align-center= variant.sku
|
||||
%td.actions
|
||||
= link_to_with_icon('icon-edit', Spree.t(:edit), edit_object_url(variant, @url_filters), no_text: true) unless variant.deleted?
|
||||
= link_to_delete(variant, { url: object_url(variant, @url_filters), no_text: true }) unless variant.deleted?
|
||||
= link_to_edit(variant, no_text: true) unless variant.deleted?
|
||||
= link_to_delete(variant, no_text: true) unless variant.deleted?
|
||||
|
||||
- if @product.empty_option_values?
|
||||
%p.first_add_option_types.no-objects-found
|
||||
@@ -41,6 +41,6 @@
|
||||
- content_for :page_actions do
|
||||
%ul.inline-menu
|
||||
%li#new_var_link
|
||||
= link_to_with_icon('icon-plus', t('.new_variant'), new_admin_product_variant_url(@product, @url_filters), class: 'button')
|
||||
= link_to_with_icon('icon-plus', t('.new_variant'), new_admin_product_variant_url(@product), class: 'button')
|
||||
|
||||
%li= link_to_with_icon('icon-filter', @deleted.blank? ? t('.show_deleted') : t('.show_active'), admin_product_variants_url(@product, @url_filters.merge(deleted: @deleted.blank? ? "on" : "off")), class: 'button')
|
||||
%li= link_to_with_icon('icon-filter', @deleted.blank? ? t('.show_deleted') : t('.show_active'), admin_product_variants_url(@product, deleted: @deleted.blank? ? "on" : "off"), class: 'button')
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
= render partial: 'spree/shared/error_messages', locals: { target: @variant }
|
||||
|
||||
= form_for [:admin, @product, @variant], :url => admin_product_variants_path(@product, @url_filters) do |f|
|
||||
= form_for [:admin, @product, @variant] do |f|
|
||||
%fieldset{'data-hook' => "admin_variant_new_form"}
|
||||
%legend{align: "center"}= t('.new_variant')
|
||||
= render partial: 'form', locals: { f: f }
|
||||
|
||||
.form-buttons.filter-actions.actions
|
||||
= button t('actions.create'), 'icon-ok'
|
||||
%span.or= t(:or)
|
||||
= button_link_to t('actions.cancel'), collection_url(@url_filters), icon: 'icon-remove'
|
||||
= render partial: 'spree/admin/shared/new_resource_links'
|
||||
|
||||
@@ -9,11 +9,11 @@ ar:
|
||||
shipment_state: حالة الشحن
|
||||
completed_at: 'تم الانتهاء عند '
|
||||
number: 'رقم '
|
||||
state: محافظة
|
||||
state: ولاية
|
||||
email: الايميل الالكتروني للعميل
|
||||
spree/payment:
|
||||
amount: القيمة
|
||||
state: محافظة
|
||||
state: ولاية
|
||||
source: المصدر
|
||||
spree/product:
|
||||
primary_taxon: "نوع المنتج "
|
||||
@@ -34,7 +34,7 @@ ar:
|
||||
email:
|
||||
taken: "يوجد حساب متصل بهذا الايميل.\nالرجاء الدخول او اعادة تعيين كلمة السر."
|
||||
spree/order:
|
||||
no_card: لا توجد بطاقات ائتمان معتمدة لشحنها
|
||||
no_card: لا يوجد بطاقة ائتمان معتمدة متاحة لاتمام عملية الدفع
|
||||
spree/credit_card:
|
||||
attributes:
|
||||
base:
|
||||
@@ -53,12 +53,12 @@ ar:
|
||||
order_management/reports/enterprise_fee_summary/parameters:
|
||||
start_at: "البداية "
|
||||
end_at: "النهاية"
|
||||
distributor_ids: "مراكز "
|
||||
distributor_ids: "منافذ"
|
||||
producer_ids: "المنتجين"
|
||||
order_cycle_ids: "دورات الطلب"
|
||||
enterprise_fee_ids: "أسماء الرسوم"
|
||||
shipping_method_ids: "طرق الشحن"
|
||||
payment_method_ids: "طرق الدفع"
|
||||
payment_method_ids: "طريقة الدفع"
|
||||
errors:
|
||||
messages:
|
||||
inclusion: "غير مدرجة في القائمة"
|
||||
@@ -120,10 +120,6 @@ ar:
|
||||
integer_array_validator:
|
||||
not_array_error: "يجب أن يكون مصفوفة"
|
||||
invalid_element_error: "يجب أن يحتوي فقط على أعداد صحيحة فاعلة"
|
||||
datetime_picker_ui:
|
||||
current_text: الآن
|
||||
close_text: تم
|
||||
time_text: الوقت
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "يرجى تأكيد عنوان البريد الإلكتروني ل %{enterprise}"
|
||||
@@ -148,7 +144,7 @@ ar:
|
||||
instructions: "تم شحن طلبك"
|
||||
shipment_summary: "ملخص الشحن"
|
||||
subject: "إشعار الشحن"
|
||||
thanks: "شكرا لك على تعاملاتك."
|
||||
thanks: "شكرا لك على اعمالك."
|
||||
track_information: "معلومات التتبع : %{tracking}"
|
||||
track_link: "رابط التتبع: %{url}"
|
||||
subscription_mailer:
|
||||
@@ -601,7 +597,7 @@ ar:
|
||||
order_date: "اكتمل في"
|
||||
max: "اعلى"
|
||||
product_unit: "المنتج: وحدة"
|
||||
weight_volume: "الوزن / الحجم (جم)"
|
||||
weight_volume: "الوزن / الحجم"
|
||||
ask: "يطلب؟"
|
||||
page_title: "ادارة طلب الجملة "
|
||||
actions_delete: "حذف المواد المختارة"
|
||||
@@ -638,8 +634,6 @@ ar:
|
||||
acn_placeholder: على سبيل المثال. 123 456 789
|
||||
display_invoice_logo: عرض الشعار في الفواتير
|
||||
invoice_text: أضف نصًا مخصصًا في نهاية الفواتير
|
||||
terms_and_conditions: "الأحكام والشروط"
|
||||
remove_terms_and_conditions: "إزالة الملف"
|
||||
contact:
|
||||
name: اسم
|
||||
name_placeholder: على سبيل المثال. برقوق غوستاف
|
||||
@@ -662,8 +656,6 @@ ar:
|
||||
promo_image_note1: 'يرجى الملاحظة:'
|
||||
promo_image_note2: سيتم اقتصاص أي صورة ترويجية تم تحميلها هنا إلى 1200 × 260.
|
||||
promo_image_note3: يتم عرض صورة الترويجي في الجزء العلوي من صفحة الملف الشخصي للشركات والنوافذ المنبثقة.
|
||||
remove_logo: "إزالة الصورة"
|
||||
remove_promo_image: "إزالة الصورة"
|
||||
inventory_settings:
|
||||
text1: يمكنك اختيار إدارة مستويات المخزون والأسعار عبر
|
||||
inventory: المخزون
|
||||
@@ -762,7 +754,7 @@ ar:
|
||||
confirm_modal:
|
||||
title: تواصل مع Stripe
|
||||
part1: Stripe هي خدمة معالجة دفع تسمح للمحلات على شبكة الغذاء المفتوح بقبول مدفوعات بطاقات الائتمان من العملاء.
|
||||
part2: لاستخدام هذه الميزة ، يجب عليك توصيل حساب Stripe الخاص بك بـ شبكة الغذاء المفتوح. النقر فوق 'أوافق' أدناه إلى إعادة توجيهك إلى موقع Stripe على الويب حيث يمكنك توصيل حساب Stripe الموجود ، أو إنشاء حساب جديد إذا لم يكن لديك حساب بالفعل.
|
||||
part2: لاستخدام هذه الميزة ، يجب عليك توصيل حساب Stripe الخاص بك بـ شبكة الغذاء المفتوح. النقر فوق "أوافق" أدناه إلى إعادة توجيهك إلى موقع Stripe على الويب حيث يمكنك توصيل حساب Stripe الموجود ، أو إنشاء حساب جديد إذا لم يكن لديك حساب بالفعل.
|
||||
part3: سيتيح هذا لشبكة الغذاء المفتوح قبول مدفوعات بطاقات الائتمان من العملاء نيابة عنك. يرجى ملاحظة أنك سوف تحتاج إلى الحفاظ على حساب Stripe الخاص بك ، ودفع رسوم Stripe والتعامل مع أي عمليات رد المبالغ المدفوعة وخدمة العملاء بنفسك.
|
||||
i_agree: أنا موافق
|
||||
cancel: إلغاء
|
||||
@@ -850,6 +842,14 @@ ar:
|
||||
new:
|
||||
title: شركة جديدة
|
||||
back_link: العودة إلى قائمة المؤسسات
|
||||
remove_logo:
|
||||
remove: "إزالة الصورة"
|
||||
removed_successfully: "تمت إزالة الشعار بنجاح"
|
||||
immediate_removal_warning: "سيتم إزالة الشعار مباشرة بعد التأكيد."
|
||||
remove_promo_image:
|
||||
remove: "إزالة الصورة"
|
||||
removed_successfully: "تمت إزالة الصورة الترويجية بنجاح"
|
||||
immediate_removal_warning: "ستتم إزالة صورة الترويجي فور التأكيد."
|
||||
welcome:
|
||||
welcome_title: مرحبا بكم في شبكة الغذاء المفتوح!
|
||||
welcome_text: لقد نجحت في إنشاء
|
||||
@@ -1147,17 +1147,12 @@ ar:
|
||||
destroy_attachment_does_not_exist: "الشعار غير موجود"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "الصورة الترويجية غير موجودة"
|
||||
enterprise_terms_and_conditions:
|
||||
destroy_attachment_does_not_exist: "ملف الشروط والأحكام غير موجود"
|
||||
orders:
|
||||
failed_to_update: "فشل في تحديث الطلب"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "سلة التسوق"
|
||||
message_html: "لديك طلب لدورة الطلب هذه بالفعل. تحقق من %{cart} لرؤية العناصر التي طلبتها من قبل. يمكنك أيضًا إلغاء العناصر طالما كانت دورة الطلب مفتوحة."
|
||||
terms_and_conditions:
|
||||
message_html: "من خلال تقديم هذا الطلب ، فإنك توافق على %{terms_and_conditions_link}."
|
||||
link_text: "شروط الخدمة"
|
||||
failed: "فشل الخروج. يرجى إعلامنا حتى نتمكن من معالجة طلبك."
|
||||
shops:
|
||||
hubs:
|
||||
@@ -1185,17 +1180,17 @@ ar:
|
||||
register: "سجل هنا"
|
||||
footer:
|
||||
footer_secure: "آمن وموثوق به."
|
||||
footer_secure_text: "تستخدم منصة فلاحة - شبكة الغذاء المفتوح تشفير ( 2048 بت RSA) في كل مكان للحفاظ على خصوصية معلومات التسوق والدفع. لا تقوم خوادمنا بتخزين تفاصيل بطاقة الائتمان الخاصة بك ، وتتم معالجة المدفوعات بواسطة خدمات متوافقة مع PCI."
|
||||
footer_secure_text: "تستخدم شبكة الغذاء المفتوح تشفير( SSL 2048 بت RSA) في كل مكان للحفاظ على خصوصية معلومات التسوق والدفع. لا تقوم خوادمنا بتخزين تفاصيل بطاقة الائتمان الخاصة بك ، وتتم معالجة المدفوعات بواسطة خدمات متوافقة مع PCI."
|
||||
footer_contact_headline: "أبق على اتصال"
|
||||
footer_contact_email: "راسلنا "
|
||||
footer_contact_email: "راسلنا عبر البريد الإلكتروني"
|
||||
footer_nav_headline: "التنقل"
|
||||
footer_join_headline: "انضم إلينا"
|
||||
footer_join_body: "إنشاء مركز تجاري أو متجر أو مجموعة على منصة فلاحة - شبكة الغذاء المفتوح."
|
||||
footer_join_body: "إنشاء قائمة أو متجر أو دليل المجموعة على شبكة الغذاء المفتوح."
|
||||
footer_join_cta: "اخبرني المزيد!"
|
||||
footer_legal_call: "اقراء"
|
||||
footer_legal_tos: "الأحكام والشروط"
|
||||
footer_legal_visit: "تجدنا على"
|
||||
footer_legal_text_html: "فلاحة شبكة الغذاء المفتوح عبارة عن منصة حرة ومفتوحة البرمجيات. تم ترخيص المحتوى الخاص بنا باستخدام %{content_license} ورمزنا مع %{code_license}."
|
||||
footer_legal_text_html: "شبكة الغذاء المفتوح عبترة عن منصة حرة ومفتوحة برمجيات المصدر. تم ترخيص المحتوى الخاص بنا باستخدام %{content_license} ورمزنا مع %{code_license}."
|
||||
footer_data_text_with_privacy_policy_html: "نحن نحرص على البيانات الخاصة بك. انظر %{privacy_policy} و %{cookies_policy}"
|
||||
footer_data_text_without_privacy_policy_html: "نحن نحرص على البيانات الخاصة بك. انظر %{cookies_policy} لدينا"
|
||||
footer_data_privacy_policy: "سياسة خاصة"
|
||||
@@ -1384,26 +1379,26 @@ ar:
|
||||
cookies_policy_link: "اتفاقية ملفات تعريف الارتباط"
|
||||
cookies_accept_button: "قبول ملفات تعريف الارتباط"
|
||||
home_shop: تسوق الآن
|
||||
brandstory_headline: "قم بدعم الانتاج المحلي"
|
||||
brandstory_intro: "سيساعدك المجتمع عبر الإنترنت في بناء مشروعك الغذائي بنجاح ..."
|
||||
brandstory_part1: "تتيح منصة فلاحة - شبكة الغذاء المفتوح للمزارعين ببيع منتجاتهم عبر الإنترنت بسعر يناسبهم. لقد تم تصميمه خصيصًا لبيع الغذاء حتى يتمكن من التعامل مع الإجراءات الصعبة أو و بمعايير مناسبة للافراد و العائلات كعدد من حبات البندورة الى الكيلو انتهاءا بالطن, دزينة من البيض ، وضمةمن البقدونس ، ودجاجة كاملة بمختلف الاوزان ..."
|
||||
brandstory_part2: "يمكن لمنتجي الغذاء إنشاء متجر الكتروني ، وتحصيل المدفوعات ، والبيع من خلال متاجر أخرى على المنصة والوصول إلى خدمات التوصيل بأسعار مخفضة. "
|
||||
brandstory_part3: "يمكن لتجار الجملة دمج منصة فلاحة مع أنظمتهم الحالية وإدارة مجموعات الشراء لتزويد العملاء بمنتجاتهم من خلال شبكتنا الوطنية و مراكز البيع ومتاجر الأغذية."
|
||||
brandstory_part4: "يمكن للمجتمعات أن تجمع المنتجين في منطقتهم المحلية لإنشاء أسواق افتراضية للمزارعين ، وبناء اقتصاد غذائي محلي مرن."
|
||||
brandstory_part5_strong: "وما لا يقل أهمية عن المنصة نفسها هو القيم التي تدعمها."
|
||||
brandstory_part6: "إذا كنت تبيع طعامًا جيدًا - كمزارع ، سوق زراعي، جمعية تعاونية منتجة، مركز طعام - فاختر برنامجًا يتوافق مع قيمك لبناء أنظمة غذائية للناس و الوطن. من خلال العمل الجماعي بدلاً من التنافس ، نشارك تكاليف تطوير برامج جديدة ، ونضمن أن مشروعنا مرن!"
|
||||
brandstory_headline: "الغذاء ، غير مدمج."
|
||||
brandstory_intro: "في بعض الأحيان تكون أفضل طريقة لإصلاح النظام هي بدء نظام جديد ..."
|
||||
brandstory_part1: "نبدأ من الألف إلى الياء. مع المزارعين على استعداد لرواية قصصهم بفخر وحقا. مع الموزعين على استعداد لتوصيل الأشخاص بالمنتجات بطريقة عادلة وبصدق. مع المشترين الذين يعتقدون أن أفضل قرارات التسوق الأسبوعية يمكن أن تغير العالم بشكل خطير."
|
||||
brandstory_part2: "ثم نحن بحاجة إلى وسيلة لجعلها حقيقية. طريقة لتمكين كل من يزرع, يبيع ويشتري الغذاء. طريقة لرواية جميع القصص ، للتعامل مع جميع الخدمات اللوجستية. طريقة لتحويل المعاملة إلى تطور كل يوم."
|
||||
brandstory_part3: "لذلك نقوم ببناء سوق على الإنترنت يعمل على تسوية الملعب. بشكل شفاف ، وذلك لخلق علاقات حقيقية. إنه مفتوح المصدر ، لذلك يمتلكه الجميع. يتم توسيعه حسب المناطق والأمم ، لذا يبدأ الناس بالإصدارات في جميع أنحاء العالم."
|
||||
brandstory_part4: "إنه يعمل في كل مكان. إنه يغير كل شيء."
|
||||
brandstory_part5_strong: "نحن نسميها شبكة الغذاء المفتوح."
|
||||
brandstory_part6: "كلنا نحب الطعام. الآن يمكننا أن نحب نظامنا الغذائي أيضا."
|
||||
learn_body: "استكشف النماذج والقصص والموارد لدعمك لتطوير أعمالك التجارية أو مؤسستك الخاصة بالطعام الجيد. البحث عن التدريب والأحداث والفرص الأخرى للتعلم من أقرانهم."
|
||||
learn_cta: "اشعل حماسك"
|
||||
connect_body: "ابحث في الدلائل الكاملة للمنتجين والمراكز والمجموعات للعثور على تجار المواد الغذائية العادلة بالقرب منك. أدرج عملك أو مؤسستك على شبكة الغذاء المفتوحة حتى يتمكن المشترون من العثور عليك. انضم إلى المجتمع للحصول على المشورة وحل المشكلات معًا."
|
||||
connect_cta: "الذهاب لاستكشاف"
|
||||
system_headline: "البيع على منصة فلاحة 3 خطوات سهلة"
|
||||
system_step1: "1. أنشئ مؤسستك"
|
||||
system_step1_text: "قم بإعداد مؤسستك بالاسم والوصف والصور وتفاصيل الاتصال وروابط الوسائط الاجتماعية."
|
||||
system_step2: "2. أضف منتجاتك"
|
||||
system_step2_text: "أضف منتجات إلى متجرك - خاصة بك و / أو من منتجين آخرين من حولك. تعيين الصور والأوصاف والأسعار المخزون والأوزان والمقاييس المرنة!"
|
||||
system_step3: "3. عمليات التسليم الخاصة بك"
|
||||
system_step3_text: "قم بإعداد طرق الدفع. إنشاء نقاط استلام متعددة وتفاصيل التسليم. إنشاء أوامر متكررة وتوزيعات منتظمة."
|
||||
cta_headline: "شبكة الغذاء المستدامة في المستقبل."
|
||||
system_headline: "التسوق - إليك كيف تعمل."
|
||||
system_step1: "1. البحث"
|
||||
system_step1_text: "ابحث في متاجرنا المتنوعة والمستقلة للطعام المحلي الموسمي. البحث عن طريق الحي وفئة الطعام ، أو ما إذا كنت تفضل التسليم أو الاستلام."
|
||||
system_step2: "2. متجر"
|
||||
system_step2_text: "حول معاملاتك الغذائية المحلية بأسعار معقولة من مختلف المنتجين والمراكز. تعرف على القصص وراء طعامك والأشخاص الذين يصنعونه!"
|
||||
system_step3: "3. الاستلام / التسليم"
|
||||
system_step3_text: "تشبث بالتسليم ، أو تفضل بزيارة المنتج أو المحور للحصول على اتصال شخصي أكثر مع طعامك. التسوق الطعام متنوعة مثل الطبيعة المقصود منه."
|
||||
cta_headline: "التسوق الذي يجعل العالم مكانًا أفضل."
|
||||
cta_label: "أنا مستعد"
|
||||
stats_headline: "نحن بصدد إنشاء نظام غذائي جديد."
|
||||
stats_producers: "منتجي المواد الغذائية"
|
||||
@@ -2311,7 +2306,6 @@ ar:
|
||||
enterprise_name_error: "لقد اتخذت بالفعل. إذا كانت هذه هي مؤسستك وترغب في المطالبة بالملكية ، أو إذا كنت ترغب في التداول مع هذا المشروع ، فيرجى الاتصال بالمدير الحالي لملف التعريف هذا على %{email}."
|
||||
enterprise_owner_error: "^ %{email} غير مسموح به لامتلاك أي مؤسسات أخرى (الحد الأقصى هو %{enterprise_limit})."
|
||||
enterprise_role_uniqueness_error: "^ هذا الدور موجود بالفعل."
|
||||
enterprise_terms_and_conditions_type_error: "يسمح فقط بملفات PDF"
|
||||
inventory_item_visibility_error: يجب أن تكون صحيحة أو خاطئة
|
||||
product_importer_file_error: "خطأ: لم يتم تحميل الملف"
|
||||
product_importer_spreadsheet_error: "لا يمكن معالجة الملف: ملف غير صالح"
|
||||
@@ -2576,15 +2570,6 @@ ar:
|
||||
error_saving: "خطأ في حفظ الاشتراك"
|
||||
new:
|
||||
please_select_a_shop: "يرجى اختيار متجر"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "تمت إزالة الشعار بنجاح"
|
||||
immediate_logo_removal_warning: "سيتم إزالة الشعار مباشرة بعد التأكيد."
|
||||
removed_promo_image_successfully: "تمت إزالة الصورة الترويجية بنجاح"
|
||||
immediate_promo_image_removal_warning: "ستتم إزالة صورة الترويجي فور التأكيد."
|
||||
immediate_terms_and_conditions_removal_warning: "ستتم إزالة ملف الشروط والأحكام فورًا بعد التأكيد."
|
||||
removed_terms_and_conditions_successfully: "تمت إزالة ملف الشروط والأحكام بنجاح"
|
||||
insufficient_stock: "مخزون غير متوفر ، تبقى %{on_hand}"
|
||||
out_of_stock:
|
||||
reduced_stock_available: انخفاض المخزون المتاح
|
||||
@@ -2658,11 +2643,6 @@ ar:
|
||||
signup_or_login: "البدء بالتسجيل (أو تسجيل الدخول)"
|
||||
have_an_account: "هل لديك حساب؟"
|
||||
action_login: "تسجيل الدخول الآن."
|
||||
stripe_elements:
|
||||
unknown_error_from_stripe: |
|
||||
كانت هناك مشكلة في إعداد بطاقتك في بوابة المدفوعات الخاصة بنا.
|
||||
يرجى تحديث الصفحة والمحاولة مرة أخرى ، إذا فشلت مرة أخرى ،
|
||||
يرجى الاتصال بنا للحصول على الدعم.
|
||||
inflections:
|
||||
each:
|
||||
zero: "كل"
|
||||
|
||||
@@ -120,10 +120,6 @@ ca:
|
||||
integer_array_validator:
|
||||
not_array_error: "ha de ser una matriu"
|
||||
invalid_element_error: "ha de contenir només nombres enters vàlids"
|
||||
datetime_picker_ui:
|
||||
current_text: Ara
|
||||
close_text: Fet
|
||||
time_text: Hora
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Sisplau, confirma l'adreça electrònica d'%{enterprise}"
|
||||
@@ -601,7 +597,7 @@ ca:
|
||||
order_date: "Completada a"
|
||||
max: "Màx"
|
||||
product_unit: "Producte: Unitat"
|
||||
weight_volume: "Pes / Volum (g)"
|
||||
weight_volume: "Pes/Volum"
|
||||
ask: "Preguntar?"
|
||||
page_title: "Gestió de les comandes en bloc"
|
||||
actions_delete: "Suprimeix seleccionats"
|
||||
@@ -638,8 +634,6 @@ ca:
|
||||
acn_placeholder: p. ex. 123 456 789
|
||||
display_invoice_logo: Mostreu el logotip a les factures
|
||||
invoice_text: Afegeix text personalitzat al final de les factures
|
||||
terms_and_conditions: "Termes i condicions"
|
||||
remove_terms_and_conditions: "Elimina el fitxer"
|
||||
contact:
|
||||
name: Nom
|
||||
name_placeholder: 'p. ex: Josep Ribes'
|
||||
@@ -662,8 +656,6 @@ ca:
|
||||
promo_image_note1: 'ATENCIÓ:'
|
||||
promo_image_note2: Qualsevol imatge promocional que es carregui aquí es tallarà a 1200 x 260.
|
||||
promo_image_note3: 'La imatge promocional es mostra a la part superior de la pàgina de perfil i finestres emergents d''una organització '
|
||||
remove_logo: "Elimina la imatge "
|
||||
remove_promo_image: "Elimina la imatge "
|
||||
inventory_settings:
|
||||
text1: 'Pots optar per gestionar els nivells d''existències i els preus a través del teu '
|
||||
inventory: inventari
|
||||
@@ -854,6 +846,14 @@ ca:
|
||||
new:
|
||||
title: Nova organització
|
||||
back_link: 'Tornar a la llista d''organitzacions '
|
||||
remove_logo:
|
||||
remove: "Elimina la imatge"
|
||||
removed_successfully: "Logotip eliminat correctament"
|
||||
immediate_removal_warning: "El logotip s'eliminarà immediatament després de confirmar."
|
||||
remove_promo_image:
|
||||
remove: "Elimina la imatge "
|
||||
removed_successfully: "Imatge promocional eliminada correctament"
|
||||
immediate_removal_warning: "La imatge promocional s'eliminarà immediatament després de confirmar."
|
||||
welcome:
|
||||
welcome_title: Benvingut a Katuma - Open Food Network!
|
||||
welcome_text: Heu creat correctament un
|
||||
@@ -1151,17 +1151,12 @@ ca:
|
||||
destroy_attachment_does_not_exist: "El logotip no existeix"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "La imatge promocional no existeix"
|
||||
enterprise_terms_and_conditions:
|
||||
destroy_attachment_does_not_exist: "El fitxer de termes i condicions no existeix"
|
||||
orders:
|
||||
failed_to_update: "No s'ha pogut actualitzar la comanda"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cistella"
|
||||
message_html: "Ja teniu una comanda per a aquest cicle de comanda. Consulteu %{cart} per veure els articles que heu demanat anteriorment. També podeu cancel·lar articles sempre que el cicle de comanda estigui obert."
|
||||
terms_and_conditions:
|
||||
message_html: "En fer aquesta comanda accepteu %{terms_and_conditions_link}."
|
||||
link_text: "Termes del servei"
|
||||
failed: "La comanda ha fallat. Informeu-nos perquè puguem processar la vostra comanda."
|
||||
shops:
|
||||
hubs:
|
||||
@@ -2307,7 +2302,6 @@ ca:
|
||||
enterprise_name_error: "ja ha estat agafat. Si aquesta és la vostra organització i voleu reclamar-ne la propietat o si voleu comerciar amb aquesta organització, poseu-vos en contacte amb l'administradora actual d'aquest perfil %{email}."
|
||||
enterprise_owner_error: "^ %{email} no està autoritzat a tenir més organitzacions (el límit és %{enterprise_limit})."
|
||||
enterprise_role_uniqueness_error: "^ Aquest rol ja està present."
|
||||
enterprise_terms_and_conditions_type_error: "Només s’admeten fitxers PDF"
|
||||
inventory_item_visibility_error: ha de ser veritable o falsa
|
||||
product_importer_file_error: "error: no s'ha carregat cap fitxer"
|
||||
product_importer_spreadsheet_error: "no s'ha pogut processar el fitxer: tipus de fitxer no vàlid"
|
||||
@@ -2582,15 +2576,6 @@ ca:
|
||||
error_saving: "S'ha produït un error en desar la subscripció"
|
||||
new:
|
||||
please_select_a_shop: "Si us plau, seleccioneu una botiga"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logotip eliminat correctament"
|
||||
immediate_logo_removal_warning: "El logotip s'eliminarà immediatament després de confirmar."
|
||||
removed_promo_image_successfully: "Imatge promocional eliminada correctament"
|
||||
immediate_promo_image_removal_warning: "La imatge promocional s'eliminarà immediatament després de confirmar."
|
||||
immediate_terms_and_conditions_removal_warning: "El fitxer de termes i condicions s’eliminarà immediatament després de confirmar-ho."
|
||||
removed_terms_and_conditions_successfully: "El fitxer de termes i condicions s’ha eliminat correctament"
|
||||
insufficient_stock: "No hi ha prou estoc disponible, només queda %{on_hand}"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Estoc reduït disponible
|
||||
@@ -2664,9 +2649,6 @@ ca:
|
||||
signup_or_login: "Comenceu registrant-vos (o iniciant sessió)"
|
||||
have_an_account: "Ja tens un compte?"
|
||||
action_login: "Inicia la sessió ara."
|
||||
stripe_elements:
|
||||
unknown_error_from_stripe: |
|
||||
Hi ha hagut un problema al configurar la vostra targeta a la nostra passarel·la de pagaments. Actualitzeu la pàgina i torneu-ho a provar; si falla una segona vegada, poseu-vos en contacte amb nosaltres per obtenir assistència.
|
||||
inflections:
|
||||
each:
|
||||
one: "cadascun"
|
||||
|
||||
@@ -586,6 +586,7 @@ de_DE:
|
||||
order_date: "Abgeschlossen am"
|
||||
max: "Max"
|
||||
product_unit: "Produkt: Einheit"
|
||||
weight_volume: "Gewicht / Volumen"
|
||||
ask: "Fragen?"
|
||||
page_title: "Massenbearbeitung von Bestellungen"
|
||||
actions_delete: "Ausgewählte löschen"
|
||||
@@ -644,8 +645,6 @@ de_DE:
|
||||
promo_image_note1: 'BITTE BEACHTEN SIE:'
|
||||
promo_image_note2: Jedes hier hochgeladene Werbebild wird auf 1200 x 260 beschnitten.
|
||||
promo_image_note3: Das Werbebild wird oben auf der Profilseite eines Unternehmens und in Pop-ups angezeigt.
|
||||
remove_logo: "Bild entfernen"
|
||||
remove_promo_image: "Bild entfernen"
|
||||
inventory_settings:
|
||||
text1: Sie verwalten optional Ihre Lagerbestände und Preise auch in Ihrem
|
||||
inventory: Katalog
|
||||
@@ -832,6 +831,14 @@ de_DE:
|
||||
new:
|
||||
title: Neues Unternehmen
|
||||
back_link: Zurück zur Unternehmensliste
|
||||
remove_logo:
|
||||
remove: "Bild entfernen"
|
||||
removed_successfully: "Das Logo wurde erfolgreich entfernt"
|
||||
immediate_removal_warning: "Das Logo wird sofort nach der Bestätigung entfernt."
|
||||
remove_promo_image:
|
||||
remove: "Bild entfernen"
|
||||
removed_successfully: "Werbebild wurde erfolgreich entfernt"
|
||||
immediate_removal_warning: "Das Werbebild wird sofort nach der Bestätigung entfernt."
|
||||
welcome:
|
||||
welcome_title: Willkommen im Open Food Network!
|
||||
welcome_text: 'Erfolgreich erstellt:'
|
||||
@@ -2522,13 +2529,6 @@ de_DE:
|
||||
error_saving: "Fehler beim Speichern des Abonnements"
|
||||
new:
|
||||
please_select_a_shop: "Bitte wählen Sie einen Laden"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Das Logo wurde erfolgreich entfernt"
|
||||
immediate_logo_removal_warning: "Das Logo wird sofort nach der Bestätigung entfernt."
|
||||
removed_promo_image_successfully: "Werbebild wurde erfolgreich entfernt"
|
||||
immediate_promo_image_removal_warning: "Das Werbebild wird sofort nach der Bestätigung entfernt."
|
||||
insufficient_stock: "Nicht genügend Lagerbestand verfügbar, nur noch %{on_hand} verfügbar"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduzierter Bestand verfügbar
|
||||
|
||||
@@ -145,10 +145,6 @@ en:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
|
||||
datetime_picker_ui:
|
||||
current_text: Now
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -656,7 +652,7 @@ en:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume (g)"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -694,8 +690,6 @@ en:
|
||||
acn_placeholder: eg. 123 456 789
|
||||
display_invoice_logo: Display logo in invoices
|
||||
invoice_text: Add customized text at the end of invoices
|
||||
terms_and_conditions: "Terms and Conditions"
|
||||
remove_terms_and_conditions: "Remove File"
|
||||
contact:
|
||||
name: Name
|
||||
name_placeholder: eg. Gustav Plum
|
||||
@@ -718,8 +712,6 @@ en:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -904,6 +896,14 @@ en:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -1211,8 +1211,6 @@ en:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
enterprise_terms_and_conditions:
|
||||
destroy_attachment_does_not_exist: "Terms and Conditions file does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
|
||||
@@ -1225,9 +1223,6 @@ en:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
|
||||
terms_and_conditions:
|
||||
message_html: "By placing this order you agree to the %{terms_and_conditions_link}."
|
||||
link_text: "Terms of Service"
|
||||
failed: "The checkout failed. Please let us know so that we can process your order."
|
||||
shops:
|
||||
hubs:
|
||||
@@ -2438,7 +2433,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}."
|
||||
enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
|
||||
enterprise_role_uniqueness_error: "^That role is already present."
|
||||
enterprise_terms_and_conditions_type_error: "Only PDFs are allowed"
|
||||
inventory_item_visibility_error: must be true or false
|
||||
product_importer_file_error: "error: no file uploaded"
|
||||
product_importer_spreadsheet_error: "could not process file: invalid filetype"
|
||||
@@ -2704,15 +2698,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
immediate_terms_and_conditions_removal_warning: "The Terms and Conditions file will be removed immediately after you confirm."
|
||||
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -113,8 +113,6 @@ en_AU:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -580,6 +578,7 @@ en_AU:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -638,8 +637,6 @@ en_AU:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -834,6 +831,14 @@ en_AU:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2510,13 +2515,6 @@ en_AU:
|
||||
subscriptions:
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -112,8 +112,6 @@ en_BE:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -569,6 +567,7 @@ en_BE:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -627,8 +626,6 @@ en_BE:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -809,6 +806,14 @@ en_BE:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2470,13 +2475,6 @@ en_BE:
|
||||
subscriptions:
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -120,10 +120,6 @@ en_CA:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
current_text: Now
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -601,7 +597,7 @@ en_CA:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume (g)"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -638,8 +634,6 @@ en_CA:
|
||||
acn_placeholder: eg.80781 2466
|
||||
display_invoice_logo: Display logo in invoices
|
||||
invoice_text: Add customized text at the end of invoices
|
||||
terms_and_conditions: "Terms and Conditions"
|
||||
remove_terms_and_conditions: "Remove File"
|
||||
contact:
|
||||
name: Name
|
||||
name_placeholder: eg. Gustav Plum
|
||||
@@ -662,8 +656,6 @@ en_CA:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -851,6 +843,14 @@ en_CA:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -1148,17 +1148,12 @@ en_CA:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
enterprise_terms_and_conditions:
|
||||
destroy_attachment_does_not_exist: "Terms and Conditions file does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
|
||||
terms_and_conditions:
|
||||
message_html: "By placing this order you agree to the %{terms_and_conditions_link}."
|
||||
link_text: "Terms of Service"
|
||||
failed: "The checkout failed. Please let us know so that we can process your order."
|
||||
shops:
|
||||
hubs:
|
||||
@@ -2304,7 +2299,6 @@ en_CA:
|
||||
enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}."
|
||||
enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
|
||||
enterprise_role_uniqueness_error: "^That role is already present."
|
||||
enterprise_terms_and_conditions_type_error: "Only PDFs are allowed"
|
||||
inventory_item_visibility_error: must be true or false
|
||||
product_importer_file_error: "error: no file uploaded"
|
||||
product_importer_spreadsheet_error: "could not process file: invalid filetype"
|
||||
@@ -2575,15 +2569,6 @@ en_CA:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
immediate_terms_and_conditions_removal_warning: "The Terms and Conditions file will be removed immediately after you confirm."
|
||||
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -113,8 +113,6 @@ en_DE:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -577,6 +575,7 @@ en_DE:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -635,8 +634,6 @@ en_DE:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -817,6 +814,14 @@ en_DE:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2480,13 +2485,6 @@ en_DE:
|
||||
subscriptions:
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -120,10 +120,6 @@ en_FR:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
current_text: Now
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -601,7 +597,7 @@ en_FR:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume (g)"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -638,8 +634,6 @@ en_FR:
|
||||
acn_placeholder: eg. 123 456 789
|
||||
display_invoice_logo: Display logo in invoices
|
||||
invoice_text: Add customized text at the end of invoices
|
||||
terms_and_conditions: "Terms and Conditions"
|
||||
remove_terms_and_conditions: "Remove File"
|
||||
contact:
|
||||
name: Name
|
||||
name_placeholder: eg. Gustav Plum
|
||||
@@ -662,8 +656,6 @@ en_FR:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -851,6 +843,14 @@ en_FR:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -1148,17 +1148,12 @@ en_FR:
|
||||
destroy_attachment_does_not_exist: "Logo does not exist"
|
||||
enterprise_promo_image:
|
||||
destroy_attachment_does_not_exist: "Promo image does not exist"
|
||||
enterprise_terms_and_conditions:
|
||||
destroy_attachment_does_not_exist: "Terms and Conditions file does not exist"
|
||||
orders:
|
||||
failed_to_update: "Failed to update order"
|
||||
checkout:
|
||||
already_ordered:
|
||||
cart: "cart"
|
||||
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
|
||||
terms_and_conditions:
|
||||
message_html: "By placing this order you agree to the%{terms_and_conditions_link}."
|
||||
link_text: "Terms of Service"
|
||||
failed: "The checkout failed. Please let us know so that we can process your order."
|
||||
shops:
|
||||
hubs:
|
||||
@@ -1248,9 +1243,9 @@ en_FR:
|
||||
menu_3_url: "/producers"
|
||||
menu_4_title: "Groups"
|
||||
menu_4_url: "/groups"
|
||||
menu_5_title: "Open my shop"
|
||||
menu_5_title: "About"
|
||||
menu_5_url: "https://apropos.coopcircuits.fr/"
|
||||
menu_6_title: "About"
|
||||
menu_6_title: "Connect"
|
||||
menu_6_url: "https://apropos.coopcircuits.fr/blog/"
|
||||
menu_7_title: "Learn"
|
||||
menu_7_url: "https://apropos.coopcircuits.fr/ressources/"
|
||||
@@ -2304,7 +2299,6 @@ en_FR:
|
||||
enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}."
|
||||
enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
|
||||
enterprise_role_uniqueness_error: "^That role is already present."
|
||||
enterprise_terms_and_conditions_type_error: "Only PDFs are allowed"
|
||||
inventory_item_visibility_error: must be true or false
|
||||
product_importer_file_error: "error: no file uploaded"
|
||||
product_importer_spreadsheet_error: "could not process file: invalid filetype"
|
||||
@@ -2576,15 +2570,6 @@ en_FR:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
immediate_terms_and_conditions_removal_warning: "The Terms and Conditions file will be removed immediately after you confirm."
|
||||
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -120,9 +120,6 @@ en_GB:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -600,6 +597,7 @@ en_GB:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -658,8 +656,6 @@ en_GB:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -847,6 +843,14 @@ en_GB:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2572,13 +2576,6 @@ en_GB:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -120,9 +120,6 @@ en_IE:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -599,6 +596,7 @@ en_IE:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -657,8 +655,6 @@ en_IE:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -844,6 +840,14 @@ en_IE:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2569,13 +2573,6 @@ en_IE:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
@@ -119,9 +119,6 @@ en_IN:
|
||||
integer_array_validator:
|
||||
not_array_error: "must be an array"
|
||||
invalid_element_error: "must contain only valid integers"
|
||||
datetime_picker_ui:
|
||||
close_text: Done
|
||||
time_text: Time
|
||||
enterprise_mailer:
|
||||
confirmation_instructions:
|
||||
subject: "Please confirm the email address for %{enterprise}"
|
||||
@@ -595,6 +592,7 @@ en_IN:
|
||||
order_date: "Completed at"
|
||||
max: "Max"
|
||||
product_unit: "Product: Unit"
|
||||
weight_volume: "Weight/Volume"
|
||||
ask: "Ask?"
|
||||
page_title: "Bulk Order Management"
|
||||
actions_delete: "Delete Selected"
|
||||
@@ -653,8 +651,6 @@ en_IN:
|
||||
promo_image_note1: 'PLEASE NOTE:'
|
||||
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
|
||||
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
|
||||
remove_logo: "Remove Image"
|
||||
remove_promo_image: "Remove Image"
|
||||
inventory_settings:
|
||||
text1: You may opt to manage stock levels and prices in via your
|
||||
inventory: inventory
|
||||
@@ -840,6 +836,14 @@ en_IN:
|
||||
new:
|
||||
title: New Enterprise
|
||||
back_link: Back to enterprises list
|
||||
remove_logo:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Logo removed successfully"
|
||||
immediate_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
remove_promo_image:
|
||||
remove: "Remove Image"
|
||||
removed_successfully: "Promo image removed successfully"
|
||||
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
welcome:
|
||||
welcome_title: Welcome to the Open Food Network!
|
||||
welcome_text: You have successfully created a
|
||||
@@ -2563,13 +2567,6 @@ en_IN:
|
||||
error_saving: "Error saving subscription"
|
||||
new:
|
||||
please_select_a_shop: "Please select a shop"
|
||||
enterprises:
|
||||
form:
|
||||
images:
|
||||
removed_logo_successfully: "Logo removed successfully"
|
||||
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
|
||||
removed_promo_image_successfully: "Promo image removed successfully"
|
||||
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
|
||||
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
|
||||
out_of_stock:
|
||||
reduced_stock_available: Reduced stock available
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user