mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-16 19:16:49 +00:00
Compare commits
115 Commits
RachL-patc
...
v5.0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee2a6bf2e6 | ||
|
|
7ca5927411 | ||
|
|
118ed915dc | ||
|
|
6e40e4da60 | ||
|
|
693bef1e7a | ||
|
|
42940f4729 | ||
|
|
f2da3bb11c | ||
|
|
f8003b00db | ||
|
|
521b72a6c9 | ||
|
|
aa4552aac4 | ||
|
|
93a3130851 | ||
|
|
f3a30f94db | ||
|
|
16cae2dbcc | ||
|
|
4c71ea3866 | ||
|
|
bc970927a5 | ||
|
|
c331d57cdb | ||
|
|
5845fee663 | ||
|
|
de938f6f10 | ||
|
|
697f430156 | ||
|
|
c41c15b895 | ||
|
|
af200ab4a0 | ||
|
|
4c6c1eedb1 | ||
|
|
bbdee7c0f3 | ||
|
|
11959515b8 | ||
|
|
cb781536b6 | ||
|
|
5719d0682d | ||
|
|
c4c95d472e | ||
|
|
3e7f61c4d1 | ||
|
|
db76cd1659 | ||
|
|
e791184468 | ||
|
|
23287573f4 | ||
|
|
925ac2ea6a | ||
|
|
355c9686e3 | ||
|
|
58d174fad9 | ||
|
|
d90c4f6aed | ||
|
|
f5b9ca361c | ||
|
|
16d6e1f935 | ||
|
|
1e6fbadd8b | ||
|
|
d102652c03 | ||
|
|
1b50217242 | ||
|
|
73819a4638 | ||
|
|
9ab2a3ae3d | ||
|
|
d413a142c9 | ||
|
|
48ad7ed8a0 | ||
|
|
a2c4c44eea | ||
|
|
e7ece294cc | ||
|
|
d7313ffec9 | ||
|
|
b42cba8c37 | ||
|
|
7726c7d129 | ||
|
|
d4d995851f | ||
|
|
12cf62c2ff | ||
|
|
0569b30e0d | ||
|
|
9f3da1af4f | ||
|
|
afb336d789 | ||
|
|
92c4cb9b7f | ||
|
|
724d5a2ca0 | ||
|
|
6251814152 | ||
|
|
cf13dc2ff6 | ||
|
|
4906c19c8e | ||
|
|
129ccc33f8 | ||
|
|
9399c7e129 | ||
|
|
c17eddd69b | ||
|
|
b30096317c | ||
|
|
c89b4fb86b | ||
|
|
3a367ceb6e | ||
|
|
f9fb7bf399 | ||
|
|
0f9b933117 | ||
|
|
7cbe77668a | ||
|
|
479eacc956 | ||
|
|
e7213dba68 | ||
|
|
078e191d26 | ||
|
|
b554eda7c7 | ||
|
|
477447ad92 | ||
|
|
039399ee37 | ||
|
|
d36438037a | ||
|
|
5b58f7b20e | ||
|
|
02e2214caa | ||
|
|
0ec8d13641 | ||
|
|
151fc7bf85 | ||
|
|
15c920c911 | ||
|
|
b4aaa0fae1 | ||
|
|
efe0a2a701 | ||
|
|
3f905cce16 | ||
|
|
5c5213e872 | ||
|
|
3a7aed154c | ||
|
|
60ace5d3ff | ||
|
|
1dec3debe1 | ||
|
|
711f37bce1 | ||
|
|
a493d70f5c | ||
|
|
c0887b1806 | ||
|
|
3d09ac01cc | ||
|
|
3a3d729dcb | ||
|
|
283706114e | ||
|
|
7ca544540b | ||
|
|
b1b4b10417 | ||
|
|
3b83200a14 | ||
|
|
7cd8311dcb | ||
|
|
14e7c57102 | ||
|
|
9f859f420d | ||
|
|
af33fc357e | ||
|
|
6a8cc410d2 | ||
|
|
61e7c1db07 | ||
|
|
0d8df5d2a8 | ||
|
|
73a1698aad | ||
|
|
97d41c230e | ||
|
|
1b4efd2164 | ||
|
|
1e13005fb5 | ||
|
|
7a5074cc90 | ||
|
|
41ffe848ed | ||
|
|
0797314360 | ||
|
|
3302f0e78d | ||
|
|
bafb881c46 | ||
|
|
32ab821839 | ||
|
|
008d764c34 | ||
|
|
9c51615b03 |
@@ -34,12 +34,6 @@ Lint/EmptyClass:
|
||||
Exclude:
|
||||
- 'spec/lib/reports/report_loader_spec.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Configuration parameters: AllowComments.
|
||||
Lint/EmptyFile:
|
||||
Exclude:
|
||||
- 'spec/lib/open_food_network/enterprise_injection_data_spec.rb'
|
||||
|
||||
# Offense count: 2
|
||||
Lint/FloatComparison:
|
||||
Exclude:
|
||||
@@ -92,7 +86,6 @@ Metrics/AbcSize:
|
||||
- 'app/controllers/admin/enterprises_controller.rb'
|
||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
||||
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||
- 'app/controllers/spree/admin/variants_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||
@@ -127,7 +120,7 @@ Metrics/BlockNesting:
|
||||
Exclude:
|
||||
- 'app/models/spree/payment/processing.rb'
|
||||
|
||||
# Offense count: 46
|
||||
# Offense count: 47
|
||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||
Metrics/ClassLength:
|
||||
Exclude:
|
||||
@@ -137,6 +130,7 @@ Metrics/ClassLength:
|
||||
- 'app/controllers/admin/resource_controller.rb'
|
||||
- 'app/controllers/admin/subscriptions_controller.rb'
|
||||
- 'app/controllers/application_controller.rb'
|
||||
- 'app/controllers/checkout_controller.rb'
|
||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||
- 'app/controllers/spree/admin/orders_controller.rb'
|
||||
- 'app/controllers/spree/admin/payment_methods_controller.rb'
|
||||
@@ -183,7 +177,7 @@ Metrics/ClassLength:
|
||||
Metrics/CyclomaticComplexity:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/enterprises_controller.rb'
|
||||
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/helpers/checkout_helper.rb'
|
||||
- 'app/helpers/order_cycles_helper.rb'
|
||||
@@ -208,13 +202,12 @@ Metrics/CyclomaticComplexity:
|
||||
- 'lib/spree/localized_number.rb'
|
||||
- 'spec/models/product_importer_spec.rb'
|
||||
|
||||
# Offense count: 24
|
||||
# Offense count: 23
|
||||
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
||||
Metrics/MethodLength:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/enterprises_controller.rb'
|
||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||
- 'app/models/spree/ability.rb'
|
||||
@@ -293,19 +286,17 @@ Metrics/ParameterLists:
|
||||
- 'spec/support/controller_requests_helper.rb'
|
||||
- 'spec/system/admin/reports_spec.rb'
|
||||
|
||||
# Offense count: 4
|
||||
# Offense count: 3
|
||||
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
||||
Metrics/PerceivedComplexity:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||
- 'app/models/enterprise_relationship.rb'
|
||||
- 'app/models/spree/ability.rb'
|
||||
- 'app/models/spree/order/checkout.rb'
|
||||
|
||||
# Offense count: 8
|
||||
# Offense count: 7
|
||||
Naming/AccessorMethodName:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/admin/taxonomies_controller.rb'
|
||||
- 'app/mailers/producer_mailer.rb'
|
||||
- 'app/models/spree/order.rb'
|
||||
- 'app/services/checkout/post_checkout_actions.rb'
|
||||
@@ -353,7 +344,7 @@ Naming/VariableNumber:
|
||||
- 'spec/models/spree/tax_rate_spec.rb'
|
||||
- 'spec/requests/api/orders_spec.rb'
|
||||
|
||||
# Offense count: 142
|
||||
# Offense count: 143
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
# Configuration parameters: ResponseMethods.
|
||||
# ResponseMethods: response, last_response
|
||||
@@ -557,7 +548,7 @@ RSpecRails/InferredSpecType:
|
||||
- 'spec/requests/voucher_adjustments_spec.rb'
|
||||
- 'spec/routing/stripe_spec.rb'
|
||||
|
||||
# Offense count: 22
|
||||
# Offense count: 21
|
||||
# Configuration parameters: IgnoreScopes, Include.
|
||||
# Include: app/models/**/*.rb
|
||||
Rails/InverseOf:
|
||||
@@ -572,7 +563,6 @@ Rails/InverseOf:
|
||||
- 'app/models/spree/price.rb'
|
||||
- 'app/models/spree/product.rb'
|
||||
- 'app/models/spree/stock_item.rb'
|
||||
- 'app/models/spree/taxonomy.rb'
|
||||
- 'app/models/spree/variant.rb'
|
||||
- 'app/models/subscription_line_item.rb'
|
||||
|
||||
@@ -720,7 +710,7 @@ Style/GlobalStdStream:
|
||||
- 'lib/tasks/subscriptions/debug.rake'
|
||||
- 'lib/tasks/subscriptions/test.rake'
|
||||
|
||||
# Offense count: 12
|
||||
# Offense count: 10
|
||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||
# Configuration parameters: AllowSplatArgument.
|
||||
Style/HashConversion:
|
||||
@@ -728,9 +718,7 @@ Style/HashConversion:
|
||||
- 'app/controllers/admin/column_preferences_controller.rb'
|
||||
- 'app/controllers/admin/variant_overrides_controller.rb'
|
||||
- 'app/controllers/spree/admin/products_controller.rb'
|
||||
- 'app/models/order_cycle.rb'
|
||||
- 'app/models/product_import/product_importer.rb'
|
||||
- 'app/models/spree/shipping_method.rb'
|
||||
- 'app/serializers/api/admin/exchange_serializer.rb'
|
||||
- 'app/services/variants_stock_levels.rb'
|
||||
- 'spec/controllers/admin/inventory_items_controller_spec.rb'
|
||||
|
||||
@@ -89,4 +89,4 @@ RUN ./script/install-bundler
|
||||
RUN yarn install
|
||||
|
||||
# Run bundler install in parallel with the amount of available CPUs
|
||||
RUN bundle install --jobs="$(nproc)"
|
||||
RUN bundle install --jobs="$(nproc)"
|
||||
2
Gemfile
2
Gemfile
@@ -86,7 +86,7 @@ gem "active_model_serializers", "0.8.4"
|
||||
gem 'activerecord-session_store'
|
||||
gem 'acts-as-taggable-on'
|
||||
gem 'angularjs-file-upload-rails', '~> 2.4.1'
|
||||
gem 'bigdecimal', '3.0.2'
|
||||
gem 'bigdecimal'
|
||||
gem 'bootsnap', require: false
|
||||
gem 'geocoder'
|
||||
gem 'gmaps4rails'
|
||||
|
||||
@@ -180,7 +180,7 @@ GEM
|
||||
base64 (0.2.0)
|
||||
bcp47_spec (0.2.1)
|
||||
bcrypt (3.1.20)
|
||||
bigdecimal (3.0.2)
|
||||
bigdecimal (3.1.8)
|
||||
bindata (2.5.0)
|
||||
bindex (0.8.1)
|
||||
bootsnap (1.18.3)
|
||||
@@ -865,7 +865,7 @@ DEPENDENCIES
|
||||
angularjs-rails (= 1.8.0)
|
||||
arel-helpers (~> 2.12)
|
||||
aws-sdk-s3
|
||||
bigdecimal (= 3.0.2)
|
||||
bigdecimal
|
||||
bootsnap
|
||||
bugsnag
|
||||
bullet
|
||||
|
||||
32
alpine.Dockerfile
Normal file
32
alpine.Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
||||
FROM ruby:3.1.4-alpine3.19 AS base
|
||||
ENV LANG=C.UTF-8 \
|
||||
LC_ALL=C.UTF-8 \
|
||||
TZ=Europe/London \
|
||||
RAILS_ROOT=/usr/src/app
|
||||
RUN apk --no-cache upgrade && \
|
||||
apk add --no-cache tzdata postgresql-client imagemagick imagemagick-jpeg && \
|
||||
apk add --no-cache --virtual wkhtmltopdf
|
||||
|
||||
WORKDIR $RAILS_ROOT
|
||||
|
||||
# Development dependencies
|
||||
FROM base AS development-base
|
||||
RUN apk add --no-cache --virtual .build-deps \
|
||||
build-base postgresql-dev git nodejs yarn && \
|
||||
apk add --no-cache --virtual .dev-utils \
|
||||
bash curl less vim chromium-chromedriver zlib-dev openssl-dev \
|
||||
readline-dev yaml-dev sqlite-dev libxml2-dev libxslt-dev libffi-dev vips-dev && \
|
||||
curl -o /usr/local/bin/wait-for-it https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \
|
||||
chmod +x /usr/local/bin/wait-for-it
|
||||
|
||||
# Install yarn dependencies separately for caching
|
||||
FROM development-base AS yarn-dependencies
|
||||
COPY package.json yarn.lock ./
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
# Install Ruby gems
|
||||
FROM development-base
|
||||
COPY . $RAILS_ROOT
|
||||
COPY Gemfile Gemfile.lock ./
|
||||
RUN bundle install --jobs "$(nproc)"
|
||||
COPY --from=yarn-dependencies $RAILS_ROOT/node_modules ./node_modules
|
||||
@@ -20,10 +20,13 @@ angular.module('Darkswarm').directive 'mapSearch', ($timeout, Search) ->
|
||||
$timeout =>
|
||||
map = ctrl.getMap()
|
||||
|
||||
searchBox = scope.createSearchBox map
|
||||
scope.bindSearchResponse map, searchBox
|
||||
scope.biasResults map, searchBox
|
||||
scope.performUrlSearch map
|
||||
if !map
|
||||
alert(t('gmap_load_failure'))
|
||||
else
|
||||
searchBox = scope.createSearchBox map
|
||||
scope.bindSearchResponse map, searchBox
|
||||
scope.biasResults map, searchBox
|
||||
scope.performUrlSearch map
|
||||
|
||||
scope.createSearchBox = (map) ->
|
||||
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
|
||||
|
||||
@@ -44,9 +44,9 @@ module Admin
|
||||
|
||||
create_connected_app
|
||||
|
||||
jwt_service = VineJwtService.new(secret: connected_app_params[:vine_secret])
|
||||
vine_api = VineApiService.new(api_key: connected_app_params[:vine_api_key],
|
||||
jwt_generator: jwt_service)
|
||||
jwt_service = Vine::JwtService.new(secret: connected_app_params[:vine_secret])
|
||||
vine_api = Vine::ApiService.new(api_key: connected_app_params[:vine_api_key],
|
||||
jwt_generator: jwt_service)
|
||||
|
||||
if !@app.connect(api_key: connected_app_params[:vine_api_key],
|
||||
secret: connected_app_params[:vine_secret], vine_api:)
|
||||
@@ -77,7 +77,7 @@ module Admin
|
||||
|
||||
def log_and_notify_exception(exception)
|
||||
Rails.logger.error exception.inspect
|
||||
Bugsnag.notify(exception)
|
||||
Alert.raise(exception)
|
||||
end
|
||||
|
||||
def vine_params_empty?
|
||||
|
||||
@@ -30,13 +30,13 @@ module Admin
|
||||
def validate_data
|
||||
return unless process_data('validate')
|
||||
|
||||
render json: @importer.import_results, response: 200
|
||||
render json: @importer.import_results
|
||||
end
|
||||
|
||||
def save_data
|
||||
return unless process_data('save')
|
||||
|
||||
render json: @importer.save_results, response: 200
|
||||
render json: @importer.save_results
|
||||
end
|
||||
|
||||
def reset_absent_products
|
||||
@@ -76,7 +76,7 @@ module Admin
|
||||
begin
|
||||
@importer.public_send("#{method}_entries")
|
||||
rescue StandardError => e
|
||||
render json: e.message, response: 500
|
||||
render plain: e.message, status: :internal_server_error
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ module Api
|
||||
end
|
||||
|
||||
def error_during_processing(exception)
|
||||
Bugsnag.notify(exception)
|
||||
Alert.raise(exception)
|
||||
|
||||
render(json: { exception: exception.message },
|
||||
status: :unprocessable_entity) && return
|
||||
|
||||
@@ -52,7 +52,7 @@ module Api
|
||||
end
|
||||
|
||||
def error_during_processing(exception)
|
||||
Bugsnag.notify(exception)
|
||||
Alert.raise(exception)
|
||||
|
||||
if Rails.env.development? || Rails.env.test?
|
||||
render status: :unprocessable_entity,
|
||||
|
||||
@@ -78,6 +78,18 @@ class CheckoutController < BaseController
|
||||
|
||||
return true if redirect_to_payment_gateway
|
||||
|
||||
# Redeem VINE voucher
|
||||
vine_voucher_redeemer = Vine::VoucherRedeemerService.new(order: @order)
|
||||
unless vine_voucher_redeemer.redeem
|
||||
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
|
||||
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
|
||||
vine_voucher_redeemer.errors[:redeeming_failed]
|
||||
else
|
||||
I18n.t('checkout.errors.voucher_redeeming_error')
|
||||
end
|
||||
return false
|
||||
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
|
||||
end
|
||||
@order.process_payments!
|
||||
@order.confirm!
|
||||
order_completion_reset @order
|
||||
|
||||
@@ -50,9 +50,7 @@ module OrderCompletion
|
||||
end
|
||||
|
||||
def order_invalid!
|
||||
Bugsnag.notify("Notice: invalid order loaded during checkout") do |payload|
|
||||
payload.add_metadata :order, :order, @order
|
||||
end
|
||||
Alert.raise_with_record("Notice: invalid order loaded during checkout", @order)
|
||||
|
||||
flash[:error] = t('checkout.order_not_loaded')
|
||||
redirect_to main_app.shop_path
|
||||
@@ -92,9 +90,7 @@ module OrderCompletion
|
||||
end
|
||||
|
||||
def notify_failure(error = RuntimeError.new(order_processing_error))
|
||||
Bugsnag.notify(error) do |payload|
|
||||
payload.add_metadata :order, @order
|
||||
end
|
||||
Alert.raise_with_record(error, @order)
|
||||
flash[:error] = order_processing_error if flash.blank?
|
||||
end
|
||||
|
||||
|
||||
@@ -20,9 +20,7 @@ module OrderStockCheck
|
||||
def check_order_cycle_expiry
|
||||
return unless current_order_cycle&.closed?
|
||||
|
||||
Bugsnag.notify("Notice: order cycle closed during checkout completion") do |payload|
|
||||
payload.add_metadata :order, :order, current_order
|
||||
end
|
||||
Alert.raise_with_record("Notice: order cycle closed during checkout completion", current_order)
|
||||
current_order.empty!
|
||||
current_order.set_order_cycle! nil
|
||||
|
||||
|
||||
@@ -4,11 +4,6 @@ class ErrorsController < ApplicationController
|
||||
layout "errors"
|
||||
|
||||
def not_found
|
||||
Bugsnag.notify("404") do |event|
|
||||
event.severity = "info"
|
||||
|
||||
event.add_metadata(:request, :env, request.env)
|
||||
end
|
||||
render status: :not_found, formats: :html
|
||||
end
|
||||
|
||||
|
||||
@@ -24,9 +24,12 @@ module Spree
|
||||
end
|
||||
|
||||
def create
|
||||
# Try to redeem VINE voucher first as we don't want to create a payment and complete
|
||||
# the order if it fails
|
||||
return redirect_to spree.admin_order_payments_path(@order) unless redeem_vine_voucher
|
||||
|
||||
@payment = @order.payments.build(object_params)
|
||||
load_payment_source
|
||||
|
||||
begin
|
||||
unless @payment.save
|
||||
redirect_to spree.admin_order_payments_path(@order)
|
||||
@@ -51,6 +54,10 @@ module Spree
|
||||
event = params[:e]
|
||||
return unless event && @payment.payment_source
|
||||
|
||||
# capture_and_complete_order will complete the order, so we want to try to redeem VINE
|
||||
# voucher first and exit if it fails
|
||||
return if event == "capture_and_complete_order" && !redeem_vine_voucher
|
||||
|
||||
# Because we have a transition method also called void, we do this to avoid conflicts.
|
||||
event = "void_transaction" if event == "void"
|
||||
if allowed_events.include?(event) && @payment.public_send("#{event}!")
|
||||
@@ -60,7 +67,7 @@ module Spree
|
||||
end
|
||||
rescue StandardError => e
|
||||
logger.error e.message
|
||||
Bugsnag.notify(e)
|
||||
Alert.raise(e)
|
||||
flash[:error] = e.message
|
||||
ensure
|
||||
redirect_to request.referer
|
||||
@@ -182,6 +189,22 @@ module Spree
|
||||
%w{capture void_transaction credit refund resend_authorization_email
|
||||
capture_and_complete_order}
|
||||
end
|
||||
|
||||
def redeem_vine_voucher
|
||||
vine_voucher_redeemer = Vine::VoucherRedeemerService.new(order: @order)
|
||||
if vine_voucher_redeemer.redeem == false
|
||||
# rubocop:disable Rails/DeprecatedActiveModelErrorsMethods
|
||||
flash[:error] = if vine_voucher_redeemer.errors.keys.include?(:redeeming_failed)
|
||||
vine_voucher_redeemer.errors[:redeeming_failed]
|
||||
else
|
||||
I18n.t('checkout.errors.voucher_redeeming_error')
|
||||
end
|
||||
# rubocop:enable Rails/DeprecatedActiveModelErrorsMethods
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -213,7 +213,7 @@ module Spree
|
||||
end
|
||||
|
||||
def notify_bugsnag(error, product, variant)
|
||||
Bugsnag.notify(error) do |report|
|
||||
Alert.raise(error) do |report|
|
||||
report.add_metadata(:product,
|
||||
{ product: product.attributes, variant: variant.attributes })
|
||||
report.add_metadata(:product, :product_error, product.errors.first) unless product.valid?
|
||||
|
||||
@@ -70,8 +70,7 @@ module Spree
|
||||
@order.recreate_all_fees! # Enterprise fees on line items and on the order itself
|
||||
|
||||
# Re apply the voucher
|
||||
VoucherAdjustmentsService.new(@order).update
|
||||
@order.update_totals_and_states
|
||||
OrderManagement::Order::Updater.new(@order).update_voucher
|
||||
|
||||
if @order.complete?
|
||||
@order.update_payment_fees!
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'open_food_network/error_logger'
|
||||
require "spree/core/controller_helpers/auth"
|
||||
require "spree/core/controller_helpers/common"
|
||||
require "spree/core/controller_helpers/order"
|
||||
@@ -37,7 +36,7 @@ class UserRegistrationsController < Devise::RegistrationsController
|
||||
end
|
||||
end
|
||||
rescue StandardError => e
|
||||
OpenFoodNetwork::ErrorLogger.notify(e)
|
||||
Alert.raise(e)
|
||||
render_error(message: I18n.t('unknown_error', scope: I18N_SCOPE))
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,16 @@ class VoucherAdjustmentsController < BaseController
|
||||
before_action :set_order
|
||||
|
||||
def create
|
||||
if add_voucher
|
||||
if voucher_params[:voucher_code].blank?
|
||||
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
|
||||
return render_error
|
||||
end
|
||||
|
||||
voucher = load_voucher
|
||||
|
||||
return render_error unless valid_voucher?(voucher)
|
||||
|
||||
if add_voucher_to_order(voucher)
|
||||
update_payment_section
|
||||
elsif @order.errors.present?
|
||||
render_error
|
||||
@@ -30,19 +39,28 @@ class VoucherAdjustmentsController < BaseController
|
||||
@order = current_order
|
||||
end
|
||||
|
||||
def add_voucher
|
||||
if voucher_params[:voucher_code].blank?
|
||||
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
voucher = Voucher.find_by(code: voucher_params[:voucher_code], enterprise: @order.distributor)
|
||||
def valid_voucher?(voucher)
|
||||
return false if @order.errors.present?
|
||||
|
||||
if voucher.nil?
|
||||
@order.errors.add(:voucher_code, I18n.t('checkout.errors.voucher_not_found'))
|
||||
return false
|
||||
end
|
||||
|
||||
if !voucher.valid?
|
||||
@order.errors.add(
|
||||
:voucher_code,
|
||||
I18n.t(
|
||||
'checkout.errors.create_voucher_error', error: voucher.errors.full_messages.to_sentence
|
||||
)
|
||||
)
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def add_voucher_to_order(voucher)
|
||||
adjustment = voucher.create_adjustment(voucher.code, @order)
|
||||
|
||||
unless adjustment.persisted?
|
||||
@@ -51,14 +69,38 @@ class VoucherAdjustmentsController < BaseController
|
||||
return false
|
||||
end
|
||||
|
||||
# calculate_voucher_adjustment
|
||||
clear_payments
|
||||
|
||||
VoucherAdjustmentsService.new(@order).update
|
||||
@order.update_totals_and_states
|
||||
OrderManagement::Order::Updater.new(@order).update_voucher
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def load_voucher
|
||||
voucher = Voucher.find_by(code: voucher_params[:voucher_code],
|
||||
enterprise: @order.distributor)
|
||||
return voucher unless voucher.nil? || voucher.is_a?(Vouchers::Vine)
|
||||
|
||||
vine_voucher
|
||||
end
|
||||
|
||||
def vine_voucher
|
||||
vine_voucher_validator = Vine::VoucherValidatorService.new(
|
||||
voucher_code: voucher_params[:voucher_code], enterprise: @order.distributor
|
||||
)
|
||||
voucher = vine_voucher_validator.validate
|
||||
|
||||
return nil if vine_voucher_validator.errors[:not_found_voucher].present?
|
||||
|
||||
if vine_voucher_validator.errors.present?
|
||||
@order.errors.add(:voucher_code, I18n.t('checkout.errors.add_voucher_error'))
|
||||
return nil
|
||||
end
|
||||
|
||||
voucher
|
||||
end
|
||||
|
||||
def update_payment_section
|
||||
render cable_ready: cable_car.replace(
|
||||
selector: "#checkout-payment-methods",
|
||||
|
||||
@@ -19,9 +19,7 @@ class BackorderJob < ApplicationJob
|
||||
rescue StandardError => e
|
||||
# Errors here shouldn't affect the checkout. So let's report them
|
||||
# separately:
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata(:order, :order, order)
|
||||
end
|
||||
Alert.raise_with_record(e, order)
|
||||
end
|
||||
|
||||
def perform(order)
|
||||
|
||||
@@ -22,11 +22,7 @@ class ReportJob < ApplicationJob
|
||||
|
||||
broadcast_result(channel, format, blob) if channel
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata :report, {
|
||||
report_class:, user:, params:, format:
|
||||
}
|
||||
end
|
||||
Alert.raise(e, { report: { report_class:, user:, params:, format: } })
|
||||
|
||||
broadcast_error(channel)
|
||||
end
|
||||
|
||||
@@ -16,9 +16,7 @@ class StockSyncJob < ApplicationJob
|
||||
rescue StandardError => e
|
||||
# Errors here shouldn't affect the shopping. So let's report them
|
||||
# separately:
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata(:order, :order, order)
|
||||
end
|
||||
Alert.raise_with_record(e, order)
|
||||
end
|
||||
|
||||
def self.sync_linked_catalogs_now(order)
|
||||
@@ -29,9 +27,7 @@ class StockSyncJob < ApplicationJob
|
||||
rescue StandardError => e
|
||||
# Errors here shouldn't affect the shopping. So let's report them
|
||||
# separately:
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata(:order, :order, order)
|
||||
end
|
||||
Alert.raise_with_record(e, order)
|
||||
end
|
||||
|
||||
def self.catalog_ids(order)
|
||||
|
||||
@@ -55,9 +55,7 @@ class SubscriptionConfirmJob < ApplicationJob
|
||||
if order.errors.any?
|
||||
send_failed_payment_email(order)
|
||||
else
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata :order, :order, order
|
||||
end
|
||||
Alert.raise_with_record(e, order)
|
||||
send_failed_payment_email(order, e.message)
|
||||
end
|
||||
end
|
||||
@@ -108,8 +106,6 @@ class SubscriptionConfirmJob < ApplicationJob
|
||||
record_and_log_error(:failed_payment, order, error_message)
|
||||
SubscriptionMailer.failed_payment_email(order).deliver_now
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata :subscription_data, { order:, error_message: }
|
||||
end
|
||||
Alert.raise(e, { subscription_data: { order:, error_message: } })
|
||||
end
|
||||
end
|
||||
|
||||
@@ -28,7 +28,7 @@ module Calculator
|
||||
# In theory it should never be called any more after this has been deployed.
|
||||
# If the message below doesn't show up in Bugsnag, we can safely delete this method and all
|
||||
# the related methods below it.
|
||||
Bugsnag.notify("Calculator::DefaultTax was called with legacy tax calculations")
|
||||
Alert.raise("Calculator::DefaultTax was called with legacy tax calculations")
|
||||
|
||||
calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor,
|
||||
order.order_cycle)
|
||||
|
||||
31
app/models/concerns/vouchers/flat_ratable.rb
Normal file
31
app/models/concerns/vouchers/flat_ratable.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "active_support/concern"
|
||||
|
||||
module Vouchers
|
||||
module FlatRatable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
validates :amount,
|
||||
presence: true,
|
||||
numericality: { greater_than: 0 }
|
||||
end
|
||||
|
||||
def display_value
|
||||
Spree::Money.new(amount)
|
||||
end
|
||||
|
||||
# We limit adjustment to the maximum amount needed to cover the order, ie if the voucher
|
||||
# covers more than the order.total we only need to create an adjustment covering the order.total
|
||||
def compute_amount(order)
|
||||
-amount.clamp(0, order.pre_discount_total)
|
||||
end
|
||||
|
||||
def rate(order)
|
||||
amount = compute_amount(order)
|
||||
|
||||
amount / order.pre_discount_total
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -481,7 +481,7 @@ class Enterprise < ApplicationRecord
|
||||
|
||||
image_variant_url_for(image.variant(name))
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify "Enterprise ##{id} #{image.try(:name)} error: #{e.message}"
|
||||
Alert.raise "Enterprise ##{id} #{image.try(:name)} error: #{e.message}"
|
||||
Rails.logger.error(e.message)
|
||||
|
||||
nil
|
||||
|
||||
@@ -79,10 +79,9 @@ module ProductImport
|
||||
if entry.attributes['on_hand'].present?
|
||||
new_variant.on_hand = entry.attributes['on_hand']
|
||||
end
|
||||
check_on_hand_nil(entry, new_variant)
|
||||
end
|
||||
|
||||
check_on_hand_nil(entry, new_variant)
|
||||
|
||||
if new_variant.valid?
|
||||
entry.product_object = new_variant
|
||||
entry.validates_as = 'new_variant' unless entry.errors?
|
||||
@@ -161,7 +160,7 @@ module ProductImport
|
||||
end
|
||||
|
||||
def unit_fields_validation(entry)
|
||||
unit_types = ['g', 'oz', 'lb', 'kg', 't', 'ml', 'l', 'kl', '']
|
||||
unit_types = ['mg', 'g', 'kg', 'oz', 'lb', 't', 'ml', 'cl', 'dl', 'l', 'kl', 'gal', '']
|
||||
|
||||
if entry.units.blank?
|
||||
mark_as_invalid(entry, attribute: 'units',
|
||||
@@ -297,7 +296,7 @@ module ProductImport
|
||||
unscaled_units = entry.unscaled_units.to_f || 0
|
||||
entry.unit_value = unscaled_units * unit_scale unless unit_scale.nil?
|
||||
|
||||
if entry.match_inventory_variant?(existing_variant)
|
||||
if entry.match_variant?(existing_variant)
|
||||
variant_override = create_inventory_item(entry, existing_variant)
|
||||
return validate_inventory_item(entry, variant_override)
|
||||
end
|
||||
|
||||
@@ -85,10 +85,6 @@ module ProductImport
|
||||
end
|
||||
|
||||
def match_variant?(variant)
|
||||
match_display_name?(variant) && variant.unit_value.to_d == unscaled_units.to_d
|
||||
end
|
||||
|
||||
def match_inventory_variant?(variant)
|
||||
match_display_name?(variant) && variant.unit_value.to_d == unit_value.to_d
|
||||
end
|
||||
|
||||
|
||||
@@ -32,14 +32,18 @@ module ProductImport
|
||||
|
||||
def unit_scales
|
||||
{
|
||||
'mg' => { scale: 0.001, unit: 'weight' },
|
||||
'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' },
|
||||
'cl' => { scale: 0.01, unit: 'volume' },
|
||||
'dl' => { scale: 0.1, unit: 'volume' },
|
||||
'l' => { scale: 1, unit: 'volume' },
|
||||
'kl' => { scale: 1000, unit: 'volume' }
|
||||
'kl' => { scale: 1000, unit: 'volume' },
|
||||
'gal' => { scale: 4.54609, unit: 'volume' },
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ module Spree
|
||||
|
||||
image_variant_url_for(variant(size))
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify "Product ##{viewable_id} Image ##{id} error: #{e.message}"
|
||||
Alert.raise "Product ##{viewable_id} Image ##{id} error: #{e.message}"
|
||||
Rails.logger.error(e.message)
|
||||
|
||||
self.class.default_image_url(size)
|
||||
|
||||
@@ -535,7 +535,7 @@ module Spree
|
||||
# because an outdated shipping fee is not as bad as a lost payment.
|
||||
# And the shipping fee is already up-to-date when this error occurs.
|
||||
# https://github.com/openfoodfoundation/openfoodnetwork/issues/3924
|
||||
Bugsnag.notify(e) do |report|
|
||||
Alert.raise(e) do |report|
|
||||
report.add_metadata(:order, attributes)
|
||||
report.add_metadata(:shipment, shipment.attributes)
|
||||
report.add_metadata(:shipment_in_db, Spree::Shipment.find_by(id: shipment.id).attributes)
|
||||
|
||||
@@ -106,7 +106,7 @@ module Spree
|
||||
calculator.compute(item)
|
||||
else
|
||||
# Tax refund should not be possible with the way our production server are configured
|
||||
Bugsnag.notify(
|
||||
Alert.raise(
|
||||
"Notice: Tax refund should not be possible, please check the default zone and " \
|
||||
"the tax rate zone configuration"
|
||||
) do |payload|
|
||||
|
||||
@@ -293,7 +293,7 @@ module Spree
|
||||
end
|
||||
|
||||
def ensure_unit_value
|
||||
Bugsnag.notify("Trying to set unit_value to NaN") if unit_value&.nan?
|
||||
Alert.raise("Trying to set unit_value to NaN") if unit_value&.nan?
|
||||
return unless (variant_unit == "items" && unit_value.nil?) || unit_value&.nan?
|
||||
|
||||
self.unit_value = 1.0
|
||||
|
||||
@@ -15,7 +15,7 @@ class StripeAccount < ApplicationRecord
|
||||
|
||||
destroy && Stripe::OAuth.deauthorize(stripe_user_id:)
|
||||
rescue Stripe::OAuth::OAuthError => e
|
||||
Bugsnag.notify(
|
||||
Alert.raise(
|
||||
e,
|
||||
stripe_account: stripe_user_id,
|
||||
enterprise_id:
|
||||
|
||||
@@ -48,8 +48,8 @@ class VariantOverride < ApplicationRecord
|
||||
|
||||
def move_stock!(quantity)
|
||||
unless stock_overridden?
|
||||
Bugsnag.notify RuntimeError.new "Attempting to move stock of a VariantOverride " \
|
||||
"without a count_on_hand specified."
|
||||
Alert.raise "Attempting to move stock of a VariantOverride " \
|
||||
"without a count_on_hand specified."
|
||||
return
|
||||
end
|
||||
|
||||
@@ -73,8 +73,8 @@ class VariantOverride < ApplicationRecord
|
||||
self.attributes = { on_demand: false, count_on_hand: default_stock }
|
||||
save
|
||||
else
|
||||
Bugsnag.notify RuntimeError.new "Attempting to reset stock level for a variant " \
|
||||
"with no default stock level."
|
||||
Alert.raise "Attempting to reset stock level for a variant " \
|
||||
"with no default stock level."
|
||||
end
|
||||
end
|
||||
self
|
||||
|
||||
@@ -14,7 +14,7 @@ class Voucher < ApplicationRecord
|
||||
class_name: 'Spree::Adjustment',
|
||||
dependent: nil
|
||||
|
||||
validates :code, presence: true, uniqueness: { scope: :enterprise_id }
|
||||
validates :code, presence: true
|
||||
|
||||
TYPES = ["Vouchers::FlatRate", "Vouchers::PercentageRate"].freeze
|
||||
|
||||
|
||||
@@ -2,24 +2,8 @@
|
||||
|
||||
module Vouchers
|
||||
class FlatRate < Voucher
|
||||
validates :amount,
|
||||
presence: true,
|
||||
numericality: { greater_than: 0 }
|
||||
include FlatRatable
|
||||
|
||||
def display_value
|
||||
Spree::Money.new(amount)
|
||||
end
|
||||
|
||||
# We limit adjustment to the maximum amount needed to cover the order, ie if the voucher
|
||||
# covers more than the order.total we only need to create an adjustment covering the order.total
|
||||
def compute_amount(order)
|
||||
-amount.clamp(0, order.pre_discount_total)
|
||||
end
|
||||
|
||||
def rate(order)
|
||||
amount = compute_amount(order)
|
||||
|
||||
amount / order.pre_discount_total
|
||||
end
|
||||
validates_with ScopedUniquenessValidator
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ module Vouchers
|
||||
validates :amount,
|
||||
presence: true,
|
||||
numericality: { greater_than: 0, less_than_or_equal_to: 100 }
|
||||
validates_with ScopedUniquenessValidator
|
||||
|
||||
def display_value
|
||||
ActionController::Base.helpers.number_to_percentage(amount, precision: 2)
|
||||
|
||||
13
app/models/vouchers/vine.rb
Normal file
13
app/models/vouchers/vine.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
module Vouchers
|
||||
class Vine < Voucher
|
||||
include FlatRatable
|
||||
|
||||
# a VINE voucher :
|
||||
# - can potentially be associated with mutiple enterprise
|
||||
# - code ( "short code" in VINE ) can be recycled, but they shouldn't be linked to the same
|
||||
# voucher_id
|
||||
validates :code, uniqueness: { scope: [:enterprise_id, :external_voucher_id] }
|
||||
end
|
||||
end
|
||||
38
app/services/alert.rb
Normal file
38
app/services/alert.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# A handy wrapper around error reporting libraries like Bugsnag.
|
||||
#
|
||||
# Bugsnag's API is great for general purpose but overly complex for our use.
|
||||
# It also changes over time and we often make mistakes using it. So this class
|
||||
# aims at:
|
||||
#
|
||||
# * Abstracting from Bugsnag, open for other services.
|
||||
# * Simpler interface to reduce user error.
|
||||
# * Central place to update Bugsnag API usage when it changes.
|
||||
#
|
||||
class Alert
|
||||
# Alert Bugsnag with additional metadata to appear in tabs.
|
||||
#
|
||||
# Alert.raise(
|
||||
# "Invalid order during checkout",
|
||||
# {
|
||||
# order: { number: "ABC123", state: "awaiting_return" },
|
||||
# env: { referer: "example.com" }
|
||||
# }
|
||||
# )
|
||||
def self.raise(error, metadata = {}, &block)
|
||||
Bugsnag.notify(error) do |payload|
|
||||
metadata.each do |name, data|
|
||||
payload.add_metadata(name, data)
|
||||
end
|
||||
block.call(payload)
|
||||
end
|
||||
end
|
||||
|
||||
def self.raise_with_record(error, record, &)
|
||||
metadata = {
|
||||
record.class.name => record&.attributes || { record_was_nil: true }
|
||||
}
|
||||
self.raise(error, metadata, &)
|
||||
end
|
||||
end
|
||||
@@ -36,7 +36,7 @@ class FdcBackorderer
|
||||
.map { |id| find_order(id) }
|
||||
.compact
|
||||
# Just in case someone completed the order without updating our database:
|
||||
.select { |o| o.orderStatus[:path] == "Held" }
|
||||
.select { |o| o.orderStatus == order_status.HELD }
|
||||
.first
|
||||
# The DFC Connector doesn't recognise status values properly yet.
|
||||
# So we are overriding the value with something that can be exported.
|
||||
@@ -52,7 +52,7 @@ class FdcBackorderer
|
||||
def find_last_open_order
|
||||
graph = import(urls.orders_url)
|
||||
open_orders = graph&.select do |o|
|
||||
o.semanticType == "dfc-b:Order" && o.orderStatus[:path] == "Held"
|
||||
o.semanticType == "dfc-b:Order" && o.orderStatus == order_status.HELD
|
||||
end
|
||||
|
||||
return if open_orders.blank?
|
||||
@@ -160,4 +160,10 @@ class FdcBackorderer
|
||||
session.semanticId = urls.sale_session_url
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def order_status
|
||||
DfcLoader.vocabulary("vocabulary").STATES.ORDERSTATE
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,8 +33,7 @@ class FdcOfferBroker
|
||||
production_flow = catalog_item("#{product_id}/AsPlannedProductionFlow")
|
||||
|
||||
if production_flow
|
||||
wholesale_product_id = production_flow.product
|
||||
catalog_item(wholesale_product_id)
|
||||
production_flow.product
|
||||
else
|
||||
# We didn't find a wholesale variant, falling back to the given product.
|
||||
catalog_item(product_id)
|
||||
@@ -57,7 +56,7 @@ class FdcOfferBroker
|
||||
consumption_flow = catalog_item(
|
||||
production_flow.semanticId.sub("AsPlannedProductionFlow", "AsPlannedConsumptionFlow")
|
||||
)
|
||||
retail_product_id = consumption_flow.product
|
||||
retail_product_id = consumption_flow.product.semanticId
|
||||
|
||||
contained_quantity = consumption_flow.quantity.value.to_i
|
||||
|
||||
@@ -77,7 +76,7 @@ class FdcOfferBroker
|
||||
end
|
||||
|
||||
def flow_producing(wholesale_product_id)
|
||||
@production_flows_by_product_id ||= production_flows.index_by(&:product)
|
||||
@production_flows_by_product_id ||= production_flows.index_by { |flow| flow.product.semanticId }
|
||||
@production_flows_by_product_id[wholesale_product_id]
|
||||
end
|
||||
|
||||
|
||||
@@ -24,9 +24,7 @@ class PlaceProxyOrder
|
||||
send_placement_email
|
||||
rescue StandardError => e
|
||||
summarizer.record_and_log_error(:processing, order, e.message)
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata :order, :order, order
|
||||
end
|
||||
Alert.raise_with_record(e, order)
|
||||
end
|
||||
|
||||
private
|
||||
@@ -56,9 +54,7 @@ class PlaceProxyOrder
|
||||
|
||||
true
|
||||
rescue StandardError => e
|
||||
Bugsnag.notify(e) do |payload|
|
||||
payload.add_metadata(:proxy_order, { subscription:, proxy_order: })
|
||||
end
|
||||
Alert.raise(e, { proxy_order: { subscription:, proxy_order: } })
|
||||
false
|
||||
end
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ module Sets
|
||||
end
|
||||
|
||||
def notify_bugsnag(error, product, variant, variant_attributes)
|
||||
Bugsnag.notify(error) do |report|
|
||||
Alert.raise(error) do |report|
|
||||
report.add_metadata( :product_set,
|
||||
{ product: product.attributes, variant_attributes:,
|
||||
variant: variant.attributes } )
|
||||
|
||||
@@ -58,7 +58,7 @@ module VariantUnits
|
||||
def option_value_value_unit_scaled
|
||||
unit_scale, unit_name = scale_for_unit_value
|
||||
|
||||
value = (@nameable.unit_value / unit_scale).to_d.truncate(2)
|
||||
value = (@nameable.unit_value.to_d / unit_scale).round(2)
|
||||
|
||||
[value, unit_name]
|
||||
end
|
||||
|
||||
81
app/services/vine/api_service.rb
Normal file
81
app/services/vine/api_service.rb
Normal file
@@ -0,0 +1,81 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "faraday"
|
||||
|
||||
module Vine
|
||||
class ApiService
|
||||
attr_reader :api_key, :jwt_generator
|
||||
|
||||
def initialize(api_key:, jwt_generator:)
|
||||
@vine_api_url = ENV.fetch("VINE_API_URL")
|
||||
@api_key = api_key
|
||||
@jwt_generator = jwt_generator
|
||||
end
|
||||
|
||||
def my_team
|
||||
my_team_url = "#{@vine_api_url}/my-team"
|
||||
|
||||
call_with_logging do
|
||||
connection.get(my_team_url)
|
||||
end
|
||||
end
|
||||
|
||||
def voucher_validation(voucher_short_code)
|
||||
voucher_validation_url = "#{@vine_api_url}/voucher-validation"
|
||||
|
||||
call_with_logging do
|
||||
connection.post(
|
||||
voucher_validation_url,
|
||||
{ type: "voucher_code", value: voucher_short_code },
|
||||
'Content-Type': "application/json"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def voucher_redemptions(voucher_id, voucher_set_id, amount)
|
||||
voucher_redemptions_url = "#{@vine_api_url}/voucher-redemptions"
|
||||
|
||||
call_with_logging do
|
||||
connection.post(
|
||||
voucher_redemptions_url,
|
||||
{ voucher_id:, voucher_set_id:, amount: amount.to_i },
|
||||
'Content-Type': "application/json"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def connection
|
||||
jwt = jwt_generator.generate_token
|
||||
Faraday.new(
|
||||
request: { timeout: 30 },
|
||||
headers: {
|
||||
'X-Authorization': "JWT #{jwt}",
|
||||
Accept: "application/json"
|
||||
}
|
||||
) do |f|
|
||||
f.request :json
|
||||
f.response :json
|
||||
f.request :authorization, 'Bearer', api_key
|
||||
f.use Faraday::Response::RaiseError
|
||||
end
|
||||
end
|
||||
|
||||
def call_with_logging
|
||||
yield
|
||||
rescue Faraday::ClientError, Faraday::ServerError => e
|
||||
# caller_location(2,1) gets us the second entry in the stacktrace,
|
||||
# ie the method where `call_with_logging` is called from
|
||||
log_error("#{self.class}##{caller_locations(2, 1)[0].label}", e.response)
|
||||
|
||||
# Re raise the same exception
|
||||
raise
|
||||
end
|
||||
|
||||
def log_error(prefix, response)
|
||||
Rails.logger.error "#{prefix} -- response_status: #{response[:status]}"
|
||||
Rails.logger.error "#{prefix} -- response: #{response[:body]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
23
app/services/vine/jwt_service.rb
Normal file
23
app/services/vine/jwt_service.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Vine
|
||||
class JwtService
|
||||
ALGORITHM = "HS256"
|
||||
ISSUER = "openfoodnetwork"
|
||||
|
||||
def initialize(secret: )
|
||||
@secret = secret
|
||||
end
|
||||
|
||||
def generate_token
|
||||
generation_time = Time.zone.now
|
||||
payload = {
|
||||
iss: ISSUER,
|
||||
iat: generation_time.to_i,
|
||||
exp: (generation_time + 1.minute).to_i,
|
||||
}
|
||||
|
||||
JWT.encode(payload, @secret, ALGORITHM)
|
||||
end
|
||||
end
|
||||
end
|
||||
62
app/services/vine/voucher_redeemer_service.rb
Normal file
62
app/services/vine/voucher_redeemer_service.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Vine
|
||||
class VoucherRedeemerService
|
||||
attr_reader :order, :errors
|
||||
|
||||
def initialize(order: )
|
||||
@order = order
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def redeem
|
||||
# Do nothing if we don't have a vine voucher added to the order
|
||||
@voucher_adjustment = order.voucher_adjustments.first
|
||||
@voucher = @voucher_adjustment&.originator
|
||||
|
||||
return true if @voucher_adjustment.nil? || !@voucher.is_a?(Vouchers::Vine)
|
||||
|
||||
return false if vine_settings.nil?
|
||||
|
||||
call_vine_api
|
||||
|
||||
@voucher_adjustment.close
|
||||
|
||||
true
|
||||
rescue Faraday::ClientError => e
|
||||
handle_errors(e.response)
|
||||
false
|
||||
rescue Faraday::Error => e
|
||||
Rails.logger.error e.inspect
|
||||
Bugsnag.notify(e)
|
||||
|
||||
errors[:vine_api] = I18n.t("vine_voucher_validator_service.errors.vine_api")
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def vine_settings
|
||||
@vine_settings ||= ConnectedApps::Vine.find_by(enterprise: order.distributor)&.data
|
||||
end
|
||||
|
||||
def call_vine_api
|
||||
jwt_service = Vine::JwtService.new(secret: vine_settings["secret"])
|
||||
vine_api = Vine::ApiService.new(api_key: vine_settings["api_key"], jwt_generator: jwt_service)
|
||||
|
||||
# Voucher adjustment amount is stored in dollars and negative, VINE expect cents
|
||||
amount = -1 * @voucher_adjustment.amount * 100
|
||||
vine_api.voucher_redemptions(
|
||||
@voucher.external_voucher_id, @voucher.external_voucher_set_id, amount
|
||||
)
|
||||
end
|
||||
|
||||
def handle_errors(response)
|
||||
if response[:status] == 400
|
||||
errors[:redeeming_failed] = I18n.t("vine_voucher_redeemer_service.errors.redeeming_failed")
|
||||
else
|
||||
errors[:vine_api] = I18n.t("vine_voucher_redeemer_service.errors.vine_api")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
71
app/services/vine/voucher_validator_service.rb
Normal file
71
app/services/vine/voucher_validator_service.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Vine
|
||||
class VoucherValidatorService
|
||||
attr_reader :voucher_code, :errors
|
||||
|
||||
def initialize(voucher_code:, enterprise:)
|
||||
@voucher_code = voucher_code
|
||||
@enterprise = enterprise
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def validate
|
||||
return nil if vine_settings.nil?
|
||||
|
||||
response = call_vine_api
|
||||
|
||||
save_voucher(response)
|
||||
rescue Faraday::ClientError => e
|
||||
handle_errors(e.response)
|
||||
nil
|
||||
rescue Faraday::Error => e
|
||||
Rails.logger.error e.inspect
|
||||
Bugsnag.notify(e)
|
||||
|
||||
errors[:vine_api] = I18n.t("vine_voucher_validator_service.errors.vine_api")
|
||||
nil
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def vine_settings
|
||||
@vine_settings ||= ConnectedApps::Vine.find_by(enterprise: @enterprise)&.data
|
||||
end
|
||||
|
||||
def call_vine_api
|
||||
# Check voucher is valid
|
||||
jwt_service = Vine::JwtService.new(secret: vine_settings["secret"])
|
||||
vine_api = Vine::ApiService.new(api_key: vine_settings["api_key"], jwt_generator: jwt_service)
|
||||
|
||||
vine_api.voucher_validation(voucher_code)
|
||||
end
|
||||
|
||||
def handle_errors(response)
|
||||
if response[:status] == 400
|
||||
errors[:invalid_voucher] = I18n.t("vine_voucher_validator_service.errors.invalid_voucher")
|
||||
elsif response[:status] == 404
|
||||
errors[:not_found_voucher] =
|
||||
I18n.t("vine_voucher_validator_service.errors.not_found_voucher")
|
||||
else
|
||||
errors[:vine_api] = I18n.t("vine_voucher_validator_service.errors.vine_api")
|
||||
end
|
||||
end
|
||||
|
||||
def save_voucher(response)
|
||||
voucher_data = response.body["data"]
|
||||
|
||||
# Check if voucher already exist
|
||||
voucher = Vouchers::Vine.find_or_initialize_by(
|
||||
code: voucher_code,
|
||||
enterprise: @enterprise,
|
||||
external_voucher_id: voucher_data["id"],
|
||||
external_voucher_set_id: voucher_data["voucher_set_id"]
|
||||
)
|
||||
voucher.amount = voucher_data["voucher_value_remaining"].to_f / 100
|
||||
voucher.save
|
||||
|
||||
voucher
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,39 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "faraday"
|
||||
|
||||
class VineApiService
|
||||
attr_reader :api_key, :jwt_generator
|
||||
|
||||
def initialize(api_key:, jwt_generator:)
|
||||
@vine_api_url = ENV.fetch("VINE_API_URL")
|
||||
@api_key = api_key
|
||||
@jwt_generator = jwt_generator
|
||||
end
|
||||
|
||||
def my_team
|
||||
my_team_url = "#{@vine_api_url}/my-team"
|
||||
|
||||
jwt = jwt_generator.generate_token
|
||||
connection = Faraday.new(
|
||||
request: { timeout: 30 },
|
||||
headers: {
|
||||
'X-Authorization': "JWT #{jwt}",
|
||||
Accept: "application/json"
|
||||
}
|
||||
) do |f|
|
||||
f.request :json
|
||||
f.response :json
|
||||
f.request :authorization, 'Bearer', api_key
|
||||
end
|
||||
|
||||
response = connection.get(my_team_url)
|
||||
|
||||
if !response.success?
|
||||
Rails.logger.error "VineApiService#my_team -- response_status: #{response.status}"
|
||||
Rails.logger.error "VineApiService#my_team -- response: #{response.body}"
|
||||
end
|
||||
|
||||
response
|
||||
end
|
||||
end
|
||||
@@ -1,21 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class VineJwtService
|
||||
ALGORITHM = "HS256"
|
||||
ISSUER = "openfoodnetwork"
|
||||
|
||||
def initialize(secret: )
|
||||
@secret = secret
|
||||
end
|
||||
|
||||
def generate_token
|
||||
generation_time = Time.zone.now
|
||||
payload = {
|
||||
iss: ISSUER,
|
||||
iat: generation_time.to_i,
|
||||
exp: (generation_time + 1.minute).to_i,
|
||||
}
|
||||
|
||||
JWT.encode(payload, @secret, ALGORITHM)
|
||||
end
|
||||
end
|
||||
25
app/validators/vouchers/scoped_uniqueness_validator.rb
Normal file
25
app/validators/vouchers/scoped_uniqueness_validator.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
# frozen_string_literal: false
|
||||
|
||||
# paranoia doesn't support unique validation including deleted records:
|
||||
# https://github.com/rubysherpas/paranoia/pull/333
|
||||
# We use a custom validator to fix the issue, so we don't need to fork/patch the gem
|
||||
module Vouchers
|
||||
class ScopedUniquenessValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
@record = record
|
||||
|
||||
return unless unique_voucher_code_per_enterprise?
|
||||
|
||||
record.errors.add :code, :taken, value: @record.code
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def unique_voucher_code_per_enterprise?
|
||||
query = Voucher.with_deleted.where(code: @record.code, enterprise_id: @record.enterprise_id)
|
||||
query = query.where.not(id: @record.id) unless @record.id.nil?
|
||||
|
||||
query.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,7 @@
|
||||
= t('.add_new')
|
||||
%br
|
||||
|
||||
- if @enterprise.vouchers.with_deleted.present?
|
||||
- if @enterprise.vouchers.where.not(type: "Vouchers::Vine").with_deleted.present?
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
@@ -17,7 +17,7 @@
|
||||
/%th= t('.customers')
|
||||
/%th= t('.net_value')
|
||||
%tbody
|
||||
- @enterprise.vouchers.with_deleted.order(deleted_at: :desc, code: :asc).each do |voucher|
|
||||
- @enterprise.vouchers.where.not(type: "Vouchers::Vine").with_deleted.order(deleted_at: :desc, code: :asc).each do |voucher|
|
||||
%tr
|
||||
%td= voucher.code
|
||||
%td= voucher.display_value
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
= f.hidden_field :variant_unit_scale
|
||||
= f.select :variant_unit_with_scale,
|
||||
options_for_select(WeightsAndMeasures.variant_unit_options, variant.variant_unit_with_scale),
|
||||
{ include_blank: true },
|
||||
{ include_blank: t('.select_unit_scale') },
|
||||
{ class: "fullwidth no-input", 'aria-label': t('admin.products_page.columns.unit_scale'), data: { "controller": "tom-select", "tom-select-options-value": '{ "plugins": [] }', action: "change->toggle-control#displayIfMatch" }, required: true }
|
||||
= error_message_on variant, :variant_unit, 'data-toggle-control-target': 'control'
|
||||
.field
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.medium-6#checkout-payment-methods
|
||||
- if @order.distributor.vouchers.present?
|
||||
- if @order.distributor.vouchers.present? || @order.distributor.connected_apps.vine.present?
|
||||
%div.checkout-substep
|
||||
= render partial: "checkout/voucher_section", locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
#{t :producer_mail_greeting} #{@producer.name},
|
||||
#{t :producer_mail_greeting} #{raw(@producer.name)},
|
||||
\
|
||||
= t :producer_mail_text_before
|
||||
\
|
||||
- @distributors_pickup_times.each do |distributor_name, pickup_time|
|
||||
\- #{distributor_name} (#{pickup_time})
|
||||
\- #{raw(distributor_name)} (#{pickup_time})
|
||||
\
|
||||
- if @receival_instructions
|
||||
= t :producer_mail_delivery_instructions
|
||||
= @receival_instructions
|
||||
= raw(@receival_instructions)
|
||||
\
|
||||
Orders summary
|
||||
================
|
||||
@@ -15,22 +15,22 @@ Orders summary
|
||||
= t :producer_mail_order_text
|
||||
\
|
||||
- @grouped_line_items.each_pair do |product_and_full_name, line_items|
|
||||
#{line_items.first.variant.sku} - #{raw(line_items.first.variant.supplier.name)} - #{raw(product_and_full_name)} (QTY: #{line_items.sum(&:quantity)}) @ #{line_items.first.single_money} = #{Spree::Money.new(line_items.sum(&:total), currency: line_items.first.currency)}
|
||||
#{line_items.first.variant.sku} - #{raw(line_items.first.variant.supplier.name)} - #{raw(product_and_full_name)} (#{t(:producer_mail_qty)}: #{line_items.sum(&:quantity)}) @ #{line_items.first.single_money} = #{Spree::Money.new(line_items.sum(&:total), currency: line_items.first.currency)} (#{t(:with_tax_incl, amount: Spree::Money.new(line_items.sum(&:included_tax), currency: line_items.first.currency))})
|
||||
\
|
||||
\
|
||||
#{t :total}: #{@total}
|
||||
#{t :total}: #{@total} (#{t(:with_tax_incl, amount: @tax_total)})
|
||||
\
|
||||
- if @customer_grouped_line_items
|
||||
- if @customer_line_items
|
||||
= t :producer_mail_order_customer_text
|
||||
\
|
||||
- @customer_line_items.each do |line_item|
|
||||
#{line_item[:sku]} - #{raw(line_item[:supplier_name])} - #{raw(line_item[:product_and_full_name])} (QTY: #{line_item[:quantity]}) - #{raw(line_item[:first_name])} #{raw(line_item[:last_name])}
|
||||
#{line_item[:sku]} - #{raw(line_item[:supplier_name])} - #{raw(line_item[:product_and_full_name])} (#{t(:producer_mail_qty)}: #{line_item[:quantity]}) - #{raw(line_item[:first_name])} #{raw(line_item[:last_name])}
|
||||
\
|
||||
\
|
||||
= t :producer_mail_text_after
|
||||
|
||||
#{t :producer_mail_signoff},
|
||||
#{@coordinator.name}
|
||||
#{@coordinator.address.address1}, #{@coordinator.address.city}, #{@coordinator.address.zipcode}
|
||||
#{raw(@coordinator.name)}
|
||||
#{raw(@coordinator.address.address1)}, #{raw(@coordinator.address.city)}, #{raw(@coordinator.address.zipcode)}
|
||||
#{@coordinator.phone}
|
||||
#{@coordinator.contact.email}
|
||||
|
||||
@@ -13,6 +13,7 @@ import { ru } from "flatpickr/dist/l10n/ru";
|
||||
import { sv } from "flatpickr/dist/l10n/sv";
|
||||
import { tr } from "flatpickr/dist/l10n/tr";
|
||||
import { en } from "flatpickr/dist/l10n/default.js";
|
||||
import { hu } from "flatpickr/dist/l10n/hu";
|
||||
import ShortcutButtonsPlugin from "shortcut-buttons-flatpickr";
|
||||
import labelPlugin from "flatpickr/dist/plugins/labelPlugin/labelPlugin";
|
||||
|
||||
@@ -36,6 +37,7 @@ export default class extends Flatpickr {
|
||||
sv: sv,
|
||||
tr: tr,
|
||||
en: en,
|
||||
hu: hu,
|
||||
};
|
||||
|
||||
initialize() {
|
||||
|
||||
@@ -12,8 +12,8 @@ export const useOpenAndCloseAsAModal = (controller) => {
|
||||
}.bind(controller),
|
||||
|
||||
close: function (_event, remove = false) {
|
||||
// Only execute close if there is an open modal
|
||||
if (!document.querySelector("body").classList.contains('modal-open')) return;
|
||||
// Only execute close if the current modal is open
|
||||
if (!this.modalTarget.classList.contains('in')) return;
|
||||
|
||||
this.modalTarget.classList.remove("in");
|
||||
this.backgroundTarget.classList.remove("in");
|
||||
|
||||
@@ -10,7 +10,8 @@ export default class extends Controller {
|
||||
|
||||
changePage(event) {
|
||||
const productsForm = document.querySelector("#products-form");
|
||||
productsForm.scrollIntoView({ behavior: "smooth" });
|
||||
if (productsForm) productsForm.scrollIntoView({ behavior: "smooth" });
|
||||
|
||||
this.page.value = event.target.dataset.page;
|
||||
this.submitSearch();
|
||||
this.page.value = 1;
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:10.19
|
||||
@@ -24,6 +22,8 @@ services:
|
||||
- .:/usr/src/app
|
||||
- gems:/bundles
|
||||
- ./config/database.yml:/usr/src/app/config/database.yml
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
depends_on:
|
||||
- db
|
||||
- redis
|
||||
@@ -32,6 +32,7 @@ services:
|
||||
OFN_DB_HOST: db
|
||||
OFN_REDIS_URL: redis://redis/
|
||||
OFN_REDIS_JOBS_URL: redis://redis
|
||||
OFN_REDIS_TEST_URL: redis://redis/3
|
||||
WEBPACKER_DEV_SERVER_HOST: webpack
|
||||
command: >
|
||||
bash -c "wait-for-it -t 30 db:5432 &&
|
||||
@@ -6,5 +6,9 @@ Bugsnag.configure do |config|
|
||||
config.logger = Logger.new(STDOUT)
|
||||
config.logger.level = Logger::ERROR
|
||||
end
|
||||
config.notify_release_stages = %w(production staging)
|
||||
|
||||
# If you want to notify Bugsnag in dev or test then set the env var:
|
||||
# spring stop
|
||||
# BUGSNAG=true ./bin/rails console
|
||||
config.notify_release_stages = %w(production staging) unless ENV["BUGSNAG"]
|
||||
end
|
||||
|
||||
@@ -351,6 +351,8 @@ en:
|
||||
sku: "SKU"
|
||||
subtotal: "Subtotal"
|
||||
tax_rate: "Tax rate"
|
||||
with_tax_incl: "%{amount} tax incl."
|
||||
producer_mail_qty: QTY
|
||||
validators:
|
||||
date_time_string_validator:
|
||||
not_string_error: "must be a string"
|
||||
@@ -574,7 +576,15 @@ en:
|
||||
depth: "Depth"
|
||||
payment_could_not_process: "The payment could not be processed"
|
||||
payment_could_not_complete: "The payment could not be completed"
|
||||
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API"
|
||||
redeeming_failed: "Redeeming the voucher failed"
|
||||
actions:
|
||||
create_and_add_another: "Create and Add Another"
|
||||
create: "Create"
|
||||
@@ -973,6 +983,7 @@ en:
|
||||
category_field_name: "Category"
|
||||
tax_category_field_name: "Tax Category"
|
||||
producer_field_name: "Producer"
|
||||
select_unit_scale: Select unit scale
|
||||
clone:
|
||||
success: Successfully cloned the product
|
||||
error: Unable to clone the product
|
||||
@@ -2123,6 +2134,8 @@ en:
|
||||
no_shipping_methods_available: Checkout is not possible due to absence of shipping options. Please contact the shop owner.
|
||||
voucher_not_found: Not found
|
||||
add_voucher_error: There was an error while adding the voucher
|
||||
create_voucher_error: "There was an error while creating the voucher: %{error}"
|
||||
voucher_redeeming_error: There was an error while trying to redeem your voucher
|
||||
shops:
|
||||
hubs:
|
||||
show_closed_shops: "Show closed shops"
|
||||
@@ -2787,6 +2800,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
|
||||
confirm_hub_change: "Are you sure? This will change your selected hub and remove any items in your shopping cart."
|
||||
confirm_oc_change: "Are you sure? This will change your selected order cycle and remove any items in your shopping cart."
|
||||
location_placeholder: "Type in a location..."
|
||||
gmap_load_failure: "Unable to load map. Please check your browser settings and allow 3rd party cookies for this website."
|
||||
error_required: "can't be blank"
|
||||
error_number: "must be number"
|
||||
error_email: "must be email address"
|
||||
|
||||
@@ -107,6 +107,9 @@ en_CA:
|
||||
count_on_hand:
|
||||
using_producer_stock_settings_but_count_on_hand_set: "must be blank because you are using producer stock settings"
|
||||
limited_stock_but_no_count_on_hand: "must be specified because you are forcing limited stock"
|
||||
connected_apps:
|
||||
vine:
|
||||
api_request_error: "An error occured when connecting to Vine API"
|
||||
messages:
|
||||
confirmation: "doesn't match %{attribute}"
|
||||
blank: "can't be blank"
|
||||
@@ -435,7 +438,7 @@ en_CA:
|
||||
cancel_order: "Cancel Order"
|
||||
confirm_send_invoice: "An invoice for this order will be sent to the customer. Are you sure you want to continue?"
|
||||
confirm_resend_order_confirmation: "Are you sure you want to resend the order confirmation email?"
|
||||
must_have_valid_business_number: "%{enterprise_name} must have a valid business number before invoices can be used."
|
||||
must_have_valid_business_number: "%{enterprise_name} must have a valid business number before invoices can be used. Enter a number in enterprise settings."
|
||||
invoice: "Invoice"
|
||||
invoices: "Invoices"
|
||||
file: "File"
|
||||
@@ -525,6 +528,15 @@ en_CA:
|
||||
depth: "Depth"
|
||||
payment_could_not_process: "The payment could not be processed"
|
||||
payment_could_not_complete: "The payment could not be completed"
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API"
|
||||
redeeming_failed: "Redeeming the voucher failed"
|
||||
actions:
|
||||
create_and_add_another: "Create and Add Another"
|
||||
create: "Create"
|
||||
@@ -584,11 +596,11 @@ en_CA:
|
||||
clone: Clone
|
||||
delete: Delete
|
||||
remove: Remove
|
||||
preview: Prévisualisation
|
||||
preview: Preview
|
||||
image:
|
||||
edit: Edit
|
||||
product_preview:
|
||||
product_preview: Prévisualisation du produit
|
||||
product_preview: Product preview
|
||||
shop_tab: Shop
|
||||
product_details_tab: Product details
|
||||
adjustments:
|
||||
@@ -606,8 +618,8 @@ en_CA:
|
||||
first_name: First Name
|
||||
last_name: Last Name
|
||||
on_hand: On Hand
|
||||
on_demand: On Demand
|
||||
on_demand?: On Demand?
|
||||
on_demand: Unlimited
|
||||
on_demand?: Unlimited?
|
||||
order_cycle: Order Cycle
|
||||
payment: Payment
|
||||
payment_method: Payment Method
|
||||
@@ -717,6 +729,7 @@ en_CA:
|
||||
connected_apps_enabled:
|
||||
discover_regen: Discover Regenerative portal
|
||||
affiliate_sales_data: DFC anonymised orders API for research purposes
|
||||
vine: Voucher Integration Engine (VINE)
|
||||
update:
|
||||
resource: Connected app settings
|
||||
customers:
|
||||
@@ -896,6 +909,7 @@ en_CA:
|
||||
category_field_name: "Category"
|
||||
tax_category_field_name: "Tax Category"
|
||||
producer_field_name: "Producer"
|
||||
select_unit_scale: Select unit scale
|
||||
clone:
|
||||
success: Successfully cloned the product
|
||||
error: Unable to clone the product
|
||||
@@ -1014,7 +1028,7 @@ en_CA:
|
||||
variant_unit_name: Variant Unit Name
|
||||
price: Price
|
||||
on_hand: On Hand
|
||||
on_demand: On Demand
|
||||
on_demand: Unlimited
|
||||
shipping_category: Shipping Category
|
||||
tax_category: Tax Category
|
||||
variant_overrides:
|
||||
@@ -1097,9 +1111,9 @@ en_CA:
|
||||
business_details:
|
||||
legend: "Business Details"
|
||||
upload: 'upload'
|
||||
abn: Business Number
|
||||
abn_placeholder: eg. 80781 2466
|
||||
acn: Busines Number
|
||||
abn: Business Number (if applicable)
|
||||
abn_placeholder: 1234 My Business
|
||||
acn: GST Number (if applicable)
|
||||
acn_placeholder: eg.80781 2466
|
||||
display_invoice_logo: Display logo in invoices
|
||||
invoice_text: Add customized text at the end of invoices
|
||||
@@ -1373,9 +1387,25 @@ en_CA:
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
vine:
|
||||
title: "Voucher Integration Engine (VINE)"
|
||||
tagline: "Allow redemption of VINE vouchers in your shopfront."
|
||||
enable: "Donate"
|
||||
disable: "Disconnect"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
vine_api_key: "VINE API Key"
|
||||
vine_secret: "VINE secret"
|
||||
description_html: |
|
||||
<p>
|
||||
To enable VINE for your enterprise, enter your API key and secret.
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" target="_blank"><b>VINE</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
api_parameters_empty: "Please enter an API key and a secret"
|
||||
api_parameters_error: "Check you entered your API key and secret correctly, contact your instance manager if the error persists"
|
||||
connection_error: "API connection error, please try again"
|
||||
setup_error: "VINE API is not configured, please contact your instance manager"
|
||||
actions:
|
||||
edit_profile: Settings
|
||||
properties: Properties
|
||||
@@ -1672,6 +1702,7 @@ en_CA:
|
||||
pack_by_customer: Pack By Customer
|
||||
pack_by_supplier: Pack By Supplier
|
||||
pack_by_product: Pack By Product
|
||||
pay_your_suppliers: Pay your suppliers
|
||||
display:
|
||||
report_is_big: "This report is big and may slow down your device."
|
||||
display_anyway: "Display anyway"
|
||||
@@ -1715,8 +1746,10 @@ en_CA:
|
||||
name: Xero Invoices
|
||||
description: Invoices for import into Xero
|
||||
enterprise_fee_summary:
|
||||
name: "Enterprise Fee Summary"
|
||||
name: "All Fees Summary"
|
||||
description: "Summary of Enterprise Fees collected"
|
||||
suppliers:
|
||||
name: Suppliers
|
||||
enterprise_fees_with_tax_report_by_order: "Enterprise Fees With Tax Report By Order"
|
||||
enterprise_fees_with_tax_report_by_producer: "Enterprise Fees With Tax Report By Producer"
|
||||
errors:
|
||||
@@ -2006,6 +2039,8 @@ en_CA:
|
||||
no_shipping_methods_available: Checkout is not possible because no shipping/pick-up options are available. Please contact the shop owner.
|
||||
voucher_not_found: Not found
|
||||
add_voucher_error: There was an error while adding the voucher
|
||||
create_voucher_error: "There was an error while creating the voucher: %{error}"
|
||||
voucher_redeeming_error: There was an error while trying to redeem your voucher
|
||||
shops:
|
||||
hubs:
|
||||
show_closed_shops: "Show closed shops"
|
||||
@@ -2619,6 +2654,7 @@ en_CA:
|
||||
confirm_hub_change: "Are you sure? This will change your selected hub and remove any items in your shopping cart."
|
||||
confirm_oc_change: "Are you sure? This will change your selected order cycle and remove any items in your shopping cart."
|
||||
location_placeholder: "Type in a location..."
|
||||
gmap_load_failure: "Unable to load map. Please check your browser settings and allow 3rd party cookies for this website."
|
||||
error_required: "can't be blank"
|
||||
error_number: "must be number"
|
||||
error_email: "must be email address"
|
||||
@@ -3003,6 +3039,8 @@ en_CA:
|
||||
report_render_options: Rendering Options
|
||||
report_header_ofn_uid: OFN UID
|
||||
report_header_order_cycle: Order Cycle
|
||||
report_header_order_cycle_start_date: OC Start Date
|
||||
report_header_order_cycle_end_date: OC End Date
|
||||
report_header_user: User
|
||||
report_header_email: Email
|
||||
report_header_status: Status
|
||||
@@ -3023,6 +3061,7 @@ en_CA:
|
||||
report_header_hub_legal_name: "Hub Legal Name"
|
||||
report_header_hub_contact_name: "Hub Contact Name"
|
||||
report_header_hub_email: "Hub Public Email"
|
||||
report_header_hub_contact_email: Hub Contact Email
|
||||
report_header_hub_owner_email: Hub Owner Email
|
||||
report_header_hub_phone: "Hub Phone Number"
|
||||
report_header_hub_address_line1: "Hub Address Line 1"
|
||||
@@ -3095,6 +3134,8 @@ en_CA:
|
||||
report_header_producer_suburb: Producer City/Town
|
||||
report_header_producer_tax_status: Producer Tax Status
|
||||
report_header_producer_charges_sales_tax?: Tax registered
|
||||
report_header_producer_abn_acn: Producer ABN/ACN
|
||||
report_header_producer_address: Producer Address
|
||||
report_header_unit: Unit
|
||||
report_header_group_buy_unit_quantity: Group Buy Unit Quantity
|
||||
report_header_cost: Cost
|
||||
@@ -3155,7 +3196,11 @@ en_CA:
|
||||
report_header_total_units: Total Units
|
||||
report_header_sum_max_total: "Sum Max Total"
|
||||
report_header_total_excl_vat: "Total excl. tax (%{currency_symbol})"
|
||||
report_header_total_fees_excl_tax: "Total fees excl. tax (%{currency_symbol})"
|
||||
report_header_total_tax_on_fees: "Total tax on fees (%{currency_symbol})"
|
||||
report_header_total: "Total (%{currency_symbol})"
|
||||
report_header_total_incl_vat: "Total incl. tax (%{currency_symbol})"
|
||||
report_header_total_excl_fees_and_tax: "Total excl. fees and tax (%{currency_symbol})"
|
||||
report_header_temp_controlled: TempControlled?
|
||||
report_header_is_producer: Producer?
|
||||
report_header_not_confirmed: Not Confirmed
|
||||
|
||||
@@ -528,6 +528,15 @@ en_FR:
|
||||
depth: "Depth"
|
||||
payment_could_not_process: "The payment could not be processed"
|
||||
payment_could_not_complete: "The payment could not be completed"
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API"
|
||||
redeeming_failed: "Redeeming the voucher failed"
|
||||
actions:
|
||||
create_and_add_another: "Create and Add Another"
|
||||
create: "Create"
|
||||
@@ -900,6 +909,7 @@ en_FR:
|
||||
category_field_name: "Category"
|
||||
tax_category_field_name: "Tax Category"
|
||||
producer_field_name: "Producer"
|
||||
select_unit_scale: Select unit scale
|
||||
clone:
|
||||
success: Successfully cloned the product
|
||||
error: Unable to clone the product
|
||||
@@ -1341,7 +1351,7 @@ en_FR:
|
||||
connected_apps:
|
||||
legend: "Connected apps"
|
||||
affiliate_sales_data:
|
||||
title: "INRAE / UFC QUE CHOISIR Research"
|
||||
title: "INRAE Research"
|
||||
tagline: "Allow this research project to access your orders data anonymously"
|
||||
enable: "Allow data sharing"
|
||||
disable: "Stop sharing"
|
||||
@@ -1349,7 +1359,7 @@ en_FR:
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
description_html: |
|
||||
<p>
|
||||
INRAE and UFC QUE CHOISIR are teaming up to study food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
INRAE are teaming up to study food prices in short food systems and compare them with prices in the supermarket, for a given set of products. The data that is used by INRAE is mixed with data coming from other short food chain platforms in France. No individual product prices will be publicly disclosed through this project.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://apropos.coopcircuits.fr/"
|
||||
@@ -1382,7 +1392,7 @@ en_FR:
|
||||
vine:
|
||||
title: "Voucher Integration Engine (VINE)"
|
||||
tagline: "Allow redemption of VINE vouchers in your shopfront."
|
||||
enable: "About"
|
||||
enable: "Connect"
|
||||
disable: "Disconnect"
|
||||
need_to_be_manager: "Only managers can connect apps."
|
||||
vine_api_key: "VINE API Key"
|
||||
@@ -2032,6 +2042,8 @@ en_FR:
|
||||
no_shipping_methods_available: Checkout is not possible due to absence of shipping options. Please contact the shop owner.
|
||||
voucher_not_found: Not found
|
||||
add_voucher_error: There was an error while adding the voucher
|
||||
create_voucher_error: "There was an error while creating the voucher: %{error}"
|
||||
voucher_redeeming_error: There was an error while trying to redeem your voucher
|
||||
shops:
|
||||
hubs:
|
||||
show_closed_shops: "Show closed shops"
|
||||
@@ -2645,6 +2657,7 @@ en_FR:
|
||||
confirm_hub_change: "Are you sure? This will change your selected hub and remove any items in your shopping cart."
|
||||
confirm_oc_change: "Are you sure? This will change your selected order cycle and remove any items in your shopping cart."
|
||||
location_placeholder: "Type in a location..."
|
||||
gmap_load_failure: "Unable to load map. Please check your browser settings and allow 3rd party cookies for this website."
|
||||
error_required: "can't be blank"
|
||||
error_number: "must be number"
|
||||
error_email: "must be email address"
|
||||
|
||||
@@ -3124,7 +3124,7 @@ en_GB:
|
||||
report_header_producer_suburb: Producer Suburb
|
||||
report_header_producer_tax_status: Tax Rate Name
|
||||
report_header_producer_charges_sales_tax?: GST/VAT Registered
|
||||
report_header_producer_abn_acn: Producer ABN/ACN
|
||||
report_header_producer_abn_acn: Producer company number
|
||||
report_header_producer_address: Producer Address
|
||||
report_header_unit: Unit
|
||||
report_header_group_buy_unit_quantity: Group Buy Unit Quantity
|
||||
|
||||
@@ -32,7 +32,7 @@ es:
|
||||
fee_type: Tipo de Comisión
|
||||
spree/order:
|
||||
payment_state: Estado del pago
|
||||
shipment_state: Estado del envío
|
||||
shipment_state: Provincia de envío
|
||||
completed_at: Completado en
|
||||
number: Número
|
||||
state: Estado
|
||||
@@ -50,6 +50,7 @@ es:
|
||||
primary_taxon: "categoría del producto"
|
||||
shipping_category_id: "Categoría de envío"
|
||||
supplier: "Proveedora"
|
||||
variant_unit: "Valor unidad"
|
||||
variant_unit_name: "Nombre de la unidad de la variante"
|
||||
unit_value: "Valor unidad"
|
||||
spree/credit_card:
|
||||
@@ -65,10 +66,24 @@ es:
|
||||
spree/payment_method/calculator:
|
||||
preferred_flat_percent: "Calculadora Porcentaje fijo:"
|
||||
preferred_amount: "Calculadora Importe:"
|
||||
preferred_first_item: "Calculadora Primer elemento:"
|
||||
preferred_additional_item: "Calculadora Coste del artículo adicional:"
|
||||
preferred_max_items: "Calculadora Max Items:"
|
||||
preferred_minimal_amount: "Calculadora Importe mínimo:"
|
||||
preferred_normal_amount: "Calculadora Cantidad normal:"
|
||||
preferred_discount_amount: "Calculadora Importe del descuento:"
|
||||
preferred_unit_from_list: "Calculadora Unidad De la Lista:"
|
||||
preferred_per_unit: "Calculadora por unidad:"
|
||||
enterprise:
|
||||
white_label_logo_link: "Enlace para el logo que se usara en el escaparate"
|
||||
errors:
|
||||
models:
|
||||
enterprise_fee:
|
||||
inherit_tax_requires_per_item_calculator: "Heredar la categoría fiscal requiere una calculadora por artículo."
|
||||
spree/image:
|
||||
attributes:
|
||||
attachment:
|
||||
integrity_error: "no se ha podido cargar. Compruebe que el archivo no esté dañado e inténtelo de nuevo."
|
||||
spree/user:
|
||||
attributes:
|
||||
email:
|
||||
@@ -93,7 +108,9 @@ es:
|
||||
vine:
|
||||
api_request_error: "Un error se ha producido al conectarse a Vine API"
|
||||
messages:
|
||||
confirmation: "No coincide"
|
||||
blank: "no puede estar vacío"
|
||||
too_short: "es demasiado corto (el mínimo es %{count}caracteres)"
|
||||
errors:
|
||||
messages:
|
||||
content_type_invalid: "Tiene un tipo de contenido invalido"
|
||||
@@ -104,6 +121,8 @@ es:
|
||||
aspect_ratio_not_landscape: "debe ser una imagen de paisaje"
|
||||
aspect_ratio_unknown: "tiene una relación de aspecto desconocida"
|
||||
image_not_processable: "no es una imagen valida"
|
||||
not_found:
|
||||
title: "La página que estas buscando no existe (404)"
|
||||
internal_server_error:
|
||||
title: "Lo sentimos pero algo fue mal (500)"
|
||||
unprocessable_entity:
|
||||
@@ -187,6 +206,7 @@ es:
|
||||
not_available_to_shop: "no está disponible para %{shop}"
|
||||
card_details: "Detalles de tarjeta"
|
||||
card_type: "Tipo de tarjeta"
|
||||
card_type_is: "El tipo de tarjeta es"
|
||||
what_is_this: "¿Qué es esto?"
|
||||
cardholder_name: "Nombre del titular de la tarjeta"
|
||||
community_forum_url: "URL del foro de la comunidad"
|
||||
@@ -449,6 +469,13 @@ es:
|
||||
depth: "Profundidad"
|
||||
payment_could_not_process: "No se pudo procesar el pago"
|
||||
payment_could_not_complete: "No se pudo completar el pago"
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
invalid_voucher: "El bono no es válido"
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
vine_api: "Ha habido un error en la comunicación con el API"
|
||||
redeeming_failed: "Error al canjear el bono"
|
||||
actions:
|
||||
create_and_add_another: "Crear y agregar otro"
|
||||
create: "Crear"
|
||||
@@ -504,6 +531,7 @@ es:
|
||||
clone: Duplicar
|
||||
delete: Borrar
|
||||
remove: Eliminar
|
||||
preview: Vista previa
|
||||
image:
|
||||
edit: Editar
|
||||
product_preview:
|
||||
@@ -624,6 +652,11 @@ es:
|
||||
info_html: "Matomo es una aplicación de análisis web y móvil. Puede alojar Matomo localmente o utilizar un servicio alojado en la nube. Ver <a href='http://matomo.org' target='_blank'>matomo.org</a> para más información."
|
||||
config_instructions_html: "Aquí puede configurar la integración de OFN Matomo. La siguiente URL de Matomo debe apuntar a la instancia de Matomo a la que se enviará la información de seguimiento del usuario; si se deja vacío, el seguimiento del usuario Matomo se desactivará. El campo ID del sitio no es obligatorio, pero es útil si está rastreando más de un sitio web en una sola instancia de Matomo; se puede encontrar en la consola de la instancia de Matomo."
|
||||
config_instructions_tag_manager_html: "La configuración de la URL de Matomo Tag Manager habilita Matomo Tag Manager. Esta herramienta le permite configurar eventos analíticos. La URL de Matomo Tag Manager se copia de la sección Código de instalación de Matomo Tag Manager. Asegúrese de seleccionar el contenedor y el entorno correctos, ya que estas opciones cambian la URL."
|
||||
connected_app_settings:
|
||||
edit:
|
||||
title: "Ajustes de la aplicación conectada"
|
||||
update:
|
||||
resource: Ajustes de la aplicación conectada
|
||||
customers:
|
||||
index:
|
||||
new_customer: "Nuevo Consumidor"
|
||||
@@ -715,6 +748,7 @@ es:
|
||||
variants:
|
||||
infinity: "infinito"
|
||||
to_order_tip: "Los artículos hechos según demanda no tienen un nivel de stock, como por ejemplo panes hechos según demanda."
|
||||
back_to_products_list: "Volver a la lista de productos"
|
||||
editing_product: "Editando producto"
|
||||
tabs:
|
||||
product_details: "Detalles del Producto"
|
||||
@@ -742,6 +776,9 @@ es:
|
||||
search_for_producers: Buscar productoras
|
||||
select_producer: Seleccionar productora
|
||||
all_producers: Todas las productoras
|
||||
search_for_categories: Buscar por categorías
|
||||
select_category: Seleccionar categoría
|
||||
all_categories: Todas las categorías
|
||||
producers:
|
||||
label: Productoras
|
||||
categories:
|
||||
@@ -762,11 +799,20 @@ es:
|
||||
new_variant: Nueva variante
|
||||
bulk_update:
|
||||
success: Cambios guardados
|
||||
delete_product:
|
||||
success: ' El producto ha sido eliminado'
|
||||
error: No se puede eliminar el producto
|
||||
delete_variant:
|
||||
success: ' La variante ha sido eliminada'
|
||||
error: No se puede eliminar la variante
|
||||
variant_row:
|
||||
none_tax_category: Ninguno
|
||||
category_field_name: "Categoría"
|
||||
tax_category_field_name: "Categoría de impuestos"
|
||||
producer_field_name: "Productora"
|
||||
clone:
|
||||
success: Se ha clonado el producto
|
||||
error: No se ha podido clonar el producto
|
||||
product_import:
|
||||
title: Importación de productos
|
||||
file_not_found: Archivo no encontrado o no se pudo abrir
|
||||
@@ -779,7 +825,9 @@ es:
|
||||
conditional_blank: no puede estar en blanco si unit_type está en blanco
|
||||
no_product: no coincide con ningún producto en la base de datos
|
||||
not_found: no encontrado en la base de datos
|
||||
category_not_found: no coincide con las categorías permitidas. Consulta las categorías correctas para elegir en la página de importación de productos o comprueba que no haya ningún error ortográfico.
|
||||
not_updatable: No se puede actualizar sobre productos existentes a través de la importación de productos
|
||||
values_must_be_same: debe ser el mismo para los productos con el mismo nombre
|
||||
blank: no puede estar vacío
|
||||
products_no_permission: no tienes permiso para administrar productos para esta organización
|
||||
inventory_no_permission: no tienes permiso para crear inventario para esta productora
|
||||
@@ -809,6 +857,7 @@ es:
|
||||
dfc_import_form:
|
||||
title: "Importar del catálogo DFC"
|
||||
enterprise: "Organización"
|
||||
catalog_url: "URL del catálogo DFC"
|
||||
import: "Importar"
|
||||
import:
|
||||
review: Revisión
|
||||
@@ -911,6 +960,7 @@ es:
|
||||
orders:
|
||||
edit:
|
||||
order_sure_want_to: ¿Está seguro de que desea %{event} este pedido?
|
||||
tax_on_fees: "Impuesto sobre las tasas"
|
||||
invoice_email_sent: 'Se ha enviado correo electrónico con la factura.'
|
||||
order_email_resent: 'El correo electrónico del pedido se ha reenviado'
|
||||
bulk_management:
|
||||
@@ -996,6 +1046,8 @@ es:
|
||||
phone: Teléfono
|
||||
phone_placeholder: ej. 98 7654 3210
|
||||
whatsapp_phone: Número de teléfono WhatsApp
|
||||
whatsapp_phone_placeholder: e. +34 666 666666
|
||||
whatsapp_phone_tip: "Este número se mostrará en tu perfil público para que se abra como un enlace de WhatsApp."
|
||||
website: Website
|
||||
website_placeholder: ej. www.truffles.com
|
||||
enterprise_fees:
|
||||
@@ -1062,7 +1114,7 @@ es:
|
||||
permalink:
|
||||
permalink: Permalink (sin espacios)
|
||||
permalink_tip: "Se usa para crear la URL de tu tienda: %{link}nombre-de-tu-tienda/shop"
|
||||
link_to_front: Link a la tienda
|
||||
link_to_front: Enlace a la tienda
|
||||
link_to_front_tip: Enlace directo a tu tienda en Open Food Networks
|
||||
ofn_uid: UID de OFN
|
||||
ofn_uid_tip: La identificación única utilizada para identificar la organización en Open Food Network.
|
||||
@@ -1119,6 +1171,7 @@ es:
|
||||
shopfront_sort_by_producer: "Por productora"
|
||||
shopfront_sort_by_category_placeholder: "Categoría"
|
||||
shopfront_sort_by_producer_placeholder: "Productora"
|
||||
display_remaining_stock: "Mostrar las existencias restantes en el escaparate si hay pocas disponibles"
|
||||
display_remaining_stock_tip: "Informe a los compradores cuando solo queden 3 artículos o menos."
|
||||
enabled: "Habilitado"
|
||||
disabled: "Deshabilitado"
|
||||
@@ -1175,25 +1228,42 @@ es:
|
||||
voucher_code: Código promocional
|
||||
rate: Impuesto
|
||||
label: Etiqueta
|
||||
purpose: Propósito
|
||||
expiry: Caducidad
|
||||
use_limit: Utilización/Límite
|
||||
customers: Consumidora
|
||||
net_value: Valor neto
|
||||
active: ¿Activo?
|
||||
add_new: Añadir nuevo
|
||||
no_voucher_yet: Todavía no hay bonos
|
||||
white_label:
|
||||
legend: "Etiqueta blanca"
|
||||
hide_ofn_navigation: "Ocultar la navegación de OFN"
|
||||
upload_logo: "Logo que se utilizará en el escaparate"
|
||||
remove_logo: "Eliminar el logo"
|
||||
remove_logo_confirm: "¿Está seguro de que desea eliminar este logo?"
|
||||
remove_logo_success: "Logo eliminado"
|
||||
white_label_logo_link_label: "Enlace para el log que se usara en el escaparate"
|
||||
hide_groups_tab: "Ocultar la pestaña de grupos en el escaparate"
|
||||
create_custom_tab: "Crear pestaña personalizada en el escaparate"
|
||||
custom_tab_title: "Título de la pestaña personalizada"
|
||||
custom_tab_content: "Contenido de la ficha personalizada"
|
||||
connected_apps:
|
||||
legend: "Aplicaciones connectadas"
|
||||
affiliate_sales_data:
|
||||
enable: "Permitir compartir datos"
|
||||
disable: "Dejar de compartir"
|
||||
loading: "Cargando"
|
||||
need_to_be_manager: "Sólo los administradores pueden conectar aplicaciones."
|
||||
discover_regen:
|
||||
enable: "Permitir compartir datos"
|
||||
disable: "Dejar de compartir"
|
||||
loading: "Cargando"
|
||||
need_to_be_manager: "Sólo los administradores pueden conectar aplicaciones."
|
||||
vine:
|
||||
enable: "Conectar"
|
||||
disable: "Desconectar"
|
||||
need_to_be_manager: "Sólo los administradores pueden conectar aplicaciones."
|
||||
actions:
|
||||
edit_profile: Configuración
|
||||
properties: Propiedades
|
||||
@@ -1246,8 +1316,10 @@ es:
|
||||
contact_name: Nombre de Contacto
|
||||
edit:
|
||||
editing: 'Configuración:'
|
||||
back_link: Volver a la lista de organizaciones
|
||||
new:
|
||||
title: Nueva Organización
|
||||
back_link: Volver a la lista de organizaciones
|
||||
welcome:
|
||||
welcome_title: Bienvenida a Open Food Network!
|
||||
welcome_text: Has creado correctamente un
|
||||
@@ -1285,6 +1357,7 @@ es:
|
||||
re_notify_producers: Re notificar a los productores
|
||||
notify_producers_tip: Esto le enviará un correo a cada productor con su lista de pedidos.
|
||||
date_time_warning_modal_content:
|
||||
proceed: 'Proceda de todos modos'
|
||||
cancel: 'Cancelar'
|
||||
incoming:
|
||||
incoming: "Entrante"
|
||||
@@ -1412,6 +1485,7 @@ es:
|
||||
could_not_resume_the_order: No se pudo reanudar el pedido
|
||||
select2:
|
||||
searching: Buscando...
|
||||
no_matches: No se han encontrado coincidencias
|
||||
shared:
|
||||
user_guide_link:
|
||||
user_guide: Manual de Usuario
|
||||
@@ -1419,6 +1493,8 @@ es:
|
||||
has_no_payment_methods: "%{enterprise} no tiene formas de pago"
|
||||
has_no_shipping_methods: "%{enterprise} no tiene ningún método de envío"
|
||||
has_no_enterprise_fees: "%{enterprise} no tiene comisiones de organización"
|
||||
flashes:
|
||||
dismiss: Desestimar
|
||||
side_menu:
|
||||
enterprise:
|
||||
primary_details: "Detalles Principales"
|
||||
@@ -1438,6 +1514,8 @@ es:
|
||||
shop_preferences: "Configuración de la tienda"
|
||||
users: "Usuarias"
|
||||
vouchers: Bonos
|
||||
white_label: "Etiqueta blanca"
|
||||
connected_apps: "Aplicaciones connectadas"
|
||||
enterprise_group:
|
||||
primary_details: "Detalles Principales"
|
||||
users: "Usuarias"
|
||||
@@ -1473,10 +1551,14 @@ es:
|
||||
pack_by_customer: Pack por Consumidor
|
||||
pack_by_supplier: Pack por proveedor
|
||||
pack_by_product: Empaquetar por producto
|
||||
display:
|
||||
display_anyway: "Mostrar de todos modos"
|
||||
download:
|
||||
button: "Descargar informe"
|
||||
show:
|
||||
report_link_label: Descargar informe (si está disponible)
|
||||
revenues_by_hub:
|
||||
description: Ingresos por grupo
|
||||
orders_and_distributors:
|
||||
name: Pedidos y Distribuidores
|
||||
description: Pedidos con detalles de distribuidor
|
||||
@@ -1505,6 +1587,8 @@ es:
|
||||
enterprise_fee_summary:
|
||||
name: "Resumen de las comisiones de la organización"
|
||||
description: "Resumen de las comisiones de la organización recolectadas"
|
||||
suppliers:
|
||||
name: Proveedoras
|
||||
errors:
|
||||
no_report_type: "Por favor especifique un tipo de reporte"
|
||||
report_not_found: "El reporte no fue encontrado"
|
||||
@@ -1540,6 +1624,7 @@ es:
|
||||
oidc_settings:
|
||||
index:
|
||||
connect: "Conecta tu cuenta"
|
||||
disconnect: "Desconectar"
|
||||
view_account: "Para ver tu cuenta, ver:"
|
||||
subscriptions:
|
||||
index:
|
||||
@@ -2447,6 +2532,7 @@ es:
|
||||
contact_field_required: "Debes introducir un contacto principal."
|
||||
phone_field: "Número de teléfono"
|
||||
whatsapp_phone_field: "Número de teléfono WhatsApp"
|
||||
whatsapp_phone_tooltip: "Este número se mostrará en tu perfil público para que se abra como un enlace de WhatsApp."
|
||||
phone_field_placeholder: "p.ej. 93 250 16 45"
|
||||
type:
|
||||
title: "Tipo"
|
||||
@@ -2765,6 +2851,10 @@ es:
|
||||
report_header_hub_contact_name: "Nombre de contacto del grupo"
|
||||
report_header_hub_email: "Correo electrónico público del grupo"
|
||||
report_header_hub_owner_email: Correo electrónico del responsable de grupo
|
||||
report_header_hub_address_line1: "Dirección 1 del grupo"
|
||||
report_header_hub_address_line2: "Dirección 2 del grupo"
|
||||
report_header_hub_address_zipcode: "Código postal del grupo"
|
||||
report_header_hub_address_state_name: "Región del grupo"
|
||||
report_header_code: Código
|
||||
report_header_paid: ¿Pagado?
|
||||
report_header_delivery: ¿Entregado?
|
||||
@@ -2775,7 +2865,7 @@ es:
|
||||
report_header_ship_street_2: Calle de envío 2
|
||||
report_header_ship_city: Ciudad de envío
|
||||
report_header_ship_postcode: Código postal de envío
|
||||
report_header_ship_state: Estado del envío
|
||||
report_header_ship_state: Provincia de envío
|
||||
report_header_billing_street: Calle de facturación
|
||||
report_header_billing_street_2: Calle de facturación 2
|
||||
report_header_billing_street_3: Calle de facturación 3
|
||||
@@ -2827,6 +2917,7 @@ es:
|
||||
report_header_supplier: Proveedor
|
||||
report_header_producer: Productora
|
||||
report_header_producer_suburb: Barrio Productora
|
||||
report_header_producer_address: Dirección de la productora
|
||||
report_header_unit: Unidad
|
||||
report_header_group_buy_unit_quantity: Agrupar por cantidad unidad
|
||||
report_header_cost: Coste
|
||||
@@ -2900,6 +2991,8 @@ es:
|
||||
report_header_transaction_fee: Comisión por transacción (sin impuestos)
|
||||
report_header_total_untaxable_admin: Total de ajustes administrativos no tributables (sin impuestos)
|
||||
report_header_total_taxable_admin: Total de ajustes tributarios de administración (impuestos incluidos)
|
||||
report_header_voucher_label: Etiqueta del bono
|
||||
report_header_voucher_amount: "Cantidad del bono (%{currency_symbol})"
|
||||
invoice_date: "Fecha de factura"
|
||||
due_date: "Fecha de vencimiento"
|
||||
account_code: "Código de cuenta"
|
||||
@@ -3209,6 +3302,7 @@ es:
|
||||
processing: "procesando"
|
||||
void: "pendiente"
|
||||
invalid: "inválido"
|
||||
quantity_unavailable: "Existencias insuficientes. ¡Artículo no guardado!"
|
||||
quantity_unchanged: "Cantidad sin cambios respecto a la cantidad anterior."
|
||||
resend_user_email_confirmation:
|
||||
resend: "Reenviar"
|
||||
@@ -3344,7 +3438,9 @@ es:
|
||||
link: "Enlace"
|
||||
numbers: "Numeros"
|
||||
redo: "Rehacer"
|
||||
strike: "Tachado"
|
||||
undo: "Deshacer"
|
||||
unlink: "Desenlazar"
|
||||
url: "URL"
|
||||
urlPlaceholder: "Por favor introduzca una URL para insertar"
|
||||
inflections:
|
||||
@@ -3584,6 +3680,7 @@ es:
|
||||
resend: "Reenviar"
|
||||
back_to_orders_list: "Volver a la lista de pedidos"
|
||||
back_to_payments_list: "Volver a la lista de pagos"
|
||||
back_to_states_list: "Volver a la lista de regiones"
|
||||
return_authorizations: "Autorizaciones de devolución"
|
||||
cannot_create_returns: "No se pueden crear devoluciones ya que este pedido no tiene unidades enviadas."
|
||||
select_stock: "Seleccionar stock"
|
||||
@@ -3628,6 +3725,7 @@ es:
|
||||
credit_card: "Tarjeta de crédito"
|
||||
new_payment: "Nuevo pago"
|
||||
capture: "Pagado"
|
||||
capture_and_complete_order: "Capturar y completar el pedido"
|
||||
void: "Pendiente"
|
||||
login: "Iniciar sesión"
|
||||
password: "Contraseña"
|
||||
@@ -3671,6 +3769,7 @@ es:
|
||||
tax_rate_amount_explanation: "Las tasas de impuestos son una cantidad decimal para ayudar en los cálculos (es decir, si la tasa de impuestos es del 5%, introduzca 0.05)"
|
||||
included_in_price: "Incluido en el precio"
|
||||
show_rate_in_label: "Mostrar impuesto en la etiqueta"
|
||||
back_to_tax_rates_list: "Volver a la lista de impuestos"
|
||||
tax_settings: "Configuración de Impuestos"
|
||||
zones: "Zonas"
|
||||
new_zone: "Nueva zona"
|
||||
@@ -3683,6 +3782,7 @@ es:
|
||||
iso_name: "Nombre ISO"
|
||||
states_required: "Estados requeridos"
|
||||
editing_country: "Editar país"
|
||||
back_to_countries_list: "Volver a la lista de países"
|
||||
states: "Estados"
|
||||
abbreviation: "Abreviatura"
|
||||
new_state: "Nuevo estado"
|
||||
@@ -3696,6 +3796,7 @@ es:
|
||||
shipping_categories: "Categorías de envío"
|
||||
new_shipping_category: "Nueva categoría de envío"
|
||||
back_to_shipping_categories: "Volver a las categorías de envío"
|
||||
editing_shipping_category: "Edición de la categoría de envío"
|
||||
name: "Nombre"
|
||||
description: "Descripción"
|
||||
type: "Tipo"
|
||||
@@ -3894,7 +3995,7 @@ es:
|
||||
one: "1 pedido seleccionado"
|
||||
sortable_header:
|
||||
payment_state: "Estado del pago"
|
||||
shipment_state: "Estado del envío"
|
||||
shipment_state: "Provincia de envío"
|
||||
completed_at: "Completado en"
|
||||
number: "Número"
|
||||
state: "Estado"
|
||||
@@ -4074,6 +4175,7 @@ es:
|
||||
product_name: nombre del producto
|
||||
primary_taxon_form:
|
||||
product_category: categoría del producto
|
||||
search_for_categories: "Buscar por categorias"
|
||||
group_buy_form:
|
||||
group_buy: "¿Agrupado por?"
|
||||
bulk_unit_size: Tamaño de la unidad a granel
|
||||
@@ -4097,11 +4199,13 @@ es:
|
||||
back_to_users_list: "Volver a la lista de usuarias"
|
||||
general_settings: "Configuración general"
|
||||
form:
|
||||
disabled: "¿Deshabilitado?"
|
||||
email: "Email"
|
||||
roles: "Roles"
|
||||
enterprise_limit: "Límite de la Organización"
|
||||
confirm_password: "Confirmar contraseña"
|
||||
password: "Contraseña"
|
||||
locale: "Idioma"
|
||||
email_confirmation:
|
||||
confirmation_pending: "La confirmación por correo electrónico está pendiente. Hemos enviado un correo electrónico de confirmación a %{address}."
|
||||
variants:
|
||||
@@ -4142,13 +4246,19 @@ es:
|
||||
completed_at: "Completado en"
|
||||
state: "Provincia"
|
||||
payment_state: "Estado del pago"
|
||||
shipment_state: "Estado del envío"
|
||||
shipment_state: "Provincia de envío"
|
||||
email: "Email"
|
||||
total: "Total"
|
||||
billing_address_name: "Nombre"
|
||||
taxons:
|
||||
back_to_list: "Volver a la lista de categoría de producto"
|
||||
index:
|
||||
title: "Categorías de Producto"
|
||||
new_taxon: 'Nueva categoría de producto'
|
||||
new:
|
||||
title: "Nueva categoría de producto"
|
||||
edit:
|
||||
title: "Editar la categoría del producto"
|
||||
form:
|
||||
name: Nombre
|
||||
description: Descripción
|
||||
@@ -4261,6 +4371,7 @@ es:
|
||||
thanks: "Gracias por hacer negocios."
|
||||
track_information: "Información de seguimiento: %{tracking}"
|
||||
track_link: "Enlace de seguimiento: %{url}"
|
||||
picked_up_subject: "Notificación de recogida"
|
||||
test_mailer:
|
||||
test_email:
|
||||
greeting: "¡Felicidades!"
|
||||
@@ -4448,3 +4559,4 @@ es:
|
||||
previous: Anterior
|
||||
invisible_captcha:
|
||||
sentence_for_humans: "Por favor, dejalo vacio"
|
||||
timestamp_error_message: "Por favor, inténtelo de nuevo después de 5 segundos."
|
||||
|
||||
@@ -527,6 +527,15 @@ fr:
|
||||
depth: "Profondeur"
|
||||
payment_could_not_process: "Le paiement n'a pas pu être traité"
|
||||
payment_could_not_complete: "Le paiement n'a pas pu être finalisé"
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
vine_api: "Il y a eu une erreur de communication avec l'API, merci de réessayer."
|
||||
invalid_voucher: "Le bon de réduction n'est pas valide."
|
||||
not_found_voucher: "Désolé, nous n'avons pas trouvé ce bon de réduction. Merci de vérifier le code qui vous a été transmis."
|
||||
vine_voucher_redeemer_service:
|
||||
errors:
|
||||
vine_api: "Il y a eu une erreur de communication avec l'API"
|
||||
redeeming_failed: "Echec de la prise en compte du bon de réduction"
|
||||
actions:
|
||||
create_and_add_another: "Créer et ajouter nouveau"
|
||||
create: "Créer"
|
||||
@@ -718,7 +727,7 @@ fr:
|
||||
enabled_legend: "Applications connectées autorisées"
|
||||
connected_apps_enabled:
|
||||
discover_regen: Portail Discover Regenerative
|
||||
affiliate_sales_data: API de commandes anonymisées DFC à fins de recherche
|
||||
affiliate_sales_data: API DFC de commandes anonymisées à fins de recherche
|
||||
vine: Éditeur de bons de réduction (VINE)
|
||||
update:
|
||||
resource: Paramètres de l'application connectée
|
||||
@@ -901,6 +910,7 @@ fr:
|
||||
category_field_name: "Catégorie"
|
||||
tax_category_field_name: "TVA applicable"
|
||||
producer_field_name: "Producteur"
|
||||
select_unit_scale: Sélectionner l'échelle d'unité
|
||||
clone:
|
||||
success: Le produit a bien été dupliqué
|
||||
error: Impossible de dupliquer le produit
|
||||
@@ -1343,7 +1353,7 @@ fr:
|
||||
connected_apps:
|
||||
legend: "Applications connectées"
|
||||
affiliate_sales_data:
|
||||
title: "Programme de recherche INRAE / UFC QUE CHOISIR"
|
||||
title: "Programme de recherche INRAE"
|
||||
tagline: "Autoriser ce programme de recherche à accéder à vos données de commandes anonymisées"
|
||||
enable: "Autoriser le partage de données"
|
||||
disable: "Arrêter le partage"
|
||||
@@ -1351,7 +1361,7 @@ fr:
|
||||
need_to_be_manager: "Seuls les gestionnaires peuvent connecter des applications."
|
||||
description_html: |
|
||||
<p>
|
||||
L'INRAE et UFC QUE CHOISIR travaillent conjointement sur les prix des produits distribués en circuit court, comparés aux prix des mêmes produits vendus en supermarché, pour un échantillon de produits. Les données utilisées dans le cadre de ce programme de recherche sont une agrégation des données fournies par plusieurs plateformes de vente en circuit court en France. Aucun prix de produit d'une boutique en particulier ne sera transmis publiquement à travers ce programme.
|
||||
L'INRAE travaille sur les prix des produits distribués en circuit court, comparés aux prix des mêmes produits vendus en supermarché, pour un échantillon de produits. Les données utilisées dans le cadre de ce programme de recherche sont une agrégation des données fournies par plusieurs plateformes de vente en circuit court en France. Aucun prix de produit d'une boutique en particulier ne sera transmis publiquement à travers ce programme.
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://apropos.coopcircuits.fr/"
|
||||
@@ -2038,6 +2048,8 @@ fr:
|
||||
no_shipping_methods_available: Il n'est pas possible de passer commande car il n'y a pas d'options de livraison / récupération de commande. Veuillez contacter le gestionnaire de la boutique.
|
||||
voucher_not_found: Non trouvé
|
||||
add_voucher_error: Il y a eu une erreur lors de l'ajout de votre réduction.
|
||||
create_voucher_error: "Il y a eu une erreur lors de la création du bon de réduction : %{error}"
|
||||
voucher_redeeming_error: Il y a eu une erreur lors de la tentative d'utilisation de votre bon de réduction.
|
||||
shops:
|
||||
hubs:
|
||||
show_closed_shops: "Afficher toutes les boutiques"
|
||||
@@ -2651,6 +2663,7 @@ fr:
|
||||
confirm_hub_change: "Confirmer? Cette action modifiera la boutique sélectionnée et tous les articles de votre panier seront effacés."
|
||||
confirm_oc_change: "Confirmer? Cette action modifiera le cycle de vente sélectionné et tous les articles de votre panier seront effacés."
|
||||
location_placeholder: "Saisissez une localisation..."
|
||||
gmap_load_failure: "Impossible de charger la carte. Veuillez vérifier les paramètres de votre navigateur et accepter les cookies pour ce site web."
|
||||
error_required: "Champ obligatoire"
|
||||
error_number: "saisir un nombre"
|
||||
error_email: "saisir une adresse email"
|
||||
|
||||
@@ -107,6 +107,9 @@ fr_CA:
|
||||
count_on_hand:
|
||||
using_producer_stock_settings_but_count_on_hand_set: "doit être vide car utilise les informations de stock du producteur"
|
||||
limited_stock_but_no_count_on_hand: "doit être spécifié car pas \"à volonté\""
|
||||
connected_apps:
|
||||
vine:
|
||||
api_request_error: "Une erreur s'est produite lors de la connexion à l'API VINE"
|
||||
messages:
|
||||
confirmation: "ne correspond pas %{attribute}"
|
||||
blank: "Champ obligatoire"
|
||||
@@ -525,6 +528,10 @@ fr_CA:
|
||||
depth: "Profondeur"
|
||||
payment_could_not_process: "Le paiement n'a pas pu être traité"
|
||||
payment_could_not_complete: "Le paiement n'a pas pu être finalisé"
|
||||
vine_voucher_validator_service:
|
||||
errors:
|
||||
vine_api: "There was an error communicating with the API, please try again later."
|
||||
invalid_voucher: "The voucher is not valid"
|
||||
actions:
|
||||
create_and_add_another: "Créer et ajouter nouveau"
|
||||
create: "Créer"
|
||||
@@ -717,6 +724,7 @@ fr_CA:
|
||||
connected_apps_enabled:
|
||||
discover_regen: Portail Discover Regenerative
|
||||
affiliate_sales_data: API de commandes anonymisées DFC à fins de recherche
|
||||
vine: Éditeur de bons de réduction (VINE)
|
||||
update:
|
||||
resource: Paramètres de l'application connectée
|
||||
customers:
|
||||
@@ -898,6 +906,7 @@ fr_CA:
|
||||
category_field_name: "Catégorie"
|
||||
tax_category_field_name: "Type de taxe"
|
||||
producer_field_name: "Producteur"
|
||||
select_unit_scale: Select unit scale
|
||||
clone:
|
||||
success: Le produit a bien été dupliqué
|
||||
error: Impossible de dupliquer le produit
|
||||
@@ -1376,9 +1385,25 @@ fr_CA:
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
vine:
|
||||
title: "Éditeur de bons de réduction (VINE)"
|
||||
tagline: "Autoriser l'utilisation de bons de réduction VINE dans votre boutique"
|
||||
enable: "Se connecter"
|
||||
disable: "Déconnecter"
|
||||
need_to_be_manager: "Seuls les gestionnaires peuvent connecter des applications."
|
||||
vine_api_key: "clé API VINE"
|
||||
vine_secret: "VINE secret"
|
||||
description_html: |
|
||||
<p>
|
||||
Pour mettre en place l'éditeur de bons de réduction VINE pour votre entreprise, entrer votre clé API et secret.
|
||||
</p>
|
||||
<p>
|
||||
<a href="#" target="_blank"><b>VINE</b>
|
||||
<i class="icon-external-link"></i></a>
|
||||
</p>
|
||||
api_parameters_empty: "Entrer une clé API et un secret"
|
||||
api_parameters_error: "Vérifiez que vous avez entré la clé API et le secret correctement. Contactez l'équipe support de la plateforme si l'erreur persiste. "
|
||||
connection_error: "Erreur de connexion à l'API. Merci de réessayer."
|
||||
setup_error: "L'API VINE n'est pas configurée. Veuillez contacter l'équipe support de la plateforme."
|
||||
actions:
|
||||
edit_profile: Paramètres
|
||||
properties: Labels / propriétés
|
||||
@@ -1675,6 +1700,7 @@ fr_CA:
|
||||
pack_by_customer: Préparation des commandes par Acheteur
|
||||
pack_by_supplier: Préparation des commandes par Producteur
|
||||
pack_by_product: Préparation des commandes par Produit
|
||||
pay_your_suppliers: Payer vos fournisseurs
|
||||
display:
|
||||
report_is_big: "Ce rapport est volumineux et risque de ralentir l'appareil sur lequel vous êtes en train de le consulter."
|
||||
display_anyway: "Afficher quand même"
|
||||
@@ -1722,6 +1748,8 @@ fr_CA:
|
||||
enterprise_fee_summary:
|
||||
name: "Résumé des marges et commissions"
|
||||
description: "Résumé des marges et commissions collectées"
|
||||
suppliers:
|
||||
name: Fournisseurs
|
||||
enterprise_fees_with_tax_report_by_order: "Détail des montants de taxe par commande"
|
||||
enterprise_fees_with_tax_report_by_producer: "Détail des montants de taxe par producteur"
|
||||
errors:
|
||||
@@ -2625,6 +2653,7 @@ fr_CA:
|
||||
confirm_hub_change: "Confirmer? Cette action modifiera la boutique sélectionnée et tous les articles de votre panier seront effacés."
|
||||
confirm_oc_change: "Confirmer? Cette action modifiera le cycle de vente sélectionné et tous les articles de votre panier seront effacés."
|
||||
location_placeholder: "Saisissez une localisation..."
|
||||
gmap_load_failure: "Unable to load map. Please check your browser settings and allow 3rd party cookies for this website."
|
||||
error_required: "Champ obligatoire"
|
||||
error_number: "saisir un nombre"
|
||||
error_email: "saisir une adresse email"
|
||||
@@ -3009,6 +3038,8 @@ fr_CA:
|
||||
report_render_options: Mise en forme
|
||||
report_header_ofn_uid: ID OFN
|
||||
report_header_order_cycle: Cycle de Vente
|
||||
report_header_order_cycle_start_date: Date d'ouverture du cycle de vente
|
||||
report_header_order_cycle_end_date: Date de fermeture du cycle de vente
|
||||
report_header_user: Utilisateur
|
||||
report_header_email: Email
|
||||
report_header_status: Statut
|
||||
@@ -3029,6 +3060,7 @@ fr_CA:
|
||||
report_header_hub_legal_name: "Raison sociale"
|
||||
report_header_hub_contact_name: "Nom du contact"
|
||||
report_header_hub_email: "Email public"
|
||||
report_header_hub_contact_email: e-mail de contact de la boutique multi-producteurs
|
||||
report_header_hub_owner_email: Email gestionnaire principal
|
||||
report_header_hub_phone: "Numéro de téléphone"
|
||||
report_header_hub_address_line1: "Adresse ligne 1"
|
||||
@@ -3101,6 +3133,8 @@ fr_CA:
|
||||
report_header_producer_suburb: Ville Producteur
|
||||
report_header_producer_tax_status: Soumis à la taxe
|
||||
report_header_producer_charges_sales_tax?: Soumis à la GST
|
||||
report_header_producer_abn_acn: Numéro de SIRET/SIREN du producteur
|
||||
report_header_producer_address: Adresse du producteur
|
||||
report_header_unit: Unité
|
||||
report_header_group_buy_unit_quantity: Nb d'unités achetées (vente par lots)
|
||||
report_header_cost: Coût
|
||||
@@ -3161,7 +3195,11 @@ fr_CA:
|
||||
report_header_total_units: Vol. total
|
||||
report_header_sum_max_total: "Somme Max Total"
|
||||
report_header_total_excl_vat: "Total HT (%{currency_symbol})"
|
||||
report_header_total_fees_excl_tax: "Total commission boutique hors taxe (%{currency_symbol})"
|
||||
report_header_total_tax_on_fees: "Total taxe sur la commission boutique (%{currency_symbol})"
|
||||
report_header_total: "Total (%{currency_symbol})"
|
||||
report_header_total_incl_vat: "Total TTC (%{currency_symbol})"
|
||||
report_header_total_excl_fees_and_tax: "Total hors commission boutique et taxe (%{currency_symbol})"
|
||||
report_header_temp_controlled: Temp Contrôlée ?
|
||||
report_header_is_producer: Producteur ?
|
||||
report_header_not_confirmed: Non confirmé
|
||||
@@ -3739,7 +3777,7 @@ fr_CA:
|
||||
many: "pièces"
|
||||
other: "pièces"
|
||||
pot:
|
||||
one: "pots"
|
||||
one: "pot"
|
||||
many: "pots"
|
||||
other: "pots"
|
||||
bundle:
|
||||
|
||||
@@ -297,7 +297,7 @@ hu:
|
||||
producer_signup_case_studies_html: "Termelői regisztrációs esettanulmányok HTML"
|
||||
producer_signup_detail_html: "Termelői regisztráció részletek HTML"
|
||||
producer_signup_pricing_table_html: "Termelői regisztrációs ártáblázat HTML"
|
||||
producers_social: "Termelői szövetkezet"
|
||||
producers_social: "Közösségi média"
|
||||
resume_order: "Rendelés folytatása"
|
||||
sku: "SKU"
|
||||
subtotal: "Részösszeg"
|
||||
@@ -534,7 +534,7 @@ hu:
|
||||
producer: Termelő
|
||||
category: Kategória
|
||||
sku: SKU kód
|
||||
on_hand: "Raktáron"
|
||||
on_hand: "Készlet"
|
||||
on_demand: "Igény szerint"
|
||||
tax_category: "Adókategória"
|
||||
inherits_properties: "Megörökli az tulajdonságokat?"
|
||||
@@ -546,7 +546,7 @@ hu:
|
||||
producer: Termelő
|
||||
category: Kategória
|
||||
sku: SKU kód
|
||||
on_hand: "Raktáron"
|
||||
on_hand: "Készlet"
|
||||
on_demand: "Igény szerint"
|
||||
tax_category: "Adókategória"
|
||||
inherits_properties: "Megörökli az tulajdonságokat?"
|
||||
@@ -2195,7 +2195,7 @@ hu:
|
||||
cookies_policy_link_desc: "Ha többet szeretne megtudni, nézze meg oldalunkat"
|
||||
cookies_policy_link: "cookie-kra vonatkozó szabályzat"
|
||||
cookies_accept_button: "Cookie-k elfogadása"
|
||||
home_shop: Tovább a termelőkhöz, átvételi pontokhoz.
|
||||
home_shop: Tovább a termelőkhöz, átvételi pontokhoz
|
||||
brandstory_headline: "Együtt, az élelem önrendelkezésért!"
|
||||
brandstory_intro: "Közösség által irányított élelmiszerrendszert építünk."
|
||||
brandstory_part1: "Az alapoktól kezdjük. \nA gazdálkodókkal, akiknek fontos, hogy közösen, egy fenntartható és mindenki számára átlátható, hazai élelemrendszert hozzunk létre. \nA bevásárlóközösségekkel, fogyasztói csoportokkal, más elosztókkal, akik összekapcsolják az embereket a termelőkkel és a termékekkel, és biztosítani szeretnék, hogy a termelők tisztességes díjazásban részesüljenek. \nAzokkal a fogyasztókkal, akik hisznek abban, hogy döntéseiknek hatása van."
|
||||
@@ -2212,7 +2212,7 @@ hu:
|
||||
system_step3: "3. Átvétel / kiszállítás"
|
||||
system_step3_text: "Válaszd a kiszállítást, vagy a személyesebb kapcsolat érdekében keresd fel a termelőt, vagy az átvételi pontot."
|
||||
cta_headline: "A jövőnk fenntartható élelmiszerhálózata."
|
||||
cta_label: "Tovább a termelőkhöz, átvételi pontokhoz."
|
||||
cta_label: "Tovább a termelőkhöz, átvételi pontokhoz"
|
||||
stats_headline: "Termelők és fogyasztók közösségét építjük."
|
||||
stats_producers: "élelmiszer-termelők"
|
||||
stats_shops: "átvételi pontok"
|
||||
@@ -2372,7 +2372,7 @@ hu:
|
||||
maps_open: "Nyitva"
|
||||
maps_closed: "Zárva"
|
||||
map_title: "Térkép"
|
||||
hubs_buy: "Kínálat:"
|
||||
hubs_buy: "Termékkínálat:"
|
||||
hubs_shopping_here: "Vásárlás itt"
|
||||
hubs_orders_closed: "A rendelések lezárva"
|
||||
hubs_profile_only: "Csak profil"
|
||||
@@ -2419,7 +2419,7 @@ hu:
|
||||
products_changes_saved: "Változtatások elmentve."
|
||||
products_no_results_html: "Sajnáljuk, nem található találat a következőre: %{query}"
|
||||
products_clear_search: "Keresés törlése"
|
||||
search_no_results_html: "Sajnáljuk, nem találtunk Átvételi pontot/Termelőt a következő szűrésre: %{query} Próbálkozz másik kereséssel!"
|
||||
search_no_results_html: "Sajnáljuk, nem találtunk Átvételi pontot/Termelőt a következő szűrésre: %{query} \nPróbálkozz másik kereséssel!"
|
||||
components_profiles_popover: "A Profiloknak nincs online kirakata az Open Food Network-ben, de lehet, hogy van saját fizikai vagy online átvételi pontjuk máshol."
|
||||
components_profiles_show: "Profilok megjelenítése"
|
||||
components_filters_nofilters: "Nincsenek szűrők"
|
||||
@@ -2458,7 +2458,7 @@ hu:
|
||||
groups_signup_detail: "Itt a részlet."
|
||||
login_invalid: "Rossz email cím vagy jelszó"
|
||||
producers_about: Rólunk
|
||||
producers_buy: Vásárolni valakinek
|
||||
producers_buy: 'Kínálat:'
|
||||
producers_contact: Kapcsolat
|
||||
producers_contact_phone: Hívás
|
||||
producers_contact_social: Kövesse
|
||||
@@ -2494,7 +2494,7 @@ hu:
|
||||
sell_hubs: "Átvételi Pontok"
|
||||
sell_groups: "Csoportok"
|
||||
sell_producers_detail: "Őstermelő, kistermelő, családi gazdálkodó, vagy épp kisválllalkozás vagy? Hozz létre termelői profilt az OFN-en percek alatt. Bármikor frissítheted profilod egy online áruházra, és közvetlenül ajánlhatod termékeidet a fogyasztóknak."
|
||||
sell_hubs_detail: "Bevásárlóközösséget indítanál? Vagy csak összefognál a termelőtársakkal és közösen szólítanátok meg a fogyasztókat? Hozz létre új profilt, vagy bármikor frissítheted a profilodat egy többtermelős átvételi pontra."
|
||||
sell_hubs_detail: "Bevásárlóközösséget indítanál, vagy termelői piacot működtetsz? Vagy csak összefognál a termelőtársakkal és közösen szólítanátok meg a fogyasztókat? Hozz létre új profilt, vagy bármikor frissítheted a profilodat egy többtermelős átvételi pontra."
|
||||
sell_groups_detail: "Hozz létre egy személyre szabott jegyzéket (termelők és egyéb élelmiszeripari vállalkozások) régiója vagy szervezete számára."
|
||||
sell_user_guide: "Tudj meg többet használati útmutatónkból."
|
||||
sell_listing_price: "A termelői regisztráció az OFN-en ingyenes, és az is marad. A platformon történő értékesítés volumenétől függően azonban közösségi hozzájárulást kérünk, a szoftver üzemeltetéshez és IT support biztosításához . \nRészletek hamarosan. "
|
||||
@@ -4066,7 +4066,7 @@ hu:
|
||||
product_properties:
|
||||
index:
|
||||
inherits_properties_checkbox_hint: "Tulajdonságokat örököl a következőtől: %{supplier}? (hacsak nincs felülírva)"
|
||||
add_product_properties: "Add hozzá a termék tulajdonságait"
|
||||
add_product_properties: "További termék tulajdonság hozzáadása"
|
||||
properties:
|
||||
index:
|
||||
properties: "Tulajdonságok"
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class AddExternalVoucherIdExternalVoucherSetIdVoucherTypeToVouchers < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :vouchers, :external_voucher_id, :uuid
|
||||
add_column :vouchers, :external_voucher_set_id, :uuid
|
||||
add_column :vouchers, :voucher_type, :string
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
class UpdateIndexAndRemoveVoucherTypeFromVoucher < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
remove_column :vouchers, :voucher_type
|
||||
remove_index :vouchers, [:code, :enterprise_id], unique: true
|
||||
|
||||
add_index :vouchers, [:code, :enterprise_id]
|
||||
add_index :vouchers, [:code, :enterprise_id, :external_voucher_id], name: "index_vouchers_on_code_and_enterprise_id_and_ext_voucher_id"
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_10_30_033956) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2024_11_12_230401) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "plpgsql"
|
||||
@@ -1110,7 +1110,10 @@ ActiveRecord::Schema[7.0].define(version: 2024_10_30_033956) do
|
||||
t.datetime "deleted_at", precision: nil
|
||||
t.decimal "amount", precision: 10, scale: 2, default: "0.0", null: false
|
||||
t.string "type", limit: 255, default: "Vouchers::FlatRate", null: false
|
||||
t.index ["code", "enterprise_id"], name: "index_vouchers_on_code_and_enterprise_id", unique: true
|
||||
t.uuid "external_voucher_id"
|
||||
t.uuid "external_voucher_set_id"
|
||||
t.index ["code", "enterprise_id", "external_voucher_id"], name: "index_vouchers_on_code_and_enterprise_id_and_ext_voucher_id"
|
||||
t.index ["code", "enterprise_id"], name: "index_vouchers_on_code_and_enterprise_id"
|
||||
t.index ["deleted_at"], name: "index_vouchers_on_deleted_at"
|
||||
t.index ["enterprise_id"], name: "index_vouchers_on_enterprise_id"
|
||||
end
|
||||
|
||||
@@ -21,7 +21,8 @@ Note: There is no need to install Docker Desktop on Linux.
|
||||
* You may have to deselect the option to use Docker Compose V2 in Docker settings to make our scripts work.
|
||||
|
||||
## Getting Started
|
||||
### Linux
|
||||
|
||||
1. **Clone the Repository**:
|
||||
* Open a terminal with a shell.
|
||||
* Clone the repository. If you're planning on contributing code to the project (which we [LOVE](CONTRIBUTING.md)), begin by forking this repo with the Fork button in the top-right corner of this screen.
|
||||
* Use git clone to copy your fork onto your local machine.
|
||||
@@ -32,48 +33,50 @@ $ git clone https://github.com/YOUR_GITHUB_USERNAME_HERE/openfoodnetwork
|
||||
```sh
|
||||
$ git clone git@github.com:openfoodfoundation/openfoodnetwork.git
|
||||
```
|
||||
* Go at the root of the app:
|
||||
```sh
|
||||
$ cd openfoodnetwork
|
||||
```
|
||||
* Download the Docker images, build the Docker containers, seed the database with sample data, AND log the screen output from these tasks:
|
||||
```sh
|
||||
$ docker/build
|
||||
```
|
||||
* Run the Rails server and its required Docker containers:
|
||||
```sh
|
||||
$ docker/server
|
||||
```
|
||||
* The default admin user is 'ofn@example.com' with the password 'ofn123'.
|
||||
* View the app in the browser at `http://localhost:3000`.
|
||||
* You will then get the trace of the containers in the terminal. You can stop the containers using Ctrl-C in the terminal.
|
||||
* You can find some useful tips and commands [here](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Docker:-useful-tips-and-commands).
|
||||
|
||||
### Windows
|
||||
* Prerequisite : don't forget to activate the execution of powershell scripts following the instruction on [this page chosing "Using RemoteSigned Execution Policy"](https://shellgeek.com/powershell-fix-running-scripts-is-disabled-on-this-system/)
|
||||
* Open a terminal with a shell command.
|
||||
* Clone the repository. If you're planning on contributing code to the project (which we [LOVE](CONTRIBUTING.md)), begin by forking this repo with the Fork button in the top-right corner of this screen.
|
||||
* Use git clone to copy your fork onto your local machine.
|
||||
```command
|
||||
$ git clone https://github.com/YOUR_GITHUB_USERNAME_HERE/openfoodnetwork
|
||||
```
|
||||
* Otherwise, if you just want to get things running, clone from the OFN main repo:
|
||||
```command
|
||||
$ git clone git@github.com:openfoodfoundation/openfoodnetwork.git
|
||||
```
|
||||
* Go at the root of the app:
|
||||
```command
|
||||
2. **Navigate to the App Directory**:
|
||||
```sh
|
||||
$ cd openfoodnetwork
|
||||
```
|
||||
* Download the Docker images, build the Docker containers, seed the database with sample data, AND log the screen output from these tasks:
|
||||
```command
|
||||
$ docker/build.ps1
|
||||
```
|
||||
|
||||
3. **Choose and Build Docker Image**:
|
||||
* You have two choices of images you can build. The default Ubuntu image is most similar to the production servers but is larger in size and will take longer to build. Alternatively, you can use the Alpine image which is smaller, faster to setup, and should be compatible with the Ubuntu. However, it will need to be updated when ruby is updated. To download the Docker images, build the Docker containers, seed the database with sample data, AND log the screen output from these tasks:
|
||||
- **Ubuntu Image** (larger, production-like):
|
||||
- **Linux**:
|
||||
```sh
|
||||
$ docker/build
|
||||
```
|
||||
- **Windows**:
|
||||
```command
|
||||
$ docker/build.ps1
|
||||
```
|
||||
- **Alpine Image** (smaller, faster):
|
||||
- **Linux**:
|
||||
```sh
|
||||
$ docker/build alpine.Dockerfile
|
||||
```
|
||||
- **Windows**:
|
||||
```command
|
||||
$ docker/build.ps1 alpine.Dockerfile
|
||||
```
|
||||
|
||||
4. **Run the Rails Server**:
|
||||
* Run the Rails server and its required Docker containers:
|
||||
```command
|
||||
$ docker/server.ps1
|
||||
```
|
||||
You may need to wait several minutes before getting the server up and running properly.
|
||||
- **Linux**:
|
||||
```sh
|
||||
$ docker/server
|
||||
```
|
||||
- **Windows**:
|
||||
```command
|
||||
$ docker/server.ps1
|
||||
```
|
||||
* To run tests or access the server directly, you can use bash:
|
||||
```sh
|
||||
$ docker compose exec web bash
|
||||
```
|
||||
|
||||
> **Note**: Windows users may need to enable PowerShell script execution by setting the RemoteSigned policy. See instructions [here](https://shellgeek.com/powershell-fix-running-scripts-is-disabled-on-this-system/).
|
||||
|
||||
* The default admin user is 'ofn@example.com' with the password 'ofn123'.
|
||||
* View the app in the browser at `http://localhost:3000`.
|
||||
* You will then get the trace of the containers in the terminal. You can stop the containers using Ctrl-C in the terminal.
|
||||
|
||||
@@ -4,5 +4,5 @@ set -e
|
||||
# This script builds the Docker container, seeds the app with sample data, and logs the screen output.
|
||||
|
||||
DATE=`date +%Y%m%d-%H%M%S-%3N`
|
||||
docker/build-log 2>&1 | tee log/build-$DATE.log
|
||||
docker/build-log $1 2>&1 | tee log/build-$DATE.log
|
||||
docker/seed 2>&1 | tee log/seed-$DATE.log
|
||||
|
||||
@@ -6,7 +6,11 @@ wait
|
||||
echo '###########################'
|
||||
echo 'BEGIN: docker compose build'
|
||||
echo '###########################'
|
||||
docker compose build # Set up the Docker containers
|
||||
if [ -n "$1" ]; then
|
||||
docker build -f $1 . # Set up the Docker containers
|
||||
else
|
||||
docker compose build # Set up the Docker containers
|
||||
fi
|
||||
echo '##############################'
|
||||
echo 'FINISHED: docker compose build'
|
||||
echo '##############################'
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
Write-Host "Docker cleaning: remove old containers" -ForegroundColor Blue
|
||||
docker compose down -v --remove-orphans
|
||||
Write-Host "Docker build: set up the docker containers" -ForegroundColor Blue
|
||||
docker compose build
|
||||
|
||||
# Check if an argument is provided
|
||||
if ($args.Count -gt 0) {
|
||||
# Run the build command with the argument and log output
|
||||
docker build -f $1 .
|
||||
} else {
|
||||
docker compose build
|
||||
}
|
||||
Write-Host "Docker build finished"
|
||||
@@ -4,5 +4,11 @@
|
||||
|
||||
$DateTime=Get-Date -Format "yyyyMMdd-HHmmss"
|
||||
|
||||
docker/build-log.ps1 > log/build-$DateTime.log 2>&1
|
||||
# Check if an argument is provided
|
||||
if ($args.Count -gt 0) {
|
||||
# Run the build command with the argument and log output
|
||||
docker/build-log.ps1 $args[0] > log/build-$DateTime.log 2>&1
|
||||
} else {
|
||||
docker/build-log.ps1 > log/build-$DateTime.log 2>&1
|
||||
}
|
||||
docker/seed.ps1 > log/seed-$DateTime.log 2>&1
|
||||
|
||||
@@ -12,7 +12,10 @@ class AffiliateSalesDataRowBuilder < DfcBuilder
|
||||
def build_supplier
|
||||
DataFoodConsortium::Connector::Enterprise.new(
|
||||
nil,
|
||||
localizations: [build_address(item[:supplier_postcode])],
|
||||
localizations: [build_address(
|
||||
item[:supplier_postcode],
|
||||
item[:supplier_country]
|
||||
)],
|
||||
suppliedProducts: [build_product],
|
||||
)
|
||||
end
|
||||
@@ -20,7 +23,10 @@ class AffiliateSalesDataRowBuilder < DfcBuilder
|
||||
def build_distributor
|
||||
DataFoodConsortium::Connector::Enterprise.new(
|
||||
nil,
|
||||
localizations: [build_address(item[:distributor_postcode])],
|
||||
localizations: [build_address(
|
||||
item[:distributor_postcode],
|
||||
item[:distributor_country]
|
||||
)],
|
||||
)
|
||||
end
|
||||
|
||||
@@ -89,9 +95,10 @@ class AffiliateSalesDataRowBuilder < DfcBuilder
|
||||
)
|
||||
end
|
||||
|
||||
def build_address(postcode)
|
||||
def build_address(postcode, country)
|
||||
DataFoodConsortium::Connector::Address.new(
|
||||
nil,
|
||||
country:,
|
||||
postalCode: postcode,
|
||||
)
|
||||
end
|
||||
|
||||
@@ -38,9 +38,11 @@ class AffiliateSalesQuery
|
||||
JOIN spree_products ON spree_products.id = spree_variants.product_id
|
||||
JOIN enterprises AS suppliers ON suppliers.id = spree_variants.supplier_id
|
||||
JOIN spree_addresses AS supplier_addresses ON supplier_addresses.id = suppliers.address_id
|
||||
JOIN spree_countries AS supplier_countries ON supplier_countries.id = supplier_addresses.country_id
|
||||
JOIN spree_orders ON spree_orders.id = spree_line_items.order_id
|
||||
JOIN enterprises AS distributors ON distributors.id = spree_orders.distributor_id
|
||||
JOIN spree_addresses AS distributor_addresses ON distributor_addresses.id = distributors.address_id
|
||||
JOIN spree_countries AS distributor_countries ON distributor_countries.id = distributor_addresses.country_id
|
||||
SQL
|
||||
end
|
||||
|
||||
@@ -53,7 +55,9 @@ class AffiliateSalesQuery
|
||||
spree_variants.unit_presentation,
|
||||
spree_line_items.price,
|
||||
distributor_addresses.zipcode AS distributor_postcode,
|
||||
distributor_countries.name AS distributor_country,
|
||||
supplier_addresses.zipcode AS supplier_postcode,
|
||||
supplier_countries.name AS supplier_country,
|
||||
|
||||
SUM(spree_line_items.quantity) AS quantity_sold
|
||||
SQL
|
||||
@@ -68,7 +72,9 @@ class AffiliateSalesQuery
|
||||
spree_variants.unit_presentation,
|
||||
spree_line_items.price,
|
||||
distributor_postcode,
|
||||
supplier_postcode
|
||||
supplier_postcode,
|
||||
distributor_country,
|
||||
supplier_country
|
||||
SQL
|
||||
end
|
||||
|
||||
@@ -82,7 +88,9 @@ class AffiliateSalesQuery
|
||||
unit_presentation
|
||||
price
|
||||
distributor_postcode
|
||||
distributor_country
|
||||
supplier_postcode
|
||||
supplier_country
|
||||
quantity_sold
|
||||
]
|
||||
end
|
||||
|
||||
@@ -2,15 +2,31 @@
|
||||
|
||||
class DfcLoader
|
||||
def self.connector
|
||||
@connector ||= load_vocabularies
|
||||
unless @connector
|
||||
@connector = DataFoodConsortium::Connector::Connector.instance
|
||||
load_context
|
||||
load_vocabularies
|
||||
end
|
||||
|
||||
@connector
|
||||
end
|
||||
|
||||
def self.load_context
|
||||
JSON::LD::Context.add_preloaded("http://www.datafoodconsortium.org/") {
|
||||
JSON::LD::Context.parse(read_file("context_1.8.2")["@context"])
|
||||
}
|
||||
end
|
||||
|
||||
def self.vocabulary(name)
|
||||
@vocabs ||= {}
|
||||
@vocabs[name] ||= connector.__send__(:loadThesaurus, read_file(name))
|
||||
end
|
||||
|
||||
def self.load_vocabularies
|
||||
connector = DataFoodConsortium::Connector::Connector.instance
|
||||
connector.loadMeasures(read_file("measures"))
|
||||
connector.loadFacets(read_file("facets"))
|
||||
connector.loadProductTypes(read_file("productTypes"))
|
||||
connector
|
||||
vocabulary("vocabulary") # order states etc
|
||||
end
|
||||
|
||||
def self.read_file(name)
|
||||
|
||||
@@ -9,3 +9,4 @@ mkdir -p "$dst"
|
||||
curl --location "$src/facets.json" > "$dst/facets.json"
|
||||
curl --location "$src/measures.json" > "$dst/measures.json"
|
||||
curl --location "$src/productTypes.json" > "$dst/productTypes.json"
|
||||
curl --location "$src/vocabulary.json" > "$dst/vocabulary.json"
|
||||
|
||||
@@ -53,9 +53,15 @@ RSpec.describe AffiliateSalesQuery do
|
||||
it "converts an array to a hash" do
|
||||
row = [
|
||||
"Apples",
|
||||
"item", "item", nil, nil,
|
||||
"item",
|
||||
"item",
|
||||
nil,
|
||||
nil,
|
||||
15.50,
|
||||
"3210", "3211",
|
||||
"3210",
|
||||
"country1",
|
||||
"3211",
|
||||
"country2",
|
||||
3,
|
||||
]
|
||||
expect(query.label_row(row)).to eq(
|
||||
@@ -67,7 +73,9 @@ RSpec.describe AffiliateSalesQuery do
|
||||
unit_presentation: nil,
|
||||
price: 15.50,
|
||||
distributor_postcode: "3210",
|
||||
distributor_country: "country1",
|
||||
supplier_postcode: "3211",
|
||||
supplier_country: "country2",
|
||||
quantity_sold: 3,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -9,6 +9,12 @@ RSpec.describe DfcIo do
|
||||
let(:enterprise) do
|
||||
DataFoodConsortium::Connector::Enterprise.new("Pete's Pumpkins")
|
||||
end
|
||||
let(:order) do
|
||||
DataFoodConsortium::Connector::Order.new("https://example.net", orderStatus: orderstate.HELD)
|
||||
end
|
||||
let(:orderstate) do
|
||||
DfcLoader.vocabulary("vocabulary").STATES.ORDERSTATE
|
||||
end
|
||||
|
||||
describe ".export" do
|
||||
it "exports nothing" do
|
||||
@@ -33,5 +39,20 @@ RSpec.describe DfcIo do
|
||||
*%w(@id @type dfc-b:affiliates)
|
||||
)
|
||||
end
|
||||
|
||||
it "recognises loaded vocabularies" do
|
||||
json = DfcIo.export(order)
|
||||
result = JSON.parse(json)
|
||||
|
||||
expect(result["dfc-b:hasOrderStatus"]).to eq "dfc-v:Held"
|
||||
end
|
||||
end
|
||||
|
||||
describe ".import" do
|
||||
it "recognises loaded vocabularies" do
|
||||
result = DfcIo.import(DfcIo.export(order))
|
||||
|
||||
expect(result.orderStatus).to eq orderstate.HELD
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,4 +21,10 @@ RSpec.describe DfcLoader do
|
||||
)
|
||||
expect(result["dfc-b:name"]).to eq "Tomato"
|
||||
end
|
||||
|
||||
it "loads vocabularies" do
|
||||
terms = DfcLoader.vocabulary("vocabulary")
|
||||
expect(terms.STATES.ORDERSTATE.HELD.semanticId)
|
||||
.to eq "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Held"
|
||||
end
|
||||
end
|
||||
|
||||
450
engines/dfc_provider/vendor/context_1.8.2.json
vendored
Normal file
450
engines/dfc_provider/vendor/context_1.8.2.json
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
{
|
||||
"@context": {
|
||||
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
||||
"skos" : "http://www.w3.org/2004/02/skos/core#",
|
||||
"dfc": "https://github.com/datafoodconsortium/ontology/releases/latest/download/DFC_FullModel.owl#",
|
||||
"dc": "http://purl.org/dc/elements/1.1/#",
|
||||
"dfc-b": "https://github.com/datafoodconsortium/ontology/releases/latest/download/DFC_BusinessOntology.owl#",
|
||||
"dfc-t": "https://github.com/datafoodconsortium/ontology/releases/latest/download/DFC_TechnicalOntology.owl#",
|
||||
"dfc-m": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/measures.rdf#",
|
||||
"dfc-pt": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/productTypes.rdf#",
|
||||
"dfc-f": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/facets.rdf#",
|
||||
"dfc-v": "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#",
|
||||
"ontosec": "http://www.semanticweb.org/ontologies/2008/11/OntologySecurity.owl#",
|
||||
"dfc-b:DFC_BusinessOntology_ObjectProperty": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:DFC_Interface_Property": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:addressOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:affiliatedTo": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:affiliates": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:allergenCharacteristicOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:belongsTo": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:brandOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:certificateOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:characteristicOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:claimOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:composedOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:composes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:concernedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:concerns": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:constituedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:constitutes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:consumedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:consumes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:containerInformationOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:coordinatedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:coordinates": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:definedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:defines": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:deliveredAt": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:facetOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:from": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:geographicalOriginOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasAddress": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasAllergenCharacteristic": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasAllergenDimension": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasBrand": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasCertification": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasCharacteristic": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasClaim": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasContainerInformation": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasDimension": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasFacet": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasFulfilmentStatus": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasGeographicalOrigin": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasIngredient": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasInput": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasLabellingCharacteristic": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasLabellingDimension": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasMainContact": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasNatureOrigin": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasNutrientCharacteristic": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasNutrientDimension": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasObject": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasOffer": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasOption": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasOrderStatus": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasOutput": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPart": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPartOrigin": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPaymentMethod": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPaymentStatus": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPhoneNumber": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPhysicalCharacteristic": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPhysicalDimension": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasPrice": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasProcess": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasQuantity": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasReference": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasSocialMedia": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasStatus": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasTemperature": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasTransformationType": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasType": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hasUnit": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:holds": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hostedAt": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:hosts": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:identifiedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:identifies": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:industrializedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:industrializes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:inputOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:isIngredientOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:isPriceOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:isTemperatureOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:labellingCharacteristicOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:listedIn": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:lists": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:localizedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:localizes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:mainContactOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:maintainedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:maintains": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:managedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:manages": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:natureOriginOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:nutrientCharacteristicOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:objectOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:offeredThrough": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:offers": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:offersTo": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:optionOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:orderedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:orders": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:outputOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:ownedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:owns": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:paidWith": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:partOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:partOriginOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:phoneNumberOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:physicalCharacteristicOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:pickedUpAt": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:processOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:producedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:produces": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:proposedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:proposes": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:referenceOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:referencedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:references": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:refersTo": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:representedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:represents": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:requestedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:requests": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:satisfiedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:satisfies": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:selectedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:selects": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:sells": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:socialMediaOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:soldBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:storedIn": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:stores": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:suppliedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:supplies": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:suppliesTo": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:to": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:tracedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:traces": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:transformedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:transforms": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:typeOf": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-b:uses": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-t:represent": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-t:hasPivot": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-t:hostedBy": {
|
||||
"@type": "@id"
|
||||
},
|
||||
"dfc-t:owner": {
|
||||
"@type": "@id"
|
||||
}
|
||||
}
|
||||
}
|
||||
351
engines/dfc_provider/vendor/vocabulary.json
vendored
Normal file
351
engines/dfc_provider/vendor/vocabulary.json
vendored
Normal file
@@ -0,0 +1,351 @@
|
||||
[ {
|
||||
"@graph" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#",
|
||||
"@type" : [ "http://www.w3.org/2002/07/owl#Ontology" ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Cancelled",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#OrderState"
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#PaymentState"
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#FulfilmentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Cancelled"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Complete",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#OrderState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Complete"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#ConceptScheme" ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "DFC_Vocabulary"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Draft",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#OrderState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Draft"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Fulfilled",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#FulfilmentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Fulfilled"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#FulfilmentState",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#States"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Fulfilment state"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Held",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#OrderState"
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#FulfilmentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Held"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#OrderState",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#States"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Order state"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Paid",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#PaymentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Paid"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#PaymentState",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#States"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Payment state"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#States",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "States"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#topConceptOf" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Unfulfilled",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#FulfilmentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Unfulfilled"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#Unpaid",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#PaymentState"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Unpaid"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#accept",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "accept"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#c_734fc709",
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "FulfilmentState"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#combine",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "combine"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#consume",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "consume"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#dropoff",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "dropoff"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#lower",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "lower"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#modify",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "modify"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#move",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "move"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#pickup",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "pickup"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#produce",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "produce"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#raise",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "raise"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#separate",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "separate"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "Transformation type"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#topConceptOf" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ]
|
||||
}, {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#use",
|
||||
"@type" : [ "http://www.w3.org/2004/02/skos/core#Concept" ],
|
||||
"http://www.w3.org/2004/02/skos/core#broader" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#transformationType"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#inScheme" : [ {
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#DFC_Vocabulary"
|
||||
} ],
|
||||
"http://www.w3.org/2004/02/skos/core#prefLabel" : [ {
|
||||
"@language" : "en",
|
||||
"@value" : "use"
|
||||
} ]
|
||||
} ],
|
||||
"@id" : "https://github.com/datafoodconsortium/taxonomies/releases/latest/download/vocabulary.rdf#"
|
||||
} ]
|
||||
@@ -161,6 +161,11 @@ module OrderManagement
|
||||
persist_totals
|
||||
end
|
||||
|
||||
def update_voucher
|
||||
VoucherAdjustmentsService.new(order).update
|
||||
update_totals_and_states
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cancel_payments_requiring_auth
|
||||
|
||||
@@ -460,6 +460,26 @@ module OrderManagement
|
||||
end
|
||||
end
|
||||
|
||||
describe "#update_voucher" do
|
||||
let(:voucher_service) { instance_double(VoucherAdjustmentsService) }
|
||||
|
||||
it "calls VoucherAdjustmentsService" do
|
||||
expect(VoucherAdjustmentsService).to receive(:new).and_return(voucher_service)
|
||||
expect(voucher_service).to receive(:update)
|
||||
|
||||
updater.update_voucher
|
||||
end
|
||||
|
||||
it "calls update_totals_and_states" do
|
||||
allow(VoucherAdjustmentsService).to receive(:new).and_return(voucher_service)
|
||||
allow(voucher_service).to receive(:update)
|
||||
|
||||
expect(updater).to receive(:update_totals_and_states)
|
||||
|
||||
updater.update_voucher
|
||||
end
|
||||
end
|
||||
|
||||
def update_order_quantity(order)
|
||||
order.line_items.first.update_attribute(:quantity, 2)
|
||||
end
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Our error logging API currently wraps Bugsnag.
|
||||
# It makes us more flexible if we wanted to replace Bugsnag or change logging
|
||||
# behaviour.
|
||||
module OpenFoodNetwork
|
||||
module ErrorLogger
|
||||
# Tries to escalate the error to a developer.
|
||||
# If Bugsnag is configured, it will notify it. It would be nice to implement
|
||||
# some kind of fallback.
|
||||
def self.notify(error)
|
||||
Bugsnag.notify(error)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -4,6 +4,12 @@ module Reporting
|
||||
module Reports
|
||||
module ProductsAndInventory
|
||||
class AllProducts < Base
|
||||
def default_params
|
||||
{
|
||||
fields_to_hide: [:tax_category]
|
||||
}
|
||||
end
|
||||
|
||||
def message
|
||||
I18n.t("spree.admin.reports.products_and_inventory.all_products.message")
|
||||
end
|
||||
@@ -19,7 +25,8 @@ module Reporting
|
||||
super.merge(
|
||||
{
|
||||
on_demand: proc{ |variant| variant.on_demand },
|
||||
on_hand: proc{ |variant| variant.on_demand ? I18n.t(:on_demand) : variant.on_hand }
|
||||
on_hand: proc{ |variant| variant.on_demand ? I18n.t(:on_demand) : variant.on_hand },
|
||||
tax_category: proc { |variant| variant.tax_category_id && variant.tax_category.name }
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
@@ -46,10 +46,14 @@ namespace :ofn do
|
||||
unconfirmed_email = concat(id, '_ofn_user@example.com')")
|
||||
Customer.where(user_id: nil)
|
||||
.update_all("email = concat(id, '_ofn_customer@example.com'),
|
||||
name = concat('Customer Number ', id, ' (without connected User)')")
|
||||
name = concat('Customer Number ', id, ' (without connected User)'),
|
||||
first_name = concat('Customer Number ', id),
|
||||
last_name = '(without connected User)'")
|
||||
Customer.where.not(user_id: nil)
|
||||
.update_all("email = concat(user_id, '_ofn_user@example.com'),
|
||||
name = concat('Customer Number ', id, ' - User ', user_id)")
|
||||
name = concat('Customer Number ', id, ' - User ', user_id),
|
||||
first_name = concat('Customer Number ', id),
|
||||
last_name = concat('User ', user_id)")
|
||||
|
||||
Spree::Order.update_all("email = concat(id, '_ofn_order@example.com')")
|
||||
end
|
||||
|
||||
@@ -32,12 +32,12 @@
|
||||
"stimulus-flatpickr": "^1.4.0",
|
||||
"stimulus_reflex": "3.5.1",
|
||||
"tom-select": "^2.3.1",
|
||||
"trix": "^2.1.8",
|
||||
"trix": "^2.1.9",
|
||||
"turbo_power": "^0.7.0",
|
||||
"webpack": "~4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jasmine-core": "~5.4.0",
|
||||
"jasmine-core": "~5.5.0",
|
||||
"jest": "^27.4.7",
|
||||
"karma": "~6.4.4",
|
||||
"karma-chrome-launcher": "~3.2.0",
|
||||
|
||||
@@ -433,6 +433,7 @@ RSpec.describe CheckoutController, type: :controller do
|
||||
|
||||
context "summary step" do
|
||||
let(:step) { "summary" }
|
||||
let(:checkout_params) { { confirm_order: "Complete order" } }
|
||||
|
||||
before do
|
||||
order.bill_address = address
|
||||
@@ -496,6 +497,58 @@ RSpec.describe CheckoutController, type: :controller do
|
||||
end
|
||||
end
|
||||
|
||||
context "with a VINE voucher", feature: :connected_apps do
|
||||
let(:vine_voucher) {
|
||||
create(:vine_voucher, code: 'some_code', enterprise: distributor, amount: 6)
|
||||
}
|
||||
let(:vine_voucher_redeemer) { instance_double(Vine::VoucherRedeemerService) }
|
||||
|
||||
before do
|
||||
# Adding voucher to the order
|
||||
vine_voucher.create_adjustment(vine_voucher.code, order)
|
||||
OrderManagement::Order::Updater.new(order).update_voucher
|
||||
|
||||
allow(Vine::VoucherRedeemerService).to receive(:new).and_return(vine_voucher_redeemer)
|
||||
end
|
||||
|
||||
it "completes the order and redirects to order confirmation" do
|
||||
expect(vine_voucher_redeemer).to receive(:redeem).and_return(true)
|
||||
|
||||
put(:update, params:)
|
||||
|
||||
expect(response).to redirect_to order_path(order, order_token: order.token)
|
||||
expect(order.reload.state).to eq "complete"
|
||||
end
|
||||
|
||||
context "when redeeming the voucher fails" do
|
||||
it "returns 422 and some error" do
|
||||
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
|
||||
allow(vine_voucher_redeemer).to receive(:errors).and_return(
|
||||
{ redeeming_failed: "Redeeming the voucher failed" }
|
||||
)
|
||||
|
||||
put(:update, params:)
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(flash[:error]).to match "Redeeming the voucher failed"
|
||||
end
|
||||
end
|
||||
|
||||
context "when an other error happens" do
|
||||
it "returns 422 and some error" do
|
||||
allow(vine_voucher_redeemer).to receive(:redeem).and_return(false)
|
||||
allow(vine_voucher_redeemer).to receive(:errors).and_return(
|
||||
{ vine_api: "There was an error communicating with the API" }
|
||||
)
|
||||
|
||||
put(:update, params:)
|
||||
|
||||
expect(response.status).to eq 422
|
||||
expect(flash[:error]).to match "There was an error while trying to redeem your voucher"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when an external payment gateway is used" do
|
||||
before do
|
||||
expect(Checkout::PaymentMethodFetcher).
|
||||
|
||||
@@ -27,7 +27,7 @@ RSpec.describe UserRegistrationsController, type: :controller do
|
||||
|
||||
it "returns error when emailing fails" do
|
||||
allow(Spree::UserMailer).to receive(:confirmation_instructions).and_raise("Some error")
|
||||
expect(OpenFoodNetwork::ErrorLogger).to receive(:notify)
|
||||
expect(Alert).to receive(:raise)
|
||||
|
||||
post :create, xhr: true, params: { spree_user: user_params, use_route: :spree }
|
||||
|
||||
|
||||
@@ -14,4 +14,10 @@ FactoryBot.define do
|
||||
factory :voucher_percentage_rate, parent: :voucher, class: Vouchers::PercentageRate do
|
||||
amount { rand(1..100) }
|
||||
end
|
||||
|
||||
factory :vine_voucher, parent: :voucher, class: Vouchers::Vine do
|
||||
amount { 20 }
|
||||
external_voucher_id { SecureRandom.uuid }
|
||||
external_voucher_set_id { SecureRandom.uuid }
|
||||
end
|
||||
end
|
||||
|
||||
291
spec/fixtures/vcr_cassettes/Alert/reaches_the_Bugsnag_service_for_real.yml
vendored
Normal file
291
spec/fixtures/vcr_cassettes/Alert/reaches_the_Bugsnag_service_for_real.yml
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://notify.bugsnag.com/
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"apiKey":"<HIDDEN-BUGSNAG_API_KEY>","notifier":{"name":"Ruby Bugsnag
|
||||
Notifier","version":"6.26.4","url":"https://www.bugsnag.com"},"payloadVersion":"4.0","events":[{"app":{"version":null,"releaseStage":"test","type":"rails"},"breadcrumbs":[{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.385Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.387Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.389Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.390Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.437Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.492Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.527Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.546Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.585Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.593Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.796Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.814Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.886Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"Spree::Country Exists?","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","binds":"{\"name\":\"?\",\"LIMIT\":\"?\"}","connection_id":42100},"timestamp":"2024-11-20T04:51:11.888Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"Spree::Country Exists?","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","binds":"{\"name\":\"?\",\"LIMIT\":\"?\"}","connection_id":42100},"timestamp":"2024-11-20T04:51:11.890Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.890Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"Spree::Country Load","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","binds":"{\"name\":\"?\",\"LIMIT\":\"?\"}","connection_id":42100},"timestamp":"2024-11-20T04:51:11.891Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.894Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.901Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"SCHEMA","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.904Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"Spree::Preference Load","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","binds":"{\"key\":\"?\",\"LIMIT\":\"?\"}","connection_id":42100},"timestamp":"2024-11-20T04:51:11.905Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"Spree::Country Load","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","binds":"{\"iso\":\"?\",\"LIMIT\":\"?\"}","connection_id":42100},"timestamp":"2024-11-20T04:51:11.933Z"},{"name":"Read
|
||||
cache","type":"process","metaData":{"hit":true,"event_name":"cache_read.active_support","event_id":"4779ed9ba580ae3d3290"},"timestamp":"2024-11-20T04:51:11.933Z"},{"name":"Read
|
||||
cache","type":"process","metaData":{"hit":true,"event_name":"cache_read.active_support","event_id":"4779ed9ba580ae3d3290"},"timestamp":"2024-11-20T04:51:11.933Z"},{"name":"ActiveRecord
|
||||
SQL query","type":"process","metaData":{"name":"TRANSACTION","event_name":"sql.active_record","event_id":"4779ed9ba580ae3d3290","connection_id":42100},"timestamp":"2024-11-20T04:51:11.970Z"}],"device":{"hostname":"blackbox","runtimeVersions":{"ruby":"3.1.4","rails":"7.0.8","rack":"2.2.9"},"time":"2024-11-20T04:51:11.978Z"},"exceptions":[{"errorClass":"RuntimeError","message":"Testing
|
||||
Bugsnag from RSpec","stacktrace":[{"lineNumber":129,"file":"gems/bugsnag-6.26.4/lib/bugsnag/report.rb","method":"initialize","code":{"126":" self.configuration
|
||||
= passed_configuration","127":"","128":" @original_error = exception","129":" self.raw_exceptions
|
||||
= generate_raw_exceptions(exception)","130":" self.exceptions = generate_exception_list","131":" @errors
|
||||
= generate_error_list","132":""}},{"lineNumber":90,"file":"gems/bugsnag-6.26.4/lib/bugsnag.rb","method":"new","code":{"87":"","88":" exception
|
||||
= NIL_EXCEPTION_DESCRIPTION if exception.nil?","89":"","90":" report
|
||||
= Report.new(exception, configuration, auto_notify)","91":"","92":" #
|
||||
If this is an auto_notify we yield the block before the any middleware is
|
||||
run","93":" begin"}},{"lineNumber":90,"file":"gems/bugsnag-6.26.4/lib/bugsnag.rb","method":"notify","code":{"87":"","88":" exception
|
||||
= NIL_EXCEPTION_DESCRIPTION if exception.nil?","89":"","90":" report
|
||||
= Report.new(exception, configuration, auto_notify)","91":"","92":" #
|
||||
If this is an auto_notify we yield the block before the any middleware is
|
||||
run","93":" begin"}},{"lineNumber":29,"inProject":true,"file":"app/services/alert.rb","method":"raise","code":{"26":" # }","27":" # )","28":" def
|
||||
self.raise(error, metadata = {}, &block)","29":" Bugsnag.notify(error)
|
||||
do |payload|","30":" metadata.each do |name, data|","31":" payload.add_metadata(name,
|
||||
data)","32":" end"}},{"lineNumber":34,"inProject":true,"file":"spec/services/alert_spec.rb","method":"block
|
||||
(2 levels) in <main>","code":{"31":" config.delivery_method = :synchronous","32":" end","33":"","34":" Alert.raise(","35":" \"Testing
|
||||
Bugsnag from RSpec\",","36":" { RSpec: { file: __FILE__ }, env: { BUGSNAG:
|
||||
ENV[\"BUGSNAG\"] } }","37":" )"}},{"lineNumber":263,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"260":" begin","261":" run_before_example","262":" RSpec.current_scope
|
||||
= :example","263":" @example_group_instance.instance_exec(self,
|
||||
&@example_block)","264":"","265":" if pending?","266":" Pending.mark_fixed!
|
||||
self"}},{"lineNumber":263,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"block
|
||||
in run","code":{"260":" begin","261":" run_before_example","262":" RSpec.current_scope
|
||||
= :example","263":" @example_group_instance.instance_exec(self,
|
||||
&@example_block)","264":"","265":" if pending?","266":" Pending.mark_fixed!
|
||||
self"}},{"lineNumber":511,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"block
|
||||
in with_around_and_singleton_context_hooks","code":{"508":" def with_around_and_singleton_context_hooks","509":" singleton_context_hooks_host
|
||||
= example_group_instance.singleton_class","510":" singleton_context_hooks_host.run_before_context_hooks(example_group_instance)","511":" with_around_example_hooks
|
||||
{ yield }","512":" ensure","513":" singleton_context_hooks_host.run_after_context_hooks(example_group_instance)","514":" end"}},{"lineNumber":468,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"block
|
||||
in with_around_example_hooks","code":{"465":"","466":" def with_around_example_hooks","467":" RSpec.current_scope
|
||||
= :before_example_hook","468":" hooks.run(:around, :example, self)
|
||||
{ yield }","469":" rescue Support::AllExceptionsExceptOnesWeMustNotRescue
|
||||
=> e","470":" set_exception(e)","471":" end"}},{"lineNumber":486,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
in run","code":{"483":" case position","484":" when
|
||||
:before then run_example_hooks_for(example_or_group, :before, :reverse_each)","485":" when
|
||||
:after then run_example_hooks_for(example_or_group, :after, :each)","486":" when
|
||||
:around then run_around_example_hooks_for(example_or_group) { yield }","487":" end","488":" end","489":" end"}},{"lineNumber":626,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
in run_around_example_hooks_for","code":{"623":"","624":" return
|
||||
yield if hooks.empty? # exit early to avoid the extra allocation cost of `Example::Procsy`","625":"","626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call"}},{"lineNumber":352,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"call","code":{"349":" #
|
||||
Calls the proc and notes that the example has been executed.","350":" def
|
||||
call(*args, &block)","351":" @executed = true","352":" @proc.call(*args,
|
||||
&block)","353":" end","354":" alias run call","355":""}},{"lineNumber":75,"file":"gems/rspec-rails-6.1.2/lib/rspec/rails/adapters.rb","method":"block
|
||||
(2 levels) in <module:MinitestLifecycleAdapter>","code":{"72":"","73":" group.around
|
||||
do |example|","74":" before_setup","75":" example.run","76":" after_teardown","77":" end","78":" end"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":390,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"execute_with","code":{"387":" #
|
||||
@private","388":" class AroundHook < Hook","389":" def execute_with(example,
|
||||
procsy)","390":" example.instance_exec(procsy, &block)","391":" return
|
||||
if procsy.executed?","392":" Pending.mark_skipped!(example,","393":" \"#{hook_description}
|
||||
did not execute the example\")"}},{"lineNumber":628,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
(2 levels) in run_around_example_hooks_for","code":{"625":"","626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call","630":" end","631":""}},{"lineNumber":352,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"call","code":{"349":" #
|
||||
Calls the proc and notes that the example has been executed.","350":" def
|
||||
call(*args, &block)","351":" @executed = true","352":" @proc.call(*args,
|
||||
&block)","353":" end","354":" alias run call","355":""}},{"lineNumber":153,"inProject":true,"file":"spec/base_spec_helper.rb","method":"block
|
||||
(3 levels) in <main>","code":{"150":"","151":" # Reset locale for all specs.","152":" config.around(:each)
|
||||
do |example|","153":" I18n.with_locale(:en_AU) { example.run }","154":" end","155":"","156":" #
|
||||
Reset all feature toggles to prevent leaking."}},{"lineNumber":351,"file":"gems/i18n-1.14.5/lib/i18n.rb","method":"with_locale","code":{"348":" current_locale
|
||||
= self.locale","349":" self.locale = tmp_locale","350":" begin","351":" yield","352":" ensure","353":" self.locale
|
||||
= current_locale","354":" end"}},{"lineNumber":153,"inProject":true,"file":"spec/base_spec_helper.rb","method":"block
|
||||
(2 levels) in <main>","code":{"150":"","151":" # Reset locale for all specs.","152":" config.around(:each)
|
||||
do |example|","153":" I18n.with_locale(:en_AU) { example.run }","154":" end","155":"","156":" #
|
||||
Reset all feature toggles to prevent leaking."}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":390,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"execute_with","code":{"387":" #
|
||||
@private","388":" class AroundHook < Hook","389":" def execute_with(example,
|
||||
procsy)","390":" example.instance_exec(procsy, &block)","391":" return
|
||||
if procsy.executed?","392":" Pending.mark_skipped!(example,","393":" \"#{hook_description}
|
||||
did not execute the example\")"}},{"lineNumber":628,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
(2 levels) in run_around_example_hooks_for","code":{"625":"","626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call","630":" end","631":""}},{"lineNumber":352,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"call","code":{"349":" #
|
||||
Calls the proc and notes that the example has been executed.","350":" def
|
||||
call(*args, &block)","351":" @executed = true","352":" @proc.call(*args,
|
||||
&block)","353":" end","354":" alias run call","355":""}},{"lineNumber":39,"file":"gems/webmock-3.23.1/lib/webmock/rspec.rb","method":"block
|
||||
(2 levels) in <main>","code":{"36":" end","37":"","38":" config.around(:each)
|
||||
do |example|","39":" example.run","40":" WebMock.reset!","41":" end","42":"}"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":390,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"execute_with","code":{"387":" #
|
||||
@private","388":" class AroundHook < Hook","389":" def execute_with(example,
|
||||
procsy)","390":" example.instance_exec(procsy, &block)","391":" return
|
||||
if procsy.executed?","392":" Pending.mark_skipped!(example,","393":" \"#{hook_description}
|
||||
did not execute the example\")"}},{"lineNumber":628,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
(2 levels) in run_around_example_hooks_for","code":{"625":"","626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call","630":" end","631":""}},{"lineNumber":352,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"call","code":{"349":" #
|
||||
Calls the proc and notes that the example has been executed.","350":" def
|
||||
call(*args, &block)","351":" @executed = true","352":" @proc.call(*args,
|
||||
&block)","353":" end","354":" alias run call","355":""}},{"lineNumber":124,"file":"gems/rspec-retry-0.6.2/lib/rspec/retry.rb","method":"block
|
||||
in run","code":{"121":" example.metadata[:retry_exceptions] ||= []","122":"","123":" example.clear_exception","124":" ex.run","125":"","126":" self.attempts
|
||||
+= 1","127":""}},{"lineNumber":110,"file":"gems/rspec-retry-0.6.2/lib/rspec/retry.rb","method":"loop","code":{"107":" def
|
||||
run","108":" example = current_example","109":"","110":" loop do","111":" if
|
||||
attempts > 0","112":" RSpec.configuration.formatters.each { |f| f.retry(example)
|
||||
if f.respond_to? :retry }","113":" if verbose_retry?"}},{"lineNumber":110,"file":"gems/rspec-retry-0.6.2/lib/rspec/retry.rb","method":"run","code":{"107":" def
|
||||
run","108":" example = current_example","109":"","110":" loop do","111":" if
|
||||
attempts > 0","112":" RSpec.configuration.formatters.each { |f| f.retry(example)
|
||||
if f.respond_to? :retry }","113":" if verbose_retry?"}},{"lineNumber":12,"file":"gems/rspec-retry-0.6.2/lib/rspec_ext/rspec_ext.rb","method":"run_with_retry","code":{"9":"","10":" class
|
||||
Procsy","11":" def run_with_retry(opts = {})","12":" RSpec::Retry.new(self,
|
||||
opts).run","13":" end","14":"","15":" def attempts"}},{"lineNumber":37,"file":"gems/rspec-retry-0.6.2/lib/rspec/retry.rb","method":"block
|
||||
(2 levels) in setup","code":{"34":" config.add_setting :retry_callback,
|
||||
:default => nil","35":"","36":" config.around(:each) do |ex|","37":" ex.run_with_retry","38":" end","39":" end","40":" end"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":457,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"instance_exec","code":{"454":"","455":" #
|
||||
@private","456":" def instance_exec(*args, &block)","457":" @example_group_instance.instance_exec(*args,
|
||||
&block)","458":" end","459":"","460":" private"}},{"lineNumber":390,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"execute_with","code":{"387":" #
|
||||
@private","388":" class AroundHook < Hook","389":" def execute_with(example,
|
||||
procsy)","390":" example.instance_exec(procsy, &block)","391":" return
|
||||
if procsy.executed?","392":" Pending.mark_skipped!(example,","393":" \"#{hook_description}
|
||||
did not execute the example\")"}},{"lineNumber":628,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"block
|
||||
(2 levels) in run_around_example_hooks_for","code":{"625":"","626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call","630":" end","631":""}},{"lineNumber":352,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"call","code":{"349":" #
|
||||
Calls the proc and notes that the example has been executed.","350":" def
|
||||
call(*args, &block)","351":" @executed = true","352":" @proc.call(*args,
|
||||
&block)","353":" end","354":" alias run call","355":""}},{"lineNumber":629,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"run_around_example_hooks_for","code":{"626":" initial_procsy
|
||||
= Example::Procsy.new(example) { yield }","627":" hooks.inject(initial_procsy)
|
||||
do |procsy, around_hook|","628":" procsy.wrap { around_hook.execute_with(example,
|
||||
procsy) }","629":" end.call","630":" end","631":"","632":" if
|
||||
respond_to?(:singleton_class) && singleton_class.ancestors.include?(singleton_class)"}},{"lineNumber":486,"file":"gems/rspec-core-3.13.0/lib/rspec/core/hooks.rb","method":"run","code":{"483":" case
|
||||
position","484":" when :before then run_example_hooks_for(example_or_group,
|
||||
:before, :reverse_each)","485":" when :after then run_example_hooks_for(example_or_group,
|
||||
:after, :each)","486":" when :around then run_around_example_hooks_for(example_or_group)
|
||||
{ yield }","487":" end","488":" end","489":" end"}},{"lineNumber":468,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"with_around_example_hooks","code":{"465":"","466":" def
|
||||
with_around_example_hooks","467":" RSpec.current_scope = :before_example_hook","468":" hooks.run(:around,
|
||||
:example, self) { yield }","469":" rescue Support::AllExceptionsExceptOnesWeMustNotRescue
|
||||
=> e","470":" set_exception(e)","471":" end"}},{"lineNumber":511,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"with_around_and_singleton_context_hooks","code":{"508":" def
|
||||
with_around_and_singleton_context_hooks","509":" singleton_context_hooks_host
|
||||
= example_group_instance.singleton_class","510":" singleton_context_hooks_host.run_before_context_hooks(example_group_instance)","511":" with_around_example_hooks
|
||||
{ yield }","512":" ensure","513":" singleton_context_hooks_host.run_after_context_hooks(example_group_instance)","514":" end"}},{"lineNumber":259,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example.rb","method":"run","code":{"256":" if
|
||||
skipped?","257":" Pending.mark_pending! self, skip","258":" elsif
|
||||
!RSpec.configuration.dry_run?","259":" with_around_and_singleton_context_hooks
|
||||
do","260":" begin","261":" run_before_example","262":" RSpec.current_scope
|
||||
= :example"}},{"lineNumber":646,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example_group.rb","method":"block
|
||||
in run_examples","code":{"643":" next if RSpec.world.wants_to_quit","644":" instance
|
||||
= new(example.inspect_output)","645":" set_ivars(instance, before_context_ivars)","646":" succeeded
|
||||
= example.run(instance, reporter)","647":" if !succeeded && reporter.fail_fast_limit_met?","648":" RSpec.world.wants_to_quit
|
||||
= true","649":" end"}},{"lineNumber":642,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example_group.rb","method":"map","code":{"639":"","640":" #
|
||||
@private","641":" def self.run_examples(reporter)","642":" ordering_strategy.order(filtered_examples).map
|
||||
do |example|","643":" next if RSpec.world.wants_to_quit","644":" instance
|
||||
= new(example.inspect_output)","645":" set_ivars(instance, before_context_ivars)"}},{"lineNumber":642,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example_group.rb","method":"run_examples","code":{"639":"","640":" #
|
||||
@private","641":" def self.run_examples(reporter)","642":" ordering_strategy.order(filtered_examples).map
|
||||
do |example|","643":" next if RSpec.world.wants_to_quit","644":" instance
|
||||
= new(example.inspect_output)","645":" set_ivars(instance, before_context_ivars)"}},{"lineNumber":607,"file":"gems/rspec-core-3.13.0/lib/rspec/core/example_group.rb","method":"run","code":{"604":" begin","605":" RSpec.current_scope
|
||||
= :before_context_hook","606":" run_before_context_hooks(new(''before(:context)
|
||||
hook'')) if should_run_context_hooks","607":" result_for_this_group
|
||||
= run_examples(reporter)","608":" results_for_descendants = ordering_strategy.order(children).map
|
||||
{ |child| child.run(reporter) }.all?","609":" result_for_this_group
|
||||
&& results_for_descendants","610":" rescue Pending::SkipDeclaredInExample
|
||||
=> ex"}},{"lineNumber":121,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"block
|
||||
(3 levels) in run_specs","code":{"118":" return @configuration.failure_exit_code","119":" end","120":"","121":" example_groups.map
|
||||
{ |g| g.run(reporter) }.all?","122":" end","123":" end","124":""}},{"lineNumber":121,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"map","code":{"118":" return
|
||||
@configuration.failure_exit_code","119":" end","120":"","121":" example_groups.map
|
||||
{ |g| g.run(reporter) }.all?","122":" end","123":" end","124":""}},{"lineNumber":121,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"block
|
||||
(2 levels) in run_specs","code":{"118":" return @configuration.failure_exit_code","119":" end","120":"","121":" example_groups.map
|
||||
{ |g| g.run(reporter) }.all?","122":" end","123":" end","124":""}},{"lineNumber":2091,"file":"gems/rspec-core-3.13.0/lib/rspec/core/configuration.rb","method":"with_suite_hooks","code":{"2088":" begin","2089":" RSpec.current_scope
|
||||
= :before_suite_hook","2090":" run_suite_hooks(\"a `before(:suite)`
|
||||
hook\", @before_suite_hooks)","2091":" yield","2092":" ensure","2093":" RSpec.current_scope
|
||||
= :after_suite_hook","2094":" run_suite_hooks(\"an `after(:suite)`
|
||||
hook\", @after_suite_hooks)"}},{"lineNumber":116,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"block
|
||||
in run_specs","code":{"113":" def run_specs(example_groups)","114":" examples_count
|
||||
= @world.example_count(example_groups)","115":" examples_passed = @configuration.reporter.report(examples_count)
|
||||
do |reporter|","116":" @configuration.with_suite_hooks do","117":" if
|
||||
examples_count == 0 && @configuration.fail_if_no_examples","118":" return
|
||||
@configuration.failure_exit_code","119":" end"}},{"lineNumber":74,"file":"gems/rspec-core-3.13.0/lib/rspec/core/reporter.rb","method":"report","code":{"71":" def
|
||||
report(expected_example_count)","72":" start(expected_example_count)","73":" begin","74":" yield
|
||||
self","75":" ensure","76":" finish","77":" end"}},{"lineNumber":115,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"run_specs","code":{"112":" # failed.","113":" def
|
||||
run_specs(example_groups)","114":" examples_count = @world.example_count(example_groups)","115":" examples_passed
|
||||
= @configuration.reporter.report(examples_count) do |reporter|","116":" @configuration.with_suite_hooks
|
||||
do","117":" if examples_count == 0 && @configuration.fail_if_no_examples","118":" return
|
||||
@configuration.failure_exit_code"}},{"lineNumber":89,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"run","code":{"86":" setup(err,
|
||||
out)","87":" return @configuration.reporter.exit_early(exit_code) if
|
||||
RSpec.world.wants_to_quit","88":"","89":" run_specs(@world.ordered_example_groups).tap
|
||||
do","90":" persist_example_statuses","91":" end","92":" end"}},{"lineNumber":71,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"run","code":{"68":" if
|
||||
options.options[:runner]","69":" options.options[:runner].call(options,
|
||||
err, out)","70":" else","71":" new(options).run(err, out)","72":" end","73":" end","74":""}},{"lineNumber":45,"file":"gems/rspec-core-3.13.0/lib/rspec/core/runner.rb","method":"invoke","code":{"42":" #
|
||||
code.","43":" def self.invoke","44":" disable_autorun!","45":" status
|
||||
= run(ARGV, $stderr, $stdout).to_i","46":" exit(status) if status !=
|
||||
0","47":" end","48":""}},{"lineNumber":4,"file":"gems/rspec-core-3.13.0/exe/rspec","method":"<main>","code":{"1":"#!/usr/bin/env
|
||||
ruby","2":"","3":"require ''rspec/core''","4":"RSpec::Core::Runner.invoke"}},{"lineNumber":18,"file":"gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb","method":"load","code":{"15":"","16":" def
|
||||
call","17":" ::RSpec.configuration.start_time = Time.now if defined?(::RSpec.configuration.start_time)","18":" load
|
||||
Gem.bin_path(gem_name, exec_name)","19":" end","20":" end","21":""}},{"lineNumber":18,"file":"gems/spring-commands-rspec-1.0.4/lib/spring/commands/rspec.rb","method":"call","code":{"15":"","16":" def
|
||||
call","17":" ::RSpec.configuration.start_time = Time.now if defined?(::RSpec.configuration.start_time)","18":" load
|
||||
Gem.bin_path(gem_name, exec_name)","19":" end","20":" end","21":""}},{"lineNumber":38,"file":"gems/spring-4.2.1/lib/spring/command_wrapper.rb","method":"call","code":{"35":"","36":" def
|
||||
call","37":" if command.respond_to?(:call)","38":" command.call","39":" else","40":" load
|
||||
exec","41":" end"}},{"lineNumber":226,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"block
|
||||
in serve","code":{"223":" invoke_after_fork_callbacks","224":" shush_backtraces","225":"","226":" command.call","227":" }","228":"","229":" disconnect_database"}},{"lineNumber":190,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"fork","code":{"187":" Rails.application.reloader.reload!","188":" end","189":"","190":" pid
|
||||
= fork {","191":" # Make sure to close other clients otherwise their
|
||||
graceful termination","192":" # will be impossible due to reference
|
||||
from this fork.","193":" @clients.each_key { |c| c.close if c != client
|
||||
}"}},{"lineNumber":190,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"serve","code":{"187":" Rails.application.reloader.reload!","188":" end","189":"","190":" pid
|
||||
= fork {","191":" # Make sure to close other clients otherwise their
|
||||
graceful termination","192":" # will be impossible due to reference
|
||||
from this fork.","193":" @clients.each_key { |c| c.close if c != client
|
||||
}"}},{"lineNumber":153,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"block
|
||||
in run","code":{"150":" if terminating? || watcher_stale? || preload_failed?","151":" exit","152":" else","153":" serve
|
||||
manager.recv_io(UNIXSocket)","154":" end","155":" end","156":" end"}},{"lineNumber":147,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"loop","code":{"144":" state
|
||||
:running","145":" manager.puts","146":"","147":" loop do","148":" IO.select
|
||||
[manager, @interrupt.first]","149":"","150":" if terminating? || watcher_stale?
|
||||
|| preload_failed?"}},{"lineNumber":147,"file":"gems/spring-4.2.1/lib/spring/application.rb","method":"run","code":{"144":" state
|
||||
:running","145":" manager.puts","146":"","147":" loop do","148":" IO.select
|
||||
[manager, @interrupt.first]","149":"","150":" if terminating? || watcher_stale?
|
||||
|| preload_failed?"}},{"lineNumber":25,"file":"gems/spring-4.2.1/lib/spring/application/boot.rb","method":"<top
|
||||
(required)>","code":{"19":" app.spawn_env,","20":" ].compact","21":" \"spring
|
||||
app | #{attributes.join(\" | \")}\"","22":"end","23":"","24":"app.eager_preload
|
||||
if ENV.delete(\"SPRING_PRELOAD\") == \"1\"","25":"app.run"}},{"lineNumber":1,"file":"-e","method":"<main>","code":null}]}],"featureFlags":[],"metaData":{"RSpec":{"file":"/home/maikel/code/openfoodnetwork/spec/services/alert_spec.rb"},"env":{}},"severity":"warning","severityReason":{"type":"handledException"},"unhandled":false,"user":{}}]}'
|
||||
headers:
|
||||
Bugsnag-Api-Key:
|
||||
- "<HIDDEN-BUGSNAG_API_KEY>"
|
||||
Bugsnag-Payload-Version:
|
||||
- '4.0'
|
||||
Bugsnag-Sent-At:
|
||||
- '2024-11-20T04:51:11.998Z'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
Accept:
|
||||
- "*/*"
|
||||
User-Agent:
|
||||
- Ruby
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
Bugsnag-Event-Id:
|
||||
- 673d6ac0010cfda42d8e0000
|
||||
Date:
|
||||
- Wed, 20 Nov 2024 04:51:12 GMT
|
||||
Content-Length:
|
||||
- '2'
|
||||
Content-Type:
|
||||
- text/plain; charset=utf-8
|
||||
Via:
|
||||
- 1.1 google
|
||||
Alt-Svc:
|
||||
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: OK
|
||||
recorded_at: Wed, 20 Nov 2024 04:51:12 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
@@ -0,0 +1,57 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://vine-staging.openfoodnetwork.org.au/api/v1/voucher-validation
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"type":"voucher_code","value":"CI3922"}'
|
||||
headers:
|
||||
X-Authorization:
|
||||
- "<HIDDEN-VINE-TOKEN>"
|
||||
Accept:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Faraday v2.9.0
|
||||
Content-Type:
|
||||
- application/json
|
||||
Authorization:
|
||||
- "<HIDDEN-AUTHORIZATION-HEADER>"
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Content-Type:
|
||||
- application/json
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Connection:
|
||||
- keep-alive
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
Cache-Control:
|
||||
- no-cache, private
|
||||
Date:
|
||||
- Sun, 20 Oct 2024 03:32:37 GMT
|
||||
X-Ratelimit-Limit:
|
||||
- '60'
|
||||
X-Ratelimit-Remaining:
|
||||
- '58'
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Xss-Protection:
|
||||
- 1; mode=block
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: '{"meta":{"responseCode":200,"limit":50,"offset":0,"message":""},"data":{"id":"9d2437c8-4559-4dda-802e-8d9c642a0c1d","voucher_short_code":"CI3922","voucher_set_id":"9d24349c-1fe8-4090-988b-d7355ed32559","is_test":1,"voucher_value_original":500,"voucher_value_remaining":500,"num_voucher_redemptions":0,"last_redemption_at":null,"created_at":"2024-10-01T13:20:02.000000Z","updated_at":"2024-10-01T13:20:02.000000Z","deleted_at":null}}'
|
||||
recorded_at: Sun, 20 Oct 2024 03:32:37 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://vine-staging.openfoodnetwork.org.au/api/v1/voucher-validation
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"type":"voucher_code","value":"KM1891"}'
|
||||
headers:
|
||||
X-Authorization:
|
||||
- "<HIDDEN-VINE-TOKEN>"
|
||||
Accept:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Faraday v2.9.0
|
||||
Content-Type:
|
||||
- application/json
|
||||
Authorization:
|
||||
- "<HIDDEN-AUTHORIZATION-HEADER>"
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
response:
|
||||
status:
|
||||
code: 400
|
||||
message: Bad Request
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Content-Type:
|
||||
- application/json
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Connection:
|
||||
- keep-alive
|
||||
Cache-Control:
|
||||
- no-cache, private
|
||||
Date:
|
||||
- Sun, 20 Oct 2024 03:42:25 GMT
|
||||
X-Ratelimit-Limit:
|
||||
- '60'
|
||||
X-Ratelimit-Remaining:
|
||||
- '59'
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"meta":{"responseCode":400,"limit":50,"offset":0,"message":"Invalid
|
||||
merchant team."},"data":[]}'
|
||||
recorded_at: Sun, 20 Oct 2024 03:42:25 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
@@ -0,0 +1,55 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: post
|
||||
uri: https://vine-staging.openfoodnetwork.org.au/api/v1/voucher-redemptions
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: '{"voucher_id":"9d316d27-4e3c-4c8c-b3c8-8e23cc171f20","voucher_set_id":"9d314daa-0878-4b73-922d-698047640cf4","amount":1}'
|
||||
headers:
|
||||
X-Authorization:
|
||||
- "<HIDDEN-VINE-TOKEN>"
|
||||
Accept:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Faraday v2.9.0
|
||||
Content-Type:
|
||||
- application/json
|
||||
Authorization:
|
||||
- "<HIDDEN-AUTHORIZATION-HEADER>"
|
||||
Accept-Encoding:
|
||||
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Content-Type:
|
||||
- application/json
|
||||
Transfer-Encoding:
|
||||
- chunked
|
||||
Connection:
|
||||
- keep-alive
|
||||
Vary:
|
||||
- Accept-Encoding
|
||||
Cache-Control:
|
||||
- no-cache, private
|
||||
Date:
|
||||
- Wed, 23 Oct 2024 03:16:39 GMT
|
||||
Access-Control-Allow-Origin:
|
||||
- "*"
|
||||
X-Frame-Options:
|
||||
- SAMEORIGIN
|
||||
X-Xss-Protection:
|
||||
- 1; mode=block
|
||||
X-Content-Type-Options:
|
||||
- nosniff
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: '{"meta":{"responseCode":200,"limit":50,"offset":0,"message":"Redemption
|
||||
successful. This was a test redemption. Do NOT provide the person with goods
|
||||
or services."},"data":{"voucher_id":"9d316d27-4e3c-4c8c-b3c8-8e23cc171f20","voucher_set_id":"9d314daa-0878-4b73-922d-698047640cf4","redeemed_by_user_id":8,"redeemed_by_team_id":4,"redeemed_amount":1,"is_test":1,"updated_at":"2024-10-23T03:16:39.000000Z","created_at":"2024-10-23T03:16:39.000000Z","id":7}}'
|
||||
recorded_at: Wed, 23 Oct 2024 03:16:39 GMT
|
||||
recorded_with: VCR 6.2.0
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user