Compare commits

..

1 Commits

Author SHA1 Message Date
Maikel Linke
e6a1021d6e Update latest translations 2020-09-15 16:19:00 +10:00
172 changed files with 1654 additions and 7547 deletions

View File

@@ -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. -->

View File

@@ -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" && \

View File

@@ -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)

View File

@@ -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) ->

View File

@@ -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);

View File

@@ -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)

View File

@@ -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) ->

View File

@@ -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

View File

@@ -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()

View File

@@ -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'
})

View File

@@ -52,4 +52,3 @@ angular.module("admin.resources").factory 'Enterprises', ($q, EnterpriseResource
removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo)
removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage)
removeTermsAndConditions: performActionOnEnterpriseResource(EnterpriseResource.removeTermsAndConditions)

View File

@@ -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}"

View File

@@ -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();
}
})
};

View File

@@ -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();
});

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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;
}

View 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;
}

View File

@@ -212,7 +212,7 @@ nav.top-bar {
}
.off-canvas-wrap {
overflow: initial;
overflow: inherit;
}
.off-canvas-list li.language-switcher ul li {

View File

@@ -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?

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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] }]

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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',

View File

@@ -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' },

View File

@@ -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|

View File

@@ -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

View 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

View File

@@ -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

View 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

View 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

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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?

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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?

View File

@@ -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

View File

@@ -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.

View File

@@ -1,3 +1,3 @@
class Api::StateSerializer < ActiveModel::Serializer
attributes :id, :name, :abbr, :country_id
attributes :id, :name, :abbr
end

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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')

View File

@@ -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')

View File

@@ -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

View File

@@ -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|

View File

@@ -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?

View 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"}

View File

@@ -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');
}
});

View File

@@ -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

View File

@@ -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'

View File

@@ -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 }

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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'

View File

@@ -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'

View File

@@ -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'

View File

@@ -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 &nbsp;
.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' }

View File

@@ -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}}
'

View File

@@ -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'

View 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 %>

View File

@@ -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)

View File

@@ -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>

View File

@@ -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),

View File

@@ -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'

View File

@@ -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')

View File

@@ -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'

View File

@@ -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 الخاص بك بـ شبكة الغذاء المفتوح. النقر فوق &quot;أوافق&quot; أدناه إلى إعادة توجيهك إلى موقع 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: "كل"

View File

@@ -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 sadmeten 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 seliminarà immediatament després de confirmar-ho."
removed_terms_and_conditions_successfully: "El fitxer de termes i condicions sha 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"

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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