diff --git a/app/views/spree/admin/variants/search.rabl b/app/views/spree/admin/variants/search.rabl
index 8206932c5f..b65ef4d768 100644
--- a/app/views/spree/admin/variants/search.rabl
+++ b/app/views/spree/admin/variants/search.rabl
@@ -2,7 +2,7 @@
# overriding spree/core/app/views/spree/admin/variants/search.rabl
#
collection @variants
-attributes :sku, :options_text, :in_stock?, :on_demand, :count_on_hand, :id, :cost_price
+attributes :sku, :options_text, :in_stock?, :on_demand, :on_hand, :id, :cost_price
node(:name) do |v|
# TODO: when products must have a unit, full_name will always be present
diff --git a/config/initializers/bugsnag.rb b/config/initializers/bugsnag.rb
new file mode 100644
index 0000000000..89da91d9e0
--- /dev/null
+++ b/config/initializers/bugsnag.rb
@@ -0,0 +1,5 @@
+Bugsnag.configure do |config|
+ config.api_key = ENV['BUGSNAG_API_KEY']
+ config.notify_release_stages = %w(production staging)
+ config.use_ssl = true
+end
diff --git a/config/initializers/user_class_extensions.rb b/config/initializers/user_class_extensions.rb
deleted file mode 100644
index cd9ff60a0c..0000000000
--- a/config/initializers/user_class_extensions.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-Spree::Core::Engine.config.to_prepare do
- if Spree.user_class
- Spree.user_class.class_eval do
-
- # Override of spree method to ignore orders associated with account_invoices
- def last_incomplete_spree_order
- spree_orders.incomplete.where("id NOT IN (?)", account_invoices.map(&:order_id)).order('created_at DESC').first
- end
- end
- end
-end
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index f340592af3..b47a8890bb 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -31,6 +31,16 @@ ca:
on_demand_but_count_on_hand_set: "ha d'estar en blanc si és sota demanda"
limited_stock_but_no_count_on_hand: "cal especificar-se perquè força existències limitades"
activemodel:
+ attributes:
+ order_management/reports/enterprise_fee_summary/parameters:
+ start_at: "Començar"
+ end_at: "Acabar"
+ distributor_ids: "Grups"
+ producer_ids: "Productors"
+ order_cycle_ids: "Cicles de comanda"
+ enterprise_fee_ids: "Noms de les comissions"
+ shipping_method_ids: "Mètodes d'enviament"
+ payment_method_ids: "Mètodes de Pagament"
errors:
models:
subscription_validator:
@@ -74,6 +84,13 @@ ca:
models:
order_cycle:
cloned_order_cycle_name: "CÒPIA DE %{order_cycle}"
+ validators:
+ date_time_string_validator:
+ not_string_error: "ha de ser una seqüència"
+ invalid_format_error: "ha de ser vàlid"
+ integer_array_validator:
+ not_array_error: "ha de ser una matriu"
+ invalid_element_error: "ha de contenir només nombres enters vàlids"
enterprise_mailer:
confirmation_instructions:
subject: "Sisplau, confirma l'adreça electrònica d'%{enterprise}"
@@ -318,7 +335,7 @@ ca:
business_model_configuration:
edit:
business_model_configuration: "Model de sostenibilitat"
- business_model_configuration_tip: "Configureu la tarifa què es cobrarà a les botigues cada mes per utilitzar la Xarxa Open Food."
+ business_model_configuration_tip: "Configureu la tarifa què es cobrarà a les botigues cada mes per utilitzar Open Food Network."
bill_calculation_settings: "Configuració del càlcul de ticket"
bill_calculation_settings_tip: "Ajusteu la quantitat que es facturarà a les organitzacions cada mes per utilitzar l'OFN."
shop_trial_length: "Durada de la prova de la botiga (dies)"
@@ -418,9 +435,9 @@ ca:
user_guide: Guia de l'usuari
enterprise_fees:
index:
- title: Tarifes de l'organització
+ title: Comissions de l'organització
enterprise: Organització
- fee_type: Tipus de tarifa
+ fee_type: Tipus de comissió
name: Nom
tax_category: Categoria d'impostos
calculator: Calculadora
@@ -634,8 +651,8 @@ ca:
website_placeholder: 'p. ex.: www.hortajosepribes.com'
enterprise_fees:
name: Nom
- fee_type: Tipus de tarifa
- manage_fees: Gestioneu les tarifes de l'organització
+ fee_type: Tipus de comissió
+ manage_fees: Gestioneu les comissions de l'organització
no_fees_yet: Encara no tens cap tipus de comissió de l'organització
create_button: Crea'n una ara
images:
@@ -737,7 +754,7 @@ ca:
title: Connectar amb Stripe
part1: Stripe és un servei de processament de pagaments que permet que les botigues de l'OFN acceptin els pagaments amb targeta de crèdit de les consumidores.
part2: Per utilitzar aquesta funció heu de connectar el vostre compte Stripe a l'OFN. Si feu clic a "Accepto", us redirigirem al lloc web de Stripe on podeu connectar un compte Stripe existent o bé crear-ne un si encara no en teniu cap.
- part3: Això permetrà que Open Food Network accepti pagaments amb targeta de crèdit de consumidores en nom vostre. Tingueu en compte que haureu de mantenir el vostre propi compte de Stripe, pagar-ne les tarifes i mantenir el servei a les consumidores pel teu compte.
+ part3: Això permetrà que Open Food Network accepti pagaments amb targeta de crèdit de consumidores en nom vostre. Tingueu en compte que haureu de mantenir el vostre propi compte de Stripe, pagar-ne les comissions i mantenir el servei a les consumidores pel teu compte.
i_agree: Accepto
cancel: Cancel·lar
tag_rules:
@@ -775,7 +792,7 @@ ca:
payment_methods_tip: Aquesta organització no té mètodes de pagament
shipping_methods: Mètodes d'enviament
shipping_methods_tip: 'Aquesta organització té mètodes d''enviament '
- enterprise_fees: Honoraris de l'organització
+ enterprise_fees: Comissions de l'organització
enterprise_fees_tip: Aquesta organització no té comissions
admin_index:
name: Nom
@@ -873,7 +890,7 @@ ca:
incoming: Entrant
supplier: Proveïdora
receival_details: Detalls de recepció
- fees: Tarifes
+ fees: Comissions
outgoing: Sortint
distributor: Distribuïdora
products: Productes
@@ -911,7 +928,7 @@ ca:
customer_instructions: Instruccions de la consumidora
customer_instructions_placeholder: Notes de recollida o de lliurament
products: Productes
- fees: Tarifes
+ fees: Comissions
destroy_errors:
orders_present: Una consumidora ha seleccionat aquest Cicle de Comanda i no es pot esborrar. Per evitar que les consumidores hi accedeixin, tanqueu-lo.
schedule_present: Aquest cicle de comanda està vinculat a una programació i no es pot esborrar. Desenllaça o suprimeix primer la programació.
@@ -996,6 +1013,9 @@ ca:
description: Factures per a la importació a Xero
packing:
name: Informes d'embalatge
+ enterprise_fee_summary:
+ name: "Resum de les comissions de l'organització"
+ description: "Resum de les comissions de l'organització recollides"
subscriptions:
subscriptions: Subscripcions
new: Nova subscripció
@@ -1883,7 +1903,7 @@ ca:
shipping_method_destroy_error: "Aquest mètode d'enviament no es pot esborrar perquè s'hi fa referència en una comanda: %{number}."
accounts_and_billing_task_already_running_error: "Ja s'està executant una tasca, espera fins que hagi acabat"
accounts_and_billing_start_task_notice: "Tasca en cua"
- fees: "Tarifes"
+ fees: "Comissions"
item_cost: "Cost de l'article"
bulk: "A granel"
shop_variant_quantity_min: "min"
@@ -1955,7 +1975,7 @@ ca:
process_my_order: "Processa la meva comanda"
delivery_instructions: Instruccions de lliurament
delivery_method: Mètode de lliurament
- fee_type: "Tipus de tarifa"
+ fee_type: "Tipus de comissió"
tax_category: "Categoria d'impostos"
calculator: "Calculadora"
calculator_values: "Valors de la calculadora"
@@ -2000,7 +2020,6 @@ ca:
spree_admin_enterprises_none_text: "Encara no tens cap organització"
spree_admin_enterprises_tabs_hubs: "GRUPS"
spree_admin_enterprises_producers_manage_products: "GESTIONA ELS PRODUCTES"
- spree_admin_enterprises_any_active_products_text: "No tens cap producte actiu."
spree_admin_enterprises_create_new_product: "CREA UN NOU PRODUCTE"
spree_admin_single_enterprise_alert_mail_confirmation: "Si us plau confirma l'adreça de correu electrònic de"
spree_admin_single_enterprise_alert_mail_sent: "Hem enviat un correu electrònic a"
@@ -2127,7 +2146,7 @@ ca:
report_header_sales_tax: "Impost sobre vendes (%{currency_symbol})"
report_header_delivery_charge: "Càrrec de lliurament (%{currency_symbol})"
report_header_tax_on_delivery: "Impost sobre el lliurament (%{currency_symbol})"
- report_header_tax_on_fees: "Impost sobre les tarifes (%{currency_symbol})"
+ report_header_tax_on_fees: "Impost sobre les comissions (%{currency_symbol})"
report_header_total_tax: "Impost total (%{currency_symbol})"
report_header_enterprise: Organització
report_header_customer: Consumidora
@@ -2248,7 +2267,7 @@ ca:
shipping: "Enviament"
shipping_methods: "Mètodes d'enviament"
payment_methods: "Mètodes de Pagament"
- payment_method_fee: "Tarifa de transacció"
+ payment_method_fee: "Comissió de transacció"
inventory_settings: "Configuració de l'inventari"
tag_rules: "Regles d'etiqueta"
shop_preferences: "Preferències de la botiga"
@@ -2526,6 +2545,45 @@ ca:
producers:
signup:
start_free_profile: "Comença amb un perfil gratuït i amplia'l quan estiguis preparada."
+ order_management:
+ reports:
+ enterprise_fee_summary:
+ date_end_before_start_error: "ha de ser després de l'inici"
+ parameter_not_allowed_error: "No esteu autoritzats a utilitzar un o més filtres seleccionats per a aquest informe."
+ fee_calculated_on_transfer_through_all: "Tots"
+ fee_calculated_on_transfer_through_entire_orders: "Comandes completades a través de"
+ tax_category_various: "Varis"
+ fee_type:
+ payment_method: "Transacció de pagament"
+ shipping_method: "Enviament"
+ fee_placements:
+ supplier: "Entrant"
+ distributor: "Sortint"
+ coordinator: "Coordinador"
+ tax_category_name:
+ shipping_instance_rate: "Tarifa de la plataforma"
+ formats:
+ csv:
+ header:
+ fee_type: "Tipus de comissió"
+ enterprise_name: "Propietària de l'organització"
+ fee_name: "Nom de la comissió"
+ customer_name: "Consumidora"
+ fee_placement: "Col·locació de comissions"
+ fee_calculated_on_transfer_through_name: "Càlcul de comissions a través de transferència"
+ tax_category_name: "Categoria d'impostos"
+ total_amount: "€€ SUM"
+ html:
+ header:
+ fee_type: "Tipus de comissió"
+ enterprise_name: "Propietària de l'organització"
+ fee_name: "Nom de la comissió"
+ customer_name: "Consumidora"
+ fee_placement: "Col·locació de comissions"
+ fee_calculated_on_transfer_through_name: "Càlcul de comissions a través de transferència"
+ tax_category_name: "Categoria d'impostos"
+ total_amount: "€€ SUM"
+ invalid_filter_parameters: "Els filtres que heu seleccionat per a aquest informe no són vàlids."
spree:
email: Correu electrònic
account_updated: "Compte actualitzat!"
@@ -2569,6 +2627,11 @@ ca:
distributor: "Distribuïdora:"
order_cycle: "Cicle de comanda:"
overview:
+ products:
+ active_products:
+ zero: "No tens cap producte actiu."
+ one: "Teniu un producte actiu"
+ other: "Teniu %{count} productes actius"
order_cycles:
order_cycles: "Cicles de comanda"
order_cycles_tip: "Els cicles de comanda determinen quan i on els teus productes estan disponibles per a les consumidores."
@@ -2642,6 +2705,14 @@ ca:
bulk_coop_allocation: 'Compra grupal - Assignació'
bulk_coop_packing_sheets: 'Compra grupal - Fulls de preparació de cistelles'
bulk_coop_customer_payments: 'Compra grupal - Pagaments de les consumidores'
+ enterprise_fee_summaries:
+ filters:
+ date_range: "Interval de dates"
+ report_format_csv: "Descarrega com a CSV"
+ generate_report: "Generar informe"
+ report:
+ none: "No productora"
+ select_and_search: "Seleccioneu els filtres i feu clic a GENERAR INFORME per accedir a les dades."
users:
index:
listing_users: "Llistat d'usuàries"
diff --git a/config/locales/en.yml b/config/locales/en.yml
index d7afd039af..bd0ca8624f 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -202,17 +202,9 @@ en:
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 ABN before invoices can be sent."
invoice: "Invoice"
- percentage_of_sales: "%{percentage} of sales"
- capped_at_cap: "capped at %{cap}"
- per_month: "per month"
- free: "free"
- free_trial: "free trial"
- plus_tax: "plus GST"
- min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}"
more: "More"
say_no: "No"
say_yes: "Yes"
- then: then
ongoing: Ongoing
bill_address: Billing Address
ship_address: Shipping Address
@@ -238,6 +230,7 @@ en:
enterprise_groups: Groups
reports: Reports
variant_overrides: Inventory
+ import: Import
spree_products: Spree Products
all: All
current: Current
@@ -348,28 +341,6 @@ en:
unsaved_confirm_leave: "There are unsaved changed on this page. Continue without saving?"
unsaved_changes: "You have unsaved changes"
- accounts_and_billing_settings:
- method_settings:
- default_accounts_payment_method: "Default Accounts Payment Method"
- default_accounts_shipping_method: "Default Accounts Shipping Method"
- edit:
- accounts_and_billing: "Accounts & Billing"
- accounts_administration_distributor: "Accounts Administration Distributor"
- admin_settings: "Settings"
- update_invoice: "Update Invoices"
- auto_update_invoices: "Auto-update invoices nightly at 1:00am"
- finalise_invoice: "Finalise Invoices"
- auto_finalise_invoices: "Auto-finalise invoices monthly on the 2nd at 1:30am"
- manually_run_task: "Manually Run Task "
- update_user_invoice_explained: "Use this button to immediately update invoices for the month to date for each enterprise user in the system. This task can be set up to run automatically every night."
- finalise_user_invoices: "Finalise User Invoices"
- finalise_user_invoice_explained: "Use this button to finalize all invoices in the system for the previous calendar month. This task can be set up to run automatically once a month."
- update_user_invoices: "Update User Invoices"
- errors:
- accounts_distributor: must be set if you wish to create invoices for enterprise users.
- default_payment_method: must be set if you wish to create invoices for enterprise users.
- default_shipping_method: must be set if you wish to create invoices for enterprise users.
-
shopfront_settings:
embedded_shopfront_settings: "Embedded Shopfront Settings"
enable_embedded_shopfronts: "Enable Embedded Shopfronts"
@@ -379,43 +350,15 @@ en:
number_localization_settings: "Number Localization Settings"
enable_localized_number: "Use the international thousand/decimal separator logic"
- business_model_configuration:
- edit:
- business_model_configuration: "Business Model"
- business_model_configuration_tip: "Configure the rate at which shops will be charged each month for use of the Open Food Network."
- bill_calculation_settings: "Bill Calculation Settings"
- bill_calculation_settings_tip: "Adjust the amount that enterprises will be billed each month for use of the OFN."
- shop_trial_length: "Shop Trial Length (Days)"
- shop_trial_length_tip: "The length of time (in days) that enterprises who are set up as shops can run as a trial period."
- fixed_monthly_charge: "Fixed Monthly Charge"
- fixed_monthly_charge_tip: "A fixed monthly charge for all enterprises who are set up as a shop and have exceeded the minimum billable turnover (if set)."
- percentage_of_turnover: "Percentage of turnover"
- percentage_of_turnover_tip: "When greater than zero, this rate (0.0 - 1.0) will be applied to the total turnover of each shop and added to any fixed charges (to the left) to calculate the monthly bill."
- monthly_cap_excl_tax: "monthly cap (excl. GST)"
- monthly_cap_excl_tax_tip: "When greater than zero, this value will be used as a cap on the amount that shops will be charged each month."
- tax_rate: "Tax Rate"
- tax_rate_tip: "Tax rate that applies to the the monthly bill that enterprises are charged for using the system."
- minimum_monthly_billable_turnover: "Minimum Monthly Billable Turnover"
- minimum_monthly_billable_turnover_tip: "Minimum monthly turnover before a shopfront will be charged for using OFN. Enterprises turning over less than this amount in a month will not be charged, either as a percentage or fixed rate."
- example_bill_calculator: "Example Bill Calculator"
- example_bill_calculator_legend: "Alter the example turnover to visualise the effect of the settings to the left."
- example_monthly_turnover: "Example Monthly Turnover"
- example_monthly_turnover_tip: "An example monthly turnover for an enterprise which will be used to generate calculate an example monthly bill below."
- cap_reached?: "Cap Reached ?"
- cap_reached?_tip: "Whether the cap (specified to the left) has been reached, given the settings and the turnover provided."
- included_tax: "Included tax"
- included_tax_tip: "The total tax included in the example monthly bill, given the settings and the turnover provided."
- total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)"
- total_monthly_bill_incl_tax_tip: "The example total monthly bill with tax included, given the settings and the turnover provided."
-
cache_settings:
- show:
- title: Caching
- distributor: Distributor
- order_cycle: Order Cycle
- status: Status
- diff: Diff
- error: Error
+ edit:
+ title: "Caching"
+ distributor: "Distributor"
+ order_cycle: "Order Cycle"
+ status: "Status"
+ diff: "Diff"
+ error: "Error"
+ enable_products_cache: "Enable Products Cache?"
invoice_settings:
edit:
@@ -1818,10 +1761,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
products_distributor_info: When you select a distributor for your order, their address and pickup times will be displayed here.
products_distribution_adjustment_label: "Product distribution by %{distributor} for %{product}"
- shop_trial_expires_in: "Your shopfront trial expires in"
- shop_trial_expired_notice: "Good news! We have decided to extend shopfront trials until further notice."
-
-
# keys used in javascript
password: Password
remember_me: Remember Me
@@ -1871,24 +1810,60 @@ See the %{link} to find out more about %{sitename}'s features and to start using
choose_password: "Choose a password"
confirm_password: "Confirm password"
action_signup: "Sign up now"
- welcome_to_ofn: "Welcome to the Open Food Network!"
- signup_or_login: "Start By Signing Up (or logging in)"
- have_an_account: "Already have an account?"
- action_login: "Log in now."
forgot_password: "Forgot Password?"
password_reset_sent: "An email with instructions on resetting your password has been sent!"
reset_password: "Reset password"
- registration_greeting: "Greetings!"
- who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?"
update_and_recalculate_fees: "Update And Recalculate Fees"
registration:
steps:
- images:
- continue: "Continue"
- back: "Back"
- headline: "Thanks!"
- description: "Let's upload some pretty pictures so your profile looks great! :)"
+ introduction:
+ registration_greeting: "Hi there!"
+ registration_intro: "You can now create a profile for your Producer or Hub"
+ registration_checklist: "You'll need"
+ registration_time: "5-10 minutes"
+ registration_enterprise_address: "Enterprise address"
+ registration_contact_details: "Primary contact details"
+ registration_logo: "Your logo image"
+ registration_promo_image: "Landscape image for your profile"
+ registration_about_us: "'About Us' text"
+ registration_outcome_headline: "What do I get?"
+ registration_outcome1_html: "Your profile helps people find and contact you on the Open Food Network."
+ registration_outcome2: "Use this space to tell the story of your enterprise, to help drive connections to your social and online presence."
+ registration_outcome3: "It's also the first step towards trading on the Open Food Network, or opening an online store."
+ registration_action: "Let's get started!"
+ details:
+ title: "Details"
+ headline: "Let's Get Started"
+ enterprise: "Woot! First need to know a little bit about your enterprise:"
+ producer: "Woot! First we need to know a little bit about your farm:"
+ enterprise_name_field: "Enterprise Name:"
+ producer_name_field: "Farm Name:"
+ producer_name_field_placeholder: "e.g. Charlie's Awesome Farm"
+ producer_name_field_error: "Please choose a unique name for your enterprise"
+ address1_field: "Address line 1:"
+ address1_field_placeholder: "e.g. 123 Cranberry Drive"
+ address1_field_error: "Please enter an address"
+ address2_field: "Address line 2:"
+ suburb_field: "Suburb:"
+ suburb_field_placeholder: "e.g. Northcote"
+ suburb_field_error: "Please enter a suburb"
+ postcode_field: "Postcode:"
+ postcode_field_placeholder: "e.g. 3070"
+ postcode_field_error: "Postcode required"
+ state_field: "State:"
+ state_field_error: "State required"
+ country_field: "Country:"
+ country_field_error: "Please select a country"
+ contact:
+ title: "Contact"
+ who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?"
+ contact_field: "Primary Contact"
+ contact_field_placeholder: "Contact Name"
+ contact_field_required: "You need to enter a primary contact."
+ phone_field: "Phone number"
+ phone_field_placeholder: "eg. (03) 1234 5678"
type:
+ title: "Type"
headline: "Last step to add %{enterprise}!"
question: "Are you a producer?"
yes_producer: "Yes, I'm a producer"
@@ -1897,164 +1872,76 @@ See the %{link} to find out more about %{sitename}'s features and to start using
yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
create_profile: "Create Profile"
- enterprise:
- registration:
- modal:
- steps:
- details:
- title: 'Details'
- headline: "Let's Get Started"
- enterprise: "Woot! First we need to know a little bit about your enterprise:"
- producer: "Woot! First we need to know a little bit about your farm:"
- enterprise_name_field: "Enterprise Name:"
- producer_name_field: "Farm Name:"
- producer_name_field_placeholder: "e.g. Charlie's Awesome Farm"
- producer_name_field_error: "Please choose a unique name for your enterprise"
- address1_field: "Address line 1:"
- address1_field_placeholder: "e.g. 123 Cranberry Drive"
- address1_field_error: "Please enter an address"
- address2_field: "Address line 2:"
- suburb_field: "Suburb:"
- suburb_field_placeholder: "e.g. Northcote"
- suburb_field_error: "Please enter a suburb"
- postcode_field: "Postcode:"
- postcode_field_placeholder: "e.g. 3070"
- postcode_field_error: "Postcode required"
- state_field: "State:"
- state_field_error: "State required"
- country_field: "Country:"
- country_field_error: "Please select a country"
- contact:
- title: 'Contact'
- contact_field: 'Primary Contact'
- contact_field_placeholder: 'Contact Name'
- contact_field_required: "You need to enter a primary contact."
- email_field: 'Email address'
- email_field_placeholder: 'eg. charlie@thefarm.com'
- phone_field: 'Phone number'
- phone_field_placeholder: 'eg. (03) 1234 5678'
- type:
- title: 'Type'
- about:
- title: 'About'
- images:
- title: 'Images'
- social:
- title: 'Social'
- # TODO: Remove these once the enterprise.registration.modal keys are translated
- enterprise_contact: "Primary Contact"
- enterprise_contact_placeholder: "Contact Name"
- enterprise_contact_required: "You need to enter a primary contact."
- enterprise_email_address: "Email address"
- enterprise_email_placeholder: "eg. charlie@thefarm.com"
- enterprise_phone: "Phone number"
- enterprise_phone_placeholder: "eg. (03) 1234 5678"
- # END
+ about:
+ title: "About"
+ headline: "Nice one!"
+ message: "Now let's flesh out the details about"
+ success: "Success! %{enterprise} added to the Open Food Network"
+ registration_exit_message: "If you exit this wizard at any stage, you can continue to create your profile by going to the admin interface."
+ enterprise_description: "Short Description"
+ enterprise_description_placeholder: "A short sentence describing your enterprise"
+ enterprise_long_desc: "Long Description"
+ enterprise_long_desc_placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words."
+ enterprise_long_desc_length: "%{num} characters / up to 600 recommended"
+ enterprise_abn: "ABN"
+ enterprise_abn_placeholder: "eg. 99 123 456 789"
+ enterprise_acn: "ACN"
+ enterprise_acn_placeholder: "eg. 123 456 789"
+ enterprise_tax_required: "You need to make a selection."
+ images:
+ title: "Images"
+ headline: "Thanks!"
+ description: "Let's upload some pretty pictures so your profile looks great! :)"
+ uploading: "Uploading..."
+ continue: "Continue"
+ back: "Back"
+ logo:
+ select_logo: "Step 1. Select Logo Image"
+ logo_tip: "Tip: Square images will work best, preferably at least 300×300px"
+ logo_label: "Choose a logo image"
+ logo_drag: "Drag and drop your logo here"
+ review_logo: "Step 2. Review Your Logo"
+ review_logo_tip: "Tip: for best results, your logo should fill the available space"
+ logo_placeholder: "Your logo will appear here for review once uploaded"
+ promo:
+ select_promo_image: "Step 3. Select Promo Image"
+ promo_image_tip: "Tip: Shown as a banner, preferred size is 1200×260px"
+ promo_image_label: "Choose a promo image"
+ promo_image_drag: "Drag and drop your promo here"
+ review_promo_image: "Step 4. Review Your Promo Banner"
+ review_promo_image_tip: "Tip: for best results, your promo image should fill the available space"
+ promo_image_placeholder: "Your logo will appear here for review once uploaded"
+ social:
+ title: "Social"
+ enterprise_final_step: "Final step!"
+ enterprise_social_text: "How can people find %{enterprise} online?"
+ website: "Website"
+ website_placeholder: "eg. openfoodnetwork.org.au"
+ facebook: "Facebook"
+ facebook_placeholder: "eg. www.facebook.com/PageNameHere"
+ linkedin: "LinkedIn"
+ linkedin_placeholder: "eg. www.linkedin.com/YourNameHere"
+ twitter: "Twitter"
+ twitter_placeholder: "eg. @twitter_handle"
+ instagram: "Instagram"
+ instagram_placeholder: "eg. @instagram_handle"
+ limit_reached:
+ headline: "Oh no!"
+ message: "You have reached the limit!"
+ text: "You have reached the limit for the number of enterprises you are allowed to own on the"
+ action: "Return to the homepage"
+ finished:
+ headline: "Finished!"
+ thanks: "Thanks for filling out the details for %{enterprise}."
+ login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
+ action: "Open Food Network home"
+
back: "Back"
continue: "Continue"
- limit_reached_headline: "Oh no!"
- limit_reached_message: "You have reached the limit!"
- limit_reached_text: "You have reached the limit for the number of enterprises you are allowed to own on the"
- limit_reached_action: "Return to the homepage"
- select_promo_image: "Step 3. Select Promo Image"
- promo_image_tip: "Tip: Shown as a banner, preferred size is 1200×260px"
- promo_image_label: "Choose a promo image"
action_or: "OR"
- promo_image_drag: "Drag and drop your promo here"
- review_promo_image: "Step 4. Review Your Promo Banner"
- review_promo_image_tip: "Tip: for best results, your promo image should fill the available space"
- promo_image_placeholder: "Your logo will appear here for review once uploaded"
- uploading: "Uploading..."
- select_logo: "Step 1. Select Logo Image"
- logo_tip: "Tip: Square images will work best, preferably at least 300×300px"
- logo_label: "Choose a logo image"
- logo_drag: "Drag and drop your logo here"
- review_logo: "Step 2. Review Your Logo"
- review_logo_tip: "Tip: for best results, your logo should fill the available space"
- logo_placeholder: "Your logo will appear here for review once uploaded"
- enterprise_about_headline: "Nice one!"
- enterprise_about_message: "Now let's flesh out the details about"
- enterprise_success: "Success! %{enterprise} added to the Open Food Network "
- enterprise_registration_exit_message: "If you exit this wizard at any stage, you can continue to create your profile by going to the admin interface."
- enterprise_description: "Short Description"
- enterprise_description_placeholder: "A short sentence describing your enterprise"
- enterprise_long_desc: "Long Description"
- enterprise_long_desc_placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words."
- enterprise_long_desc_length: "%{num} characters / up to 600 recommended"
- enterprise_abn: "ABN"
- enterprise_abn_placeholder: "eg. 99 123 456 789"
- enterprise_acn: "ACN"
- enterprise_acn_placeholder: "eg. 123 456 789"
- enterprise_tax_required: "You need to make a selection."
- enterprise_final_step: "Final step!"
- enterprise_social_text: "How can people find %{enterprise} online?"
- website: "Website"
- website_placeholder: "eg. openfoodnetwork.org.au"
- facebook: "Facebook"
- facebook_placeholder: "eg. www.facebook.com/PageNameHere"
- linkedin: "LinkedIn"
- linkedin_placeholder: "eg. www.linkedin.com/YourNameHere"
- twitter: "Twitter"
- twitter_placeholder: "eg. @twitter_handle"
- instagram: "Instagram"
- instagram_placeholder: "eg. @instagram_handle"
- registration_greeting: "Hi there!"
- registration_intro: "You can now create a profile for your Producer or Hub"
- registration_action: "Let's get started!"
- registration_checklist: "You'll need"
- registration_time: "5-10 minutes"
- registration_enterprise_address: "Enterprise address"
- registration_contact_details: "Primary contact details"
- registration_logo: "Your logo image"
- registration_promo_image: "Landscape image for your profile"
- registration_about_us: "'About Us' text"
- registration_outcome_headline: "What do I get?"
- registration_outcome1_html: "Your profile helps people find and contact you on the Open Food Network."
- registration_outcome2: "Use this space to tell the story of your enterprise, to help drive connections to your social and online presence. "
- registration_outcome3: "It's also the first step towards trading on the Open Food Network, or opening an online store."
- registration_finished_headline: "Finished!"
- registration_finished_thanks: "Thanks for filling out the details for %{enterprise}."
- registration_finished_login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
- registration_finished_action: "Open Food Network home"
- registration_contact_name: 'Contact Name'
+ enterprise_limit: Enterprise Limit
- # TODO: Remove these once the enterprise.registration.modal keys are translated
- registration_type_headline: "Last step to add %{enterprise}!"
- registration_type_question: "Are you a producer?"
- registration_type_producer: "Yes, I'm a producer"
- registration_type_no_producer: "No, I'm not a producer"
- registration_type_error: "Please choose one. Are you are producer?"
- registration_type_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
- registration_type_no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
- # END
-
-
- # TODO: Remove these once the enterprise.registration.modal keys are translated
- registration_detail_headline: "Let's Get Started"
- registration_detail_enterprise: "Woot! First we need to know a little bit about your enterprise:"
- registration_detail_producer: "Woot! First we need to know a little bit about your farm:"
- registration_detail_name_enterprise: "Enterprise Name:"
- registration_detail_name_producer: "Farm Name:"
- registration_detail_name_placeholder: "e.g. Charlie's Awesome Farm"
- registration_detail_name_error: "Please choose a unique name for your enterprise"
- registration_detail_address1: "Address line 1:"
- registration_detail_address1_placeholder: "e.g. 123 Cranberry Drive"
- registration_detail_address1_error: "Please enter an address"
- registration_detail_address2: "Address line 2:"
- registration_detail_suburb: "Suburb:"
- registration_detail_suburb_placeholder: "e.g. Northcote"
- registration_detail_suburb_error: "Please enter a suburb"
- registration_detail_postcode: "Postcode:"
- registration_detail_postcode_placeholder: "e.g. 3070"
- registration_detail_postcode_error: "Postcode required"
- registration_detail_state: "State:"
- registration_detail_state_error: "State required"
- registration_detail_country: "Country:"
- registration_detail_country_error: "Please select a country"
- # END
shipping_method_destroy_error: "That shipping method cannot be deleted as it is referenced by an order: %{number}."
- accounts_and_billing_task_already_running_error: "A task is already running, please wait until it has finished"
- accounts_and_billing_start_task_notice: "Task Queued"
fees: "Fees"
item_cost: "Item cost"
bulk: "Bulk"
@@ -2207,7 +2094,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
live: "live"
manage: "Manage"
resend: "Resend"
- trial: Trial
add_and_manage_products: "Add & manage products"
add_and_manage_order_cycles: "Add & manage order cycles"
manage_order_cycles: "Manage order cycles"
@@ -2240,7 +2126,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
hub_sidebar_at_least: "At least one hub must be selected"
hub_sidebar_blue: "blue"
hub_sidebar_red: "red"
- shop_trial_in_progress: "Your shopfront trial expires in %{days}."
report_customers_distributor: "Distributor"
report_customers_supplier: "Supplier"
report_customers_cycle: "Order Cycle"
@@ -2623,11 +2508,43 @@ See the %{link} to find out more about %{sitename}'s features and to start using
orders:
index:
per_page: "%{results} per page"
- view_file: View File
- compiling_invoices: Compiling Invoices
- bulk_invoice_created: Bulk Invoice created
- bulk_invoice_failed: Failed to create Bulk Invoice
- please_wait: Please wait until the PDF is ready before closing this modal.
+ view_file: "View File"
+ compiling_invoices: "Compiling Invoices"
+ bulk_invoice_created: "Bulk Invoice created"
+ bulk_invoice_failed: "Failed to create Bulk Invoice"
+ please_wait: "Please wait until the PDF is ready before closing this modal."
+ order_state:
+ address: "address"
+ adjustments: "adjustments"
+ awaiting_return: "awaiting return"
+ canceled: "cancelled"
+ cart: "cart"
+ complete: "complete"
+ confirm: "confirm"
+ delivery: "delivery"
+ paused: "paused"
+ payment: "payment"
+ pending: "pending"
+ resumed: "resumed"
+ returned: "returned"
+ skrill: "skrill"
+ shipment_states:
+ backorder: "backorder"
+ partial: "partial"
+ pending: "pending"
+ ready: "ready"
+ shipped: "shipped"
+ payment_states:
+ balance_due: "balance due"
+ completed: "completed"
+ checkout: "checkout"
+ credit_owed: "credit owed"
+ failed: "failed"
+ paid: "paid"
+ pending: "pending"
+ processing: "processing"
+ void: "void"
+ invalid: "invalid"
resend_user_email_confirmation:
resend: "Resend"
sending: "Resend..."
@@ -2701,6 +2618,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using
spree:
users:
order: "Order"
+ registration:
+ welcome_to_ofn: "Welcome to the Open Food Network!"
+ signup_or_login: "Start By Signing Up (or logging in)"
+ have_an_account: "Already have an account?"
+ action_login: "Log in now."
+
producers:
signup:
start_free_profile: "Start with a free profile, and expand when you're ready!"
@@ -2745,7 +2668,194 @@ See the %{link} to find out more about %{sitename}'s features and to start using
total_amount: "$$ SUM"
invalid_filter_parameters: "The filters you selected for this report are invalid."
+ order: "Order"
+ distribution: "Distribution"
+ order_details: "Order Details"
+ customer_details: "Customer Details"
+ adjustments: "Adjustments"
+ payments: "Payments"
+
+ payment: "Payment"
+ payment_method: "Payment Method"
+ shipment: "Shipment"
+ shipment_inc_vat: "Shipment including VAT"
+ shipping_tax_rate: "Shipping Tax Rate"
+ category: "Category"
+ delivery: "Delivery"
+ temperature_controlled: "Temperature Controlled"
+ new_product: "New Product"
+
+ administration: "Administration"
+ logged_in_as: "Logged in as"
+ account: "Account"
+ logout: "Logout"
+
+ date_range: "Date Range"
+ status: "status"
+ new: "New"
+ start: "Start"
+ stop: "Stop"
+ first: "First"
+ previous: "Previous"
+ last: "Last"
+
spree:
+ your_order_is_empty_add_product: "Your order is empty, please search for and add a product above"
+ add_product: "Add Product"
+ name_or_sku: "Name or SKU (enter at least first 4 characters of product name)"
+ resend: Resend
+ back_to_orders_list: Back To Orders List
+ select_stock: "Select stock"
+ location: "Location"
+ count_on_hand: "Count On Hand"
+ quantity: "Quantity"
+ package_from: "package from"
+ item_description: "Item Description"
+ price: "Price"
+ total: "Total"
+ edit: "Edit"
+ split: "Split"
+ delete: "Delete"
+ cannot_set_shipping_method_without_address: "Cannot set shipping method until customer details are provided."
+ no_tracking_present: "No tracking details provided."
+ order_total: "Order Total"
+ customer_details: "Customer Details"
+ customer_search: "Customer Search"
+ choose_a_customer: "Choose a customer"
+ account: "Account"
+ billing_address: "Billing Address"
+ shipping_address: "Shipping Address"
+ first_name: "First name"
+ last_name: "Last name"
+ street_address: "Street Address"
+ street_address_2: "Street Address (cont'd)"
+ city: "City"
+ zip: "Zip"
+ country: "Country"
+ state: "State"
+ phone: "Phone"
+ update: "Update"
+ use_billing_address: "Use Billing Address"
+ adjustments: "Adjustments"
+ continue: "Continue"
+ fill_in_customer_info: "Please fill in customer info"
+ new_payment: "New Payment"
+
+ configurations: "Configurations"
+ general_settings: "General Settings"
+ site_name: "Site Name"
+ site_url: "Site URL"
+ default_seo_title: "Default Seo Title"
+ default_meta_description: "Default Meta Description"
+ default_meta_keywords: "Default Meta Keywords"
+ security_settings: "Security Settings"
+ allow_ssl_in_development_and_test: "Allow SSL to be used when in development and test modes"
+ allow_ssl_in_production: "Allow SSL to be used in production mode"
+ allow_ssl_in_staging: "Allow SSL to be used in staging mode"
+ check_for_spree_alerts: "Check for Spree alerts"
+ currency_decimal_mark: "Currency decimal mark"
+ currency_settings: "Currency Settings"
+ currency_symbol_position: Put "currency symbol before or after dollar amount?"
+ currency_thousands_separator: "Currency thousands separator"
+ hide_cents: "Hide cents"
+ display_currency: "Display currency"
+ choose_currency: "Choose Currency"
+
+ mail_method_settings: "Mail Method Settings"
+ general: "General"
+ enable_mail_delivery: "Enable Mail Delivery"
+ send_mails_as: "Send Mails As"
+ smtp_send_all_emails_as_from_following_address: "Send all mails as from the following address."
+ send_copy_of_all_mails_to: "Send Copy of All Mails To"
+ smtp_send_copy_to_this_addresses: "Sends a copy of all outgoing mails to this address. For multiple addresses, separate with commas."
+ intercept_email_address: "Intercept Email Address"
+ intercept_email_instructions: "Override email recipient and replace with this address."
+ smtp: "SMTP"
+ smtp_domain: "SMTP Domain"
+ smtp_mail_host: "SMTP Mail Host"
+ smtp_port: "SMTP Port"
+ secure_connection_type: "Secure Connection Type"
+ smtp_authentication_type: "SMTP Authentication Type"
+ smtp_username: "SMTP Username"
+ smtp_password: "SMTP Password"
+
+ image_settings: "Image Settings"
+ image_settings_warning: "You will need to regenerate thumbnails if you update the paperclip styles. Use rake paperclip:refresh:thumbnails CLASS=Spree::Image to do this."
+ attachment_default_style: Attachments Style
+ attachment_default_url: "Attachments Default URL"
+ attachment_path: "Attachments Path"
+ attachment_styles: "Paperclip Styles"
+ attachment_url: "Attachments URL"
+ add_new_style: "Add New Style"
+ image_settings_updated: "Image Settings successfully updated."
+
+ tax_categories: "Tax Categories"
+ listing_tax_categories: "Listing Tax Categories"
+ back_to_tax_categories_list: "Back To Tax Categories List"
+
+ tax rate: "Tax Rates"
+ new_tax_rate: "New Tax Rate"
+ tax_category: "Tax Category"
+ rate: "Rate"
+ tax_rate_amount_explanation: "Tax rates are a decimal amount to aid in calculations, (i.e. if the tax rate is 5% then enter 0.05)"
+ included_in_price: "Included in Price"
+ show_rate_in_label: "Show rate in label"
+ back_to_tax_rates_list: "Back to Tax Rates List"
+
+ tax_settings: "Tax Settings"
+ zones: "Zones"
+ new_zone: "New Zone"
+ default_tax: "Default Tax"
+ default_tax_zone: "Default Tax Zone"
+ country_based: "Country Based"
+ state_based: "State Based"
+
+ countries: "Countries"
+ listing_countries: "Listing Countries"
+ iso_name: "ISO Name"
+ states_required: "States Required"
+ editing_country: "Editing Country"
+ back_to_countries_list: "Back to Countries List"
+
+ states: "States"
+ abbreviation: "Abbreviation"
+ new_state: "New State"
+
+ payment_methods: "Payment Methods"
+ new_payment_method: "New Payment Method"
+ provider: "Provider"
+
+ taxonomies: "Taxonomies"
+ new_taxonomy: "New Taxonomy"
+ back_to_taxonomies_list: "Back to Taxonomies List"
+
+ shipping_methods: "Shipping Methods"
+
+ shipping_categories: "Shipping Categories"
+ new_shipping_category: "NEWEW Shipping Categories"
+ back_to_shipping_categories: "Back To Shipping Categories"
+
+ analytics_trackers: "Analytics Trackers"
+ no_trackers_found: "No Trackers Found"
+ new_tracker: "New Tracker"
+ add_one: "Add One"
+ google_analytics_id: "Analytics ID"
+ back_to_trackers_list: "Back to Trackers List"
+
+ name: "Name"
+ description: "Description"
+ type: "Type"
+ default: "default"
+ calculator: "Calculator"
+ zone: "Zone"
+ display: "Display"
+ environment: "Environment"
+ active: "Active"
+ nore: "More"
+ no_results: "No results"
+ create: "Create"
+ loading: "Loading"
+
# TODO: remove `email` key once we get to Spree 2.0
email: Email
# TODO: remove 'account_updated' key once we get to Spree 2.0
@@ -2754,6 +2864,12 @@ See the %{link} to find out more about %{sitename}'s features and to start using
date: "Date"
time: "Time"
inventory_error_flash_for_insufficient_quantity: "An item in your cart has become unavailable."
+ inventory: Inventory
+ zipcode: Postcode
+ weight: Weight (per kg)
+
+ actions:
+ update: "Update"
errors:
messages:
blank: "can't be blank"
@@ -2801,15 +2917,22 @@ See the %{link} to find out more about %{sitename}'s features and to start using
results_found: "%{number} Results found."
viewing: "Viewing %{start} to %{end}."
print_invoices: "Print Invoices"
+ sortable_header:
+ payment_state: "Payment State"
+ shipment_state: "Shipment State"
+ completed_at: "Completed At"
+ number: "Number"
+ state: "State"
+ email: "Customer E-Mail"
invoice:
- issued_on: Issued on
- tax_invoice: TAX INVOICE
- code: Code
- from: From
- to: To
+ issued_on: "Issued on"
+ tax_invoice: "TAX INVOICE"
+ code: "Code"
+ from: "From"
+ to: "To"
form:
distribution_fields:
- title: Distribution
+ title: "Distribution"
distributor: "Distributor:"
order_cycle: "Order cycle:"
overview:
@@ -2826,6 +2949,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using
one: "You have one active order cycle."
other: "You have %{count} active order cycles."
manage_order_cycles: "MANAGE ORDER CYCLES"
+ shipping_methods:
+ edit:
+ editing_shipping_method: "Editing Shipping Method"
payment_methods:
new:
new_payment_method: "New Payment Method"
@@ -2942,8 +3068,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
date_picker:
format: ! '%Y-%m-%d'
js_format: 'yy-mm-dd'
- inventory: Inventory
- zipcode: Postcode
orders:
edit:
login_to_view_order: "Please log in to view your order."
@@ -2994,23 +3118,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
ended: ended
paused: paused
canceled: cancelled
- payment_states:
- balance_due: balance due
- completed: completed
- checkout: checkout
- credit_owed: credit owed
- failed: failed
- paid: paid
- pending: pending
- processing: processing
- void: void
- invalid: invalid
- shipment_states:
- backorder: backorder
- partial: partial
- pending: pending
- ready: ready
- shipped: shipped
user_mailer:
reset_password_instructions:
request_sent_text: |
@@ -3023,8 +3130,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using
If you continue to have problems please feel free to contact us.
confirmation_instructions:
subject: Please confirm your OFN account
- weight: Weight (per kg)
- zipcode: Postcode
users:
form:
account_settings: Account Settings
diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml
new file mode 100644
index 0000000000..2055b84403
--- /dev/null
+++ b/config/locales/en_CA.yml
@@ -0,0 +1,2860 @@
+en_CA:
+ language_name: "English"
+ activerecord:
+ attributes:
+ spree/order:
+ payment_state: Payment State
+ shipment_state: Shipment State
+ completed_at: Completed At
+ number: Number
+ state: State
+ email: Customer E-Mail
+ spree/payment:
+ amount: Amount
+ order_cycle:
+ orders_close_at: Close date
+ errors:
+ models:
+ spree/user:
+ attributes:
+ email:
+ taken: "There's already an account for this email. Please login or reset your password."
+ spree/order:
+ no_card: There are no authorised credit cards available to charge
+ order_cycle:
+ attributes:
+ orders_close_at:
+ after_orders_open_at: must be after open date
+ variant_override:
+ count_on_hand:
+ using_producer_stock_settings_but_count_on_hand_set: "must be blank because you are using producer stock settings"
+ on_demand_but_count_on_hand_set: "must be blank if 'on demand' is used"
+ limited_stock_but_no_count_on_hand: "must be specified because you are forcing limited stock"
+ activemodel:
+ attributes:
+ order_management/reports/enterprise_fee_summary/parameters:
+ start_at: "Start"
+ end_at: "End"
+ distributor_ids: "Hubs"
+ producer_ids: "Producers"
+ order_cycle_ids: "Order Cycles"
+ enterprise_fee_ids: "Names for Fees"
+ shipping_method_ids: "Shipping Methods"
+ payment_method_ids: "Payment Methods"
+ errors:
+ models:
+ subscription_validator:
+ attributes:
+ subscription_line_items:
+ at_least_one_product: "^Please add at least one product"
+ not_available: "^%{name} is not available from the selected schedule"
+ ends_at:
+ after_begins_at: "must be after begins at"
+ customer:
+ does_not_belong_to_shop: "does not belong to %{shop}"
+ schedule:
+ not_coordinated_by_shop: "is not coordinated by %{shop}"
+ payment_method:
+ not_available_to_shop: "is not available to %{shop}"
+ invalid_type: "must be a Cash or Stripe method"
+ charges_not_allowed: "^Credit card charges are not allowed by this customer"
+ no_default_card: "^No default card available for this customer"
+ shipping_method:
+ not_available_to_shop: "is not available to %{shop}"
+ devise:
+ confirmations:
+ send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes."
+ failed_to_send: "An error occurred whilst sending your confirmation email."
+ resend_confirmation_email: "Resend confirmation email."
+ confirmed: "Thanks for confirming your email! You can now log in."
+ not_confirmed: "Your email address could not be confirmed. Perhaps you have already completed this step?"
+ user_registrations:
+ spree_user:
+ signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please open the link to activate your account."
+ unknown_error: "Something went wrong while creating your account. Check your email address and try again."
+ failure:
+ invalid: |
+ Invalid email or password.
+ Were you a guest last time? Perhaps you need to create an account or reset your password.
+ unconfirmed: "You have to confirm your account before continuing."
+ already_registered: "This email address is already registered. Please log in to continue, or go back and use another email address."
+ user_passwords:
+ spree_user:
+ updated_not_active: "Your password has been reset, but your email has not been confirmed yet."
+ models:
+ order_cycle:
+ cloned_order_cycle_name: "COPY OF%{order_cycle}"
+ validators:
+ date_time_string_validator:
+ not_string_error: "must be a string"
+ invalid_format_error: "must be valid"
+ integer_array_validator:
+ not_array_error: "must be an array"
+ invalid_element_error: "must contain only valid integers"
+ enterprise_mailer:
+ confirmation_instructions:
+ subject: "Please confirm the email address for %{enterprise}"
+ welcome:
+ subject: "%{enterprise} is now on %{sitename}"
+ invite_manager:
+ subject: "%{enterprise} has invited you to be a manager"
+ order_mailer:
+ cancel_email:
+ dear_customer: "Dear Customer, "
+ instructions: "Your order has been CANCELED. Please retain this cancellation information for your records. "
+ order_summary_canceled: "Order Summary [CANCELED]"
+ subject: "Cancellation of Order"
+ subtotal: "Subtotal: %{subtotal}"
+ total: "Order Total: %{total}"
+ producer_mailer:
+ order_cycle:
+ subject: "Order cycle report for %{producer}"
+ shipment_mailer:
+ shipped_email:
+ dear_customer: "Dear Customer, "
+ instructions: "Your order has been shipped"
+ shipment_summary: "Shipment Summary"
+ subject: "Shipment Notification"
+ thanks: "Thank you for your business."
+ track_information: "Tracking Information: %{tracking}"
+ track_link: "Tracking Link: %{url}"
+ subscription_mailer:
+ placement_summary_email:
+ subject: A summary of recently placed subscription orders
+ greeting: "Hi %{name},"
+ intro: "Below is a summary of the subscription orders that have just been placed for %{shop}."
+ confirmation_summary_email:
+ subject: A summary of recently confirmed subscription orders
+ greeting: "Hi %{name},"
+ intro: "Below is a summary of the subscription orders that have just been finalised for %{shop}."
+ summary_overview:
+ total: A total of %{count} subscriptions were marked for automatic processing.
+ success_zero: Of these, none were processed successfully.
+ success_some: Of these, %{count} were processed successfully.
+ success_all: All were processed successfully.
+ issues: Details of the issues encountered are provided below.
+ summary_detail:
+ no_message_provided: No error message provided
+ changes:
+ title: Insufficient Stock (%{count} orders)
+ explainer: These orders were processed but insufficient stock was available for some requested items
+ empty:
+ title: No Stock (%{count} orders)
+ explainer: These orders were unable to be processed because no stock was available for any requested items
+ complete:
+ title: Already Processed (%{count} orders)
+ explainer: These orders were already marked as complete, and were therefore left untouched
+ processing:
+ title: Error Encountered (%{count} orders)
+ explainer: Automatic processing of these orders failed due to an error. The error has been listed where possible.
+ failed_payment:
+ title: Failed Payment (%{count} orders)
+ explainer: Automatic processing of payment for these orders failed due to an error. The error has been listed where possible.
+ other:
+ title: Other Failure (%{count} orders)
+ explainer: Automatic processing of these orders failed for an unknown reason. This should not occur, please contact us if you are seeing this.
+ home: "OFN"
+ title: Open Food Network
+ welcome_to: 'Welcome to '
+ site_meta_description: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can…"
+ search_by_name: Search by name or suburb...
+ producers_join: Australian producers are now welcome to join the Open Food Network.
+ charges_sales_tax: Charges GST?
+ print_invoice: "Print Invoice"
+ print_ticket: "Print Ticket"
+ select_ticket_printer: "Select printer for tickets"
+ send_invoice: "Send Invoice"
+ resend_confirmation: "Resend Confirmation"
+ view_order: "View Order"
+ edit_order: "Edit Order"
+ ship_order: "Ship Order"
+ 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 ABN before invoices can be sent."
+ invoice: "Invoice"
+ percentage_of_sales: "%{percentage} of sales"
+ capped_at_cap: "capped at %{cap}"
+ per_month: "per month"
+ free: "free"
+ free_trial: "free trial"
+ plus_tax: "plus GST"
+ min_bill_turnover_desc: "once turnover exceeds %{mbt_amount}"
+ more: "More"
+ say_no: "No"
+ say_yes: "Yes"
+ then: then
+ ongoing: Ongoing
+ bill_address: Billing Address
+ ship_address: Shipping Address
+ sort_order_cycles_on_shopfront_by: "Sort Order Cycles On Shopfront By"
+ required_fields: Required fields are denoted with an asterisk
+ select_continue: Select and Continue
+ remove: Remove
+ or: or
+ collapse_all: Collapse all
+ expand_all: Expand all
+ loading: Loading...
+ show_more: Show more
+ show_all: Show all
+ show_all_with_more: "Show All (%{num} More)"
+ cancel: Cancel
+ edit: Edit
+ clone: Clone
+ distributors: Distributors
+ distribution: Distribution
+ bulk_order_management: Bulk Order Management
+ enterprises: Enterprises
+ enterprise_groups: Groups
+ reports: Reports
+ variant_overrides: Inventory
+ spree_products: Spree Products
+ all: All
+ current: Current
+ available: Available
+ dashboard: Dashboard
+ undefined: undefined
+ unused: unused
+ admin_and_handling: Admin & Handling
+ profile: Profile
+ supplier_only: Supplier Only
+ has_shopfront: Has Shopfront
+ weight: Weight
+ volume: Volume
+ items: Items
+ summary: Summary
+ detailed: Detailed
+ updated: Updated
+ 'yes': "Yes"
+ 'no': "No"
+ y: 'Y'
+ n: 'N'
+ powered_by: Powered by
+ blocked_cookies_alert: "Your browser may be blocking cookies needed to use this shopfront. Click below to allow cookies and reload the page."
+ allow_cookies: "Allow Cookies"
+ notes: Notes
+ error: Error
+ processing_payment: Processing payment...
+ show_only_unfulfilled_orders: Show only unfulfilled orders
+ filter_results: Filter Results
+ quantity: Quantity
+ pick_up: Pick up
+ copy: Copy
+ password_confirmation: Password Confirmation
+ reset_password_token: Reset password token
+ expired: has expired, please request a new one
+ back_to_payments_list: "Back to Payments List"
+ actions:
+ create_and_add_another: "Create and Add Another"
+ admin:
+ begins_at: Begins At
+ begins_on: Begins On
+ customer: Customer
+ date: Date
+ email: Email
+ ends_at: Ends At
+ ends_on: Ends On
+ name: Name
+ on_hand: On Hand
+ on_demand: On Demand
+ on_demand?: On Demand?
+ order_cycle: Order Cycle
+ payment: Payment
+ payment_method: Payment Method
+ phone: Phone
+ price: Price
+ producer: Producer
+ image: Image
+ product: Product
+ quantity: Quantity
+ schedule: Schedule
+ shipping: Shipping
+ shipping_method: Shipping Method
+ shop: Shop
+ sku: SKU
+ status_state: State
+ tags: Tags
+ variant: Variant
+ weight: Weight
+ volume: Volume
+ items: Items
+ select_all: Select all
+ obsolete_master: Obsolete master
+ quick_search: Quick Search
+ clear_all: Clear All
+ start_date: "Start Date"
+ end_date: "End Date"
+ form_invalid: "Form contains missing or invalid fields"
+ clear_filters: Clear Filters
+ clear: Clear
+ save: Save
+ cancel: Cancel
+ back: Back
+ show_more: Show more
+ show_n_more: Show %{num} more
+ choose: "Choose..."
+ please_select: Please select...
+ columns: Columns
+ actions: Actions
+ viewing: "Viewing: %{current_view_name}"
+ description: Description
+ whats_this: What's this?
+ tag_has_rules: "Existing rules for this tag: %{num}"
+ has_one_rule: "has one rule"
+ has_n_rules: "has %{num} rules"
+ unsaved_confirm_leave: "There are unsaved changed on this page. Continue without saving?"
+ unsaved_changes: "You have unsaved changes"
+ accounts_and_billing_settings:
+ method_settings:
+ default_accounts_payment_method: "Default Accounts Payment Method"
+ default_accounts_shipping_method: "Default Accounts Shipping Method"
+ edit:
+ accounts_and_billing: "Accounts & Billing"
+ accounts_administration_distributor: "Accounts Administration Distributor"
+ admin_settings: "Settings"
+ update_invoice: "Update Invoices"
+ auto_update_invoices: "Auto-update invoices nightly at 1:00am"
+ finalise_invoice: "Finalise Invoices"
+ auto_finalise_invoices: "Auto-finalise invoices monthly on the 2nd at 1:30am"
+ manually_run_task: "Manually Run Task "
+ update_user_invoice_explained: "Use this button to immediately update invoices for the month to date for each enterprise user in the system. This task can be set up to run automatically every night."
+ finalise_user_invoices: "Finalise User Invoices"
+ finalise_user_invoice_explained: "Use this button to finalize all invoices in the system for the previous calendar month. This task can be set up to run automatically once a month."
+ update_user_invoices: "Update User Invoices"
+ errors:
+ accounts_distributor: must be set if you wish to create invoices for enterprise users.
+ default_payment_method: must be set if you wish to create invoices for enterprise users.
+ default_shipping_method: must be set if you wish to create invoices for enterprise users.
+ shopfront_settings:
+ embedded_shopfront_settings: "Embedded Shopfront Settings"
+ enable_embedded_shopfronts: "Enable Embedded Shopfronts"
+ embedded_shopfronts_whitelist: "External Domains Whitelist"
+ number_localization:
+ number_localization_settings: "Number Localization Settings"
+ enable_localized_number: "Use the international thousand/decimal separator logic"
+ business_model_configuration:
+ edit:
+ business_model_configuration: "Business Model"
+ business_model_configuration_tip: "Configure the rate at which shops will be charged each month for use of the Open Food Network."
+ bill_calculation_settings: "Bill Calculation Settings"
+ bill_calculation_settings_tip: "Adjust the amount that enterprises will be billed each month for use of the OFN."
+ shop_trial_length: "Shop Trial Length (Days)"
+ shop_trial_length_tip: "The length of time (in days) that enterprises who are set up as shops can run as a trial period."
+ fixed_monthly_charge: "Fixed Monthly Charge"
+ fixed_monthly_charge_tip: "A fixed monthly charge for all enterprises who are set up as a shop and have exceeded the minimum billable turnover (if set)."
+ percentage_of_turnover: "Percentage of turnover"
+ percentage_of_turnover_tip: "When greater than zero, this rate (0.0 - 1.0) will be applied to the total turnover of each shop and added to any fixed charges (to the left) to calculate the monthly bill."
+ monthly_cap_excl_tax: "monthly cap (excl. GST)"
+ monthly_cap_excl_tax_tip: "When greater than zero, this value will be used as a cap on the amount that shops will be charged each month."
+ tax_rate: "Tax Rate"
+ tax_rate_tip: "Tax rate that applies to the the monthly bill that enterprises are charged for using the system."
+ minimum_monthly_billable_turnover: "Minimum Monthly Billable Turnover"
+ minimum_monthly_billable_turnover_tip: "Minimum monthly turnover before a shopfront will be charged for using OFN. Enterprises turning over less than this amount in a month will not be charged, either as a percentage or fixed rate."
+ example_bill_calculator: "Example Bill Calculator"
+ example_bill_calculator_legend: "Alter the example turnover to visualise the effect of the settings to the left."
+ example_monthly_turnover: "Example Monthly Turnover"
+ example_monthly_turnover_tip: "An example monthly turnover for an enterprise which will be used to generate calculate an example monthly bill below."
+ cap_reached?: "Cap Reached ?"
+ cap_reached?_tip: "Whether the cap (specified to the left) has been reached, given the settings and the turnover provided."
+ included_tax: "Included tax"
+ included_tax_tip: "The total tax included in the example monthly bill, given the settings and the turnover provided."
+ total_monthly_bill_incl_tax: "Total Monthly Bill (Incl. Tax)"
+ total_monthly_bill_incl_tax_tip: "The example total monthly bill with tax included, given the settings and the turnover provided."
+ cache_settings:
+ show:
+ title: Caching
+ distributor: Distributor
+ order_cycle: Order Cycle
+ status: Status
+ diff: Diff
+ error: Error
+ invoice_settings:
+ edit:
+ title: Invoice Settings
+ invoice_style2?: Use the alternative invoice model that includes total tax breakdown per rate and tax rate info per item (not yet suitable for countries displaying prices excluding tax)
+ enable_receipt_printing?: Show options for printing receipts using thermal printers in order dropdown?
+ stripe_connect_settings:
+ edit:
+ title: "Stripe Connect"
+ settings: "Settings"
+ stripe_connect_enabled: Enable shops to accept payments using Stripe Connect?
+ no_api_key_msg: No Stripe account exists for this enterprise.
+ configuration_explanation_html: For detailed instructions on configuring the Stripe Connect integration, please consult this guide.
+ status: Status
+ ok: Ok
+ instance_secret_key: Instance Secret Key
+ account_id: Account ID
+ business_name: Business Name
+ charges_enabled: Charges Enabled
+ charges_enabled_warning: "Warning: Charges are not enabled for your account"
+ auth_fail_error: The API key you provided is invalid
+ empty_api_key_error_html: No Stripe API key has been provided. To set your API key, please follow these instructions
+ matomo_settings:
+ edit:
+ title: "Matomo Settings"
+ matomo_url: "Matomo URL"
+ matomo_site_id: "Matomo Site ID"
+ info_html: "Matomo is a Web and Mobile Analytics. You can either host Matomo on-premises or use a cloud-hosted service. See matomo.org for more information."
+ config_instructions_html: "Here you can configure the OFN Matomo integration. The Matomo URL below should point to the Matomo instance where the user tracking information will be sent to; if it is left empty, Matomo user tracking will be disabled. The Site ID field is not mandatory but useful if you are tracking more than one website on a single Matomo instance; it can be found on the Matomo instance console."
+ customers:
+ index:
+ add_customer: "Add Customer"
+ new_customer: "New Customer"
+ customer_placeholder: "customer@example.org"
+ valid_email_error: Please enter a valid email address
+ add_a_new_customer_for: Add a new customer for %{shop_name}
+ code: Code
+ duplicate_code: "This code is used already."
+ bill_address: "Billing Address"
+ ship_address: "Shipping Address"
+ update_address_success: 'Address updated successfully.'
+ update_address_error: 'Sorry! Please input all of the required fields!'
+ edit_bill_address: 'Edit Billing Address'
+ edit_ship_address: 'Edit Shipping Address'
+ required_fileds: 'Required fields are denoted with an asterisk '
+ select_country: 'Select Country'
+ select_state: 'Select State'
+ edit: 'Edit'
+ update_address: 'Update Address'
+ confirm_delete: 'Sure to delete?'
+ search_by_email: "Search by email/code..."
+ guest_label: 'Guest checkout'
+ destroy:
+ has_associated_orders: 'Delete failed: customer has associated orders with his shop'
+ contents:
+ edit:
+ title: Content
+ header: Header
+ home_page: Home page
+ producer_signup_page: Producer signup page
+ hub_signup_page: Hub signup page
+ group_signup_page: Group signup page
+ main_links: Main Menu Links
+ footer_and_external_links: Footer and External Links
+ your_content: Your content
+ user_guide: User Guide
+ enterprise_fees:
+ index:
+ title: Enterprise Fees
+ enterprise: Enterprise
+ fee_type: Fee Type
+ name: Name
+ tax_category: Tax Category
+ calculator: Calculator
+ calculator_values: Calculator Values
+ enterprise_groups:
+ index:
+ new_button: New Enterprise Group
+ enterprise_roles:
+ form:
+ manages: manages
+ enterprise_role:
+ manages: manages
+ products:
+ unit_name_placeholder: 'eg. bunches'
+ index:
+ unit: Unit
+ display_as: Display As
+ category: Category
+ tax_category: Tax Category
+ inherits_properties?: Inherits Properties?
+ available_on: Available On
+ av_on: "Av. On"
+ import_date: Imported
+ upload_an_image: Upload an image
+ product_search_keywords: Product Search Keywords
+ product_search_tip: Type words to help search your products in the shops. Use space to separate each keyword.
+ SEO_keywords: SEO Keywords
+ seo_tip: Type words to help search your products in the web. Use space to separate each keyword.
+ Search: Search
+ properties:
+ property_name: Property Name
+ inherited_property: Inherited Property
+ variants:
+ to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order."
+ product_distributions: "Product Distributions"
+ group_buy_options: "Group Buy Options"
+ back_to_products_list: "Back to products list"
+ product_import:
+ title: Product Import
+ file_not_found: File not found or could not be opened
+ no_data: No data found in spreadsheet
+ confirm_reset: "This will set stock level to zero on all products for this \n enterprise that are not present in the uploaded file"
+ model:
+ no_file: "error: no file uploaded"
+ could_not_process: "could not process file: invalid filetype"
+ incorrect_value: incorrect value
+ conditional_blank: can't be blank if unit_type is blank
+ no_product: did not match any products in the database
+ not_found: not found in database
+ not_updatable: cannot be updated on existing products via product import
+ blank: can't be blank
+ products_no_permission: you do not have permission to manage products for this enterprise
+ inventory_no_permission: you do not have permission to create inventory for this producer
+ none_saved: did not save any products successfully
+ line_number: "Line %{number}:"
+ encoding_error: "Please check the language setting of your source file and ensure it is saved with UTF-8 encoding"
+ unexpected_error: "Product Import encountered an unexpected error whilst opening the file: %{error_message}"
+ index:
+ select_file: Select a spreadsheet to upload
+ spreadsheet: Spreadsheet
+ choose_import_type: Select import type
+ import_into: Import type
+ product_list: Product list
+ inventories: Inventories
+ import: Import
+ upload: Upload
+ csv_templates: CSV Templates
+ product_list_template: Download Product List template
+ inventory_template: Download Inventory template
+ category_values: Available Category Values
+ product_categories: Product Categories
+ tax_categories: Tax Categories
+ shipping_categories: Shipping Categories
+ import:
+ review: Review
+ import: Import
+ save: Save
+ results: Results
+ save_imported: Save imported products
+ no_valid_entries: No valid entries found
+ none_to_save: There are no entries that can be saved
+ some_invalid_entries: Imported file contains invalid entries
+ fix_before_import: Please fix these errors and try importing the file again
+ save_valid?: Save valid entries for now and discard the others?
+ no_errors: No errors detected!
+ save_all_imported?: Save all imported products?
+ options_and_defaults: Import options and defaults
+ no_permission: you do not have permission to manage this enterprise
+ not_found: enterprise could not be found in database
+ no_name: No name
+ blank_enterprise: some products do not have an enterprise associated
+ reset_absent?: Reset absent products
+ reset_absent_tip: Set stock to zero for all exiting products not present in the file
+ overwrite_all: Overwrite all
+ overwrite_empty: Overwrite if empty
+ default_stock: Set stock level
+ default_tax_cat: Set tax category
+ default_shipping_cat: Set shipping category
+ default_available_date: Set available date
+ validation_overview: Import validation overview
+ entries_found: Entries found in imported file
+ entries_with_errors: Items contain errors and will not be imported
+ products_to_create: Products will be created
+ products_to_update: Products will be updated
+ inventory_to_create: Inventory items will be created
+ inventory_to_update: Inventory items will be updated
+ products_to_reset: Existing products will have their stock reset to zero
+ inventory_to_reset: Existing inventory items will have their stock reset to zero
+ line: Line
+ item_line: Item line
+ import_review:
+ not_updatable_tip: "The following fields cannot be updated via bulk import for existing products:"
+ fields_ignored: These fields will be ignored when the imported products are saved.
+ entries_table:
+ not_updatable: This field is not updatable via bulk import for existing products
+ save_results:
+ final_results: Import final results
+ products_created: Products created
+ products_updated: Products updated
+ inventory_created: Inventory items created
+ inventory_updated: Inventory items updated
+ products_reset: Products had stock level reset to zero
+ inventory_reset: Inventory items had stock level reset to zero
+ all_saved: "All items saved successfully"
+ some_saved: "items saved successfully"
+ save_errors: Save errors
+ import_again: Upload Another File
+ view_products: Go To Products Page
+ view_inventory: Go To Inventory Page
+ variant_overrides:
+ loading_flash:
+ loading_inventory: LOADING INVENTORY
+ index:
+ title: Inventory
+ description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page
+ enable_reset?: Enable Stock Reset?
+ inherit?: Inherit?
+ add: Add
+ hide: Hide
+ import_date: Imported
+ select_a_shop: Select A Shop
+ review_now: Review Now
+ new_products_alert_message: There are %{new_product_count} new products available to add to your inventory.
+ currently_empty: Your inventory is currently empty
+ no_matching_products: No matching products found in your inventory
+ no_hidden_products: No products have been hidden from this inventory
+ no_matching_hidden_products: No hidden products match your search criteria
+ no_new_products: No new products are available to add to this inventory
+ no_matching_new_products: No new products match your search criteria
+ inventory_powertip: This is your inventory of products. To add products to your inventory, select 'New Products' from the Viewing dropdown.
+ hidden_powertip: These products have been hidden from your inventory and will not be available to add to your shop. You can click 'Add' to add a product to you inventory.
+ new_powertip: These products are available to be added to your inventory. Click 'Add' to add a product to your inventory, or 'Hide' to hide it from view. You can always change your mind later!
+ controls:
+ back_to_my_inventory: Back to my inventory
+ orders:
+ invoice_email_sent: 'Invoice email has been sent'
+ order_email_resent: 'Order email has been resent'
+ bulk_management:
+ tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required."
+ shared: "Shared Resource?"
+ order_no: "Order No."
+ order_date: "Completed at"
+ max: "Max"
+ product_unit: "Product: Unit"
+ weight_volume: "Weight/Volume"
+ ask: "Ask?"
+ page_title: "Bulk Order Management"
+ actions_delete: "Delete Selected"
+ loading: "Loading orders"
+ no_results: "No orders found."
+ group_buy_unit_size: "Group Buy Unit Size"
+ total_qtt_ordered: "Total Quantity Ordered"
+ max_qtt_ordered: "Max Quantity Ordered"
+ current_fulfilled_units: "Current Fulfilled Units"
+ max_fulfilled_units: "Max Fulfilled Units"
+ order_error: "Some errors must be resolved before you can update orders.\nAny fields with red borders contain errors."
+ variants_without_unit_value: "WARNING: Some variants do not have a unit value"
+ select_variant: "Select a variant"
+ enterprise:
+ select_outgoing_oc_products_from: Select outgoing OC products from
+ enterprises:
+ index:
+ title: Enterprises
+ new_enterprise: New Enterprise
+ producer?: "Producer?"
+ package: Package
+ status: Status
+ manage: Manage
+ form:
+ about_us:
+ desc_short: Short Description
+ desc_short_placeholder: Tell us about your enterprise in one or two sentences
+ desc_long: About Us
+ desc_long_placeholder: Tell customers about yourself. This information appears on your public profile.
+ business_details:
+ abn: Business number if available
+ abn_placeholder: Number will show on invoices
+ acn: Business Number if available
+ acn_placeholder: eg. 123 456 789
+ display_invoice_logo: Display logo in invoices
+ invoice_text: Add customized text at the end of invoices
+ contact:
+ name: Name
+ name_placeholder: eg. Gustav Plum
+ email_address: Public Email Address
+ email_address_placeholder: eg. inquiries@fresh-food.com
+ email_address_tip: "This email address will be displayed in your public profile"
+ phone: Phone
+ phone_placeholder: eg. 98 7654 3210
+ website: Website
+ website_placeholder: eg. www.truffles.com
+ enterprise_fees:
+ name: Name
+ fee_type: Fee Type
+ manage_fees: Manage Enterprise Fees
+ no_fees_yet: You don't have any enterprise fees yet.
+ create_button: Create One Now
+ images:
+ logo: Logo
+ promo_image_placeholder: 'This image is displayed in "About Us"'
+ promo_image_note1: 'PLEASE NOTE:'
+ promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
+ promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
+ inventory_settings:
+ text1: You may opt to manage stock levels and prices in via your
+ inventory: inventory
+ text2: >
+ If you are using the inventory tool, you can select whether new products
+ added by your suppliers need to be added to your inventory before they
+ can be stocked. If you are not using your inventory to manage your products
+ you should select the 'recommended' option below:
+ preferred_product_selection_from_inventory_only_yes: New products can be put into my shopfront (recommended)
+ preferred_product_selection_from_inventory_only_no: New products must be added to my inventory before they can be put into my shopfront
+ payment_methods:
+ name: Name
+ applies: Applies?
+ manage: Manage Payment Methods
+ not_method_yet: You don't have any payment methods yet.
+ create_button: Create New Payment Method
+ create_one_button: Create One Now
+ primary_details:
+ name: Name
+ name_placeholder: eg. Professor Plum's Biodynamic Truffles
+ groups: Groups
+ groups_tip: Select any groups or regions that you are a member of. This will help customers find your enterprise.
+ groups_placeholder: Start typing to search available groups...
+ primary_producer: Primary Producer?
+ primary_producer_tip: Select 'Producer' if you are a primary producer of food.
+ producer: Producer
+ any: Any
+ none: None
+ own: Own
+ sells: Sells
+ sells_tip: "None - enterprise does not sell to customers directly. Own - Enterprise sells own products to customers. Any - Enterprise can sell own or other enterprises products. "
+ visible_in_search: Visible in search?
+ visible_in_search_tip: Determines whether this enterprise will be visible to customers when searching the site.
+ visible: Visible
+ not_visible: Not visible
+ permalink: Permalink (no spaces)
+ permalink_tip: "This permalink is used to create the url to your shop: %{link}your-shop-name/shop"
+ link_to_front: Link to shop front
+ link_to_front_tip: A direct link to your shopfront on the Open Food Network.
+ shipping_methods:
+ name: Name
+ applies: Applies?
+ manage: Manage Shipping Methods
+ create_button: Create New Shipping Method
+ create_one_button: Create One Now
+ no_method_yet: You don't have any shipping methods yet.
+ shop_preferences:
+ shopfront_requires_login: "Publicly visible shopfront?"
+ shopfront_requires_login_tip: "Choose whether customers must login to view the shopfront or if it's visible to everybody."
+ shopfront_requires_login_false: "Public"
+ shopfront_requires_login_true: "Visible to registered customers only"
+ recommend_require_login: "We recommend to require users to login when orders can be changed."
+ allow_guest_orders: "Guest orders"
+ allow_guest_orders_tip: "Allow checkout as guest or require a registered user."
+ allow_guest_orders_false: "Require login to order"
+ allow_guest_orders_true: "Allow guest checkout"
+ allow_order_changes: "Change orders"
+ allow_order_changes_tip: "Allow customers to change their order as long the order cycle is open."
+ allow_order_changes_false: "Placed orders cannot be changed / cancelled"
+ allow_order_changes_true: "Customers can change / cancel orders while order cycle is open"
+ enable_subscriptions: "Subscriptions"
+ enable_subscriptions_tip: "Enable subscriptions functionality?"
+ enable_subscriptions_false: "Disabled"
+ enable_subscriptions_true: "Enabled"
+ shopfront_message: Shopfront Message
+ shopfront_message_placeholder: >
+ An optional explanation for customers detailing how your shopfront works,
+ to be displayed above the product list on your shop page.
+ shopfront_closed_message: Shopfront Closed Message
+ shopfront_closed_message_placeholder: >
+ A message which provides a more detailed explanation about why your
+ shop is closed and/or when customers can expect it to open again. This
+ is displayed on your shop only when you have no active order cycles
+ (ie. shop is closed).
+ shopfront_category_ordering: Shopfront Category Ordering
+ open_date: Open Date
+ close_date: Close Date
+ social:
+ twitter_placeholder: eg. @the_prof
+ instagram_placeholder: eg. www.instagram.com/YourAccountHere
+ facebook_placeholder: eg. www.facebook.com/PageNameHere
+ linkedin_placeholder: eg. www.linkedin.com/in/YourNameHere
+ stripe_connect:
+ connect_with_stripe: "Connect with Stripe"
+ stripe_connect_intro: "To accept payments using credit card, you will need to connect your stripe account to the Open Food Network. Use the button to the right to get started."
+ stripe_account_connected: "Stripe account connected."
+ disconnect: "Disconnect account"
+ confirm_modal:
+ title: Connect with Stripe
+ part1: Stripe is a payment processing service that allows shops on the OFN to accept credit card payments from customers.
+ part2: To use this feature, you must connect your Stripe account to the OFN. Clicking 'I Agree' below will redirect to you the Stripe website where you can connect an existing Stripe account, or create a new one if you don't already have one.
+ part3: This will allow the Open Food Network to accept credit card payments from customers on your behalf. Please note that you will need to maintain your own Stripe account, pay the fees Stripe charges and handle any chargebacks and customer service yourself.
+ i_agree: I Agree
+ cancel: Cancel
+ tag_rules:
+ default_rules:
+ by_default: By Default
+ no_rules_yet: No default rules apply yet
+ add_new_button: '+ Add A New Default Rule'
+ no_tags_yet: No tags apply to this enterprise yet
+ no_rules_yet: No rules apply to this tag yet
+ for_customers_tagged: 'For customers tagged:'
+ add_new_rule: '+ Add A New Rule'
+ add_new_tag: '+ Add A New Tag'
+ users:
+ email_confirmation_notice_html: "Email confirmation is pending. We've sent a confirmation email to %{email}."
+ resend: Resend
+ owner: 'Owner'
+ contact: "Contact"
+ contact_tip: "The manager who will receive enterprise emails for orders and notifications. Must have a confirmed email adress."
+ owner_tip: The primary user responsible for this enterprise.
+ notifications: Notifications
+ notifications_tip: Notifications about orders will be send to this email address.
+ notifications_placeholder: eg. gustav@truffles.com
+ notifications_note: 'Note: A new email address may need to be confirmed prior to use'
+ managers: Managers
+ managers_tip: The other users with permission to manage this enterprise.
+ invite_manager: "Invite Manager"
+ invite_manager_tip: "Invite an unregistered user to sign up and become a manager of this enterprise."
+ add_unregistered_user: "Add an unregistered user"
+ email_confirmed: "Email confirmed"
+ email_not_confirmed: "Email not confirmed"
+ actions:
+ edit_profile: Settings
+ properties: Properties
+ payment_methods: Payment Methods
+ payment_methods_tip: This enterprise has no payment methods
+ shipping_methods: Shipping Methods
+ shipping_methods_tip: This enterprise has shipping methods
+ enterprise_fees: Enterprise Fees
+ enterprise_fees_tip: This enterprise has no fees
+ admin_index:
+ name: Name
+ role: Role
+ sells: Sells
+ visible: Visible?
+ owner: Owner
+ producer: Producer
+ change_type_form:
+ producer_profile: Producer Profile
+ connect_ofn: Connect through OFN
+ always_free: ALWAYS FREE
+ producer_description_text: Add your products to Open Food Network, allowing hubs to stock your products in their stores.
+ producer_shop: Producer Shop
+ sell_your_produce: Sell your own produce
+ producer_shop_description_text: Sell your products directly to customers through your very own Open Food Network shopfront.
+ producer_shop_description_text2: A Producer Shop is for your produce only, if you want to sell produce grown/produced off site, select 'Producer Hub'.
+ producer_hub: Producer Hub
+ producer_hub_text: Sell produce from self and others
+ producer_hub_description_text: Your enterprise is the backbone of your local food system. You can sell your own produce as well as produce aggregated from other enterprises through your shopfront on the Open Food Network.
+ profile: Profile Only
+ get_listing: Get a listing
+ profile_description_text: People can find and contact you on the Open Food Network. Your enterprise will be visible on the map, and will be searchable in listings.
+ hub_shop: Hub Shop
+ hub_shop_text: Sell produce from others
+ hub_shop_description_text: Your enterprise is the backbone of your local food system. You aggregate produce from other enterprises and can sell it through your shop on the Open Food Network.
+ choose_option: Please choose one of the options above.
+ change_now: Change now
+ enterprise_user_index:
+ loading_enterprises: LOADING ENTERPRISES
+ no_enterprises_found: No enterprises found.
+ search_placeholder: Search By Name
+ manage: Manage
+ manage_link: Settings
+ producer?: "Producer?"
+ package: "Package"
+ status: "Status"
+ new_form:
+ owner: Owner
+ owner_tip: The primary user responsible for this enterprise.
+ i_am_producer: I am a Producer
+ contact_name: Contact Name
+ edit:
+ editing: 'Settings:'
+ back_link: Back to enterprises list
+ new:
+ title: New Enterprise
+ back_link: Back to enterprises list
+ remove_logo:
+ remove: "Remove Image"
+ removed_successfully: "Logo removed successfully"
+ immediate_removal_warning: "The logo will be removed immediately after you confirm."
+ remove_promo_image:
+ remove: "Remove Image"
+ removed_successfully: "Promo image removed successfully"
+ immediate_removal_warning: "The promo image will be removed immediately after you confirm."
+ welcome:
+ welcome_title: Welcome to the Open Food Network!
+ welcome_text: You have successfully created a
+ next_step: Next step
+ choose_starting_point: 'Choose your package:'
+ invite_manager:
+ user_already_exists: "User already exists"
+ error: "Something went wrong"
+ order_cycles:
+ edit:
+ advanced_settings: Advanced Settings
+ update_and_close: Update and Close
+ choose_products_from: 'Choose Products From:'
+ exchange_form:
+ pickup_time_tip: When orders from this OC will be ready for the customer
+ pickup_instructions_placeholder: "Pick-up instructions"
+ pickup_instructions_tip: These instructions are shown to customers after they complete an order
+ pickup_time_placeholder: "Ready for (ie. Date / Time)"
+ receival_instructions_placeholder: "Receival instructions"
+ add_fee: 'Add fee'
+ selected: 'selected'
+ add_exchange_form:
+ add_supplier: 'Add supplier'
+ add_distributor: 'Add distributor'
+ advanced_settings:
+ title: Advanced Settings
+ choose_product_tip: You can opt to restrict all available products (both incoming and outgoing), to only those in %{inventory}'s inventory.
+ preferred_product_selection_from_coordinator_inventory_only_here: Coordinator's Inventory Only
+ preferred_product_selection_from_coordinator_inventory_only_all: All Available Products
+ save_reload: Save and Reload Page
+ coordinator_fees:
+ add: Add coordinator fee
+ filters:
+ search_by_order_cycle_name: "Search by Order Cycle name..."
+ involving: "Involving"
+ any_enterprise: "Any Enterprise"
+ any_schedule: "Any Schedule"
+ form:
+ incoming: Incoming
+ supplier: Supplier
+ receival_details: Receival details
+ fees: Fees
+ outgoing: Outgoing
+ distributor: Distributor
+ products: Products
+ tags: Tags
+ add_a_tag: Add a tag
+ delivery_details: Pickup / Delivery details
+ debug_info: Debug information
+ index:
+ schedule: Schedule
+ schedules: Schedules
+ adding_a_new_schedule: Adding A New Schedule
+ updating_a_schedule: Updating A Schedule
+ new_schedule: New Schedule
+ create_schedule: Create Schedule
+ update_schedule: Update Schedule
+ delete_schedule: Delete Schedule
+ created_schedule: Created schedule
+ updated_schedule: Updated schedule
+ deleted_schedule: Deleted schedule
+ schedule_name_placeholder: Schedule Name
+ name_required_error: Please enter a name for this schedule
+ no_order_cycles_error: Please select at least one order cycle (drag and drop)
+ name_and_timing_form:
+ name: Name
+ orders_open: Orders open at
+ coordinator: Coordinator
+ orders_close: Orders close
+ row:
+ suppliers: suppliers
+ distributors: distributors
+ variants: variants
+ simple_form:
+ ready_for: Ready for
+ ready_for_placeholder: Date / time
+ customer_instructions: Customer instructions
+ customer_instructions_placeholder: Pick-up or delivery notes
+ products: Products
+ fees: Fees
+ destroy_errors:
+ orders_present: That order cycle has been selected by a customer and cannot be deleted. To prevent customers from accessing it, please close it instead.
+ schedule_present: That order cycle is linked to a schedule and cannot be deleted. Please unlink or delete the schedule first.
+ bulk_update:
+ no_data: Hm, something went wrong. No order cycle data found.
+ date_warning:
+ msg: This order cycle is linked to %{n} open subscription orders. Changing this date now will not affect any orders which have already been placed, but should be avoided if possible. Are you sure you want to proceed?
+ cancel: Cancel
+ proceed: Proceed
+ producer_properties:
+ index:
+ title: Producer Properties
+ proxy_orders:
+ cancel:
+ could_not_cancel_the_order: Could not cancel the order
+ resume:
+ could_not_resume_the_order: Could not resume the order
+ shared:
+ user_guide_link:
+ user_guide: User Guide
+ overview:
+ enterprises_header:
+ ofn_with_tip: Enterprises are Producers and/or Hubs and are the basic unit of organisation within the Open Food Network.
+ enterprises_hubs_tabs:
+ has_no_payment_methods: "%{enterprise} has no payment methods"
+ has_no_shipping_methods: "%{enterprise} has no shipping methods"
+ has_no_enterprise_fees: "%{enterprise} has no enterprise fees"
+ enterprise_issues:
+ create_new: Create New
+ resend_email: Resend Email
+ has_no_payment_methods: "%{enterprise} currently has no payment methods"
+ has_no_shipping_methods: "%{enterprise} currently has no shipping methods"
+ email_confirmation: "Email confirmation is pending. We've sent a confirmation email to %{email}."
+ not_visible: "%{enterprise} is not visible and so cannot be found on the map or in searches"
+ reports:
+ hidden: HIDDEN
+ unitsize: UNITSIZE
+ total: TOTAL
+ total_items: TOTAL ITEMS
+ supplier_totals: Order Cycle Supplier Totals
+ supplier_totals_by_distributor: Order Cycle Supplier Totals by Distributor
+ totals_by_supplier: Order Cycle Distributor Totals by Supplier
+ customer_totals: Order Cycle Customer Totals
+ all_products: All products
+ inventory: Inventory (on hand)
+ lettuce_share: LettuceShare
+ mailing_list: Mailing List
+ addresses: Addresses
+ payment_methods: Payment Methods Report
+ delivery: Delivery Report
+ tax_types: Tax Types
+ tax_rates: Tax Rates
+ pack_by_customer: Pack By Customer
+ pack_by_supplier: Pack By Supplier
+ orders_and_distributors:
+ name: Orders And Distributors
+ description: Orders with distributor details
+ bulk_coop:
+ name: Bulk Co-Op
+ description: Reports for Bulk Co-Op orders
+ payments:
+ name: Payment Reports
+ description: Reports for Payments
+ orders_and_fulfillment:
+ name: Orders & Fulfillment Reports
+ customers:
+ name: Customers
+ products_and_inventory:
+ name: Products & Inventory
+ sales_total:
+ name: Sales Total
+ description: Sales Total For All Orders
+ users_and_enterprises:
+ name: Users & Enterprises
+ description: Enterprise Ownership & Status
+ order_cycle_management:
+ name: Order Cycle Management
+ sales_tax:
+ name: Sales Tax
+ xero_invoices:
+ name: Xero Invoices
+ description: Invoices for import into Xero
+ packing:
+ name: Packing Reports
+ enterprise_fee_summary:
+ name: "Enterprise Fee Summary"
+ description: "Summary of Enterprise Fees collected"
+ subscriptions:
+ subscriptions: Subscriptions
+ new: New Subscription
+ create: Create Subscription
+ index:
+ please_select_a_shop: Please select a shop
+ edit_subscription: Edit Subscription
+ pause_subscription: Pause Subscription
+ unpause_subscription: Unpause Subscription
+ cancel_subscription: Cancel Subscription
+ setup_explanation:
+ just_a_few_more_steps: 'Just a few more steps before you can begin:'
+ enable_subscriptions: "Enable subscriptions for at least one of your shops"
+ enable_subscriptions_step_1_html: 1. Go to the %{enterprises_link} page, find your shop, and click "Manage"
+ enable_subscriptions_step_2: 2. Under "Shop Preferences", enable the Subscriptions option
+ set_up_shipping_and_payment_methods_html: Set up %{shipping_link} and %{payment_link} methods
+ set_up_shipping_and_payment_methods_note_html: Note that only Cash and Stripe payment methods may be used with subscriptions
+ ensure_at_least_one_customer_html: Ensure that at least one %{customer_link} exists
+ create_at_least_one_schedule: Create at least one Schedule
+ create_at_least_one_schedule_step_1_html: 1. Go to the on the %{order_cycles_link} page
+ create_at_least_one_schedule_step_2: 2. Create an order cycle if you have not already done so
+ create_at_least_one_schedule_step_3: 3. Click '+ New Schedule', and fill out the form
+ once_you_are_done_you_can_html: Once you are done, you can %{reload_this_page_link}
+ reload_this_page: reload this page
+ steps:
+ details: 1. Basic Details
+ address: 2. Address
+ products: 3. Add Products
+ review: 4. Review & Save
+ subscription_line_items:
+ this_is_an_estimate: |
+ The displayed prices are only an estimate and calculated at the time the subscription is changed.
+ If you change prices or fees, orders will be updated, but the subscription will still display the old values.
+ not_in_open_and_upcoming_order_cycles_warning: "There are no open or upcoming order cycles for this product."
+ details:
+ details: Details
+ invalid_error: Oops! Please fill in all of the required fields...
+ allowed_payment_method_types_tip: Only Cash and Stripe payment methods may be used at the moment
+ credit_card: Credit Card
+ charges_not_allowed: Charges are not allowed by this customer
+ no_default_card: Customer has no cards available to charge
+ card_ok: Customer has a card available to charge
+ loading_flash:
+ loading: LOADING SUBSCRIPTIONS
+ review:
+ details: Details
+ address: Address
+ products: Products
+ no_open_or_upcoming_order_cycle: "No Upcoming Order Cycle"
+ product_already_in_order: This product has already been added to the order. Please edit the quantity directly.
+ orders:
+ number: Number
+ confirm_edit: Are you sure you want to edit this order? Doing so may make it more difficult to automatically sync changes to the subscription in the future.
+ confirm_cancel_msg: Are you sure you want to cancel this subscription? This action cannot be undone.
+ cancel_failure_msg: 'Sorry, cancellation failed!'
+ confirm_pause_msg: Are you sure you want to pause this subscription?
+ pause_failure_msg: 'Sorry, pausing failed!'
+ confirm_unpause_msg: Are you sure you want to unpause this subscription?
+ unpause_failure_msg: 'Sorry, unpausing failed!'
+ confirm_cancel_open_orders_msg: "Some orders for this subscription are currently open. The customer has already been notified that the order will be placed. Would you like to cancel these order(s) or keep them?"
+ resume_canceled_orders_msg: "Some orders for this subscription can be resumed right now. You can resume them from the orders dropdown."
+ yes_cancel_them: Cancel them
+ no_keep_them: Keep them
+ yes_i_am_sure: Yes, I'm sure
+ order_update_issues_msg: Some orders could not be automatically updated, this is most likely because they have been manually edited. Please review the issues listed below and make any adjustments to individual orders if required.
+ no_results:
+ no_subscriptions: No subscriptions yet...
+ why_dont_you_add_one: Why don't you add one? :)
+ no_matching_subscriptions: No matching subscriptions found
+ schedules:
+ destroy:
+ associated_subscriptions_error: This schedule cannot be deleted because it has associated subscriptions
+ controllers:
+ enterprises:
+ stripe_connect_cancelled: "Connection to Stripe has been cancelled"
+ stripe_connect_success: "Stripe account connected successfully"
+ stripe_connect_fail: Sorry, the connection of your Stripe account failed
+ stripe_connect_settings:
+ resource: Stripe Connect configuration
+ api:
+ enterprise_logo:
+ destroy_attachment_does_not_exist: "Logo does not exist"
+ enterprise_promo_image:
+ destroy_attachment_does_not_exist: "Promo image does not exist"
+ checkout:
+ already_ordered:
+ cart: "cart"
+ message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
+ shops:
+ hubs:
+ show_closed_shops: "Show closed shops"
+ hide_closed_shops: "Hide closed shops"
+ show_on_map: "Show all on the map"
+ shared:
+ menu:
+ cart:
+ checkout: "Checkout now"
+ already_ordered_products: "Already ordered in this order cycle"
+ register_call:
+ selling_on_ofn: "Interested in getting on the Open Food Network?"
+ register: "Register here"
+ footer:
+ footer_global_headline: "OFN Global"
+ footer_global_home: "Home"
+ footer_global_news: "News"
+ footer_global_about: "About"
+ footer_global_contact: "Contact"
+ footer_sites_headline: "OFN Sites"
+ footer_sites_developer: "Developer"
+ footer_sites_community: "Community"
+ footer_sites_userguide: "User Guide"
+ footer_secure: "Secure and trusted."
+ footer_secure_text: "Open Food Network uses SSL encryption (2048 bit RSA) everywhere to keep your shopping and payment information private. Our servers do not store your credit card details and payments are processed by PCI-compliant services."
+ footer_contact_headline: "Keep in touch"
+ footer_contact_email: "Email us"
+ footer_nav_headline: "Navigate"
+ footer_join_headline: "Join us"
+ footer_join_body: "Create a listing, shop or group directory on the Open Food Network."
+ footer_join_cta: "Tell me more!"
+ footer_legal_call: "Read our"
+ footer_legal_tos: "Terms and conditions"
+ footer_legal_visit: "Find us on"
+ footer_legal_text_html: "Open Food Network is a free and open source software platform. Our content is licensed with %{content_license} and our code with %{code_license}."
+ footer_data_text_with_privacy_policy_html: "We take good care of your data. See our %{privacy_policy} and %{cookies_policy}"
+ footer_data_text_without_privacy_policy_html: "We take good care of your data. See our %{cookies_policy}"
+ footer_data_privacy_policy: "privacy policy"
+ footer_data_cookies_policy: "cookies policy"
+ footer_skylight_dashboard_html: Performance data is available on %{dashboard}.
+ shop:
+ messages:
+ login: "login"
+ register: "register"
+ contact: "contact"
+ require_customer_login: "This shop is for customers only."
+ require_login_html: "Please %{login} if you have an account already. Otherwise, %{register} to become a customer."
+ require_customer_html: "Please %{contact} %{enterprise} to become a customer."
+ card_could_not_be_updated: Card could not be updated
+ card_could_not_be_saved: card could not be saved
+ spree_gateway_error_flash_for_checkout: "There was a problem with your payment information: %{error}"
+ invoice_billing_address: "Billing address:"
+ invoice_column_tax: "GST"
+ invoice_column_price: "Price"
+ invoice_column_item: "Item"
+ invoice_column_qty: "Qty"
+ invoice_column_unit_price_with_taxes: "Unit price (Incl. tax)"
+ invoice_column_unit_price_without_taxes: "Unit price (Excl. tax)"
+ invoice_column_price_with_taxes: "Total price (Incl. tax)"
+ invoice_column_price_without_taxes: "Total price (Excl. tax)"
+ invoice_column_tax_rate: "Tax rate"
+ invoice_tax_total: "GST Total:"
+ tax_invoice: "TAX INVOICE"
+ tax_total: "Total tax (%{rate}):"
+ total_excl_tax: "Total (Excl. tax):"
+ total_incl_tax: "Total (Incl. tax):"
+ abn: "ABN:"
+ acn: "ACN:"
+ invoice_issued_on: "Invoice issued on:"
+ order_number: "Invoice number:"
+ date_of_transaction: "Date of transaction:"
+ ticket_column_qty: "Qty"
+ ticket_column_item: "Item"
+ ticket_column_unit_price: "Unit Price"
+ ticket_column_total_price: "Total Price"
+ menu_1_title: "Shops"
+ menu_1_url: "/shops"
+ menu_2_title: "Map"
+ menu_2_url: "/map"
+ menu_3_title: "Producers"
+ menu_3_url: "/producers"
+ menu_4_title: "Groups"
+ menu_4_url: "/groups"
+ menu_5_title: "About"
+ menu_5_url: "http://www.openfoodnetwork.org/"
+ menu_6_title: "Connect"
+ menu_6_url: "https://openfoodnetwork.org/au/connect/"
+ menu_7_title: "Learn"
+ menu_7_url: "https://openfoodnetwork.org/au/learn/"
+ logo: "Logo (640x130)"
+ logo_mobile: "Mobile logo (75x26)"
+ logo_mobile_svg: "Mobile logo (SVG)"
+ home_hero: "Hero image"
+ home_show_stats: "Show statistics"
+ footer_logo: "Logo (220x76)"
+ footer_facebook_url: "Facebook URL"
+ footer_twitter_url: "Twitter URL"
+ footer_instagram_url: "Instagram URL"
+ footer_linkedin_url: "LinkedIn URL"
+ footer_googleplus_url: "Google Plus URL"
+ footer_pinterest_url: "Pinterest URL"
+ footer_email: "Email"
+ footer_links_md: "Links"
+ footer_about_url: "About URL"
+ user_guide_link: "User Guide Link"
+ name: Name
+ first_name: First Name
+ last_name: Last Name
+ email: Email
+ phone: Phone
+ next: Next
+ address: Address
+ address_placeholder: eg. 123 High Street
+ address2: Address (contd.)
+ city: City
+ city_placeholder: eg. Northcote
+ postcode: Postcode
+ postcode_placeholder: eg. 3070
+ state: State
+ country: Country
+ unauthorized: Unauthorized
+ terms_of_service: "Terms of service"
+ on_demand: On demand
+ none: None
+ not_allowed: Not allowed
+ no_shipping: no shipping methods
+ no_payment: no payment methods
+ no_shipping_or_payment: no shipping or payment methods
+ unconfirmed: unconfirmed
+ days: days
+ label_shop: "Shop"
+ label_shops: "Shops"
+ label_map: "Map"
+ label_producer: "Producer"
+ label_producers: "Producers"
+ label_groups: "Groups"
+ label_about: "About"
+ label_connect: "Connect"
+ label_learn: "Learn"
+ label_blog: "Blog"
+ label_support: "Support"
+ label_shopping: "Shopping"
+ label_login: "Login"
+ label_logout: "Logout"
+ label_signup: "Sign up"
+ label_administration: "Administration"
+ label_admin: "Admin"
+ label_account: "Account"
+ label_more: "Show more"
+ label_less: "Show less"
+ label_notices: "Notices"
+ cart_items: "items"
+ cart_headline: "Your shopping cart"
+ total: "Total"
+ cart_updating: "Updating cart..."
+ cart_empty: "Cart empty"
+ cart_edit: "Edit your cart"
+ card_number: Card Number
+ card_securitycode: "Security Code"
+ card_expiry_date: Expiry Date
+ card_masked_digit: "X"
+ card_expiry_abbreviation: "Exp"
+ new_credit_card: "New credit card"
+ my_credit_cards: My credit cards
+ add_new_credit_card: Add new credit card
+ saved_cards: Saved cards
+ add_a_card: Add a Card
+ add_card: Add Card
+ you_have_no_saved_cards: You haven't saved any cards yet
+ saving_credit_card: Saving credit card...
+ card_has_been_removed: "Your card has been removed (number: %{number})"
+ card_could_not_be_removed: Sorry, the card could not be removed
+ ie_warning_headline: "Your browser is out of date :-("
+ ie_warning_text: "For the best Open Food Network experience, we strongly recommend upgrading your browser:"
+ ie_warning_chrome: Download Chrome
+ ie_warning_firefox: Download Firefox
+ ie_warning_ie: Upgrade Internet Explorer
+ ie_warning_other: "Can't upgrade your browser? Try Open Food Network on your smartphone :-)"
+ legal:
+ cookies_policy:
+ header: "How We Use Cookies"
+ desc_part_1: "Cookies are very small text files that are stored on your computer when you visit some websites."
+ desc_part_2: "In OFN we are fully respectful of your privacy. We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We might in the future propose you to share some of your data to build new commons services that could be useful for the ecosystem (like logistics services for short food systems) but we are not yet there, and we won’t do it without your authorization :-)"
+ desc_part_3: "We use cookies mainly to remember who you are if you 'log in' to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website. Here is the list of cookies we use!"
+ essential_cookies: "Essential Cookies"
+ essential_cookies_desc: "The following cookies are strictly necessary for the operation of our website."
+ essential_cookies_note: "Most cookies only contain a unique identifier, but no other data, so your email address and password for instance are never contained in them and never exposed."
+ cookie_domain: "Set By:"
+ cookie_session_desc: "Used to allow the website to remember users between page visits, for example, remember items in your cart."
+ cookie_consent_desc: "Used to maintain status of user consent to store cookies"
+ cookie_remember_me_desc: "Used if the user has requested the website to remember him. This cookie is automatically deleted after 12 days. If as a user you want that cookie to be deleted, you only need to logout. If you don’t want that cookie to be installed on your computer you shouldn’t check the “remember me” checkbox when logging in."
+ cookie_openstreemap_desc: "Used by our friendly open source mapping provider (OpenStreetMap) to ensure that it does not receive too many requests during a given time period, to prevent abuse of their services."
+ cookie_stripe_desc: "Data collected by our payment processor Stripe for fraud detection https://stripe.com/cookies-policy/legal. Not all shops use Stripe as a payment method but it is a good practice to prevent fraud to apply it to all pages. Stripe probably build a picture of which of our pages usually interact with their API and then flag anything unusual. So setting the Stripe cookie has a broader function than simply the provision of a payment method to a user. Removing it could affect the security of the service itself. You can learn more about Stripe and read its privacy policy at https://stripe.com/privacy."
+ statistics_cookies: "Statistics Cookies"
+ statistics_cookies_desc: "The following are not strictly necessary, but help to provide you with the best user experience by allowing us to analyse user behaviour, identify which features you use most, or don’t use, understand user experience issues, etc."
+ statistics_cookies_analytics_desc_html: "To collect and analyse platform usage data, we use Google Analytics, as it was the default service connected with Spree (the e-commerce open source software that we built on) but our vision is to switch to Matomo (ex Piwik, open source analytics tool that is GDPR compliant and protects your privacy) as soon as we can."
+ statistics_cookies_matomo_desc_html: "To collect and analyse platform usage data, we use Matomo (ex Piwik), an open source analytics tool that is GDPR compliant and protects your privacy."
+ statistics_cookies_matomo_optout: "Do you want to opt-out of Matomo analytics? We don’t collect any personal data, and Matomo helps us to improve our service, but we respect your choice :-)"
+ cookie_analytics_utma_desc: "Used to distinguish users and sessions. The cookie is created when the javascript library executes and no existing __utma cookies exists. The cookie is updated every time data is sent to Google Analytics."
+ cookie_analytics_utmt_desc: "Used to throttle request rate."
+ cookie_analytics_utmb_desc: "Used to determine new sessions/visits. The cookie is created when the javascript library executes and no existing __utmb cookies exists. The cookie is updated every time data is sent to Google Analytics."
+ cookie_analytics_utmc_desc: "Not used in ga.js. Set for interoperability with urchin.js. Historically, this cookie operated in conjunction with the __utmb cookie to determine whether the user was in a new session/visit."
+ cookie_analytics_utmz_desc: "Stores the traffic source or campaign that explains how the user reached your site. The cookie is created when the javascript library executes and is updated every time data is sent to Google Analytics."
+ cookie_matomo_basics_desc: "Matomo first party cookies to collect statistics."
+ cookie_matomo_heatmap_desc: "Matomo Heatmap & Session Recording cookie."
+ cookie_matomo_ignore_desc: "Cookie used to exclude user from being tracked."
+ disabling_cookies_header: "Warning on disabling cookies"
+ disabling_cookies_desc: "As a user you can always allow, block or delete Open Food Network’s or any other website cookies whenever you want to through your browser’s setting control. Each browser has a different operative. Here are the links:"
+ disabling_cookies_firefox_link: "https://support.mozilla.org/en-US/kb/enable-and-disable-cookies-website-preferences"
+ disabling_cookies_chrome_link: "https://support.google.com/chrome/answer/95647"
+ disabling_cookies_ie_link: "https://support.microsoft.com/en-us/help/17442/windows-internet-explorer-delete-manage-cookies"
+ disabling_cookies_safari_link: "https://www.apple.com/legal/privacy/en-ww/cookies/"
+ disabling_cookies_note: "But be aware that if you delete or modify the essential cookies used by Open Food Network, the website won’t work, you will not be able to add anything to your cart neither to checkout for instance."
+ cookies_banner:
+ cookies_usage: "This site uses cookies in order to make your navigation frictionless and secure, and to help us understand how you use it in order to improve the features we offer."
+ cookies_definition: "Cookies are very small text files that are stored on your computer when you visit some websites."
+ cookies_desc: "We use only the cookies that are necessary for delivering you the service of selling/buying food online. We don’t sell any of your data. We use cookies mainly to remember who you are if you ‘log in’ to the service, or to be able to remember the items you put in your cart even if you are not logged in. If you keep navigating on the website without clicking on “Accept cookies”, we assume you are giving us consent to store the cookies that are essential for the functioning of the website."
+ cookies_policy_link_desc: "If you want to learn more, check our"
+ cookies_policy_link: "cookies policy"
+ cookies_accept_button: "Accept Cookies"
+ home_shop: Shop Now
+ brandstory_headline: "Food, unincorporated."
+ brandstory_intro: "Sometimes the best way to fix the system is to start a new one…"
+ brandstory_part1: "We begin from the ground up. With farmers and growers ready to tell their stories proudly and truly. With distributors ready to connect people with products fairly and honestly. With buyers who believe that better weekly shopping decisions can seriously change the world."
+ brandstory_part2: "Then we need a way to make it real. A way to empower everyone who grows, sells and buys food. A way to tell all the stories, to handle all the logistics. A way to turn transaction into transformation every day."
+ brandstory_part3: "So we build an online marketplace that levels the playing field. It’s transparent, so it creates real relationships. It’s open source, so it’s owned by everyone. It scales to regions and nations, so people start versions across the world."
+ brandstory_part4: "It works everywhere. It changes everything."
+ brandstory_part5_strong: "We call it Open Food Network."
+ brandstory_part6: "We all love food. Now we can love our food system too."
+ learn_body: "Explore models, stories and resources to support you to develop your fair food business or organisation. Find training, events and other opportunities to learn from peers."
+ learn_cta: "Get Inspired"
+ connect_body: "Search our full directories of producers, hubs and groups to find fair food traders near you. List your business or organisation on the OFN so buyers can find you. Join the community to get advice and solve problems together."
+ connect_cta: "Go Exploring"
+ system_headline: "Shopping - here's how it works."
+ system_step1: "1. Search"
+ system_step1_text: "Search our diverse, independent shops for seasonal local food. Search by neighbourhood and food category, or whether you prefer delivery or pickup."
+ system_step2: "2. Shop"
+ system_step2_text: "Transform your transactions with affordable local food from diverse producers and hubs. Know the stories behind your food and the people who make it!"
+ system_step3: "3. Pick-up / Delivery"
+ system_step3_text: "Hang on for your delivery, or visit your producer or hub for a more personal connection with your food. Food shopping as diverse as nature intended it."
+ cta_headline: "Shopping that makes the world a better place."
+ cta_label: "I'm Ready"
+ stats_headline: "We're creating a new food system."
+ stats_producers: "food producers"
+ stats_shops: "food shops"
+ stats_shoppers: "food shoppers"
+ stats_orders: "food orders"
+ checkout_title: Checkout
+ checkout_now: Checkout now
+ checkout_order_ready: Order ready for
+ checkout_hide: Hide
+ checkout_expand: Expand
+ checkout_headline: "Ok, ready to checkout?"
+ checkout_as_guest: "Checkout as guest"
+ checkout_details: "Your details"
+ checkout_billing: "Billing info"
+ checkout_default_bill_address: "Save as default billing address"
+ checkout_shipping: Shipping info
+ checkout_default_ship_address: "Save as default shipping address"
+ checkout_method_free: Free
+ checkout_address_same: Shipping address same as billing address?
+ checkout_ready_for: "Ready for:"
+ checkout_instructions: "Any comments or special instructions?"
+ checkout_payment: Payment
+ checkout_send: Place order now
+ checkout_your_order: Your order
+ checkout_cart_total: Cart total
+ checkout_shipping_price: Shipping
+ checkout_total_price: Total
+ checkout_back_to_cart: "Back to Cart"
+ cost_currency: "Cost Currency"
+ order_paid: PAID
+ order_not_paid: NOT PAID
+ order_total: Total order
+ order_payment: "Paying via:"
+ order_billing_address: Billing address
+ order_delivery_on: Delivery on
+ order_delivery_address: Delivery address
+ order_delivery_time: Delivery time
+ order_special_instructions: "Your notes:"
+ order_pickup_time: Ready for collection
+ order_pickup_instructions: Collection Instructions
+ order_produce: Produce
+ order_total_price: Total
+ order_includes_tax: (includes tax)
+ order_payment_paypal_successful: Your payment via PayPal has been processed successfully.
+ order_hub_info: Hub Info
+ order_back_to_store: Back To Store
+ order_back_to_cart: Back To Cart
+ bom_tip: "Use this page to alter product quantities across multiple orders. Products may also be removed from orders entirely, if required."
+ unsaved_changes_warning: "Unsaved changes exist and will be lost if you continue."
+ unsaved_changes_error: "Fields with red borders contain errors."
+ products: "Products"
+ products_in: "in %{oc}"
+ products_at: "at %{distributor}"
+ products_elsewhere: "Products found elsewhere"
+ email_welcome: "Welcome"
+ email_confirmed: "Thank you for confirming your email address."
+ email_registered: "is now part of"
+ email_userguide_html: "The User Guide with detailed support for setting up your Producer or Hub is here: %{link}"
+ email_admin_html: "You can manage your account by logging into the %{link} or by clicking on the cog in the top right hand side of the homepage, and selecting Administration."
+ email_community_html: "We also have an online forum for community discussion related to OFN software and the unique challenges of running a food enterprise. You are encouraged to join in. We are constantly evolving and your input into this forum will shape what happens next. %{link}"
+ join_community: "Join the community"
+ email_confirmation_activate_account: "Before we can activate your new account, we need to confirm your email address."
+ email_confirmation_greeting: "Hi, %{contact}!"
+ email_confirmation_profile_created: "A profile for %{name} has been successfully created! To activate your Profile we need to confirm this email address."
+ email_confirmation_click_link: "Please click the link below to confirm your email and to continue setting up your profile."
+ email_confirmation_link_label: "Confirm this email address »"
+ email_confirmation_help_html: "After confirming your email you can access your administration account for this enterprise. See the %{link} to find out more about %{sitename}'s features and to start using your profile or online store."
+ email_confirmation_notice_unexpected: "You received this message because you signed up on %{sitename}, or were invited to sign up by someone you probably know. If you don't understand why you are receiving this email, please write to %{contact}."
+ email_social: "Connect with Us:"
+ email_contact: "Email us:"
+ email_signoff: "Cheers,"
+ email_signature: "%{sitename} Team"
+ email_confirm_customer_greeting: "Hi %{name},"
+ email_confirm_customer_intro_html: "Thanks for shopping at %{distributor}!"
+ email_confirm_customer_number_html: "Order confirmation #%{number}"
+ email_confirm_customer_details_html: "Here are your order details from %{distributor}:"
+ email_confirm_customer_signoff: "Kind regards,"
+ email_confirm_shop_greeting: "Hi %{name},"
+ email_confirm_shop_order_html: "Well done! You have a new order for %{distributor}!"
+ email_confirm_shop_number_html: "Order confirmation #%{number}"
+ email_order_summary_item: "Item"
+ email_order_summary_quantity: "Qty"
+ email_order_summary_price: "Price"
+ email_order_summary_subtotal: "Subtotal:"
+ email_order_summary_total: "Total:"
+ email_order_summary_includes_tax: "(includes tax):"
+ email_payment_paid: PAID
+ email_payment_not_paid: NOT PAID
+ email_payment_summary: Payment summary
+ email_payment_method: "Paying via:"
+ email_so_placement_intro_html: "You have a new order with %{distributor}"
+ email_so_placement_details_html: "Here are the details of your order for %{distributor}:"
+ email_so_placement_changes: "Unfortunately, not all products that you requested were available. The original quantities that you requested appear crossed-out below."
+ email_so_payment_success_intro_html: "An automatic payment has been processed for your order from %{distributor}."
+ email_so_placement_explainer_html: "This order was automatically created for you."
+ email_so_edit_true_html: "You can make changes until orders close on %{orders_close_at}."
+ email_so_edit_false_html: "You can view details of this order at any time."
+ email_so_contact_distributor_html: "If you have any questions you can contact %{distributor} via %{email}."
+ email_so_contact_distributor_to_change_order_html: "This order was automatically created for you. You can make changes until orders close on %{orders_close_at}by contacting %{distributor}via %{email}."
+ email_so_confirmation_intro_html: "Your order with %{distributor} is now confirmed"
+ email_so_confirmation_explainer_html: "This order was automatically placed for you, and it has now been finalised."
+ email_so_confirmation_details_html: "Here's everything you need to know about your order from %{distributor}:"
+ email_so_empty_intro_html: "We tried to place a new order with %{distributor}, but had some problems..."
+ email_so_empty_explainer_html: "Unfortunately, none of products that you ordered were available, so no order has been placed. The original quantities that you requested appear crossed-out below."
+ email_so_empty_details_html: "Here are the details of the unplaced order for %{distributor}:"
+ email_so_failed_payment_intro_html: "We tried to process a payment, but had some problems..."
+ email_so_failed_payment_explainer_html: "The payment for your subscription with %{distributor} failed because of a problem with your credit card. %{distributor} has been notified of this failed payment."
+ email_so_failed_payment_details_html: "Here are the details of the failure provided by the payment gateway:"
+ email_shipping_delivery_details: Delivery details
+ email_shipping_delivery_time: "Delivery on:"
+ email_shipping_delivery_address: "Delivery address:"
+ email_shipping_collection_details: Collection details
+ email_shipping_collection_time: "Ready for collection:"
+ email_shipping_collection_instructions: "Collection instructions:"
+ email_special_instructions: "Your notes:"
+ email_signup_greeting: Hello!
+ email_signup_welcome: "Welcome to %{sitename}!"
+ email_signup_confirmed_email: "Thanks for confirming your email."
+ email_signup_shop_html: "You can now log in at %{link}."
+ email_signup_text: "Thanks for joining the network. If you are a customer, we look forward to introducing you to many fantastic farmers, wonderful food hubs and delicious food! If you are a producer or food enterprise, we are excited to have you as a part of the network."
+ email_signup_help_html: "We welcome all your questions and feedback; you can use the Send Feedback button on the site or email us at %{email}"
+ invite_email:
+ greeting: "Hello!"
+ invited_to_manage: "You have been invited to manage %{enterprise} on %{instance}."
+ confirm_your_email: "You should have received or will soon receive an email with a confirmation link. You won’t be able to access %{enterprise}'s profile until you have confirmed your email."
+ set_a_password: "You will then be prompted to set a password before you are able to administer the enterprise."
+ mistakenly_sent: "Not sure why you have received this email? Please contact %{owner_email} for more information."
+ producer_mail_greeting: "Dear"
+ producer_mail_text_before: "We now have all the consumer orders for the next food drop."
+ producer_mail_order_text: "Here is a summary of the orders for your products:"
+ producer_mail_delivery_instructions: "Stock pickup/delivery instructions:"
+ producer_mail_signoff: "Thanks and best wishes"
+ shopping_oc_closed: Orders are closed
+ shopping_oc_closed_description: "Please wait until the next cycle opens (or contact us directly to see if we can accept any late orders)"
+ shopping_oc_last_closed: "The last cycle closed %{distance_of_time} ago"
+ shopping_oc_next_open: "The next cycle opens in %{distance_of_time}"
+ shopping_tabs_about: "About %{distributor}"
+ shopping_tabs_contact: "Contact"
+ shopping_contact_address: "Address"
+ shopping_contact_web: "Contact"
+ shopping_contact_social: "Follow"
+ shopping_groups_part_of: "is part of:"
+ shopping_producers_of_hub: "%{hub}'s producers:"
+ enterprises_next_closing: "Next order closing"
+ enterprises_ready_for: "Ready for"
+ enterprises_choose: "Choose when you want your order:"
+ maps_open: "Open"
+ maps_closed: "Closed"
+ hubs_buy: "Shop for:"
+ hubs_shopping_here: "Shopping here"
+ hubs_orders_closed: "Orders closed"
+ hubs_profile_only: "Profile only"
+ hubs_delivery_options: "Delivery options"
+ hubs_pickup: "Pickup"
+ hubs_delivery: "Delivery"
+ hubs_producers: "Our producers"
+ hubs_filter_by: "Filter by"
+ hubs_filter_type: "Type"
+ hubs_filter_delivery: "Delivery"
+ hubs_filter_property: "Property"
+ hubs_matches: "Did you mean?"
+ hubs_intro: Shop in your local area
+ hubs_distance: Closest to
+ hubs_distance_filter: "Show me shops near %{location}"
+ shop_changeable_orders_alert_html:
+ one: Your order with %{shop} / %{order} is open for review. You can make changes until %{oc_close}.
+ other: You have %{count} orders with %{shop} currently open for review. You can make changes until %{oc_close}.
+ orders_changeable_orders_alert_html: This order has been confirmed, but you can make changes until %{oc_close}.
+ products_clear_all: Clear all
+ products_showing: "Showing:"
+ products_with: with
+ products_search: "Search by product or producer"
+ products_loading: "Loading products..."
+ products_updating_cart: "Updating cart..."
+ products_cart_empty: "Cart empty"
+ products_edit_cart: "Edit your cart"
+ products_from: from
+ products_change: "No changes to save."
+ products_update_error: "Saving failed with the following error(s):"
+ products_update_error_msg: "Saving failed."
+ products_update_error_data: "Save failed due to invalid data:"
+ products_changes_saved: "Changes saved."
+ search_no_results_html: "Sorry, no results found for %{query}. Try another search?"
+ components_profiles_popover: "Profiles do not have a shopfront on the Open Food Network, but may have their own physical or online shop elsewhere"
+ components_profiles_show: "Show profiles"
+ components_filters_nofilters: "No filters"
+ components_filters_clearfilters: "Clear all filters"
+ groups_title: Groups
+ groups_headline: Groups / regions
+ groups_text: "Every producer is unique. Every business has something different to offer. Our groups are collectives of producers, hubs and distributors who share something in common like location, farmers market or philosophy. This makes your shopping experience easier. So explore our groups and have the curating done for you."
+ groups_search: "Search name or keyword"
+ groups_no_groups: "No groups found"
+ groups_about: "About Us"
+ groups_producers: "Our producers"
+ groups_hubs: "Our hubs"
+ groups_contact_web: Contact
+ groups_contact_social: Follow
+ groups_contact_address: Address
+ groups_contact_email: Email us
+ groups_contact_website: Visit our website
+ groups_contact_facebook: Follow us on Facebook
+ groups_signup_title: Sign up as a group
+ groups_signup_headline: Groups sign up
+ groups_signup_intro: "We're an amazing platform for collaborative marketing, the easiest way for your members and stakeholders to reach new markets. We're non-profit, affordable, and simple."
+ groups_signup_email: Email us
+ groups_signup_motivation1: We transform food systems fairly.
+ groups_signup_motivation2: It's why we get out of bed every day. We're a global non-profit, based on open source code. We play fair. You can always trust us.
+ groups_signup_motivation3: We know you have big ideas, and we want to help. We'll share our knowledge, networks and resources. We know that isolation doesn't create change, so we'll partner with you.
+ groups_signup_motivation4: We meet you where you are.
+ groups_signup_motivation5: You might be an alliance of food hubs, producers, or distributors, and an industry body, or a local government.
+ groups_signup_motivation6: Whatever your role in your local food movement, we're ready to help. However you come to wonder what Open Food Network would look like or is doing in your part of the world, let's start the conversation.
+ groups_signup_motivation7: We make food movements make more sense.
+ groups_signup_motivation8: You need to activate and enable your networks, we offer a platform for conversation and action. You need real engagement. We’ll help reach all the players, all the stakeholders, all the sectors.
+ groups_signup_motivation9: You need resourcing. We’ll bring all our experience to bear. You need cooperation. We’ll better connect you to a global network of peers.
+ groups_signup_pricing: Group Account
+ groups_signup_studies: Case Studies
+ groups_signup_contact: Ready to discuss?
+ groups_signup_contact_text: "Get in touch to discover what OFN can do for you:"
+ groups_signup_detail: "Here's the detail."
+ login_invalid: "Invalid email or password"
+ modal_hubs: "Food Hubs"
+ modal_hubs_abstract: Our food hubs are the point of contact between you and the people who make your food!
+ modal_hubs_content1: You can search for a convenient hub by location or name. Some hubs have multiple points where you can pick-up your purchases, and some will also provide delivery options. Each food hub is a sales point with independent business operations and logistics - so variations between hubs are to be expected.
+ modal_hubs_content2: You can only shop at one food hub at a time.
+ modal_groups: "Groups / Regions"
+ modal_groups_content1: These are the organisations and relationships between hubs which make up the Open Food Network.
+ modal_groups_content2: Some groups are clustered by location or council, others by non-geographic similarities.
+ modal_how: "How it works"
+ modal_how_shop: Shop the Open Food Network
+ modal_how_shop_explained: Search for a food hub near you to start shopping! You can expand each food hub to see what kinds of goodies are available, and click through to start shopping. (You can only shop one food hub at a time.)
+ modal_how_pickup: Pick-ups, delivery and shipping costs
+ modal_how_pickup_explained: Some food hubs deliver to your door, while others require you to pick-up your purchases. You can see which options are available on the homepage, and select which you'd like at the shopping and check-out pages. Delivery will cost more, and pricing differs from hub-to-hub. Each food hub is a sales point with independent business operations and logisitics - so variations between hubs are to be expected.
+ modal_how_more: Learn more
+ modal_how_more_explained: "If you want to learn more about the Open Food Network, how it works, and get involved, check out:"
+ modal_producers: "Producers"
+ modal_producers_explained: "Our producers make all the delicious food you can shop for on the Open Food Network."
+ producers_about: About us
+ producers_buy: Shop for
+ producers_contact: Contact
+ producers_contact_phone: Call
+ producers_contact_social: Follow
+ producers_buy_at_html: "Shop for %{enterprise} products at:"
+ producers_filter: Filter by
+ producers_filter_type: Type
+ producers_filter_property: Property
+ producers_title: Producers
+ producers_headline: Find local producers
+ producers_signup_title: Sign up as a producer
+ producers_signup_headline: Food producers, empowered.
+ producers_signup_motivation: Sell your food and tell your stories to diverse new markets. Save time and money on every overhead. We support innovation without the risk. We've levelled the playing field.
+ producers_signup_send: Join now
+ producers_signup_enterprise: Enterprise Accounts
+ producers_signup_studies: Stories from our producers.
+ producers_signup_cta_headline: Join now!
+ producers_signup_cta_action: Join now
+ producers_signup_detail: Here's the detail.
+ products_item: Item
+ products_description: Description
+ products_variant: Variant
+ products_quantity: Quantity
+ products_available: Available?
+ products_producer: "Producer"
+ products_price: "Price"
+ register_title: Register
+ sell_title: "Register"
+ sell_headline: "Get on the Open Food Network!"
+ sell_motivation: "Showcase your beautiful food."
+ sell_producers: "Producers"
+ sell_hubs: "Hubs"
+ sell_groups: "Groups"
+ sell_producers_detail: "Set up a profile for your business on the OFN in just minutes. At any time you can upgrade your profile to an online store and sell your products direct to customers."
+ sell_hubs_detail: "Set up a profile for your food enterprise or organisation on the OFN. At any time you can upgrade your profile to a multi-producer shop."
+ sell_groups_detail: "Set up a tailored directory of enterprises (producers and other food enterprises) for your region or for your organisation."
+ sell_user_guide: "Find out more in our user guide."
+ sell_listing_price: "Listing on the OFN is free. Opening and running a shop on OFN is free. Setting up a group directory on OFN for your organisation or regional network is free."
+ sell_embed: "We can also embed an OFN shop in your own customised website or build a customised local food network website for your region."
+ sell_ask_services: "Ask us about OFN services."
+ shops_title: Shops
+ shops_headline: Shopping, transformed.
+ shops_text: Food grows in cycles, farmers harvest in cycles, and we order food in cycles. If you find an order cycle closed, check back soon.
+ shops_signup_title: Sign up as a hub
+ shops_signup_headline: Food hubs, unlimited.
+ shops_signup_motivation: Whatever your model, we support you. However you change, we're with you. We're non-profit, independent, and open-sourced. We're the software partners you've dreamed of.
+ shops_signup_action: Join now
+ shops_signup_pricing: Enterprise Accounts
+ shops_signup_stories: Stories from our hubs.
+ shops_signup_help: We're ready to help.
+ shops_signup_help_text: You need a better return. You need new buyers and logistics partners. You need your story told across wholesale, retail, and the kitchen table.
+ shops_signup_detail: Here's the detail.
+ orders: Orders
+ orders_fees: Fees...
+ orders_edit_title: Shopping Cart
+ orders_edit_headline: Your shopping cart
+ orders_edit_time: Order ready for
+ orders_edit_continue: Continue shopping
+ orders_edit_checkout: Checkout
+ orders_form_empty_cart: "Empty cart"
+ orders_form_subtotal: Produce subtotal
+ orders_form_admin: Admin & Handling
+ orders_form_total: Total
+ orders_oc_expired_headline: Orders have closed for this order cycle
+ orders_oc_expired_text: "Sorry, orders for this order cycle closed %{time} ago! Please contact your hub directly to see if they can accept late orders."
+ orders_oc_expired_text_others_html: "Sorry, orders for this order cycle closed %{time} ago! Please contact your hub directly to see if they can accept late orders %{link}."
+ orders_oc_expired_text_link: "or see the other order cycles available at this hub"
+ orders_oc_expired_email: "Email:"
+ orders_oc_expired_phone: "Phone:"
+ orders_show_title: Order Confirmation
+ orders_show_time: Order ready on
+ orders_show_order_number: "Order #%{number}"
+ orders_show_cancelled: Cancelled
+ orders_show_confirmed: Confirmed
+ orders_your_order_has_been_cancelled: "Your order has been cancelled"
+ orders_could_not_cancel: "Sorry, the order could not be cancelled"
+ orders_cannot_remove_the_final_item: "Cannot remove the final item from an order, please cancel the order instead."
+ orders_bought_items_notice:
+ one: "An additional item is already confirmed for this order cycle"
+ other: "%{count} additional items already confirmed for this order cycle"
+ orders_bought_edit_button: Edit confirmed items
+ orders_bought_already_confirmed: "* already confirmed"
+ orders_confirm_cancel: Are you sure you want to cancel this order?
+ products_cart_distributor_choice: "Distributor for your order:"
+ products_cart_distributor_change: "Your distributor for this order will be changed to %{name} if you add this product to your cart."
+ products_cart_distributor_is: "Your distributor for this order is %{name}."
+ products_distributor_error: "Please complete your order at %{link} before shopping with another distributor."
+ products_oc: "Order cycle for your order:"
+ products_oc_change: "Your order cycle for this order will be changed to %{name} if you add this product to your cart."
+ products_oc_is: "Your order cycle for this order is %{name}."
+ products_oc_error: "Please complete your order from %{link} before shopping in a different order cycle."
+ products_oc_current: "your current order cycle"
+ products_max_quantity: Max quantity
+ products_distributor: Distributor
+ products_distributor_info: When you select a distributor for your order, their address and pickup times will be displayed here.
+ products_distribution_adjustment_label: "Product distribution by %{distributor} for %{product}"
+ shop_trial_expires_in: "Your shopfront trial expires in"
+ shop_trial_expired_notice: "Good news! We have decided to extend shopfront trials until further notice."
+ password: Password
+ remember_me: Remember Me
+ are_you_sure: "Are you sure?"
+ orders_open: Orders open
+ closing: "Closing "
+ going_back_to_home_page: "Taking you back to the home page"
+ creating: Creating
+ updating: Updating
+ failed_to_create_enterprise: "Failed to create your enterprise."
+ failed_to_create_enterprise_unknown: "Failed to create your enterprise.\nPlease ensure all fields are completely filled out."
+ failed_to_update_enterprise_unknown: "Failed to update your enterprise.\nPlease ensure all fields are completely filled out."
+ enterprise_confirm_delete_message: "This will also delete the %{product} that this enterprise supplies. Are you sure you want to continue?"
+ order_not_saved_yet: "Your order hasn't been saved yet. Give us a few seconds to finish!"
+ filter_by: "Filter by"
+ hide_filters: "Hide filters"
+ one_filter_applied: "1 filter applied"
+ x_filters_applied: " filters applied"
+ submitting_order: "Submitting your order: please wait"
+ 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..."
+ error_required: "can't be blank"
+ error_number: "must be number"
+ error_email: "must be email address"
+ error_not_found_in_database: "%{name} not found in database"
+ error_not_primary_producer: "%{name} is not enabled as a producer"
+ error_no_permission_for_enterprise: "\"%{name}\": you do not have permission to manage products for this enterprise"
+ item_handling_fees: "Item Handling Fees (included in item totals)"
+ january: "January"
+ february: "February"
+ march: "March"
+ april: "April"
+ may: "May"
+ june: "June"
+ july: "July"
+ august: "August"
+ september: "September"
+ october: "October"
+ november: "November"
+ december: "December"
+ email_not_found: "Email address not found"
+ email_unconfirmed: "You must confirm your email address before you can reset your password."
+ email_required: "You must provide an email address"
+ logging_in: "Hold on a moment, we're logging you in"
+ signup_email: "Your email"
+ choose_password: "Choose a password"
+ confirm_password: "Confirm password"
+ action_signup: "Sign up now"
+ welcome_to_ofn: "Welcome to the Open Food Network!"
+ signup_or_login: "Start By Signing Up (or logging in)"
+ have_an_account: "Already have an account?"
+ action_login: "Log in now."
+ forgot_password: "Forgot Password?"
+ password_reset_sent: "An email with instructions on resetting your password has been sent!"
+ reset_password: "Reset password"
+ who_is_managing_enterprise: "Who is responsible for managing %{enterprise}?"
+ update_and_recalculate_fees: "Update And Recalculate Fees"
+ registration:
+ steps:
+ images:
+ continue: "Continue"
+ back: "Back"
+ headline: "Thanks!"
+ description: "Let's upload some pretty pictures so your profile looks great! :)"
+ type:
+ headline: "Last step to add %{enterprise}!"
+ question: "Are you a producer?"
+ yes_producer: "Yes, I'm a producer"
+ no_producer: "No, I'm not a producer"
+ producer_field_error: "Please choose one. Are you are producer?"
+ yes_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
+ no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
+ create_profile: "Create Profile"
+ enterprise:
+ registration:
+ modal:
+ steps:
+ details:
+ title: 'Details'
+ headline: "Let's Get Started"
+ enterprise: "Woot! First we need to know a little bit about your enterprise:"
+ producer: "Woot! First we need to know a little bit about your farm:"
+ enterprise_name_field: "Enterprise Name:"
+ producer_name_field: "Farm Name:"
+ producer_name_field_placeholder: "e.g. Charlie's Awesome Farm"
+ producer_name_field_error: "Please choose a unique name for your enterprise"
+ address1_field: "Address line 1:"
+ address1_field_placeholder: "e.g. 123 Cranberry Drive"
+ address1_field_error: "Please enter an address"
+ address2_field: "Address line 2:"
+ suburb_field: "Suburb:"
+ suburb_field_placeholder: "e.g. Northcote"
+ suburb_field_error: "Please enter a suburb"
+ postcode_field: "Postcode:"
+ postcode_field_placeholder: "e.g. 3070"
+ postcode_field_error: "Postcode required"
+ state_field: "State:"
+ state_field_error: "State required"
+ country_field: "Country:"
+ country_field_error: "Please select a country"
+ contact:
+ title: 'Contact'
+ contact_field: 'Primary Contact'
+ contact_field_placeholder: 'Contact Name'
+ contact_field_required: "You need to enter a primary contact."
+ email_field: 'Email address'
+ email_field_placeholder: 'eg. charlie@thefarm.com'
+ phone_field: 'Phone number'
+ phone_field_placeholder: 'eg. (03) 1234 5678'
+ type:
+ title: 'Type'
+ about:
+ title: 'About'
+ images:
+ title: 'Images'
+ social:
+ title: 'Social'
+ enterprise_contact: "Primary Contact"
+ enterprise_contact_placeholder: "Contact Name"
+ enterprise_contact_required: "You need to enter a primary contact."
+ enterprise_email_address: "Email address"
+ enterprise_email_placeholder: "eg. charlie@thefarm.com"
+ enterprise_phone: "Phone number"
+ enterprise_phone_placeholder: "eg. (03) 1234 5678"
+ back: "Back"
+ continue: "Continue"
+ limit_reached_headline: "Oh no!"
+ limit_reached_message: "You have reached the limit!"
+ limit_reached_text: "You have reached the limit for the number of enterprises you are allowed to own on the"
+ limit_reached_action: "Return to the homepage"
+ select_promo_image: "Step 3. Select Promo Image"
+ promo_image_tip: "Tip: Shown as a banner, preferred size is 1200×260px"
+ promo_image_label: "Choose a promo image"
+ action_or: "OR"
+ promo_image_drag: "Drag and drop your promo here"
+ review_promo_image: "Step 4. Review Your Promo Banner"
+ review_promo_image_tip: "Tip: for best results, your promo image should fill the available space"
+ promo_image_placeholder: "Your logo will appear here for review once uploaded"
+ uploading: "Uploading..."
+ select_logo: "Step 1. Select Logo Image"
+ logo_tip: "Tip: Square images will work best, preferably at least 300×300px"
+ logo_label: "Choose a logo image"
+ logo_drag: "Drag and drop your logo here"
+ review_logo: "Step 2. Review Your Logo"
+ review_logo_tip: "Tip: for best results, your logo should fill the available space"
+ logo_placeholder: "Your logo will appear here for review once uploaded"
+ enterprise_about_headline: "Nice one!"
+ enterprise_about_message: "Now let's flesh out the details about"
+ enterprise_success: "Success! %{enterprise} added to the Open Food Network "
+ enterprise_registration_exit_message: "If you exit this wizard at any stage, you can continue to create your profile by going to the admin interface."
+ enterprise_description: "Short Description"
+ enterprise_description_placeholder: "A short sentence describing your enterprise"
+ enterprise_long_desc: "Long Description"
+ enterprise_long_desc_placeholder: "This is your opportunity to tell the story of your enterprise - what makes you different and wonderful? We'd suggest keeping your description to under 600 characters or 150 words."
+ enterprise_long_desc_length: "%{num} characters / up to 600 recommended"
+ enterprise_abn: "ABN"
+ enterprise_abn_placeholder: "eg. 99 123 456 789"
+ enterprise_acn: "ACN"
+ enterprise_acn_placeholder: "eg. 123 456 789"
+ enterprise_tax_required: "You need to make a selection."
+ enterprise_final_step: "Final step!"
+ enterprise_social_text: "How can people find %{enterprise} online?"
+ website: "Website"
+ website_placeholder: "eg. openfoodnetwork.org.au"
+ facebook: "Facebook"
+ facebook_placeholder: "eg. www.facebook.com/PageNameHere"
+ linkedin: "LinkedIn"
+ linkedin_placeholder: "eg. www.linkedin.com/YourNameHere"
+ twitter: "Twitter"
+ twitter_placeholder: "eg. @twitter_handle"
+ instagram: "Instagram"
+ instagram_placeholder: "eg. @instagram_handle"
+ registration_greeting: "Hi there!"
+ registration_intro: "You can now create a profile for your Producer or Hub"
+ registration_action: "Let's get started!"
+ registration_checklist: "You'll need"
+ registration_time: "5-10 minutes"
+ registration_enterprise_address: "Enterprise address"
+ registration_contact_details: "Primary contact details"
+ registration_logo: "Your logo image"
+ registration_promo_image: "Landscape image for your profile"
+ registration_about_us: "'About Us' text"
+ registration_outcome_headline: "What do I get?"
+ registration_outcome1_html: "Your profile helps people find and contact you on the Open Food Network."
+ registration_outcome2: "Use this space to tell the story of your enterprise, to help drive connections to your social and online presence. "
+ registration_outcome3: "It's also the first step towards trading on the Open Food Network, or opening an online store."
+ registration_finished_headline: "Finished!"
+ registration_finished_thanks: "Thanks for filling out the details for %{enterprise}."
+ registration_finished_login: "You can change or update your enterprise at any stage by logging into Open Food Network and going to Admin."
+ registration_finished_action: "Open Food Network home"
+ registration_contact_name: 'Contact Name'
+ registration_type_headline: "Last step to add %{enterprise}!"
+ registration_type_question: "Are you a producer?"
+ registration_type_producer: "Yes, I'm a producer"
+ registration_type_no_producer: "No, I'm not a producer"
+ registration_type_error: "Please choose one. Are you are producer?"
+ registration_type_producer_help: "Producers make yummy things to eat and/or drink. You're a producer if you grow it, raise it, brew it, bake it, ferment it, milk it or mould it."
+ registration_type_no_producer_help: "If you’re not a producer, you’re probably someone who sells and distributes food. You might be a hub, coop, buying group, retailer, wholesaler or other."
+ registration_detail_headline: "Let's Get Started"
+ registration_detail_enterprise: "Woot! First we need to know a little bit about your enterprise:"
+ registration_detail_producer: "Woot! First we need to know a little bit about your farm:"
+ registration_detail_name_enterprise: "Enterprise Name:"
+ registration_detail_name_producer: "Farm Name:"
+ registration_detail_name_placeholder: "e.g. Charlie's Awesome Farm"
+ registration_detail_name_error: "Please choose a unique name for your enterprise"
+ registration_detail_address1: "Address line 1:"
+ registration_detail_address1_placeholder: "e.g. 123 Cranberry Drive"
+ registration_detail_address1_error: "Please enter an address"
+ registration_detail_address2: "Address line 2:"
+ registration_detail_suburb: "Suburb:"
+ registration_detail_suburb_placeholder: "e.g. Northcote"
+ registration_detail_suburb_error: "Please enter a suburb"
+ registration_detail_postcode: "Postcode:"
+ registration_detail_postcode_placeholder: "e.g. 3070"
+ registration_detail_postcode_error: "Postcode required"
+ registration_detail_state: "State:"
+ registration_detail_state_error: "State required"
+ registration_detail_country: "Country:"
+ registration_detail_country_error: "Please select a country"
+ shipping_method_destroy_error: "That shipping method cannot be deleted as it is referenced by an order: %{number}."
+ accounts_and_billing_task_already_running_error: "A task is already running, please wait until it has finished"
+ accounts_and_billing_start_task_notice: "Task Queued"
+ fees: "Fees"
+ item_cost: "Item cost"
+ bulk: "Bulk"
+ shop_variant_quantity_min: "min"
+ shop_variant_quantity_max: "max"
+ follow: "Follow"
+ shop_for_products_html: "Shop for %{enterprise} products at:"
+ change_shop: "Change shop to:"
+ shop_at: "Shop now at:"
+ price_breakdown: "Full price breakdown"
+ admin_fee: "Admin fee"
+ sales_fee: "Sales fee"
+ packing_fee: "Packing fee"
+ transport_fee: "Transport fee"
+ fundraising_fee: "Fundraising fee"
+ price_graph: "Price graph"
+ included_tax: "Included tax"
+ balance: "Balance"
+ transaction: "Transaction"
+ transaction_date: "Date"
+ payment_state: "Payment status"
+ shipping_state: "Shipping status"
+ value: "Value"
+ balance_due: "Balance due"
+ credit: "Credit"
+ Paid: "Paid"
+ Ready: "Ready"
+ ok: OK
+ not_visible: not visible
+ you_have_no_orders_yet: "You have no orders yet"
+ running_balance: "Running balance"
+ outstanding_balance: "Outstanding balance"
+ admin_enterprise_relationships: "Enterprise Permissions"
+ admin_enterprise_relationships_everything: "Everything"
+ admin_enterprise_relationships_permits: "permits"
+ admin_enterprise_relationships_seach_placeholder: "Search"
+ admin_enterprise_relationships_button_create: "Create"
+ admin_enterprise_groups: "Enterprise Groups"
+ admin_enterprise_groups_name: "Name"
+ admin_enterprise_groups_owner: "Owner"
+ admin_enterprise_groups_on_front_page: "On front page ?"
+ admin_enterprise_groups_enterprise: "Enterprises"
+ admin_enterprise_groups_data_powertip: "The primary user responsible for this group."
+ admin_enterprise_groups_data_powertip_logo: "This is the logo for the group"
+ admin_enterprise_groups_data_powertip_promo_image: "This image is displayed at the top of the Group profile"
+ admin_enterprise_groups_contact: "Contact"
+ admin_enterprise_groups_contact_phone_placeholder: "eg. 98 7654 3210"
+ admin_enterprise_groups_contact_address1_placeholder: "eg. 123 High Street"
+ admin_enterprise_groups_contact_city: "Suburb"
+ admin_enterprise_groups_contact_city_placeholder: "eg. Northcote"
+ admin_enterprise_groups_contact_zipcode: "Postcode"
+ admin_enterprise_groups_contact_zipcode_placeholder: "eg. 3070"
+ admin_enterprise_groups_contact_state_id: "State"
+ admin_enterprise_groups_contact_country_id: "Country"
+ admin_enterprise_groups_web: "Web Resources"
+ admin_enterprise_groups_web_twitter: "eg. @the_prof"
+ admin_enterprise_groups_web_website_placeholder: "eg. www.truffles.com"
+ admin_order_cycles: "Admin Order Cycles"
+ open: "Open"
+ close: "Close"
+ create: "Create"
+ search: "Search"
+ supplier: "Supplier"
+ product_name: "Product Name"
+ product_description: "Product Description"
+ units: "Unit Size"
+ coordinator: "Coordinator"
+ distributor: "Distributor"
+ enterprise_fees: "Enterprise Fees"
+ process_my_order: "Process My Order"
+ delivery_instructions: Delivery Instructions
+ delivery_method: Delivery Method
+ fee_type: "Fee Type"
+ tax_category: "Tax Category"
+ calculator: "Calculator"
+ calculator_values: "Calculator values"
+ flat_percent_per_item: "Flat Percent (per item)"
+ flat_rate_per_item: "Flat Rate (per item)"
+ flat_rate_per_order: "Flat Rate (per order)"
+ flexible_rate: "Flexible Rate"
+ price_sack: "Price Sack"
+ new_order_cycles: "New Order Cycles"
+ new_order_cycle: "New Order Cycle"
+ select_a_coordinator_for_your_order_cycle: "Select a coordinator for your order cycle"
+ notify_producers: 'Notify producers'
+ edit_order_cycle: "Edit Order Cycle"
+ roles: "Roles"
+ update: "Update"
+ delete: Delete
+ add_producer_property: "Add producer property"
+ in_progress: "In Progress"
+ started_at: "Started at"
+ queued: "Queued"
+ scheduled_for: "Scheduled for"
+ customers: "Customers"
+ please_select_hub: "Please select a Hub"
+ loading_customers: "Loading Customers"
+ no_customers_found: "No customers found"
+ go: "Go"
+ hub: "Hub"
+ producer: "Producer"
+ product: "Product"
+ price: "Price"
+ on_hand: "On hand"
+ save_changes: "Save Changes"
+ order_saved: "Order Saved"
+ no_products: No Products
+ spree_admin_overview_enterprises_header: "My Enterprises"
+ spree_admin_overview_enterprises_footer: "MANAGE MY ENTERPRISES"
+ spree_admin_enterprises_hubs_name: "Name"
+ spree_admin_enterprises_create_new: "CREATE NEW"
+ spree_admin_enterprises_shipping_methods: "Shipping Methods"
+ spree_admin_enterprises_fees: "Enterprise Fees"
+ spree_admin_enterprises_none_create_a_new_enterprise: "CREATE A NEW ENTERPRISE"
+ spree_admin_enterprises_none_text: "You don't have any enterprises yet"
+ spree_admin_enterprises_tabs_hubs: "HUBS"
+ spree_admin_enterprises_producers_manage_products: "MANAGE PRODUCTS"
+ spree_admin_enterprises_create_new_product: "CREATE A NEW PRODUCT"
+ spree_admin_single_enterprise_alert_mail_confirmation: "Please confirm the email address for"
+ spree_admin_single_enterprise_alert_mail_sent: "We've sent an email to"
+ spree_admin_overview_action_required: "Action Required"
+ spree_admin_overview_check_your_inbox: "Please check your inbox for further instructions. Thanks!"
+ spree_admin_unit_value: Unit Value
+ spree_admin_unit_description: Unit Description
+ spree_admin_variant_unit: Variant unit
+ spree_admin_variant_unit_scale: Variant unit scale
+ spree_admin_supplier: Supplier
+ spree_admin_product_category: Product Category
+ spree_admin_variant_unit_name: Variant unit name
+ change_package: "Change Package"
+ spree_admin_single_enterprise_hint: "Hint: To allow people to find you, turn on your visibility under"
+ spree_admin_eg_pickup_from_school: "eg. 'Pick-up from Primary School'"
+ spree_admin_eg_collect_your_order: "eg. 'Please collect your order from 123 Imaginary St, Northcote, 3070'"
+ spree_classification_primary_taxon_error: "Taxon %{taxon} is the primary taxon of %{product} and cannot be deleted"
+ spree_order_availability_error: "Distributor or order cycle cannot supply the products in your cart"
+ spree_order_populator_error: "That distributor or order cycle can't supply all the products in your cart. Please choose another."
+ spree_order_populator_availability_error: "That product is not available from the chosen distributor or order cycle."
+ spree_distributors_error: "At least one hub must be selected"
+ spree_user_enterprise_limit_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
+ spree_variant_product_error: must have at least one variant
+ your_profil_live: "Your profile live"
+ on_ofn_map: "on the Open Food Network map"
+ see: "See"
+ live: "live"
+ manage: "Manage"
+ resend: "Resend"
+ trial: Trial
+ add_and_manage_products: "Add & manage products"
+ add_and_manage_order_cycles: "Add & manage order cycles"
+ manage_order_cycles: "Manage order cycles"
+ manage_products: "Manage products"
+ edit_profile_details: "Edit profile details"
+ edit_profile_details_etc: "Change your profile description, images, etc."
+ order_cycle: "Order Cycle"
+ order_cycles: "Order Cycles"
+ enterprise_relationships: "Enterprise permissions"
+ remove_tax: "Remove tax"
+ first_name_begins_with: "First name begins with"
+ last_name_begins_with: "Last name begins with"
+ enterprise_tos_link: "Enterprise Terms of Service link"
+ enterprise_tos_message: "We want to work with people that share our aims and values. As such we ask new enterprises to agree to our "
+ enterprise_tos_link_text: "Terms of Service."
+ enterprise_tos_agree: "I agree to the above Terms of Service"
+ tax_settings: "Tax Settings"
+ products_require_tax_category: "products require tax category"
+ admin_shared_address_1: "Address"
+ admin_shared_address_2: "Address (cont.)"
+ admin_share_city: "City"
+ admin_share_zipcode: "Postcode"
+ admin_share_country: "Country"
+ admin_share_state: "State"
+ hub_sidebar_hubs: "Hubs"
+ hub_sidebar_none_available: "None Available"
+ hub_sidebar_manage: "Manage"
+ hub_sidebar_at_least: "At least one hub must be selected"
+ hub_sidebar_blue: "blue"
+ hub_sidebar_red: "red"
+ shop_trial_in_progress: "Your shopfront trial expires in %{days}."
+ report_customers_distributor: "Distributor"
+ report_customers_supplier: "Supplier"
+ report_customers_cycle: "Order Cycle"
+ report_customers_type: "Report Type"
+ report_customers_csv: "Download as csv"
+ report_producers: "Producers: "
+ report_type: "Report Type: "
+ report_hubs: "Hubs: "
+ report_payment: "Payment Methods: "
+ report_distributor: "Distributor: "
+ report_payment_by: 'Payments By Type'
+ report_itemised_payment: 'Itemised Payment Totals'
+ report_payment_totals: 'Payment Totals'
+ report_all: 'all'
+ report_order_cycle: "Order Cycle: "
+ report_enterprises: "Enterprises: "
+ report_users: "Users: "
+ report_tax_rates: Tax rates
+ report_tax_types: Tax types
+ report_header_order_cycle: Order Cycle
+ report_header_user: User
+ report_header_email: Email
+ report_header_status: Status
+ report_header_comments: Comments
+ report_header_first_name: First Name
+ report_header_last_name: Last Name
+ report_header_phone: Phone
+ report_header_suburb: Suburb
+ report_header_address: Address
+ report_header_billing_address: Billing Address
+ report_header_relationship: Relationship
+ report_header_hub: Hub
+ report_header_hub_address: Hub Address
+ report_header_to_hub: To Hub
+ report_header_hub_code: Hub Code
+ report_header_code: Code
+ report_header_paid: Paid?
+ report_header_delivery: Delivery?
+ report_header_shipping: Shipping
+ report_header_shipping_method: Shipping Method
+ report_header_shipping_instructions: Shipping instructions
+ report_header_ship_street: Ship Street
+ report_header_ship_street_2: Ship Street 2
+ report_header_ship_city: Ship City
+ report_header_ship_postcode: Ship Postcode
+ report_header_ship_state: Ship State
+ report_header_billing_street: Billing Street
+ report_header_billing_street_2: Billing Street 2
+ report_header_billing_street_3: Billing Street 3
+ report_header_billing_street_4: Billing Street 4
+ report_header_billing_city: Billing City
+ report_header_billing_postcode: Billing Postcode
+ report_header_billing_state: Billing State
+ report_header_incoming_transport: Incoming Transport
+ report_header_special_instructions: Special Instructions
+ report_header_order_number: Order number
+ report_header_date: Date
+ report_header_confirmation_date: Confirmation Date
+ report_header_tags: Tags
+ report_header_items: Items
+ report_header_items_total: "Items total %{currency_symbol}"
+ report_header_taxable_items_total: "Taxable Items Total (%{currency_symbol})"
+ report_header_sales_tax: "Sales Tax (%{currency_symbol})"
+ report_header_delivery_charge: "Delivery Charge (%{currency_symbol})"
+ report_header_tax_on_delivery: "Tax on Delivery (%{currency_symbol})"
+ report_header_tax_on_fees: "Tax on Fees (%{currency_symbol})"
+ report_header_total_tax: "Total Tax (%{currency_symbol})"
+ report_header_enterprise: Enterprise
+ report_header_customer: Customer
+ report_header_customer_code: Customer Code
+ report_header_product: Product
+ report_header_product_properties: Product Properties
+ report_header_quantity: Quantity
+ report_header_max_quantity: Max Quantity
+ report_header_variant: Variant
+ report_header_variant_value: Variant Value
+ report_header_variant_unit: Variant Unit
+ report_header_total_available: Total available
+ report_header_unallocated: Unallocated
+ report_header_max_quantity_excess: Max Quantity Excess
+ report_header_taxons: Taxons
+ report_header_supplier: Supplier
+ report_header_producer: Producer
+ report_header_producer_suburb: Producer Suburb
+ report_header_unit: Unit
+ report_header_group_buy_unit_quantity: Group Buy Unit Quantity
+ report_header_cost: Cost
+ report_header_shipping_cost: Shipping Cost
+ report_header_curr_cost_per_unit: Curr. Cost per Unit
+ report_header_total_shipping_cost: Total Shipping Cost
+ report_header_payment_method: Payment Method
+ report_header_sells: Sells
+ report_header_visible: Visible
+ report_header_price: Price
+ report_header_unit_size: Unit Size
+ report_header_distributor: Distributor
+ report_header_distributor_address: Distributor address
+ report_header_distributor_city: Distributor city
+ report_header_distributor_postcode: Distributor postcode
+ report_header_delivery_address: Delivery Address
+ report_header_delivery_postcode: Delivery Postcode
+ report_header_bulk_unit_size: Bulk Unit Size
+ report_header_weight: Weight
+ report_header_sum_total: Sum Total
+ report_header_date_of_order: Date of Order
+ report_header_amount_owing: Amount Owing
+ report_header_amount_paid: Amount Paid
+ report_header_units_required: Units Required
+ report_header_remainder: Remainder
+ report_header_order_date: Order date
+ report_header_order_id: Order Id
+ report_header_item_name: Item name
+ report_header_temp_controlled_items: Temp Controlled Items?
+ report_header_customer_name: Customer Name
+ report_header_customer_email: Customer Email
+ report_header_customer_phone: Customer Phone
+ report_header_customer_city: Customer City
+ report_header_payment_state: Payment State
+ report_header_payment_type: Payment Type
+ report_header_item_price: "Item (%{currency})"
+ report_header_item_fees_price: "Item + Fees (%{currency})"
+ report_header_admin_handling_fees: "Admin & Handling (%{currency})"
+ report_header_ship_price: "Ship (%{currency})"
+ report_header_pay_fee_price: "Pay fee (%{currency})"
+ report_header_total_price: "Total (%{currency})"
+ report_header_product_total_price: "Product Total (%{currency})"
+ report_header_shipping_total_price: "Shipping Total (%{currency})"
+ report_header_outstanding_balance_price: "Outstanding Balance (%{currency})"
+ report_header_eft_price: "EFT (%{currency})"
+ report_header_paypal_price: "PayPal (%{currency})"
+ report_header_sku: SKU
+ report_header_amount: Amount
+ report_header_balance: Balance
+ report_header_total_cost: "Total Cost"
+ report_header_total_ordered: Total Ordered
+ report_header_total_max: Total Max
+ 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_incl_vat: "Total incl. tax (%{currency_symbol})"
+ report_header_temp_controlled: TempControlled?
+ report_header_is_producer: Producer?
+ report_header_not_confirmed: Not Confirmed
+ report_header_gst_on_income: GST on Income
+ report_header_gst_free_income: GST Free Income
+ report_header_total_untaxable_produce: Total untaxable produce (no tax)
+ report_header_total_taxable_produce: Total taxable produce (tax inclusive)
+ report_header_total_untaxable_fees: Total untaxable fees (no tax)
+ report_header_total_taxable_fees: Total taxable fees (tax inclusive)
+ report_header_delivery_shipping_cost: Delivery Shipping Cost (tax inclusive)
+ report_header_transaction_fee: Transaction Fee (no tax)
+ report_header_total_untaxable_admin: Total untaxable admin adjustments (no tax)
+ report_header_total_taxable_admin: Total taxable admin adjustments (tax inclusive)
+ initial_invoice_number: "Initial invoice number:"
+ invoice_date: "Invoice date:"
+ due_date: "Due date:"
+ account_code: "Account code:"
+ equals: "Equals"
+ contains: "contains"
+ discount: "Discount"
+ filter_products: "Filter Products"
+ delete_product_variant: "The last variant cannot be deleted!"
+ progress: "progress"
+ saving: "Saving.."
+ success: "success"
+ failure: "failure"
+ unsaved_changes_confirmation: "Unsaved changes will be lost. Continue anyway?"
+ one_product_unsaved: "Changes to one product remain unsaved."
+ products_unsaved: "Changes to %{n} products remain unsaved."
+ is_already_manager: "is already a manager!"
+ no_change_to_save: " No change to save"
+ user_invited: "%{email} has been invited to manage this enterprise"
+ add_manager: "Add an existing user"
+ users: "Users"
+ about: "About"
+ images: "Images"
+ web: "Web"
+ primary_details: "Primary Details"
+ adrdress: "Address"
+ contact: "Contact"
+ social: "Social"
+ business_details: "Business Details"
+ properties: "Properties"
+ shipping: "Shipping"
+ shipping_methods: "Shipping Methods"
+ payment_methods: "Payment Methods"
+ payment_method_fee: "Transaction fee"
+ inventory_settings: "Inventory Settings"
+ tag_rules: "Tag Rules"
+ shop_preferences: "Shop Preferences"
+ enterprise_fee_whole_order: Whole order
+ enterprise_fee_by: "%{type} fee by %{role} %{enterprise_name}"
+ validation_msg_relationship_already_established: "^That relationship is already established."
+ validation_msg_at_least_one_hub: "^At least one hub must be selected"
+ validation_msg_product_category_cant_be_blank: "^Product Category cant be blank"
+ validation_msg_tax: "^Tax Category is required"
+ validation_msg_tax_category_cant_be_blank: "^Tax Category can't be blank"
+ validation_msg_is_associated_with_an_exising_customer: "is associated with an existing customer"
+ content_configuration_pricing_table: "(TODO: Pricing table)"
+ content_configuration_case_studies: "(TODO: Case studies)"
+ content_configuration_detail: "(TODO: Detail)"
+ enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}."
+ enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
+ enterprise_role_uniqueness_error: "^That role is already present."
+ inventory_item_visibility_error: must be true or false
+ product_importer_file_error: "error: no file uploaded"
+ product_importer_spreadsheet_error: "could not process file: invalid filetype"
+ product_importer_products_save_error: did not save any products successfully
+ product_import_file_not_found_notice: 'File not found or could not be opened'
+ product_import_no_data_in_spreadsheet_notice: 'No data found in spreadsheet'
+ order_choosing_hub_notice: Your hub has been selected.
+ order_cycle_selecting_notice: Your order cycle has been selected.
+ adjustments_tax_rate_error: "^Please check that the tax rate for this adjustment is correct."
+ active_distributors_not_ready_for_checkout_message_singular: >-
+ The hub %{distributor_names} is listed in an active order cycle, but does not
+ have valid shipping and payment methods. Until you set these up, customers will
+ not be able to shop at this hub.
+ active_distributors_not_ready_for_checkout_message_plural: >-
+ The hubs %{distributor_names} are listed in an active order cycle, but do not
+ have valid shipping and payment methods. Until you set these up, customers will
+ not be able to shop at these hubs.
+ enterprise_fees_update_notice: Your enterprise fees have been updated.
+ enterprise_fees_destroy_error: "That enterprise fee cannot be deleted as it is referenced by a product distribution: %{id} - %{name}."
+ enterprise_register_package_error: "Please select a package"
+ enterprise_register_error: "Could not complete registration for %{enterprise}"
+ enterprise_register_success_notice: "Congratulations! Registration for %{enterprise} is complete!"
+ enterprise_bulk_update_success_notice: "Enterprises updated successfully"
+ enterprise_bulk_update_error: 'Update failed'
+ order_cycles_create_notice: 'Your order cycle has been created.'
+ order_cycles_update_notice: 'Your order cycle has been updated.'
+ order_cycles_bulk_update_notice: 'Order cycles have been updated.'
+ order_cycles_clone_notice: "Your order cycle %{name} has been cloned."
+ order_cycles_email_to_producers_notice: 'Emails to be sent to producers have been queued for sending.'
+ order_cycles_no_permission_to_coordinate_error: "None of your enterprises have permission to coordinate an order cycle"
+ order_cycles_no_permission_to_create_error: "You don't have permission to create an order cycle coordinated by that enterprise"
+ back_to_orders_list: "Back to order list"
+ no_orders_found: "No Orders Found"
+ order_information: "Order Information"
+ date_completed: "Date Completed"
+ amount: "Amount"
+ state_names:
+ ready: Ready
+ pending: Pending
+ shipped: Shipped
+ js:
+ saving: 'Saving...'
+ changes_saved: 'Changes saved.'
+ save_changes_first: Save changes first.
+ all_changes_saved: All changes saved
+ unsaved_changes: You have unsaved changes
+ all_changes_saved_successfully: All changes saved successfully
+ oh_no: "Oh no! I was unable to save your changes."
+ unauthorized: "You are unauthorised to access this page."
+ error: Error
+ unavailable: Unavailable
+ profile: Profile
+ hub: Hub
+ shop: Shop
+ choose: Choose
+ resolve_errors: Please resolve the following errors
+ more_items: "+ %{count} More"
+ default_card_updated: Default Card Updated
+ admin:
+ enterprise_limit_reached: "You have reached the standard limit of enterprises per account. Write to %{contact_email} if you need to increase it."
+ modals:
+ got_it: Got it
+ close: "Close"
+ invite: "Invite"
+ invite_title: "Invite an unregistered user"
+ tag_rule_help:
+ title: Tag Rules
+ overview: Overview
+ overview_text: >
+ Tag rules provide a way to describe which items are visible or otherwise
+ to which customers. Items can be Shipping Methods, Payment Methods,
+ Products and Order Cycles.
+ by_default_rules: "'By Default...' Rules"
+ by_default_rules_text: >
+ Default rules allow you to hide items so that they are not visible by
+ default. This behaviour can then be overriden by non-default rules for
+ customers with particular tags.
+ customer_tagged_rules: "'Customers Tagged...' Rules"
+ customer_tagged_rules_text: >
+ By creating rules related to a specific customer tag, you can override
+ the default behaviour (whether it be to show or to hide items) for customers
+ with the specified tag.
+ panels:
+ save: SAVE
+ saved: SAVED
+ saving: SAVING
+ enterprise_package:
+ hub_profile: Hub Profile
+ hub_profile_cost: "COST: ALWAYS FREE"
+ hub_profile_text1: >
+ People can find and contact you on the Open Food Network. Your enterprise
+ will be visible on the map, and will be searchable in listings.
+ hub_profile_text2: >
+ Having a profile, and making connections within your local food system
+ through the Open Food Network will always be free.
+ hub_shop: Hub Shop
+ hub_shop_text1: >
+ Your enterprise is the backbone of your local food system. You aggregate
+ produce from other enterprises and can sell it through your shop on
+ the Open Food Network.
+ hub_shop_text2: >
+ Hubs can take many forms, whether they be a food co-op, a buying group,
+ a veggie-box program, or a local grocery store.
+ hub_shop_text3: >
+ If you also want to sell your own products, you will need to switch
+ this enterprise to be a producer.
+ choose_package: Please Choose a Package
+ choose_package_text1: >
+ Your enterprise will not be fully activated until a package is selected
+ from the options on the left.
+ choose_package_text2: >
+ Click on an option to see more detailed information about each package,
+ and hit the red SAVE button when you are done!
+ profile_only: Profile Only
+ profile_only_cost: "COST: ALWAYS FREE"
+ profile_only_text1: >
+ A profile makes you visible and contactable to others and is a way to
+ share your story.
+ profile_only_text2: >
+ If you prefer to focus on producing food, and want to leave the work
+ of selling it to someone else, you won't require a shop on the Open
+ Food Network.
+ profile_only_text3: >
+ Add your products to Open Food Network, allowing hubs to stock your
+ products in their stores.
+ producer_shop: Producer Shop
+ producer_shop_text1: >
+ Sell your products directly to customers through your very own Open
+ Food Network shopfront.
+ producer_shop_text2: >
+ A Producer Shop is for your produce only, if you want to sell produce
+ grown/produced off site, please select 'Producer Hub'.
+ producer_hub: Producer Hub
+ producer_hub_text1: >
+ Your enterprise is the backbone of your local food system. You can sell
+ your own produce as well as produce aggregated from other enterprises
+ through your shopfront on the Open Food Network.
+ producer_hub_text2: >
+ Producer Hubs can take many forms, whether they be a CSA, a veggie-box
+ program, or a food co-op with a rooftop garden.
+ producer_hub_text3: >
+ The Open Food Network aims to support as many hub models as possible,
+ so no matter your situation, we want to provide the tools you need to
+ run your organisation or local food business.
+ get_listing: Get a listing
+ always_free: ALWAYS FREE
+ sell_produce_others: Sell produce from others
+ sell_own_produce: Sell your own produce
+ sell_both: Sell produce from self and others
+ enterprise_producer:
+ producer: Producer
+ producer_text1: >
+ Producers make yummy things to eat or drink. You're a producer if you
+ grow it, raise it, brew it, bake it, ferment it, milk it or mould it.
+ producer_text2: >
+ Producers can also perform other functions, such as aggregating food
+ from other enterprises and selling it through a shop on the Open Food
+ Network.
+ non_producer: Non-producer
+ non_producer_text1: >
+ Non-producers do not produce any food themselves, meaning that they
+ cannot create their own products for sale through the Open Food Network.
+ non_producer_text2: >
+ Instead, non-producers specialise in linking producers to the end eater,
+ whether it be by aggregating, grading, packing, selling or delivering
+ food.
+ producer_desc: Producers of food
+ producer_example: eg. GROWERS, BAKERS, BREWERS, MAKERS
+ non_producer_desc: All other food enterprises
+ non_producer_example: eg. Grocery stores, Food co-ops, Buying groups
+ enterprise_status:
+ status_title: "%{name} is set up and ready to go!"
+ severity: Severity
+ description: Description
+ resolve: Resolve
+ new_tag_rule_dialog:
+ select_rule_type: "Select a rule type:"
+ orders:
+ index:
+ per_page: "%{results} per page"
+ view_file: View File
+ compiling_invoices: Compiling Invoices
+ bulk_invoice_created: Bulk Invoice created
+ bulk_invoice_failed: Failed to create Bulk Invoice
+ please_wait: Please wait until the PDF is ready before closing this modal.
+ resend_user_email_confirmation:
+ resend: "Resend"
+ sending: "Resend..."
+ done: "Resend done ✓"
+ failed: "Resend failed ✗"
+ out_of_stock:
+ reduced_stock_available: Reduced stock available
+ out_of_stock_text: >
+ While you've been shopping, the stock levels for one or more of the products
+ in your cart have reduced. Here's what's changed:
+ now_out_of_stock: is now out of stock.
+ only_n_remainging: "now only has %{num} remaining."
+ variants:
+ on_demand:
+ 'yes': "On demand"
+ variant_overrides:
+ on_demand:
+ use_producer_settings: "Use producer stock settings"
+ 'yes': "Yes"
+ 'no': "No"
+ inventory_products: "Inventory Products"
+ hidden_products: "Hidden Products"
+ new_products: "New Products"
+ reset_stock_levels: Reset Stock Levels To Defaults
+ changes_to: Changes to
+ one_override: one override
+ overrides: overrides
+ remain_unsaved: remain unsaved.
+ no_changes_to_save: No changes to save.'
+ no_authorisation: "I couldn't get authorisation to save those changes, so they remain unsaved."
+ some_trouble: "I had some trouble saving: %{errors}"
+ changing_on_hand_stock: Changing on hand stock levels...
+ stock_reset: Stocks reset to defaults.
+ tag_rules:
+ show_hide_variants: 'Show or Hide variants in my shopfront'
+ show_hide_shipping: 'Show or Hide shipping methods at checkout'
+ show_hide_payment: 'Show or Hide payment methods at checkout'
+ show_hide_order_cycles: 'Show or Hide order cycles in my shopfront'
+ visible: VISIBLE
+ not_visible: NOT VISIBLE
+ services:
+ unsaved_changes_message: Unsaved changes currently exist, save now or ignore?
+ save: SAVE
+ ignore: IGNORE
+ add_to_order_cycle: "add to order cycle"
+ manage_products: "manage products"
+ edit_profile: "edit profile"
+ add_products_to_inventory: "add products to inventory"
+ resources:
+ could_not_delete_customer: 'Could not delete customer'
+ product_import:
+ confirmation: |
+ This will set stock level to zero on all products for this
+ enterprise that are not present in the uploaded file.
+ order_cycles:
+ create_failure: "Failed to create order cycle"
+ update_success: 'Your order cycle has been updated.'
+ update_failure: "Failed to update order cycle"
+ no_distributors: There are no distributors in this order cycle. This order cycle will not be visible to customers until you add one. Would you like to continue saving this order cycle?'
+ enterprises:
+ producer: "Producer"
+ non_producer: "Non-Producer"
+ customers:
+ select_shop: 'Please select a shop first'
+ could_not_create: Sorry! Could not create
+ subscriptions:
+ closes: closes
+ closed: closed
+ close_date_not_set: Close date not set
+ producers:
+ signup:
+ start_free_profile: "Start with a free profile, and expand when you're ready!"
+ order_management:
+ reports:
+ enterprise_fee_summary:
+ date_end_before_start_error: "must be after start"
+ parameter_not_allowed_error: "You are not authorized to use one or more selected filters for this report."
+ fee_calculated_on_transfer_through_all: "All"
+ fee_calculated_on_transfer_through_entire_orders: "Entire Orders through %{distributor}"
+ tax_category_various: "Various"
+ fee_type:
+ payment_method: "Payment Transaction"
+ shipping_method: "Shipment"
+ fee_placements:
+ supplier: "Incoming"
+ distributor: "Outgoing"
+ coordinator: "Coordinator"
+ tax_category_name:
+ shipping_instance_rate: "Platform Rate"
+ formats:
+ csv:
+ header:
+ fee_type: "Fee Type"
+ enterprise_name: "Enterprise Owner"
+ fee_name: "Fee Name"
+ customer_name: "Customer"
+ fee_placement: "Fee Placement"
+ fee_calculated_on_transfer_through_name: "Fee Calc on Transfer Through"
+ tax_category_name: "Tax Category"
+ total_amount: "$$ SUM"
+ html:
+ header:
+ fee_type: "Fee Type"
+ enterprise_name: "Enterprise Owner"
+ fee_name: "Fee Name"
+ customer_name: "Customer"
+ fee_placement: "Fee Placement"
+ fee_calculated_on_transfer_through_name: "Fee Calc on Transfer Through"
+ tax_category_name: "Tax Category"
+ total_amount: "$$ SUM"
+ invalid_filter_parameters: "The filters you selected for this report are invalid."
+ spree:
+ email: Email
+ account_updated: "Account updated!"
+ my_account: "My account"
+ date: "Date"
+ time: "Time"
+ layouts:
+ admin:
+ header:
+ store: Store
+ admin:
+ product_properties:
+ index:
+ inherits_properties_checkbox_hint: "Inherit properties from %{supplier}? (unless overridden above)"
+ orders:
+ index:
+ listing_orders: "Listing Orders"
+ new_order: "New Order"
+ capture: "Capture"
+ ship: "Ship"
+ edit: "Edit"
+ note: "Note"
+ first: "First"
+ last: "Last"
+ previous: "Previous"
+ next: "Next"
+ loading: "Loading"
+ no_orders_found: "No Orders Found"
+ results_found: " %{number}Results found."
+ viewing: "Viewing %{start} to %{end}."
+ print_invoices: "Print Invoices"
+ invoice:
+ issued_on: Issued on
+ tax_invoice: TAX INVOICE
+ code: Code
+ from: From
+ to: To
+ form:
+ distribution_fields:
+ title: Distribution
+ distributor: "Distributor:"
+ order_cycle: "Order cycle:"
+ overview:
+ products:
+ active_products:
+ zero: "You don't have any active products."
+ one: "You have one active product"
+ other: "You have %{count} active products"
+ order_cycles:
+ order_cycles: "Order Cycles"
+ order_cycles_tip: "Order cycles determine when and where your products are available to customers."
+ you_have_active:
+ zero: "You don't have any active order cycles."
+ one: "You have one active order cycle."
+ other: "You have %{count} active order cycles."
+ manage_order_cycles: "MANAGE ORDER CYCLES"
+ payment_methods:
+ new:
+ new_payment_method: "New Payment Method"
+ back_to_payment_methods_list: "Back To Payment Methods List"
+ edit:
+ editing_payment_method: "Editing Payment Method"
+ back_to_payment_methods_list: "Back To Payment Methods List"
+ stripe_connect:
+ enterprise_select_placeholder: Choose...
+ loading_account_information_msg: Loading account information from stripe, please wait...
+ stripe_disabled_msg: Stripe payments have been disabled by the system administrator.
+ request_failed_msg: Sorry. Something went wrong when trying to verify account details with Stripe...
+ account_missing_msg: No Stripe account exists for this enterprise.
+ connect_one: Connect One
+ access_revoked_msg: Access to this Stripe account has been revoked, please reconnect your account.
+ status: Status
+ connected: Connected
+ account_id: Account ID
+ business_name: Business Name
+ charges_enabled: Charges Enabled
+ payments:
+ source_forms:
+ stripe:
+ error_saving_payment: Error saving payment
+ submitting_payment: Submitting payment...
+ products:
+ new:
+ title: 'New Product'
+ unit_name_placeholder: 'eg. bunches'
+ index:
+ header:
+ title: Bulk Edit Products
+ indicators:
+ title: LOADING PRODUCTS
+ no_products: "No products yet. Why don't you add some?"
+ no_results: "Sorry, no results match"
+ products_head:
+ name: Name
+ unit: Unit
+ display_as: Display As
+ category: Category
+ tax_category: Tax Category
+ inherits_properties?: Inherits Properties?
+ available_on: Available On
+ av_on: "Av. On"
+ import_date: "Import Date"
+ products_variant:
+ variant_has_n_overrides: "This variant has %{n} override(s)"
+ new_variant: "New variant"
+ product_name: Product Name
+ primary_taxon_form:
+ product_category: Product Category
+ group_buy_form:
+ group_buy: "Group Buy?"
+ bulk_unit_size: Bulk unit size
+ display_as:
+ display_as: Display As
+ reports:
+ table:
+ select_and_search: "Select filters and click on %{option} to access your data."
+ bulk_coop:
+ bulk_coop_supplier_report: 'Bulk Co-op - Totals by Supplier'
+ bulk_coop_allocation: 'Bulk Co-op - Allocation'
+ bulk_coop_packing_sheets: 'Bulk Co-op - Packing Sheets'
+ bulk_coop_customer_payments: 'Bulk Co-op - Customer Payments'
+ enterprise_fee_summaries:
+ filters:
+ date_range: "Date Range"
+ report_format_csv: "Download as CSV"
+ generate_report: "Generate Report"
+ report:
+ none: "None"
+ select_and_search: "Select filters and click on GENERATE REPORT to access your data."
+ users:
+ index:
+ listing_users: "Listing Users"
+ new_user: "New User"
+ user: "User"
+ enterprise_limit: "Enterprise Limit"
+ search: "Search"
+ email: "Email"
+ edit:
+ editing_user: "Editing User"
+ back_to_users_list: "Back To Users List"
+ general_settings: "General Settings"
+ form:
+ email: "Email"
+ roles: "Roles"
+ enterprise_limit: "Enterprise Limit"
+ confirm_password: "Confirm Password"
+ password: "Password"
+ email_confirmation:
+ confirmation_pending: "Email confirmation is pending. We've sent a confirmation email to %{address}."
+ variants:
+ autocomplete:
+ producer_name: Producer
+ general_settings:
+ edit:
+ legal_settings: "Legal Settings"
+ cookies_consent_banner_toggle: "Display cookies consent banner"
+ privacy_policy_url: "Privacy Policy URL"
+ enterprises_require_tos: "Enterprises must accept Terms of Service"
+ cookies_policy_matomo_section: "Display Matomo section on cookies policy page"
+ cookies_policy_ga_section: "Display Google Analytics section on cookies policy page"
+ footer_tos_url: "Terms of Service URL"
+ checkout:
+ payment:
+ stripe:
+ choose_one: Choose one
+ enter_new_card: Enter details for a new card
+ used_saved_card: "Use a saved card:"
+ or_enter_new_card: "Or, enter details for a new card:"
+ remember_this_card: Remember this card?
+ date_picker:
+ format: '%Y-%m-%d'
+ js_format: 'yy-mm-dd'
+ inventory: Inventory
+ orders:
+ edit:
+ login_to_view_order: "Please log in to view your order."
+ bought:
+ item: "Already ordered in this order cycle"
+ order_mailer:
+ invoice_email:
+ hi: "Hi %{name}"
+ invoice_attached_text: Please find attached an invoice for your recent order from
+ order_state:
+ address: address
+ adjustments: adjustments
+ awaiting_return: awaiting return
+ canceled: cancelled
+ cart: cart
+ complete: complete
+ confirm: confirm
+ delivery: delivery
+ paused: paused
+ payment: payment
+ pending: pending
+ resumed: resumed
+ returned: returned
+ skrill: skrill
+ subscription_state:
+ active: active
+ pending: pending
+ ended: ended
+ paused: paused
+ canceled: cancelled
+ payment_states:
+ balance_due: balance due
+ completed: completed
+ checkout: checkout
+ credit_owed: credit owed
+ failed: failed
+ paid: paid
+ pending: pending
+ processing: processing
+ void: void
+ invalid: invalid
+ shipment_states:
+ backorder: backorder
+ partial: partial
+ pending: pending
+ ready: ready
+ shipped: shipped
+ user_mailer:
+ reset_password_instructions:
+ request_sent_text: |
+ A request to reset your password has been made.
+ If you did not make this request, simply ignore this email.
+ link_text: >
+ If you did make this request just click the link below:
+ issue_text: |
+ If the above URL does not work try copying and pasting it into your browser.
+ If you continue to have problems please feel free to contact us.
+ confirmation_instructions:
+ subject: Please confirm your OFN account
+ weight: Weight (per kg)
+ zipcode: Postcode
+ users:
+ form:
+ account_settings: Account Settings
+ show:
+ tabs:
+ orders: Orders
+ cards: Credit Cards
+ transactions: Transactions
+ settings: Account Settings
+ unconfirmed_email: "Pending email confirmation for: %{unconfirmed_email}. Your email address will be updated once the new email is confirmed."
+ orders:
+ open_orders: Open Orders
+ past_orders: Past Orders
+ transactions:
+ transaction_history: Transaction History
+ open_orders:
+ order: Order
+ shop: Shop
+ changes_allowed_until: Changes Allowed Until
+ items: Items
+ total: Total
+ edit: Edit
+ cancel: Cancel
+ closed: Closed
+ until: Until
+ past_orders:
+ order: Order
+ shop: Shop
+ completed_at: Completed At
+ items: Items
+ total: Total
+ paid?: Paid?
+ view: View
+ saved_cards:
+ default?: Default?
+ delete?: Delete?
+ cards:
+ authorised_shops: Authorised Shops
+ authorised_shops_popover: This is the list of shops which are permitted to charge your default credit card for any subscriptions (ie. repeating orders) you may have. Your card details will be kept secure and will not be shared with shop owners. You will always be notified when you are charged.
+ saved_cards_popover: This is the list of cards you have opted to save for later use. Your 'default' will be selected automatically when you checkout an order, and can be charged by any shops you have allowed to do so (see right).
+ authorised_shops:
+ shop_name: "Shop Name"
+ allow_charges?: "Allow Charges?"
+ localized_number:
+ invalid_format: has an invalid format. Please enter a number.
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 73bddfe067..fcd2d21ff7 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -31,6 +31,16 @@ es:
on_demand_but_count_on_hand_set: "debe estar en blanco si está bajo demanda"
limited_stock_but_no_count_on_hand: "se debe especificar porque se ha definido estoc limitado"
activemodel:
+ attributes:
+ order_management/reports/enterprise_fee_summary/parameters:
+ start_at: "Inicio"
+ end_at: "Final"
+ distributor_ids: "Hubs"
+ producer_ids: "Productoras"
+ order_cycle_ids: "Ciclos de Pedido"
+ enterprise_fee_ids: "Nombres de las comisiones"
+ shipping_method_ids: "Métodos de envío"
+ payment_method_ids: "Métodos de Pago"
errors:
models:
subscription_validator:
@@ -74,6 +84,13 @@ es:
models:
order_cycle:
cloned_order_cycle_name: "COPIA DE %{order_cycle}"
+ validators:
+ date_time_string_validator:
+ not_string_error: "debe ser una cadena"
+ invalid_format_error: "debe ser válido"
+ integer_array_validator:
+ not_array_error: "debe ser una matriz"
+ invalid_element_error: "debe contener solo enteros válidos"
enterprise_mailer:
confirmation_instructions:
subject: "Confirma la dirección de correo electrónico de %{enterprise}"
@@ -851,7 +868,7 @@ es:
pickup_instructions_tip: Estas instrucciones se muestran a las consumidoras después de completar un pedido.
pickup_time_placeholder: "Listo para ( Fecha / Hora)"
receival_instructions_placeholder: "Instrucciones de recepción"
- add_fee: 'Añadir tarifa'
+ add_fee: 'Añadir comisión'
selected: 'seleccionado'
add_exchange_form:
add_supplier: 'Añadir proveedora'
@@ -868,7 +885,7 @@ es:
search_by_order_cycle_name: "Buscar por nombre del Ciclo de Pedido..."
involving: "Involucrando"
any_enterprise: "Cualquier organización"
- any_schedule: "Cualquier horario"
+ any_schedule: "Cualquier programación"
form:
incoming: Entrante
supplier: Proveedora
@@ -882,19 +899,19 @@ es:
delivery_details: Detalles de Recogida / Entrega
debug_info: Información de Debug
index:
- schedule: Horario
- schedules: Horarios
- adding_a_new_schedule: Agregar un nuevo horario
- updating_a_schedule: Actualización de un horario
- new_schedule: Nuevo horario
- create_schedule: Crear horario
- update_schedule: Actualizar horario
- delete_schedule: Eliminar horario
- created_schedule: Horario creado
- updated_schedule: Horario actualizado
- deleted_schedule: Horario eliminado
- schedule_name_placeholder: Nombre del horario
- name_required_error: Por favor ingrese un nombre para este horario
+ schedule: Programación
+ schedules: Programación
+ adding_a_new_schedule: Agregar una nueva programación
+ updating_a_schedule: Actualización de una programación
+ new_schedule: Nueva programación
+ create_schedule: Crear programación
+ update_schedule: Actualizar programación
+ delete_schedule: Eliminar programación
+ created_schedule: Programación creada
+ updated_schedule: Programación actualizada
+ deleted_schedule: Programación eliminada
+ schedule_name_placeholder: Nombre de la programación
+ name_required_error: Por favor ingrese un nombre para esta programación
no_order_cycles_error: Seleccione al menos un ciclo de pedido (arrastrar y soltar)
name_and_timing_form:
name: Nombre
@@ -914,7 +931,7 @@ es:
fees: Comisiones
destroy_errors:
orders_present: Ese ciclo de pedido ha sido seleccionado por un cliente y no puede ser eliminado. Para evitar que los clientes accedan a él, ciérrelo.
- schedule_present: Ese ciclo de pedido está vinculado a un horario y no puede ser eliminado. Desvincula o elimina el calendario primero.
+ schedule_present: Ese ciclo de pedido está vinculado a una programación y no puede ser eliminado. Desvincula o elimina la programación primero.
bulk_update:
no_data: Hm, algo salió mal. No se encontraron datos de ciclo de pedido.
date_warning:
@@ -996,6 +1013,9 @@ es:
description: Facturas para la importación en Xero
packing:
name: Informes de empaquetado
+ enterprise_fee_summary:
+ name: "Resumen de las comisiones de la organización"
+ description: "Resumen de las comisiones de la organización recolectadas"
subscriptions:
subscriptions: Suscripciones
new: Nueva suscripción
@@ -1014,10 +1034,10 @@ es:
set_up_shipping_and_payment_methods_html: Configurar los métodos %{shipping_link} y %{payment_link}
set_up_shipping_and_payment_methods_note_html: Tenga en cuenta que solo se pueden usar métodos de pago en efectivo y Stripe con las suscripciones
ensure_at_least_one_customer_html: Asegúrese de que exista al menos un %{customer_link}
- create_at_least_one_schedule: Crear al menos un horario
+ create_at_least_one_schedule: Crear al menos una programación
create_at_least_one_schedule_step_1_html: 1. Vaya a la página %{order_cycles_link}
create_at_least_one_schedule_step_2: 2. Crea un ciclo de pedido si aún no lo has hecho
- create_at_least_one_schedule_step_3: 3. Haga clic en '+ Nuevo horario' y complete el formulario
+ create_at_least_one_schedule_step_3: 3. Haga clic en '+ Nueva programación' y complete el formulario
once_you_are_done_you_can_html: Una vez que haya terminado, puede %{reload_this_page_link}
reload_this_page: recarga esta página
steps:
@@ -1028,7 +1048,7 @@ es:
subscription_line_items:
this_is_an_estimate: |
Los precios mostrados son solo una estimación y se calculan en el momento en que se cambia la suscripción.
- Si cambias precios o tarifas, los pedidos se actualizarán pero la suscripción seguirá mostrando los valores anteriores.
+ Si cambias precios o comisiones, los pedidos se actualizarán pero la suscripción seguirá mostrando los valores anteriores.
not_in_open_and_upcoming_order_cycles_warning: "No hay ciclos de pedidos abiertos o próximos para este producto."
details:
details: Detalles
@@ -1616,7 +1636,7 @@ es:
shops_signup_help_text: Usted necesita un mejor retorno. Usted necesita nuevos compradores y socios de logística. Usted necesita que su historia sea contada a través de ventas al por mayor, al detalle y en la mesa de la cocina.
shops_signup_detail: Aquí está el detalle.
orders: Pedidos
- orders_fees: Tarifas...
+ orders_fees: Comisiones...
orders_edit_title: Carrito de compras
orders_edit_headline: Su carrito de compras
orders_edit_time: Pedido listo para
@@ -1688,7 +1708,7 @@ es:
error_not_found_in_database: "%{name} no se encuentra en la base de datos"
error_not_primary_producer: "%{name} no está habilitado como productora"
error_no_permission_for_enterprise: "\"%{name}\": no tiene permiso para administrar productos para esta organización"
- item_handling_fees: "Tarifa de manejo de artículo (incluída en el total de artículos)"
+ item_handling_fees: "Comisiones de manejo de artículos (incluída en el total de artículos)"
january: "Enero"
february: "Febrero"
march: "Marzo"
@@ -1717,7 +1737,7 @@ es:
password_reset_sent: "¡Le enviamos un correo electrónico con instrucciones para restaurar la contraseña!"
reset_password: "Restaurar contraseña"
who_is_managing_enterprise: "¿Quién es responsable de administrar %{enterprise}?"
- update_and_recalculate_fees: "Actualizar y recalcular tarifas"
+ update_and_recalculate_fees: "Actualizar y recalcular comisiones"
registration:
steps:
images:
@@ -1883,7 +1903,7 @@ es:
shipping_method_destroy_error: "Ese método de envío no puede ser eliminado ya que se hace referencia en un pedido: %{number}."
accounts_and_billing_task_already_running_error: "Se está ejecutando una tarea, espere hasta que haya finalizado"
accounts_and_billing_start_task_notice: "Tarea en cola"
- fees: "Tarifas"
+ fees: "Comisiones"
item_cost: "Costo del artículo"
bulk: "Agrupar"
shop_variant_quantity_min: "mínimo"
@@ -1893,11 +1913,11 @@ es:
change_shop: "Cambiar de tienda:"
shop_at: "Comprar en:"
price_breakdown: "Desglose de precios completo"
- admin_fee: "Tarifa de administración"
- sales_fee: "Tarifa de ventas"
- packing_fee: "Tarifa de empaquetado"
- transport_fee: "Tarifa de transporte"
- fundraising_fee: "Tarifa para recaudación de fondos"
+ admin_fee: "Comisión de administración"
+ sales_fee: "Comisión de ventas"
+ packing_fee: "Comisión de empaquetado"
+ transport_fee: "Comisión de transporte"
+ fundraising_fee: "Comisión para recaptación de fondos"
price_graph: "Gráfico de precios"
included_tax: "Impuesto incluido"
balance: "Saldo"
@@ -2000,7 +2020,6 @@ es:
spree_admin_enterprises_none_text: "No tienes ninguna organización"
spree_admin_enterprises_tabs_hubs: "HUBS"
spree_admin_enterprises_producers_manage_products: "GESTIONAR PRODUCTOS"
- spree_admin_enterprises_any_active_products_text: "No tienes ningún producto activo"
spree_admin_enterprises_create_new_product: "CREAR UN NUEVO PRODUCTO"
spree_admin_single_enterprise_alert_mail_confirmation: "Confirma la dirección de email para"
spree_admin_single_enterprise_alert_mail_sent: "Te hemos enviado un mail a"
@@ -2127,7 +2146,7 @@ es:
report_header_sales_tax: "Impuesto sobre las Ventas (%{currency_symbol})"
report_header_delivery_charge: "Gastos de Envío (%{currency_symbol})"
report_header_tax_on_delivery: "Impuestos sobre la entrega (%{currency_symbol})"
- report_header_tax_on_fees: "Impuesto sobre las tasas (%{currency_symbol})"
+ report_header_tax_on_fees: "Impuesto sobre las comisiones (%{currency_symbol})"
report_header_total_tax: "Total Impuestos (%{currency_symbol})"
report_header_enterprise: Organización
report_header_customer: Consumidora
@@ -2209,7 +2228,7 @@ es:
report_header_gst_free_income: Ingresos sin IVA
report_header_total_untaxable_produce: Total productos sin impuestos
report_header_total_taxable_produce: Total productos con impuestos
- report_header_total_untaxable_fees: Total comisiones sin impuestos
+ report_header_total_untaxable_fees: Total comisiones no imponibles (sin impuestos)
report_header_total_taxable_fees: Total de impuestos imponibles (impuestos incluidos)
report_header_delivery_shipping_cost: Gastos de envío (impuestos incluidos)
report_header_transaction_fee: Comisión por transacción (sin impuestos)
@@ -2248,7 +2267,7 @@ es:
shipping: "Envío"
shipping_methods: "Métodos de envío"
payment_methods: "Métodos de Pago"
- payment_method_fee: "Tarifa de Transacción"
+ payment_method_fee: "Comisión de Transacción"
inventory_settings: "Configuración del Inventario"
tag_rules: "Reglas de las Etiquetas"
shop_preferences: "Configuración de la tienda"
@@ -2527,6 +2546,45 @@ es:
producers:
signup:
start_free_profile: "Empieze con un perfil gratuito, y amplíelo cuando esté preparado!"
+ order_management:
+ reports:
+ enterprise_fee_summary:
+ date_end_before_start_error: "debe ser después del comienzo"
+ parameter_not_allowed_error: "No está autorizado a usar uno o más filtros seleccionados para este informe."
+ fee_calculated_on_transfer_through_all: "Todos"
+ fee_calculated_on_transfer_through_entire_orders: "Pedidos completos a través de %{distributor}"
+ tax_category_various: "Varios"
+ fee_type:
+ payment_method: "Transaccion de pago"
+ shipping_method: "Envío"
+ fee_placements:
+ supplier: "Entrante"
+ distributor: "Saliente"
+ coordinator: "Coordinadora"
+ tax_category_name:
+ shipping_instance_rate: "Tarifa de plataforma"
+ formats:
+ csv:
+ header:
+ fee_type: "Tipo de Comisión"
+ enterprise_name: "Propietario de la organización"
+ fee_name: "Nombre de la comisión"
+ customer_name: "Consumidora"
+ fee_placement: "Asignación de comisiones"
+ fee_calculated_on_transfer_through_name: "Cálculo de comisiones a través de transferencias"
+ tax_category_name: "Categoría de impuestos"
+ total_amount: "€€ SUM"
+ html:
+ header:
+ fee_type: "Tipo de Comisión"
+ enterprise_name: "Propietario de la organización"
+ fee_name: "Nombre de la comisión"
+ customer_name: "Consumidora"
+ fee_placement: "Asignación de comisiones"
+ fee_calculated_on_transfer_through_name: "Cálculo de comisiones a través de transferencias"
+ tax_category_name: "Categoría de impuestos"
+ total_amount: "€€ SUM"
+ invalid_filter_parameters: "Los filtros que seleccionó para este informe no son válidos."
spree:
email: Email
account_updated: "Cuenta actualizada!"
@@ -2570,6 +2628,11 @@ es:
distributor: "Distribuidora:"
order_cycle: "Ciclo de pedido:"
overview:
+ products:
+ active_products:
+ zero: "No tienes ningún producto activo"
+ one: "Tiene un producto activo."
+ other: "Tiene %{count} productos activos"
order_cycles:
order_cycles: "Ciclos de Pedido"
order_cycles_tip: "Los ciclos de pedido determinan cuándo y dónde los productos están disponibles para las consumidoras."
@@ -2643,6 +2706,14 @@ es:
bulk_coop_allocation: 'Bulk Co-op - Asignación'
bulk_coop_packing_sheets: 'Bulk Co-op - Hojas de Empaquetado'
bulk_coop_customer_payments: 'Bulk Co-op - Pagos de las Consumidoras'
+ enterprise_fee_summaries:
+ filters:
+ date_range: "Rango de fechas"
+ report_format_csv: "Descargar como CSV"
+ generate_report: "Generar informe"
+ report:
+ none: "Ninguno"
+ select_and_search: "Seleccione los filtros y haga clic en GENERAR INFORME para acceder a sus datos."
users:
index:
listing_users: "Listado de Usuarias"
diff --git a/config/routes/admin.rb b/config/routes/admin.rb
index 1f55f8d154..1bd72d4fdd 100644
--- a/config/routes/admin.rb
+++ b/config/routes/admin.rb
@@ -70,19 +70,8 @@ Openfoodnetwork::Application.routes.draw do
resource :content
- resource :accounts_and_billing_settings, only: [:edit, :update] do
- collection do
- get :show_methods
- get :start_job
- end
- end
-
- resource :business_model_configuration, only: [:edit, :update], controller: 'business_model_configuration'
-
resource :cache_settings
- resource :account, only: [:show], controller: 'account'
-
resources :column_preferences, only: [], format: :json do
put :bulk_update, on: :collection
end
diff --git a/config/schedule.rb b/config/schedule.rb
index 4bb20df545..0e0ee31289 100644
--- a/config/schedule.rb
+++ b/config/schedule.rb
@@ -33,12 +33,3 @@ every 5.minutes do
enqueue_job 'SubscriptionPlacementJob', priority: 0
enqueue_job 'SubscriptionConfirmJob', priority: 0
end
-
-every 1.day, at: '1:00am' do
- rake 'ofn:billing:update_account_invoices'
-end
-
-# On the 2nd of every month at 1:30am
-every '30 1 2 * *' do
- rake 'ofn:billing:finalize_account_invoices'
-end
diff --git a/db/migrate/20180426145632_create_default_stock.spree.rb b/db/migrate/20180426145632_create_default_stock.spree.rb
index b1fc601078..7e1d188e4a 100644
--- a/db/migrate/20180426145632_create_default_stock.spree.rb
+++ b/db/migrate/20180426145632_create_default_stock.spree.rb
@@ -1,3 +1,10 @@
+Spree::Stock::Quantifier.class_eval do
+ def initialize(variant)
+ @variant = variant
+ @stock_items = Spree::StockItem.joins(:stock_location).where(:variant_id => @variant)
+ end
+end
+
# This migration comes from spree (originally 20130213191427)
class CreateDefaultStock < ActiveRecord::Migration
def up
diff --git a/db/migrate/20190221131622_delete_account_invoices_preferences.rb b/db/migrate/20190221131622_delete_account_invoices_preferences.rb
new file mode 100644
index 0000000000..e55a61f721
--- /dev/null
+++ b/db/migrate/20190221131622_delete_account_invoices_preferences.rb
@@ -0,0 +1,22 @@
+class DeleteAccountInvoicesPreferences < ActiveRecord::Migration
+ def up
+ Spree::Preference
+ .where( key: ['spree/app_configuration/accounts_distributor_id',
+ 'spree/app_configuration/default_accounts_payment_method_id',
+ 'spree/app_configuration/default_accounts_shipping_method_id',
+ 'spree/app_configuration/auto_update_invoices',
+ 'spree/app_configuration/auto_finalize_invoices',
+ 'spree/app_configuration/account_invoices_monthly_fixed',
+ 'spree/app_configuration/account_invoices_monthly_rate',
+ 'spree/app_configuration/account_invoices_monthly_cap',
+ 'spree/app_configuration/account_invoices_tax_rate',
+ 'spree/app_configuration/shop_trial_length_days',
+ 'spree/app_configuration/minimum_billable_turnover'])
+ .destroy_all
+ end
+
+ def down
+ # If these preferences are re-added to app/models/spree/app_configuration_decorator.rb
+ # these DB entries will be regenerated
+ end
+end
diff --git a/db/migrate/20190221131741_delete_account_invoices_adjustments.rb b/db/migrate/20190221131741_delete_account_invoices_adjustments.rb
new file mode 100644
index 0000000000..1f1af59594
--- /dev/null
+++ b/db/migrate/20190221131741_delete_account_invoices_adjustments.rb
@@ -0,0 +1,11 @@
+class DeleteAccountInvoicesAdjustments < ActiveRecord::Migration
+ def up
+ Spree::Adjustment
+ .where(source_type: 'BillablePeriod')
+ .destroy_all
+ end
+
+ def down
+ # This data does not need to be recovered
+ end
+end
diff --git a/db/migrate/20190221214542_drop_enterprise_shop_trial_start_date.rb b/db/migrate/20190221214542_drop_enterprise_shop_trial_start_date.rb
new file mode 100644
index 0000000000..69dd360e2c
--- /dev/null
+++ b/db/migrate/20190221214542_drop_enterprise_shop_trial_start_date.rb
@@ -0,0 +1,9 @@
+class DropEnterpriseShopTrialStartDate < ActiveRecord::Migration
+ def up
+ remove_column :enterprises, :shop_trial_start_date
+ end
+
+ def down
+ add_column :enterprises, :shop_trial_start_date, :datetime, default: nil
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 696182139d..6e4426e2bb 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20181128054803) do
+ActiveRecord::Schema.define(:version => 20190221214542) do
create_table "account_invoices", :force => true do |t|
t.integer "user_id", :null => false
@@ -233,7 +233,6 @@ ActiveRecord::Schema.define(:version => 20181128054803) do
t.string "linkedin"
t.integer "owner_id", :null => false
t.string "sells", :default => "none", :null => false
- t.datetime "shop_trial_start_date"
t.boolean "producer_profile_only", :default => false
t.string "permalink", :null => false
t.boolean "charges_sales_tax", :default => false, :null => false
@@ -533,9 +532,9 @@ ActiveRecord::Schema.define(:version => 20181128054803) do
t.datetime "updated_at", :null => false
t.integer "max_quantity"
t.string "currency"
- t.decimal "distribution_fee", :precision => 10, :scale => 2
- t.decimal "final_weight_volume", :precision => 10, :scale => 2
- t.decimal "cost_price", :precision => 8, :scale => 2
+ t.decimal "distribution_fee", :precision => 10, :scale => 2
+ t.decimal "final_weight_volume", :precision => 10, :scale => 2
+ t.decimal "cost_price", :precision => 8, :scale => 2
t.integer "tax_category_id"
end
diff --git a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb
index 9ebec61417..d6bcb8554a 100644
--- a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb
+++ b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb
@@ -17,7 +17,7 @@ module OrderManagement
end
def result
- group_data.select_attributes
+ group_data.exclude_groups_with_zero_total.select_attributes
@scope.all
end
@@ -46,7 +46,7 @@ module OrderManagement
def find_adjustments
chain_to_scope do
- Spree::Adjustment
+ Spree::Adjustment.eligible
end
end
@@ -336,6 +336,10 @@ module OrderManagement
if params.payment_method_ids.present?
end
+ def exclude_groups_with_zero_total
+ filter_scope("spree_adjustments.amount != 0")
+ end
+
def group_data
chain_to_scope do
group("enterprise_fees.id", "enterprises.id", "customers.id", "hubs.id",
diff --git a/engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb b/engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb
index 2161bbb4c6..38a760dc96 100644
--- a/engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb
+++ b/engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb
@@ -151,6 +151,94 @@ describe OrderManagement::Reports::EnterpriseFeeSummary::ReportService do
end
end
+ describe "data exclusions" do
+ describe "invalid adjustments (through 'eligible') like failed payments" do
+ let!(:customer_order) { prepare_order(customer: customer) }
+
+ before do
+ # Make the payment fail. See Spree::Payment#revoke_adjustment_eligibility.
+ payment = customer_order.payments.first
+ payment.state = "failed"
+ payment.save!
+ end
+
+ it "is included" do
+ totals = service.list
+
+ expect(totals.length).to eq(1)
+
+ expected_result = [
+ ["Shipment", "Sample Distributor", "Sample Shipping Method", "Sample Customer",
+ nil, nil, "Platform Rate", "1.00"]
+ ]
+
+ expected_result.each_with_index do |expected_attributes, row_index|
+ expect_total_attributes(totals[row_index], expected_attributes)
+ end
+ end
+ end
+
+ describe "non-mandatory $0 adjustments (through 'eligible')" do
+ let!(:variant) { prepare_variant(outgoing_exchange_fees: [enterprise_fee]) }
+
+ let!(:enterprise_fee) do
+ create(:enterprise_fee, :per_item, name: "Sample Enterprise Fee", enterprise: distributor,
+ fee_type: "admin", amount: 0)
+ end
+
+ let!(:customer_order) { prepare_order(customer: customer) }
+
+ before do
+ # Change "eligible" in enterprise fee adjustment to false. $0 adjustments that are not
+ # mandatory are set to be ineligible, but there are no non-mandatory adjustments supported
+ # by the report yet.
+ adjustment = Spree::Adjustment.where(originator_type: "EnterpriseFee").first
+ adjustment.eligible = false
+ adjustment.save!
+ end
+
+ it "is included" do
+ totals = service.list
+
+ expect(totals.length).to eq(2)
+
+ expected_result = [
+ ["Payment Transaction", "Sample Distributor", "Sample Payment Method", "Sample Customer",
+ nil, nil, nil, "2.00"],
+ ["Shipment", "Sample Distributor", "Sample Shipping Method", "Sample Customer",
+ nil, nil, "Platform Rate", "1.00"]
+ ]
+
+ expected_result.each_with_index do |expected_attributes, row_index|
+ expect_total_attributes(totals[row_index], expected_attributes)
+ end
+ end
+ end
+
+ describe "$0 mandatory adjustments" do
+ let!(:payment_method) do
+ create(:payment_method, :per_item, amount: 0, name: "Sample Payment Method")
+ end
+
+ let!(:customer_order) { prepare_order(customer: customer) }
+
+ it "is included" do
+ totals = service.list
+
+ expect(totals.length).to eq(1)
+
+ expected_result = [
+ ["Shipment", "Sample Distributor", "Sample Shipping Method", "Sample Customer",
+ nil, nil, "Platform Rate", "1.00"]
+ ]
+
+ expected_result.each_with_index do |expected_attributes, row_index|
+ expect_total_attributes(totals[row_index], expected_attributes)
+ end
+ end
+ end
+ end
+
describe "handling of more complex cases" do
context "with non-sender fee for incoming exchange and non-receiver fee for outgoing" do
let!(:variant) do
diff --git a/knapsack_rspec_report.json b/knapsack_rspec_report.json
index 12f72f882c..45e5e437a5 100644
--- a/knapsack_rspec_report.json
+++ b/knapsack_rspec_report.json
@@ -68,14 +68,12 @@
"spec/controllers/admin/enterprises_controller_spec.rb": 4.12069845199585,
"spec/lib/open_food_network/scope_variant_to_hub_spec.rb": 3.415233612060547,
"spec/controllers/shop_controller_spec.rb": 2.8152332305908203,
- "spec/features/admin/accounts_and_billing_settings_spec.rb": 4.564471960067749,
"spec/lib/open_food_network/user_balance_calculator_spec.rb": 5.701348066329956,
"spec/features/consumer/groups_spec.rb": 4.695758104324341,
"spec/lib/open_food_network/order_cycle_form_applicator_spec.rb": 5.4417150020599365,
"spec/controllers/spree/api/products_controller_spec.rb": 9.90657091140747,
"spec/serializers/admin/exchange_serializer_spec.rb": 2.6061851978302,
"spec/controllers/api/promo_images_controller_spec.rb": 3.7358314990997314,
- "spec/jobs/update_billable_periods_spec.rb": 7.687055826187134,
"spec/controllers/enterprises_controller_spec.rb": 4.6496901512146,
"spec/features/consumer/registration_spec.rb": 4.664679765701294,
"spec/serializers/order_serializer_spec.rb": 6.241122722625732,
@@ -97,14 +95,12 @@
"spec/models/enterprise_fee_spec.rb": 2.6969127655029297,
"spec/features/consumer/shopping/embedded_groups_spec.rb": 3.5200917720794678,
"spec/lib/open_food_network/scope_variants_to_search_spec.rb": 2.9324328899383545,
- "spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb": 3.5419158935546875,
"spec/models/spree/payment_spec.rb": 3.644035816192627,
"spec/controllers/admin/schedules_controller_spec.rb": 4.086155414581299,
"spec/controllers/spree/admin/reports_controller_spec.rb": 4.6371729373931885,
"spec/helpers/enterprises_helper_spec.rb": 4.092283725738525,
"spec/features/admin/schedules_spec.rb": 4.011422872543335,
"spec/controllers/admin/order_cycles_controller_spec.rb": 3.8047308921813965,
- "spec/models/billable_period_spec.rb": 4.33881139755249,
"spec/features/admin/authentication_spec.rb": 2.6899383068084717,
"spec/controllers/spree/admin/orders/customer_details_controller_spec.rb": 3.8118021488189697,
"spec/models/enterprise_caching_spec.rb": 3.222259998321533,
@@ -118,8 +114,6 @@
"spec/lib/open_food_network/subscription_payment_updater_spec.rb": 3.8399856090545654,
"spec/features/consumer/footer_links_spec.rb": 1.9081592559814453,
"spec/jobs/subscription_placement_job_spec.rb": 3.095796823501587,
- "spec/helpers/admin/business_model_configuration_helper_spec.rb": 1.4220046997070312,
- "spec/features/admin/business_model_configuration_spec.rb": 2.1453568935394287,
"spec/controllers/admin/subscription_line_items_controller_spec.rb": 2.2608282566070557,
"spec/controllers/cart_controller_spec.rb": 2.738463878631592,
"spec/models/producer_property_spec.rb": 2.198972702026367,
@@ -206,7 +200,6 @@
"spec/models/concerns/order_shipping_method_spec.rb": 0.29420924186706543,
"spec/models/stripe_account_spec.rb": 0.23795485496520996,
"spec/controllers/admin/stripe_connect_settings_controller_spec.rb": 0.2342853546142578,
- "spec/controllers/admin/business_model_configuration_controller_spec.rb": 0.18909120559692383,
"spec/serializers/api/admin/product_serializer_spec.rb": 0.2630436420440674,
"spec/serializers/variant_serializer_spec.rb": 0.29114508628845215,
"spec/controllers/stripe/callbacks_controller_spec.rb": 0.2801051139831543,
@@ -230,7 +223,6 @@
"spec/controllers/stripe/webhooks_controller_spec.rb": 0.15674114227294922,
"spec/models/model_set_spec.rb": 0.17897748947143555,
"spec/models/spree/credit_card_spec.rb": 0.11442422866821289,
- "spec/features/admin/account_spec.rb": 0.15611958503723145,
"spec/features/consumer/confirm_invitation_spec.rb": 0.1410982608795166,
"spec/lib/open_food_network/sales_tax_report_spec.rb": 0.10101437568664551,
"spec/models/coordinator_fee_spec.rb": 0.11246252059936523,
diff --git a/lib/open_food_network/accounts_and_billing_settings_validator.rb b/lib/open_food_network/accounts_and_billing_settings_validator.rb
deleted file mode 100644
index ec1de0b6b7..0000000000
--- a/lib/open_food_network/accounts_and_billing_settings_validator.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-# This class is a lightweight model used to validate preferences for accounts and billing settings
-# when they are submitted to the AccountsAndBillingSettingsController
-
-module OpenFoodNetwork
- class AccountsAndBillingSettingsValidator
- include ActiveModel::Validations
-
- attr_accessor :accounts_distributor_id, :default_accounts_payment_method_id, :default_accounts_shipping_method_id
- attr_accessor :auto_update_invoices, :auto_finalize_invoices
-
- validate :ensure_accounts_distributor_set
- validate :ensure_default_payment_method_set
- validate :ensure_default_shipping_method_set
- # validate :ensure_billing_info_collected, unless: lambda { create_invoices_for_enterprise_users == '0' }
-
- def initialize(attr, button=nil)
- attr.each { |k,v| instance_variable_set("@#{k}", v) }
- @button = button
- end
-
- def ensure_accounts_distributor_set
- unless Enterprise.find_by_id(accounts_distributor_id)
- errors.add(:accounts_distributor, I18n.t('admin.accounts_and_billing_settings.errors.accounts_distributor'))
- end
- end
-
- def ensure_default_payment_method_set
- unless Enterprise.find_by_id(accounts_distributor_id) &&
- Enterprise.find_by_id(accounts_distributor_id).payment_methods.find_by_id(default_accounts_payment_method_id)
- errors.add(:default_payment_method, I18n.t('admin.accounts_and_billing_settings.errors.default_payment_method'))
- end
- end
-
- def ensure_default_shipping_method_set
- unless Enterprise.find_by_id(accounts_distributor_id) &&
- Enterprise.find_by_id(accounts_distributor_id).shipping_methods.find_by_id(default_accounts_shipping_method_id)
- errors.add(:default_shipping_method, I18n.t('admin.accounts_and_billing_settings.errors.default_shipping_method'))
- end
- end
- end
-end
diff --git a/lib/open_food_network/bill_calculator.rb b/lib/open_food_network/bill_calculator.rb
deleted file mode 100644
index 90f5077a14..0000000000
--- a/lib/open_food_network/bill_calculator.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module OpenFoodNetwork
- class BillCalculator
- attr_accessor :turnover, :fixed, :rate, :cap, :tax_rate, :minimum_billable_turnover
-
- def initialize(opts={})
- @turnover = opts[:turnover] || 0
- @fixed = opts[:fixed] || Spree::Config[:account_invoices_monthly_fixed]
- @rate = opts[:rate] || Spree::Config[:account_invoices_monthly_rate]
- @cap = opts[:cap] || Spree::Config[:account_invoices_monthly_cap]
- @tax_rate = opts[:tax_rate] || Spree::Config[:account_invoices_tax_rate]
- @minimum_billable_turnover = opts[:minimum_billable_turnover] || Spree::Config[:minimum_billable_turnover]
- end
-
- def bill
- return 0 if turnover < minimum_billable_turnover
- bill = fixed + (turnover * rate)
- bill = [bill, cap].min if cap > 0
- bill * (1 + tax_rate)
- end
- end
-end
diff --git a/lib/open_food_network/business_model_configuration_validator.rb b/lib/open_food_network/business_model_configuration_validator.rb
deleted file mode 100644
index 93534937db..0000000000
--- a/lib/open_food_network/business_model_configuration_validator.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-# This class is a lightweight model used to validate preferences for business model configuration
-# when they are submitted to the BusinessModelConfigurationController
-
-module OpenFoodNetwork
- class BusinessModelConfigurationValidator
- include ActiveModel::Validations
-
- attr_accessor :shop_trial_length_days, :account_invoices_monthly_fixed, :account_invoices_monthly_rate, :account_invoices_monthly_cap, :account_invoices_tax_rate, :minimum_billable_turnover
-
- validates :shop_trial_length_days, presence: true, numericality: { greater_than_or_equal_to: 0 }
- validates :account_invoices_monthly_fixed, presence: true, numericality: { greater_than_or_equal_to: 0 }
- validates :account_invoices_monthly_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }
- validates :account_invoices_monthly_cap, presence: true, numericality: { greater_than_or_equal_to: 0 }
- validates :account_invoices_tax_rate, presence: true, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 1 }
- validates :minimum_billable_turnover, presence: true, numericality: { greater_than_or_equal_to: 0 }
-
- def initialize(attr, button=nil)
- attr.each { |k,v| instance_variable_set("@#{k}", v) }
- @button = button
- end
- end
-end
diff --git a/lib/open_food_network/cached_products_renderer.rb b/lib/open_food_network/cached_products_renderer.rb
index 733455ed73..abc1f45713 100644
--- a/lib/open_food_network/cached_products_renderer.rb
+++ b/lib/open_food_network/cached_products_renderer.rb
@@ -27,19 +27,21 @@ module OpenFoodNetwork
private
def cached_products_json
- if Rails.env.production? || Rails.env.staging?
- Rails.cache.fetch("products-json-#{@distributor.id}-#{@order_cycle.id}") do
- begin
- uncached_products_json
- rescue ProductsRenderer::NoProducts
- nil
- end
+ return uncached_products_json unless use_cached_products?
+
+ Rails.cache.fetch("products-json-#{@distributor.id}-#{@order_cycle.id}") do
+ begin
+ uncached_products_json
+ rescue ProductsRenderer::NoProducts
+ nil
end
- else
- uncached_products_json
end
end
+ def use_cached_products?
+ Spree::Config[:enable_products_cache?] && (Rails.env.production? || Rails.env.staging?)
+ end
+
def uncached_products_json
ProductsRenderer.new(@distributor, @order_cycle).products_json
end
diff --git a/lib/open_food_network/scope_variant_to_hub.rb b/lib/open_food_network/scope_variant_to_hub.rb
index de99d6f7f7..52ea5f5100 100644
--- a/lib/open_food_network/scope_variant_to_hub.rb
+++ b/lib/open_food_network/scope_variant_to_hub.rb
@@ -22,20 +22,18 @@ module OpenFoodNetwork
# Uses variant_override.count_on_hand instead of Stock::Quantifier.stock_items.count_on_hand
def total_on_hand
- @variant_override.andand.count_on_hand || super
+ if @variant_override.present? && @variant_override.stock_overridden?
+ @variant_override.count_on_hand
+ else
+ super
+ end
end
def on_demand
- if @variant_override.andand.on_demand.nil?
- if @variant_override.andand.count_on_hand.present?
- # If we're overriding the stock level of an on_demand variant, show it as not
- # on_demand, so our stock control can take effect.
- false
- else
- super
- end
+ if @variant_override.present? && !@variant_override.use_producer_stock_settings?
+ @variant_override.on_demand
else
- @variant_override.andand.on_demand
+ super
end
end
diff --git a/lib/open_food_network/xero_invoices_report.rb b/lib/open_food_network/xero_invoices_report.rb
index 5e351871e8..b27291f535 100644
--- a/lib/open_food_network/xero_invoices_report.rb
+++ b/lib/open_food_network/xero_invoices_report.rb
@@ -89,7 +89,7 @@ module OpenFoodNetwork
rows = []
rows += produce_summary_rows(order, invoice_number, opts) unless detail?
- rows += fee_summary_rows(order, invoice_number, opts) unless detail? && order.account_invoice?
+ rows += fee_summary_rows(order, invoice_number, opts)
rows += shipping_summary_rows(order, invoice_number, opts)
rows += payment_summary_rows(order, invoice_number, opts)
rows += admin_adjustment_summary_rows(order, invoice_number, opts) unless detail?
@@ -158,18 +158,11 @@ module OpenFoodNetwork
end
def adjustments(order)
- account_invoice_adjustments(order) + order.adjustments.admin
- end
-
- def account_invoice_adjustments(order)
- order.adjustments.
- billable_period.
- select { |a| a.source.present? }
+ order.adjustments.admin
end
def adjustment_order(adjustment)
- adjustment.source.andand.account_invoice.andand.order ||
- (adjustment.adjustable.is_a?(Spree::Order) ? adjustment.adjustable : nil)
+ adjustment.adjustable.is_a?(Spree::Order) ? adjustment.adjustable : nil
end
def invoice_number_for(order, i)
diff --git a/lib/tasks/billing.rake b/lib/tasks/billing.rake
deleted file mode 100644
index 4c279bc41e..0000000000
--- a/lib/tasks/billing.rake
+++ /dev/null
@@ -1,13 +0,0 @@
-namespace :ofn do
- namespace :billing do
- desc 'Update enterprise user invoices'
- task update_account_invoices: :environment do
- Delayed::Job.enqueue(UpdateAccountInvoices.new) if Spree::Config[:auto_update_invoices]
- end
-
- desc 'Finalize enterprise user invoices'
- task finalize_account_invoices: :environment do
- Delayed::Job.enqueue(FinalizeAccountInvoices.new) if Spree::Config[:auto_finalize_invoices]
- end
- end
-end
diff --git a/public/product_list_template.csv b/public/product_list_template.csv
index 6eeae3701e..36f0f53ee1 100644
--- a/public/product_list_template.csv
+++ b/public/product_list_template.csv
@@ -1 +1 @@
-producer,sku,name,display_name,category,units,unit_type,variant_unit_name,price,on_hand,available_on,on_demand,shipping_category,tax_category
+producer,sku,name,display_name,category,description,units,unit_type,variant_unit_name,price,on_hand,available_on,on_demand,shipping_category,tax_category
diff --git a/spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb b/spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb
deleted file mode 100644
index 7ec9eb1ca0..0000000000
--- a/spec/controllers/admin/accounts_and_billing_settings_controller_spec.rb
+++ /dev/null
@@ -1,241 +0,0 @@
-require 'spec_helper'
-
-describe Admin::AccountsAndBillingSettingsController, type: :controller do
- let!(:pm1) { create(:payment_method) }
- let!(:sm1) { create(:shipping_method) }
- let!(:pm2) { create(:payment_method) }
- let!(:sm2) { create(:shipping_method) }
- let!(:accounts_distributor) { create(:distributor_enterprise, payment_methods: [pm1], shipping_methods: [sm1]) }
- let!(:new_distributor) { create(:distributor_enterprise, payment_methods: [pm2], shipping_methods: [sm2]) }
- let(:user) { create(:user) }
- let(:admin) { create(:admin_user) }
-
- before do
- Spree::Config.set({
- accounts_distributor_id: accounts_distributor.id,
- default_accounts_payment_method_id: pm1.id,
- default_accounts_shipping_method_id: sm1.id,
- auto_update_invoices: true,
- auto_finalize_invoices: false
- })
- end
-
- describe "edit" do
- context "as an enterprise user" do
- before { allow(controller).to receive(:spree_current_user) { user } }
-
- it "does not allow access" do
- spree_get :edit
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before { allow(controller).to receive(:spree_current_user) { admin } }
-
- it "loads relevant global settings into a locally dummy class" do
- spree_get :edit
- settings = assigns(:settings)
-
- expect(settings.accounts_distributor_id).to eq accounts_distributor.id
- expect(settings.default_accounts_payment_method_id).to eq pm1.id
- expect(settings.default_accounts_shipping_method_id).to eq sm1.id
- expect(settings.auto_update_invoices).to eq true
- expect(settings.auto_finalize_invoices).to eq false
- end
- end
- end
-
- describe "update" do
- context "as an enterprise user" do
- before { allow(controller).to receive(:spree_current_user) { user } }
-
- it "does not allow access" do
- spree_get :update
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before {allow(controller).to receive(:spree_current_user) { admin } }
- let(:params) { { settings: { } } }
-
- context "when required settings have no values" do
- before do
- params[:settings][:accounts_distributor_id] = ''
- params[:settings][:default_accounts_payment_method_id] = '0'
- params[:settings][:default_accounts_shipping_method_id] = '0'
- params[:settings][:auto_update_invoices] = '0'
- params[:settings][:auto_finalize_invoices] = '0'
- spree_get :update, params
- end
-
- it "does not allow them to be empty/false" do
- expect(response).to render_template :edit
- expect(assigns(:settings).errors.count).to be 3
- expect(Spree::Config.accounts_distributor_id).to eq accounts_distributor.id
- expect(Spree::Config.default_accounts_payment_method_id).to eq pm1.id
- expect(Spree::Config.default_accounts_shipping_method_id).to eq sm1.id
- expect(Spree::Config.auto_update_invoices).to be true
- expect(Spree::Config.auto_finalize_invoices).to be false
- end
- end
-
- context "when required settings have values" do
- before do
- params[:settings][:accounts_distributor_id] = new_distributor.id
- params[:settings][:default_accounts_payment_method_id] = pm2.id
- params[:settings][:default_accounts_shipping_method_id] = sm2.id
- params[:settings][:auto_update_invoices] = '0'
- params[:settings][:auto_finalize_invoices] = '0'
- end
-
- it "sets global config to the specified values" do
- spree_get :update, params
- expect(Spree::Config.accounts_distributor_id).to eq new_distributor.id
- expect(Spree::Config.default_accounts_payment_method_id).to eq pm2.id
- expect(Spree::Config.default_accounts_shipping_method_id).to eq sm2.id
- expect(Spree::Config.auto_update_invoices).to be false
- expect(Spree::Config.auto_finalize_invoices).to be false
- end
- end
- end
- end
-
- describe "start_job" do
- context "as an enterprise user" do
- before do
- allow(controller).to receive(:spree_current_user) { user }
- spree_post :start_job, enterprise_id: accounts_distributor.id
- end
-
- it "does not allow access" do
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before do
- allow(controller).to receive(:spree_current_user) { admin }
- end
-
- context "when settings are not valid" do
- before do
- Spree::Config.set({ accounts_distributor_id: "" })
- Spree::Config.set({ default_accounts_payment_method_id: "" })
- Spree::Config.set({ default_accounts_shipping_method_id: "" })
- spree_post :start_job, job: { name: "" }
- end
-
- it "returns immediately and renders :edit" do
- expect(assigns(:settings).errors.count).to eq 3
- expect(response).to render_template :edit
- end
- end
-
- context "when settings are valid" do
- before do
- Spree::Config.set({ accounts_distributor_id: accounts_distributor.id })
- Spree::Config.set({ default_accounts_payment_method_id: pm1.id })
- Spree::Config.set({ default_accounts_shipping_method_id: sm1.id })
- end
-
- context "and job_name is not on the known_jobs list" do
- before do
- spree_post :start_job, job: { name: "" }
- end
-
- it "returns immediately with an error" do
- expect(flash[:error]).to eq "Unknown Task: "
- expect(response).to redirect_to edit_admin_accounts_and_billing_settings_path
- end
- end
-
- context "and job_name is update_account_invoices" do
- let!(:params) { { job: { name: "update_account_invoices" } } }
-
- context "and no jobs are currently running" do
- before do
- allow(controller).to receive(:load_jobs)
- end
-
- it "runs the job" do
- expect{spree_post :start_job, params}.to enqueue_job UpdateAccountInvoices
- expect(flash[:success]).to eq "Task Queued"
- expect(response).to redirect_to edit_admin_accounts_and_billing_settings_path
- end
- end
-
- context "and there are jobs currently running" do
- before do
- allow(controller).to receive(:load_jobs)
- controller.instance_variable_set("@update_account_invoices_job", double(:update_account_invoices_job))
- end
-
- it "does not run the job" do
- expect{spree_post :start_job, params}.to_not enqueue_job UpdateAccountInvoices
- expect(flash[:error]).to eq "A task is already running, please wait until it has finished"
- expect(response).to redirect_to edit_admin_accounts_and_billing_settings_path
- end
- end
- end
-
- context "and job_name is finalize_account_invoices" do
- let!(:params) { { job: { name: "finalize_account_invoices" } } }
-
- context "and no jobs are currently running" do
- before do
- allow(controller).to receive(:load_jobs)
- end
-
- it "runs the job" do
- expect{spree_post :start_job, params}.to enqueue_job FinalizeAccountInvoices
- expect(flash[:success]).to eq "Task Queued"
- expect(response).to redirect_to edit_admin_accounts_and_billing_settings_path
- end
- end
-
- context "and there are jobs currently running" do
- before do
- allow(controller).to receive(:load_jobs)
- controller.instance_variable_set("@finalize_account_invoices_job", double(:finalize_account_invoices_job))
- end
-
- it "does not run the job" do
- expect{spree_post :start_job, params}.to_not enqueue_job FinalizeAccountInvoices
- expect(flash[:error]).to eq "A task is already running, please wait until it has finished"
- expect(response).to redirect_to edit_admin_accounts_and_billing_settings_path
- end
- end
- end
- end
- end
- end
-
- describe "show_methods" do
- context "as an enterprise user" do
- before do
- allow(controller).to receive(:spree_current_user) { user }
- spree_get :show_methods, enterprise_id: accounts_distributor.id
- end
-
- it "does not allow access" do
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before do
- allow(controller).to receive(:spree_current_user) { admin }
- spree_get :show_methods, enterprise_id: accounts_distributor.id
- end
-
- it "renders the method_settings template" do
- expect(assigns(:payment_methods)).to eq [pm1]
- expect(assigns(:shipping_methods)).to eq [sm1]
- expect(assigns(:enterprise)).to eq accounts_distributor
- expect(response).to render_template :method_settings
- end
- end
- end
-end
diff --git a/spec/controllers/admin/business_model_configuration_controller_spec.rb b/spec/controllers/admin/business_model_configuration_controller_spec.rb
deleted file mode 100644
index 3836773b08..0000000000
--- a/spec/controllers/admin/business_model_configuration_controller_spec.rb
+++ /dev/null
@@ -1,98 +0,0 @@
-require 'spec_helper'
-
-describe Admin::BusinessModelConfigurationController, type: :controller do
- let(:user) { create(:user) }
- let(:admin) { create(:admin_user) }
-
- before do
- Spree::Config.set({
- account_invoices_monthly_fixed: 5,
- account_invoices_monthly_rate: 0.02,
- account_invoices_monthly_cap: 50,
- account_invoices_tax_rate: 0.1,
- shop_trial_length_days: 30,
- minimum_billable_turnover: 0
- })
- end
-
- describe "edit" do
- context "as an enterprise user" do
- before { allow(controller).to receive(:spree_current_user) { user } }
-
- it "does not allow access" do
- spree_get :edit
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before { allow(controller).to receive(:spree_current_user) { admin } }
-
- it "allows access" do
- spree_get :edit
- expect(response).to_not redirect_to spree.unauthorized_path
- end
- end
- end
-
- describe "update" do
- context "as an enterprise user" do
- before { allow(controller).to receive(:spree_current_user) { user } }
-
- it "does not allow access" do
- spree_get :update
- expect(response).to redirect_to spree.unauthorized_path
- end
- end
-
- context "as super admin" do
- before {allow(controller).to receive(:spree_current_user) { admin } }
- let(:params) { { settings: { } } }
-
- context "when settings are invalid" do
- before do
- params[:settings][:account_invoices_monthly_fixed] = ''
- params[:settings][:account_invoices_monthly_rate] = '2'
- params[:settings][:account_invoices_monthly_cap] = '-1'
- params[:settings][:account_invoices_tax_rate] = '4'
- params[:settings][:shop_trial_length_days] = '-30'
- params[:settings][:minimum_billable_turnover] = '-1'
- spree_get :update, params
- end
-
- it "does not allow them to be set" do
- expect(response).to render_template :edit
- expect(assigns(:settings).errors.count).to be 7
- expect(Spree::Config.account_invoices_monthly_fixed).to eq 5
- expect(Spree::Config.account_invoices_monthly_rate).to eq 0.02
- expect(Spree::Config.account_invoices_monthly_cap).to eq 50
- expect(Spree::Config.account_invoices_tax_rate).to eq 0.1
- expect(Spree::Config.shop_trial_length_days).to eq 30
- expect(Spree::Config.minimum_billable_turnover).to eq 0
- end
- end
-
- context "when required settings are valid" do
- before do
- params[:settings][:account_invoices_monthly_fixed] = '10'
- params[:settings][:account_invoices_monthly_rate] = '0.05'
- params[:settings][:account_invoices_monthly_cap] = '30'
- params[:settings][:account_invoices_tax_rate] = '0.15'
- params[:settings][:shop_trial_length_days] = '20'
- params[:settings][:minimum_billable_turnover] = '10'
- end
-
- it "sets global config to the specified values" do
- spree_get :update, params
- expect(assigns(:settings).errors.count).to be 0
- expect(Spree::Config.account_invoices_monthly_fixed).to eq 10
- expect(Spree::Config.account_invoices_monthly_rate).to eq 0.05
- expect(Spree::Config.account_invoices_monthly_cap).to eq 30
- expect(Spree::Config.account_invoices_tax_rate).to eq 0.15
- expect(Spree::Config.shop_trial_length_days).to eq 20
- expect(Spree::Config.minimum_billable_turnover).to eq 10
- end
- end
- end
- end
-end
diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb
index f95bc6e8da..5c9fbea31a 100644
--- a/spec/controllers/admin/enterprises_controller_spec.rb
+++ b/spec/controllers/admin/enterprises_controller_spec.rb
@@ -344,90 +344,20 @@ module Admin
enterprise.save!
end
- context "if the trial has finished" do
- let(:trial_start) { 30.days.ago.beginning_of_day }
-
- before do
- enterprise.update_attribute(:shop_trial_start_date, trial_start)
- end
-
- it "is allowed" do
- Timecop.freeze(Time.zone.local(2015, 4, 16, 14, 0, 0)) do
- spree_post :register, { id: enterprise, sells: 'own' }
- expect(response).to redirect_to spree.admin_path
- expect(enterprise.reload.sells).to eq 'own'
- expect(enterprise.shop_trial_start_date).to eq trial_start
- end
- end
- end
-
- context "if the trial has not finished" do
- let(:trial_start) { Date.current.to_time }
-
- before do
- enterprise.update_attribute(:shop_trial_start_date, trial_start)
- end
-
- it "is allowed, but trial start date is not reset" do
- spree_post :register, { id: enterprise, sells: 'own' }
- expect(response).to redirect_to spree.admin_path
- expect(enterprise.reload.sells).to eq 'own'
- expect(enterprise.shop_trial_start_date).to eq trial_start
- end
- end
-
- context "if a trial has not started" do
- it "is allowed" do
- spree_post :register, { id: enterprise, sells: 'own' }
- expect(response).to redirect_to spree.admin_path
- expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!"
- expect(enterprise.reload.sells).to eq 'own'
- expect(enterprise.reload.shop_trial_start_date).to be > Time.zone.now-(1.minute)
- end
+ it "is allowed" do
+ spree_post :register, { id: enterprise, sells: 'own' }
+ expect(response).to redirect_to spree.admin_path
+ expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!"
+ expect(enterprise.reload.sells).to eq 'own'
end
end
context "setting 'sells' to any" do
- context "if the trial has finished" do
- let(:trial_start) { 30.days.ago.beginning_of_day }
-
- before do
- enterprise.update_attribute(:shop_trial_start_date, trial_start)
- end
-
- it "is allowed" do
- Timecop.freeze(Time.zone.local(2015, 4, 16, 14, 0, 0)) do
- spree_post :register, { id: enterprise, sells: 'any' }
- expect(response).to redirect_to spree.admin_path
- expect(enterprise.reload.sells).to eq 'any'
- expect(enterprise.shop_trial_start_date).to eq trial_start
- end
- end
- end
-
- context "if the trial has not finished" do
- let(:trial_start) { Date.current.to_time }
-
- before do
- enterprise.update_attribute(:shop_trial_start_date, trial_start)
- end
-
- it "is allowed, but trial start date is not reset" do
- spree_post :register, { id: enterprise, sells: 'any' }
- expect(response).to redirect_to spree.admin_path
- expect(enterprise.reload.sells).to eq 'any'
- expect(enterprise.shop_trial_start_date).to eq trial_start
- end
- end
-
- context "if a trial has not started" do
- it "is allowed" do
- spree_post :register, { id: enterprise, sells: 'any' }
- expect(response).to redirect_to spree.admin_path
- expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!"
- expect(enterprise.reload.sells).to eq 'any'
- expect(enterprise.reload.shop_trial_start_date).to be > Time.zone.now-(1.minute)
- end
+ it "is allowed" do
+ spree_post :register, { id: enterprise, sells: 'any' }
+ expect(response).to redirect_to spree.admin_path
+ expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!"
+ expect(enterprise.reload.sells).to eq 'any'
end
end
diff --git a/spec/controllers/api/customers_controller_spec.rb b/spec/controllers/api/customers_controller_spec.rb
index 360037cc90..f6c8f4e0a5 100644
--- a/spec/controllers/api/customers_controller_spec.rb
+++ b/spec/controllers/api/customers_controller_spec.rb
@@ -23,18 +23,6 @@ module Api
expect(json_response.length).to eq 1
expect(json_response.first[:id]).to eq customer1.id
end
-
- context "when the accounts distributor id has been set" do
- before do
- Spree::Config.set(accounts_distributor_id: customer1.enterprise.id)
- end
-
- it "ignores the customer for that enterprise (if it exists)" do
- spree_get :index
- expect(response.status).to eq 200
- expect(json_response.length).to eq 0
- end
- end
end
describe "#update" do
diff --git a/spec/controllers/cart_controller_spec.rb b/spec/controllers/cart_controller_spec.rb
index 8a7ad16dd8..5630429d6d 100644
--- a/spec/controllers/cart_controller_spec.rb
+++ b/spec/controllers/cart_controller_spec.rb
@@ -63,8 +63,8 @@ describe CartController, type: :controller do
let!(:line_item) { create(:line_item, order: order, variant: variant_in_the_order, quantity: 2, max_quantity: 3) }
before do
- variant_in_the_order.count_on_hand = 4
- variant_not_in_the_order.count_on_hand = 2
+ variant_in_the_order.on_hand = 4
+ variant_not_in_the_order.on_hand = 2
order_cycle.exchanges.outgoing.first.variants = [variant_in_the_order, variant_not_in_the_order]
order.order_cycle = order_cycle
order.distributor = hub
diff --git a/spec/controllers/spree/admin/variants_controller_spec.rb b/spec/controllers/spree/admin/variants_controller_spec.rb
index 36fd0463a2..d8178fa3a1 100644
--- a/spec/controllers/spree/admin/variants_controller_spec.rb
+++ b/spec/controllers/spree/admin/variants_controller_spec.rb
@@ -22,7 +22,7 @@ module Spree
it "applies variant overrides" do
spree_get :search, q: 'Prod', distributor_id: d.id.to_s
assigns(:variants).should == [v1]
- assigns(:variants).first.count_on_hand.should == 44
+ assigns(:variants).first.on_hand.should == 44
end
it "filters by order cycle" do
diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb
index d77e493128..dfeb9933e3 100644
--- a/spec/controllers/spree/orders_controller_spec.rb
+++ b/spec/controllers/spree/orders_controller_spec.rb
@@ -224,16 +224,9 @@ describe Spree::OrdersController, type: :controller do
} }
}
- # Before issuing the update, the second adjustment, which is associated
- # to the shipment, is already open thus restoring its state leaves it
- # also open.
- #
- # The third adjustment is originated from an EnterpriseFee and it gets
- # created by #update_distribution_charge! in
- # app/models/spree/order_decorator.rb:220, which is in turn triggered
- # by the `contents_changed` notification event defined in
- # app/models/spree/order_decorator.rb:7
- expect(order.adjustments.map(&:state)).to eq(['closed', 'open', 'closed'])
+ # The second adjustment (shipping adjustment) is open before the update
+ # so, restoring its state leaves it open.
+ expect(order.adjustments.map(&:state)).to eq(['closed', 'open'])
end
end
diff --git a/spec/controllers/spree/users_controller_spec.rb b/spec/controllers/spree/users_controller_spec.rb
index 35e0e0f6a3..95001084dd 100644
--- a/spec/controllers/spree/users_controller_spec.rb
+++ b/spec/controllers/spree/users_controller_spec.rb
@@ -14,14 +14,11 @@ describe Spree::UsersController, type: :controller do
let!(:d1_order_for_u2) { create(:completed_order_with_totals, distributor: distributor1, user_id: u2.id) }
let!(:d1o3) { create(:order, state: 'cart', distributor: distributor1, user_id: u1.id) }
let!(:d2o1) { create(:completed_order_with_totals, distributor: distributor2, user_id: u2.id) }
- let!(:accounts_distributor) { create :distributor_enterprise }
- let!(:order_account_invoice) { create(:order, distributor: accounts_distributor, state: 'complete', user: u1) }
let(:orders) { assigns(:orders) }
let(:shops) { Enterprise.where(id: orders.pluck(:distributor_id)) }
before do
- Spree::Config.set(accounts_distributor_id: accounts_distributor.id)
allow(controller).to receive(:spree_current_user) { u1 }
end
@@ -32,10 +29,6 @@ describe Spree::UsersController, type: :controller do
expect(orders).to_not include d1_order_for_u2, d1o3, d2o1
expect(shops).to include distributor1
- # Doesn't return orders belonging to the accounts distributor" do
- expect(orders).to_not include order_account_invoice
- expect(shops).to_not include accounts_distributor
-
# Doesn't return orders for irrelevant distributors" do
expect(orders).not_to include d2o1
expect(shops).not_to include distributor2
diff --git a/spec/factories.rb b/spec/factories.rb
index cbdbdab3a8..92ab4805c7 100644
--- a/spec/factories.rb
+++ b/spec/factories.rb
@@ -291,17 +291,16 @@ FactoryBot.define do
after(:create) { |c| c.set_preference(:per_kg, 0.5); c.save! }
end
- factory :order_with_totals_and_distribution, parent: :order do
+ factory :order_with_totals_and_distribution, parent: :order_with_distributor do
transient do
shipping_fee 3
end
- distributor { create(:distributor_enterprise) }
order_cycle { create(:simple_order_cycle) }
after(:create) do |order, proxy|
p = create(:simple_product, distributors: [order.distributor])
- FactoryBot.create(:line_item_with_shipment, shipping_fee: proxy.shipping_fee, order: order, product: p)
+ create(:line_item_with_shipment, shipping_fee: proxy.shipping_fee, order: order, product: p)
order.reload
end
end
@@ -416,19 +415,27 @@ FactoryBot.define do
allow_order_changes { true }
end
- factory :completed_order_with_fees, parent: :order_with_totals_and_distribution do
+ factory :completed_order_with_fees, parent: :order_with_distributor do
transient do
payment_fee 5
+ shipping_fee 3
end
ship_address { create(:address) }
+ order_cycle { create(:simple_order_cycle) }
after(:create) do |order, evaluator|
create(:line_item, order: order)
+ product = create(:simple_product, distributors: [order.distributor])
+ create(:line_item, order: order, product: product)
+
payment_calculator = build(:calculator_per_item, preferred_amount: evaluator.payment_fee)
payment_method = create(:payment_method, calculator: payment_calculator)
create(:payment, order: order, amount: order.total, payment_method: payment_method, state: 'checkout')
+ create(:shipping_method_with, :shipping_fee, shipping_fee: evaluator.shipping_fee)
+
+ order.reload
while !order.completed? do break unless order.next! end
end
end
@@ -485,26 +492,6 @@ FactoryBot.define do
bill_address { create(:address) }
end
- factory :billable_period do
- begins_at { Time.zone.now.beginning_of_month }
- ends_at { Time.zone.now.beginning_of_month + 1.month }
- sells { 'any' }
- trial { false }
- enterprise
- owner { enterprise.owner }
- turnover { rand(100000).to_f/100 }
- account_invoice do
- AccountInvoice.where(user_id: owner_id, year: begins_at.year, month: begins_at.month).first ||
- FactoryBot.create(:account_invoice, user: owner, year: begins_at.year, month: begins_at.month)
- end
- end
-
- factory :account_invoice do
- user { FactoryBot.create :user }
- year { 2000 + rand(100) }
- month { 1 + rand(12) }
- end
-
factory :filter_order_cycles_tag_rule, class: TagRule::FilterOrderCycles do
enterprise { FactoryBot.create :distributor_enterprise }
end
@@ -604,7 +591,7 @@ FactoryBot.modify do
after(:create) do |variant, evaluator|
variant.on_demand = evaluator.on_demand
- variant.count_on_hand = evaluator.on_hand
+ variant.on_hand = evaluator.on_hand
variant.save
end
end
diff --git a/spec/features/admin/account_spec.rb b/spec/features/admin/account_spec.rb
deleted file mode 100644
index f2be99c3a3..0000000000
--- a/spec/features/admin/account_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require 'spec_helper'
-
-feature 'Account Page' do
- include AuthenticationWorkflow
-
- describe "updating" do
- let!(:user) { create(:user) }
- let!(:enterprise) { create(:distributor_enterprise, owner: user) }
-
- before do
- quick_login_as user
- end
-
- context "as an enterprise user" do
- it "loads the page" do
- visit admin_account_path
- expect(page).to have_content "Account"
- end
- end
- end
-end
diff --git a/spec/features/admin/accounts_and_billing_settings_spec.rb b/spec/features/admin/accounts_and_billing_settings_spec.rb
deleted file mode 100644
index b5316f6b21..0000000000
--- a/spec/features/admin/accounts_and_billing_settings_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-require 'spec_helper'
-
-feature 'Account and Billing Settings' do
- include AuthenticationWorkflow
- include WebHelper
-
- describe "updating" do
- let!(:admin) { create(:admin_user) }
- let!(:pm1) { create(:payment_method) }
- let!(:sm1) { create(:shipping_method) }
- let!(:accounts_distributor) { create(:distributor_enterprise, payment_methods: [pm1], shipping_methods: [sm1]) }
-
- before do
- Spree::Config.set({
- accounts_distributor_id: 0,
- default_accounts_payment_method_id: 0,
- default_accounts_shipping_method_id: 0,
- auto_update_invoices: false,
- auto_finalize_invoices: false
- })
- end
-
- before do
- quick_login_as_admin
- end
-
- context "as an admin user", js: true do
- it "loads the page" do
- visit spree.admin_path
- click_link "Configuration"
- click_link "Accounts & Billing"
-
- expect(page).to have_select2 "settings_accounts_distributor_id"
- select2_select accounts_distributor.name, from: "settings_accounts_distributor_id"
- expect(page).to have_select "settings_default_accounts_payment_method_id"
- expect(page).to have_select "settings_default_accounts_shipping_method_id"
- expect(page).to have_link "Update User Invoices", href: start_job_admin_accounts_and_billing_settings_path(job: { name: 'update_account_invoices'})
- expect(page).to have_link "Finalise User Invoices", href: start_job_admin_accounts_and_billing_settings_path(job: { name: 'finalize_account_invoices'})
- end
-
- it "attributes can be changed", js: true do
- visit edit_admin_accounts_and_billing_settings_path
-
- select2_select accounts_distributor.name, from: "settings_accounts_distributor_id"
- select pm1.name, from: "settings_default_accounts_payment_method_id"
- select sm1.name, from: "settings_default_accounts_shipping_method_id"
- check "settings_auto_update_invoices"
- check "settings_auto_finalize_invoices"
-
- click_button "Update"
-
- expect(Spree::Config.accounts_distributor_id).to eq accounts_distributor.id
- expect(Spree::Config.default_accounts_payment_method_id).to eq pm1.id
- expect(Spree::Config.default_accounts_shipping_method_id).to eq sm1.id
- expect(Spree::Config.auto_update_invoices).to be true
- expect(Spree::Config.auto_finalize_invoices).to be true
- end
- end
- end
-end
diff --git a/spec/features/admin/bulk_order_management_spec.rb b/spec/features/admin/bulk_order_management_spec.rb
index 698c7bb666..f5f0c5793c 100644
--- a/spec/features/admin/bulk_order_management_spec.rb
+++ b/spec/features/admin/bulk_order_management_spec.rb
@@ -45,6 +45,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a column for user's full name" do
@@ -92,6 +93,7 @@ feature %q{
before do
visit spree.admin_bulk_order_management_path
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "sorts by customer name when the customer name header is clicked" do
@@ -260,6 +262,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a select box for producers, which filters line items by the selected supplier" do
@@ -298,6 +301,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a select box for distributors, which filters line items by the selected distributor" do
@@ -337,6 +341,7 @@ feature %q{
before do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a select box for order cycles, which filters line items by the selected order cycle" do
@@ -377,6 +382,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "allows filters to be used in combination" do
@@ -427,6 +433,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a quick search input" do
@@ -456,6 +463,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays date fields for filtering orders, with default values set" do
@@ -528,6 +536,7 @@ feature %q{
before :each do
visit '/admin/orders/bulk_management'
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
end
it "displays a checkbox for each line item in the list" do
@@ -570,6 +579,7 @@ feature %q{
expect(page).to have_no_selector "tr#li_#{li2.id}"
check "toggle_bulk"
fill_in "quick_search", with: ''
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
expect(find("tr#li_#{li1.id} input[type='checkbox'][name='bulk']").checked?).to be true
expect(find("tr#li_#{li2.id} input[type='checkbox'][name='bulk']").checked?).to be false
expect(find("input[type='checkbox'][name='toggle_bulk']").checked?).to be false
@@ -583,6 +593,7 @@ feature %q{
find("div#bulk-actions-dropdown div.menu_item", :text => "Delete Selected" ).click
expect(page).to have_no_selector "tr#li_#{li1.id}"
fill_in "quick_search", with: ''
+ wait_until { request_monitor_finished 'LineItemsCtrl' }
expect(page).to have_selector "tr#li_#{li2.id}"
expect(page).to have_no_selector "tr#li_#{li1.id}"
end
diff --git a/spec/features/admin/business_model_configuration_spec.rb b/spec/features/admin/business_model_configuration_spec.rb
deleted file mode 100644
index a16a23976e..0000000000
--- a/spec/features/admin/business_model_configuration_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'spec_helper'
-
-feature 'Business Model Configuration' do
- include AuthenticationWorkflow
- include WebHelper
-
- describe "updating" do
- let!(:admin) { create(:admin_user) }
-
- before do
- Spree::Config.set({
- account_invoices_monthly_fixed: 5,
- account_invoices_monthly_rate: 0.02,
- account_invoices_monthly_cap: 50,
- account_invoices_tax_rate: 0.1
- })
- end
-
- before do
- quick_login_as_admin
- end
-
- context "as an admin user", js: true do
- it "loads the page" do
- visit spree.admin_path
- click_link "Configuration"
- click_link "Business Model"
-
- expect(page).to have_field "settings_account_invoices_monthly_fixed", with: 5.0
- expect(page).to have_field "settings_account_invoices_monthly_rate", with: 0.02
- expect(page).to have_field "settings_account_invoices_monthly_cap", with: 50.0
- expect(page).to have_field "settings_account_invoices_tax_rate", with: 0.1
- end
-
- it "attributes can be changed", js: true do
- visit edit_admin_business_model_configuration_path
-
- fill_in "settings_account_invoices_monthly_fixed", with: 10
- fill_in "settings_account_invoices_monthly_rate", with: 0.05
- fill_in "settings_account_invoices_monthly_cap", with: 30
- fill_in "settings_account_invoices_tax_rate", with: 0.15
-
- click_button "Update"
-
- expect(page).to have_content "Business Model has been successfully updated!"
- expect(Spree::Config.account_invoices_monthly_fixed).to eq 10
- expect(Spree::Config.account_invoices_monthly_rate).to eq 0.05
- expect(Spree::Config.account_invoices_monthly_cap).to eq 30
- expect(Spree::Config.account_invoices_tax_rate).to eq 0.15
- end
- end
- end
-end
diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb
index 5f9b887b82..7f2df5eb61 100644
--- a/spec/features/admin/order_cycles_spec.rb
+++ b/spec/features/admin/order_cycles_spec.rb
@@ -117,7 +117,7 @@ feature %q{
end
describe 'listing order cycles with other locales' do
- let!(:oc_de) { create(:simple_order_cycle, name: 'oc', orders_open_at: '2012-01-01 00:00:00') }
+ let!(:oc_de) { create(:simple_order_cycle, name: 'oc', orders_open_at: '2012-01-01 00:00') }
around(:each) do |spec|
I18n.locale = :de
@@ -131,7 +131,7 @@ feature %q{
visit admin_order_cycles_path
within("tr.order-cycle-#{oc_de.id}") do
- expect(find('input.datetimepicker', match: :first).value).to start_with '2012-01-01 00:00:00'
+ expect(find('input.datetimepicker', match: :first).value).to start_with '2012-01-01 00:00'
find('img.ui-datepicker-trigger', match: :first).click
end
@@ -143,7 +143,7 @@ feature %q{
end
within("tr.order-cycle-#{oc_de.id}") do
- expect(find('input.datetimepicker', match: :first).value).to eq '2012-01-30 00:00:00'
+ expect(find('input.datetimepicker', match: :first).value).to eq '2012-01-30 00:00'
end
end
end
@@ -556,7 +556,7 @@ feature %q{
within("tr.order-cycle-#{oc3.id}") do
# Then that date/time should appear on the form
- expect(find("input#oc#{oc3.id}_orders_open_at").value).to eq "2040-12-01 00:00:00"
+ expect(find("input#oc#{oc3.id}_orders_open_at").value).to eq "2040-12-01 00:00"
# Manually fill out time
find("input#oc#{oc3.id}_name").set "Updated Order Cycle 3"
diff --git a/spec/features/admin/product_import_spec.rb b/spec/features/admin/product_import_spec.rb
index 8114c129dc..a3c1766374 100644
--- a/spec/features/admin/product_import_spec.rb
+++ b/spec/features/admin/product_import_spec.rb
@@ -462,7 +462,7 @@ feature "Product Import", js: true do
def proceed_to_validation
expect(page).to have_selector 'a.button.proceed', visible: true
- click_link I18n.t('admin.product_import.import.import')
+ within("#content") { click_link I18n.t('admin.product_import.import.import') }
expect(page).to have_selector 'form.product-import', visible: true
expect(page).to have_content I18n.t('admin.product_import.import.validation_overview')
end
diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb
index f34d2ef28e..86a6e303d7 100644
--- a/spec/features/admin/reports_spec.rb
+++ b/spec/features/admin/reports_spec.rb
@@ -308,11 +308,11 @@ xfeature %q{
product2.set_property 'Organic', 'NASAA 12345'
product1.taxons = [taxon]
product2.taxons = [taxon]
- variant1.count_on_hand = 10
+ variant1.on_hand = 10
variant1.update_column(:sku, "sku1")
- variant2.count_on_hand = 20
+ variant2.on_hand = 20
variant2.update_column(:sku, "sku2")
- variant3.count_on_hand = 9
+ variant3.on_hand = 9
variant3.update_column(:sku, "")
variant1.option_values = [create(:option_value, :presentation => "Test")]
variant2.option_values = [create(:option_value, :presentation => "Something")]
@@ -493,36 +493,6 @@ xfeature %q{
xero_invoice_summary_row('Delivery Shipping Cost (tax inclusive)', 100.55, 'GST on Income', opts)
]
end
-
- describe "account invoices" do
- let(:accounts_distributor) { create(:distributor_enterprise) }
- let(:billable_period) { create(:billable_period, account_invoice: account_invoice) }
- let(:account_invoice) { create(:account_invoice, order: account_invoice_order) }
- let!(:account_invoice_order) { create(:order, order_cycle: order_cycle, distributor: accounts_distributor) }
- let!(:adjustment) { create(:adjustment, adjustable: account_invoice_order, source: billable_period, label: 'Account invoice item', amount: 12.34) } # Tax?
-
- before do
- Spree::Config.accounts_distributor_id = accounts_distributor.id
-
- account_invoice_order.update_attribute :email, 'customer@email.com'
- Timecop.travel(Time.zone.local(2015, 4, 25, 14, 0, 0)) { account_invoice_order.finalize! }
-
- visit current_path
- end
-
- it "generates a detailed report for account invoices" do
- select 'Detailed', from: 'report_type'
- select accounts_distributor.name, from: 'q_distributor_id_eq'
- click_button 'Search'
-
- opts = {}
-
- expect(xero_invoice_table).to match_table [
- xero_invoice_header,
- xero_invoice_account_invoice_row(adjustment)
- ]
- end
- end
end
private
@@ -549,11 +519,6 @@ xfeature %q{
xero_invoice_row('', adjustment.label, adjustment.amount, '1', tax_type, opts)
end
- def xero_invoice_account_invoice_row(adjustment, opts={})
- opts.reverse_merge!({customer_name: '', address1: '', city: '', state: '', zipcode: '', country: '', invoice_number: account_invoice_order.number, order_number: account_invoice_order.number})
- xero_invoice_adjustment_row(adjustment, opts)
- end
-
def xero_invoice_row(sku, description, amount, quantity, tax_type, opts={})
opts.reverse_merge!({customer_name: 'Customer Name', address1: 'customer l1', city: 'customer city', state: 'Victoria', zipcode: '1234', country: country.name, invoice_number: order1.number, order_number: order1.number, invoice_date: '2015-04-26', due_date: '2015-05-26', account_code: 'food sales'})
diff --git a/spec/features/admin/shipping_methods_spec.rb b/spec/features/admin/shipping_methods_spec.rb
index d5f5eeceab..e81d904b20 100644
--- a/spec/features/admin/shipping_methods_spec.rb
+++ b/spec/features/admin/shipping_methods_spec.rb
@@ -109,9 +109,8 @@ feature 'shipping methods' do
click_button I18n.t("actions.create")
- expect(page).to have_no_button I18n.t("actions.create")
- message = "Shipping method \"Teleport\" has been successfully created!"
- expect(page).to have_flash_message message
+ expect(page).to have_content I18n.t('spree.admin.shipping_methods.edit.editing_shipping_method')
+ expect(flash_message).to eq I18n.t('successfully_created', resource: 'Shipping method "Teleport"')
expect(first('tags-input .tag-list ti-tag-item')).to have_content "local"
diff --git a/spec/features/consumer/account_spec.rb b/spec/features/consumer/account_spec.rb
index 19175348f3..1ea86078b5 100644
--- a/spec/features/consumer/account_spec.rb
+++ b/spec/features/consumer/account_spec.rb
@@ -13,12 +13,9 @@ feature %q{
let!(:distributor2) { create(:distributor_enterprise) }
let!(:distributor_credit) { create(:distributor_enterprise) }
let!(:distributor_without_orders) { create(:distributor_enterprise) }
- let!(:accounts_distributor) {create :distributor_enterprise}
- let!(:order_account_invoice) { create(:order, distributor: accounts_distributor, state: 'complete', user: user) }
context "as a logged in user" do
before do
- Spree::Config.accounts_distributor_id = accounts_distributor.id
login_as user
end
@@ -42,9 +39,6 @@ feature %q{
expect(page).to have_content I18n.t('spree.users.orders.past_orders')
- # Doesn't show orders from the special Accounts & Billing distributor
- expect(page).not_to have_content accounts_distributor.name
-
# Lists all other orders
expect(page).to have_content d1o1.number.to_s
expect(page).to have_content d1o2.number.to_s
@@ -59,8 +53,6 @@ feature %q{
expect(page).to have_content distributor2.name
expect(page).not_to have_content distributor_without_orders.name
- # Exclude the special Accounts & Billing distributor
- expect(page).not_to have_content accounts_distributor.name
expect(page).to have_content distributor1.name + " " + "Balance due"
expect(page).to have_content distributor_credit.name + " Credit"
diff --git a/spec/features/consumer/registration_spec.rb b/spec/features/consumer/registration_spec.rb
index 0a7756d104..efbb9deca0 100644
--- a/spec/features/consumer/registration_spec.rb
+++ b/spec/features/consumer/registration_spec.rb
@@ -139,7 +139,7 @@ feature "Registration", js: true do
fill_in "Email", with: user.email
fill_in "Password", with: user.password
click_button 'Login'
- expect(page).to have_content I18n.t('limit_reached_headline')
+ expect(page).to have_content I18n.t('registration.steps.limit_reached.headline')
end
end
end
diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb
index 4b18a62434..abf1cc7d51 100644
--- a/spec/features/consumer/shopping/shopping_spec.rb
+++ b/spec/features/consumer/shopping/shopping_spec.rb
@@ -302,6 +302,15 @@ feature "As a consumer I want to shop with a distributor", js: true do
Spree::LineItem.where(id: li).should be_empty
end
+ it "lets us add a quantity greater than on_hand value if product is on_demand" do
+ variant.update_attributes on_hand: 5, on_demand: true
+ visit shop_path
+
+ fill_in "variants[#{variant.id}]", with: '10'
+
+ page.should have_field "variants[#{variant.id}]", with: '10'
+ end
+
it "alerts us when we enter a quantity greater than the stock available" do
variant.update_attributes on_hand: 5
visit shop_path
@@ -341,6 +350,18 @@ feature "As a consumer I want to shop with a distributor", js: true do
page.should have_selector "#variants_#{variant.id}[disabled='disabled']"
end
+ it 'does not show out of stock modal if product is on_demand' do
+ expect(page).to have_content "Product"
+
+ variant.update_attributes! on_hand: 0, on_demand: true
+
+ expect(page).to have_input "variants[#{variant.id}]"
+ fill_in "variants[#{variant.id}]", with: '1'
+ wait_until { !cart_dirty }
+
+ expect(page).to_not have_selector '.out-of-stock-modal'
+ end
+
context "group buy products" do
let(:product) { create(:simple_product, group_buy: true) }
diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb
index 8638616872..5aaa0d1ac9 100644
--- a/spec/features/consumer/shopping/variant_overrides_spec.rb
+++ b/spec/features/consumer/shopping/variant_overrides_spec.rb
@@ -123,7 +123,7 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
expect do
expect do
complete_checkout
- end.to change { product1_variant3.reload.count_on_hand }.by(0)
+ end.to change { product1_variant3.reload.on_hand }.by(0)
end.to change { product1_variant3_override.reload.count_on_hand }.by(-2)
end
@@ -134,7 +134,7 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
expect do
expect do
complete_checkout
- end.to change { product3_variant2.reload.count_on_hand }.by(0)
+ end.to change { product3_variant2.reload.on_hand }.by(0)
end.to change { product3_variant2_override.reload.count_on_hand }.by(-2)
end
@@ -143,12 +143,12 @@ feature "shopping with variant overrides defined", js: true, retry: 3 do
click_checkout
expect do
complete_checkout
- end.to change { product1_variant1.reload.count_on_hand }.by(-2)
+ end.to change { product1_variant1.reload.on_hand }.by(-2)
product1_variant1_override.reload.count_on_hand.should be_nil
end
it "does not show out of stock flags on order confirmation page" do
- product1_variant3.count_on_hand = 0
+ product1_variant3.on_hand = 0
fill_in "variants[#{product1_variant3.id}]", with: "2"
click_checkout
diff --git a/spec/helpers/admin/business_model_configuration_helper_spec.rb b/spec/helpers/admin/business_model_configuration_helper_spec.rb
deleted file mode 100644
index 3490efb8be..0000000000
--- a/spec/helpers/admin/business_model_configuration_helper_spec.rb
+++ /dev/null
@@ -1,574 +0,0 @@
-require 'spec_helper'
-
-describe Admin::BusinessModelConfigurationHelper, type: :helper do
- describe "describing monthly bills for enterprises" do
-
- context "when there is no free trial" do
- before { Spree::Config.set(:shop_trial_length_days, 0) }
-
- context "when tax is applied to the service change" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.1) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
-
- context "when minimum billable turnover is 100" do
- before { Spree::Config.set(:minimum_billable_turnover, 100) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
- end
-
- context "when tax is not applied to the service change" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.0) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
-
- context "when minimum billable turnover is 100" do
- before { Spree::Config.set(:minimum_billable_turnover, 100) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "#{with_currency(10, no_cents: true)} PER MONTH" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
- end
- end
-
- context "when there is a 30 day free trial" do
- before { Spree::Config.set(:shop_trial_length_days, 30) }
-
- context "when tax is applied to the service change" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.1) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
-
- context "when minimum billable turnover is 100" do
- before { Spree::Config.set(:minimum_billable_turnover, 100) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH, PLUS GST" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH, PLUS GST" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
- end
-
- context "when tax is not applied to the service change" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.0) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
-
- context "when minimum billable turnover is 100" do
- before { Spree::Config.set(:minimum_billable_turnover, 100) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} + 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN #{with_currency(10, no_cents: true)} PER MONTH" }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.05) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)}, CAPPED AT #{with_currency(20, no_cents: true)} PER MONTH" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE TRIAL THEN 5.0% OF SALES ONCE TURNOVER EXCEEDS #{with_currency(100, no_cents: true)} PER MONTH" }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(helper.monthly_bill_description).to eq "FREE" }
- end
- end
- end
- end
- end
- end
- end
-end
diff --git a/spec/javascripts/unit/bulk_product_update_spec.js.coffee b/spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
similarity index 98%
rename from spec/javascripts/unit/bulk_product_update_spec.js.coffee
rename to spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
index c1c34cbe6b..a26fdd523e 100644
--- a/spec/javascripts/unit/bulk_product_update_spec.js.coffee
+++ b/spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee
@@ -166,7 +166,22 @@ describe "filtering products for submission to database", ->
variant_unit_scale: 1
]
- # TODO Not an exhaustive test, is there a better way to do this?
+ it "returns stock properties of a product if no variant is provided", ->
+ available_on = new Date()
+
+ testProduct =
+ id: 1
+ name: "TestProduct"
+ on_hand: 0
+ on_demand: false
+
+ expect(filterSubmitProducts([testProduct])).toEqual [
+ id: 1
+ name: "TestProduct"
+ on_hand: 0
+ on_demand: false
+ ]
+
it "only returns the properties of products which ought to be updated", ->
available_on = new Date()
@@ -183,12 +198,11 @@ describe "filtering products for submission to database", ->
shipping_category_id: null
created_at: null
updated_at: null
- count_on_hand: 0
+ on_hand: 0
+ on_demand: false
producer_id: 5
-
group_buy: null
group_buy_unit_size: null
- on_demand: false
master:
id: 2
unit_value: 250
diff --git a/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee b/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee
index 3ff397eb18..5724fe1353 100644
--- a/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee
+++ b/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee
@@ -98,7 +98,7 @@ describe "VariantOverridesCtrl", ->
beforeEach ->
# Ideally, count_on_hand is blank when the variant is on demand. However, this rule is not
# enforced.
- variant = {id: 2, on_demand: true, count_on_hand: 20, on_hand: "On demand"}
+ variant = {id: 2, on_demand: true, on_hand: 20, on_hand: "On demand"}
it "clears count_on_hand when variant override uses producer stock settings", ->
scope.variantOverrides[123][2] = {on_demand: null, count_on_hand: 1}
@@ -162,7 +162,7 @@ describe "VariantOverridesCtrl", ->
beforeEach ->
# Ideally, count_on_hand is blank when the variant is on demand. However, this rule is not
# enforced.
- variant = {id: 2, on_demand: true, count_on_hand: 20, on_hand: t("on_demand")}
+ variant = {id: 2, on_demand: true, on_hand: 20, on_hand: t("on_demand")}
it "is 'On demand' when variant override uses producer stock settings", ->
scope.variantOverrides[123][2] = {on_demand: null, count_on_hand: 1}
@@ -183,7 +183,7 @@ describe "VariantOverridesCtrl", ->
variant = null
beforeEach ->
- variant = {id: 2, on_demand: false, count_on_hand: 20, on_hand: 20}
+ variant = {id: 2, on_demand: false, on_hand: 20, on_hand: 20}
it "is variant count on hand when variant override uses producer stock settings", ->
scope.variantOverrides[123][2] = {on_demand: null, count_on_hand: 1}
diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/create_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/create_spec.js.coffee
new file mode 100644
index 0000000000..d07c80f542
--- /dev/null
+++ b/spec/javascripts/unit/admin/order_cycles/controllers/create_spec.js.coffee
@@ -0,0 +1,161 @@
+describe 'AdminCreateOrderCycleCtrl', ->
+ ctrl = null
+ scope = null
+ event = null
+ OrderCycle = null
+ Enterprise = null
+ EnterpriseFee = null
+
+ beforeEach ->
+ scope =
+ order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty'])
+ $watch: jasmine.createSpy('$watch')
+ event =
+ preventDefault: jasmine.createSpy('preventDefault')
+ OrderCycle =
+ exchangeSelectedVariants: jasmine.createSpy('exchangeSelectedVariants').and.returnValue('variants selected')
+ productSuppliedToOrderCycle: jasmine.createSpy('productSuppliedToOrderCycle').and.returnValue('product supplied')
+ variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').and.returnValue('variant supplied')
+ exchangeDirection: jasmine.createSpy('exchangeDirection').and.returnValue('exchange direction')
+ toggleProducts: jasmine.createSpy('toggleProducts')
+ setExchangeVariants: jasmine.createSpy('setExchangeVariants')
+ addSupplier: jasmine.createSpy('addSupplier')
+ addDistributor: jasmine.createSpy('addDistributor')
+ removeExchange: jasmine.createSpy('removeExchange')
+ addCoordinatorFee: jasmine.createSpy('addCoordinatorFee')
+ removeCoordinatorFee: jasmine.createSpy('removeCoordinatorFee')
+ addExchangeFee: jasmine.createSpy('addExchangeFee')
+ removeExchangeFee: jasmine.createSpy('removeExchangeFee')
+ removeDistributionOfVariant: jasmine.createSpy('removeDistributionOfVariant')
+ create: jasmine.createSpy('create')
+ new: jasmine.createSpy('new').and.returnValue "my order cycle"
+ Enterprise =
+ index: jasmine.createSpy('index').and.returnValue('enterprises list')
+ supplied_products: 'supplied products'
+ suppliedVariants: jasmine.createSpy('suppliedVariants').and.returnValue('supplied variants')
+ totalVariants: jasmine.createSpy('totalVariants').and.returnValue('variants total')
+ EnterpriseFee =
+ index: jasmine.createSpy('index').and.returnValue('enterprise fees list')
+ forEnterprise: jasmine.createSpy('forEnterprise').and.returnValue('enterprise fees for enterprise')
+ ocInstance = {}
+
+ module('admin.orderCycles')
+ inject ($controller) ->
+ ctrl = $controller 'AdminCreateOrderCycleCtrl', {$scope: scope, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee, ocInstance: ocInstance}
+
+
+ it 'Loads enterprises and supplied products', ->
+ expect(Enterprise.index).toHaveBeenCalled()
+ expect(scope.enterprises).toEqual('enterprises list')
+ expect(scope.supplied_products).toEqual('supplied products')
+
+ it 'Loads enterprise fees', ->
+ expect(EnterpriseFee.index).toHaveBeenCalled()
+ expect(scope.enterprise_fees).toEqual('enterprise fees list')
+
+ it 'Loads order cycles', ->
+ expect(scope.order_cycle).toEqual('my order cycle')
+
+ describe 'Reporting when all resources are loaded', ->
+ beforeEach inject (RequestMonitor) ->
+ RequestMonitor.loading = false
+ Enterprise.loaded = true
+ EnterpriseFee.loaded = true
+ OrderCycle.loaded = true
+
+ it 'returns true when all resources are loaded', ->
+ expect(scope.loaded()).toBe(true)
+
+ it 'returns false otherwise', ->
+ EnterpriseFee.loaded = false
+ expect(scope.loaded()).toBe(false)
+
+ it "delegates suppliedVariants to Enterprise", ->
+ expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
+ expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
+
+ it 'Delegates exchangeSelectedVariants to OrderCycle', ->
+ expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
+ expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
+
+ it "delegates setExchangeVariants to OrderCycle", ->
+ scope.setExchangeVariants('exchange', 'variants', 'selected')
+ expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
+
+ it 'Delegates enterpriseTotalVariants to Enterprise', ->
+ expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
+ expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
+
+ it 'Delegates productSuppliedToOrderCycle to OrderCycle', ->
+ expect(scope.productSuppliedToOrderCycle('product')).toEqual('product supplied')
+ expect(OrderCycle.productSuppliedToOrderCycle).toHaveBeenCalledWith('product')
+
+ it 'Delegates variantSuppliedToOrderCycle to OrderCycle', ->
+ expect(scope.variantSuppliedToOrderCycle('variant')).toEqual('variant supplied')
+ expect(OrderCycle.variantSuppliedToOrderCycle).toHaveBeenCalledWith('variant')
+
+ it 'Delegates exchangeDirection to OrderCycle', ->
+ expect(scope.exchangeDirection('exchange')).toEqual('exchange direction')
+ expect(OrderCycle.exchangeDirection).toHaveBeenCalledWith('exchange')
+
+ it 'Finds enterprises participating in the order cycle that have fees', ->
+ scope.enterprises =
+ 1: {id: 1, name: 'Eaterprises'}
+ 2: {id: 2, name: 'Pepper Tree Place'}
+ 3: {id: 3, name: 'South East'}
+ OrderCycle.participatingEnterpriseIds = jasmine.createSpy('participatingEnterpriseIds').and.returnValue([2])
+ EnterpriseFee.enterprise_fees = [ {enterprise_id: 2} ] # Pepper Tree Place has a fee
+ expect(scope.enterprisesWithFees()).toEqual([
+ {id: 2, name: 'Pepper Tree Place'}
+ ])
+
+ it 'Delegates enterpriseFeesForEnterprise to EnterpriseFee', ->
+ scope.enterpriseFeesForEnterprise('123')
+ expect(EnterpriseFee.forEnterprise).toHaveBeenCalledWith(123)
+
+ it 'Adds order cycle suppliers', ->
+ scope.new_supplier_id = 'new supplier id'
+ scope.addSupplier(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addSupplier).toHaveBeenCalledWith('new supplier id')
+
+ it 'Adds order cycle distributors', ->
+ scope.new_distributor_id = 'new distributor id'
+ scope.addDistributor(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addDistributor).toHaveBeenCalledWith('new distributor id')
+
+ it 'Removes order cycle exchanges', ->
+ scope.removeExchange(event, 'exchange')
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeExchange).toHaveBeenCalledWith('exchange')
+
+ it 'Adds coordinator fees', ->
+ scope.addCoordinatorFee(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addCoordinatorFee).toHaveBeenCalled()
+
+ it 'Removes coordinator fees', ->
+ scope.removeCoordinatorFee(event, 0)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeCoordinatorFee).toHaveBeenCalledWith(0)
+
+ it 'Adds exchange fees', ->
+ scope.addExchangeFee(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addExchangeFee).toHaveBeenCalled()
+
+ it 'Removes exchange fees', ->
+ scope.removeExchangeFee(event, 'exchange', 0)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeExchangeFee).toHaveBeenCalledWith('exchange', 0)
+
+ it 'Removes distribution of a variant', ->
+ scope.removeDistributionOfVariant('variant')
+ expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('variant')
+
+ it 'Submits the order cycle via OrderCycle create', ->
+ eventMock = {preventDefault: jasmine.createSpy()}
+ scope.submit(eventMock,'/admin/order_cycles')
+ expect(eventMock.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.create).toHaveBeenCalledWith('/admin/order_cycles')
diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/edit_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/edit_spec.js.coffee
new file mode 100644
index 0000000000..2f2016f5c7
--- /dev/null
+++ b/spec/javascripts/unit/admin/order_cycles/controllers/edit_spec.js.coffee
@@ -0,0 +1,166 @@
+describe 'AdminEditOrderCycleCtrl', ->
+ ctrl = null
+ scope = null
+ event = null
+ location = null
+ OrderCycle = null
+ Enterprise = null
+ EnterpriseFee = null
+
+ beforeEach ->
+ scope =
+ order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty', '$setPristine'])
+ $watch: jasmine.createSpy('$watch')
+ event =
+ preventDefault: jasmine.createSpy('preventDefault')
+ location =
+ absUrl: ->
+ 'example.com/admin/order_cycles/27/edit'
+ OrderCycle =
+ load: jasmine.createSpy('load')
+ exchangeSelectedVariants: jasmine.createSpy('exchangeSelectedVariants').and.returnValue('variants selected')
+ productSuppliedToOrderCycle: jasmine.createSpy('productSuppliedToOrderCycle').and.returnValue('product supplied')
+ variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').and.returnValue('variant supplied')
+ exchangeDirection: jasmine.createSpy('exchangeDirection').and.returnValue('exchange direction')
+ toggleProducts: jasmine.createSpy('toggleProducts')
+ setExchangeVariants: jasmine.createSpy('setExchangeVariants')
+ addSupplier: jasmine.createSpy('addSupplier')
+ addDistributor: jasmine.createSpy('addDistributor')
+ removeExchange: jasmine.createSpy('removeExchange')
+ addCoordinatorFee: jasmine.createSpy('addCoordinatorFee')
+ removeCoordinatorFee: jasmine.createSpy('removeCoordinatorFee')
+ addExchangeFee: jasmine.createSpy('addExchangeFee')
+ removeExchangeFee: jasmine.createSpy('removeExchangeFee')
+ removeDistributionOfVariant: jasmine.createSpy('removeDistributionOfVariant')
+ update: jasmine.createSpy('update')
+ Enterprise =
+ index: jasmine.createSpy('index').and.returnValue('enterprises list')
+ supplied_products: 'supplied products'
+ suppliedVariants: jasmine.createSpy('suppliedVariants').and.returnValue('supplied variants')
+ totalVariants: jasmine.createSpy('totalVariants').and.returnValue('variants total')
+ EnterpriseFee =
+ index: jasmine.createSpy('index').and.returnValue('enterprise fees list')
+ forEnterprise: jasmine.createSpy('forEnterprise').and.returnValue('enterprise fees for enterprise')
+
+ module('admin.orderCycles')
+ inject ($controller) ->
+ ctrl = $controller 'AdminEditOrderCycleCtrl', {$scope: scope, $location: location, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee}
+
+ it 'Loads enterprises and supplied products', ->
+ expect(Enterprise.index).toHaveBeenCalled()
+ expect(scope.enterprises).toEqual('enterprises list')
+ expect(scope.supplied_products).toEqual('supplied products')
+
+ it 'Loads enterprise fees', ->
+ expect(EnterpriseFee.index).toHaveBeenCalled()
+ expect(scope.enterprise_fees).toEqual('enterprise fees list')
+
+ it 'Loads order cycles', ->
+ expect(OrderCycle.load).toHaveBeenCalledWith('27')
+
+ describe 'Reporting when all resources are loaded', ->
+ beforeEach inject (RequestMonitor) ->
+ RequestMonitor.loading = false
+ Enterprise.loaded = true
+ EnterpriseFee.loaded = true
+ OrderCycle.loaded = true
+
+ it 'returns true when all resources are loaded', ->
+ expect(scope.loaded()).toBe(true)
+
+ it 'returns false otherwise', ->
+ EnterpriseFee.loaded = false
+ expect(scope.loaded()).toBe(false)
+
+ it "delegates suppliedVariants to Enterprise", ->
+ expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
+ expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
+
+ it 'Delegates exchangeSelectedVariants to OrderCycle', ->
+ expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
+ expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
+
+ it "delegates setExchangeVariants to OrderCycle", ->
+ scope.setExchangeVariants('exchange', 'variants', 'selected')
+ expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
+
+ it 'Delegates totalVariants to Enterprise', ->
+ expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
+ expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
+
+ it 'Delegates productSuppliedToOrderCycle to OrderCycle', ->
+ expect(scope.productSuppliedToOrderCycle('product')).toEqual('product supplied')
+ expect(OrderCycle.productSuppliedToOrderCycle).toHaveBeenCalledWith('product')
+
+ it 'Delegates variantSuppliedToOrderCycle to OrderCycle', ->
+ expect(scope.variantSuppliedToOrderCycle('variant')).toEqual('variant supplied')
+ expect(OrderCycle.variantSuppliedToOrderCycle).toHaveBeenCalledWith('variant')
+
+ it 'Delegates exchangeDirection to OrderCycle', ->
+ expect(scope.exchangeDirection('exchange')).toEqual('exchange direction')
+ expect(OrderCycle.exchangeDirection).toHaveBeenCalledWith('exchange')
+
+ it 'Finds enterprises participating in the order cycle that have fees', ->
+ scope.enterprises =
+ 1: {id: 1, name: 'Eaterprises'}
+ 2: {id: 2, name: 'Pepper Tree Place'}
+ 3: {id: 3, name: 'South East'}
+ OrderCycle.participatingEnterpriseIds = jasmine.createSpy('participatingEnterpriseIds').and.returnValue([2])
+ EnterpriseFee.enterprise_fees = [ {enterprise_id: 2} ] # Pepper Tree Place has a fee
+ expect(scope.enterprisesWithFees()).toEqual([
+ {id: 2, name: 'Pepper Tree Place'}
+ ])
+
+ it 'Delegates enterpriseFeesForEnterprise to EnterpriseFee', ->
+ scope.enterpriseFeesForEnterprise('123')
+ expect(EnterpriseFee.forEnterprise).toHaveBeenCalledWith(123)
+
+ it 'Adds order cycle suppliers', ->
+ scope.new_supplier_id = 'new supplier id'
+ scope.addSupplier(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addSupplier).toHaveBeenCalledWith('new supplier id')
+
+ it 'Adds order cycle distributors', ->
+ scope.new_distributor_id = 'new distributor id'
+ scope.addDistributor(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addDistributor).toHaveBeenCalledWith('new distributor id')
+
+ it 'Removes order cycle exchanges', ->
+ scope.removeExchange(event, 'exchange')
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeExchange).toHaveBeenCalledWith('exchange')
+ expect(scope.order_cycle_form.$dirty).toEqual true
+
+ it 'Adds coordinator fees', ->
+ scope.addCoordinatorFee(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addCoordinatorFee).toHaveBeenCalled()
+
+ it 'Removes coordinator fees', ->
+ scope.removeCoordinatorFee(event, 0)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeCoordinatorFee).toHaveBeenCalledWith(0)
+ expect(scope.order_cycle_form.$dirty).toEqual true
+
+ it 'Adds exchange fees', ->
+ scope.addExchangeFee(event)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.addExchangeFee).toHaveBeenCalled()
+
+ it 'Removes exchange fees', ->
+ scope.removeExchangeFee(event, 'exchange', 0)
+ expect(event.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.removeExchangeFee).toHaveBeenCalledWith('exchange', 0)
+ expect(scope.order_cycle_form.$dirty).toEqual true
+
+ it 'Removes distribution of a variant', ->
+ scope.removeDistributionOfVariant('variant')
+ expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('variant')
+
+ it 'Submits the order cycle via OrderCycle update', ->
+ eventMock = {preventDefault: jasmine.createSpy()}
+ scope.submit(eventMock,'/admin/order_cycles')
+ expect(eventMock.preventDefault).toHaveBeenCalled()
+ expect(OrderCycle.update).toHaveBeenCalledWith('/admin/order_cycles', scope.order_cycle_form)
diff --git a/spec/javascripts/unit/admin/order_cycles/services/enterprise_fee_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/services/enterprise_fee_spec.js.coffee
new file mode 100644
index 0000000000..8e31008aab
--- /dev/null
+++ b/spec/javascripts/unit/admin/order_cycles/services/enterprise_fee_spec.js.coffee
@@ -0,0 +1,37 @@
+describe 'EnterpriseFee service', ->
+ $httpBackend = null
+ EnterpriseFee = null
+
+ beforeEach ->
+ module 'admin.orderCycles'
+ inject ($injector, _$httpBackend_)->
+ EnterpriseFee = $injector.get('EnterpriseFee')
+ $httpBackend = _$httpBackend_
+ $httpBackend.whenGET('/admin/enterprise_fees/for_order_cycle.json').respond [
+ {id: 1, name: "Yayfee", enterprise_id: 1}
+ {id: 2, name: "FeeTwo", enterprise_id: 2}
+ ]
+
+ it 'loads enterprise fees', ->
+ enterprise_fees = EnterpriseFee.index()
+ $httpBackend.flush()
+ expected_fees = [
+ new EnterpriseFee.EnterpriseFee({id: 1, name: "Yayfee", enterprise_id: 1})
+ new EnterpriseFee.EnterpriseFee({id: 2, name: "FeeTwo", enterprise_id: 2})
+ ]
+ for fee, i in enterprise_fees
+ expect(fee.id).toEqual(expected_fees[i].id)
+
+ it 'reports its loadedness', ->
+ expect(EnterpriseFee.loaded).toBe(false)
+ EnterpriseFee.index()
+ $httpBackend.flush()
+ expect(EnterpriseFee.loaded).toBe(true)
+
+ it 'returns enterprise fees for an enterprise', ->
+ all_enterprise_fees = EnterpriseFee.index()
+ $httpBackend.flush()
+ enterprise_fees = EnterpriseFee.forEnterprise(1)
+ expect(enterprise_fees).toEqual [
+ new EnterpriseFee.EnterpriseFee({id: 1, name: "Yayfee", enterprise_id: 1})
+ ]
diff --git a/spec/javascripts/unit/admin/order_cycles/services/enterprise_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/services/enterprise_spec.js.coffee
new file mode 100644
index 0000000000..b3a7d122de
--- /dev/null
+++ b/spec/javascripts/unit/admin/order_cycles/services/enterprise_spec.js.coffee
@@ -0,0 +1,75 @@
+describe 'Enterprise service', ->
+ $httpBackend = null
+ Enterprise = null
+
+ beforeEach ->
+ module 'admin.orderCycles'
+ inject ($injector, _$httpBackend_)->
+ Enterprise = $injector.get('Enterprise')
+ $httpBackend = _$httpBackend_
+ $httpBackend.whenGET('/admin/enterprises/for_order_cycle.json').respond [
+ {id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true}
+ {id: 2, name: 'Two', supplied_products: [3, 4]}
+ {id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'}
+ ]
+
+ it 'loads enterprises as a hash', ->
+ enterprises = Enterprise.index()
+ $httpBackend.flush()
+ expect(enterprises).toEqual
+ 1: new Enterprise.Enterprise({id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true})
+ 2: new Enterprise.Enterprise({id: 2, name: 'Two', supplied_products: [3, 4]})
+ 3: new Enterprise.Enterprise({id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'})
+
+ it 'reports its loadedness', ->
+ expect(Enterprise.loaded).toBe(false)
+ Enterprise.index()
+ $httpBackend.flush()
+ expect(Enterprise.loaded).toBe(true)
+
+ it 'loads producers as an array', ->
+ Enterprise.index()
+ $httpBackend.flush()
+ expect(Enterprise.producer_enterprises).toEqual [new Enterprise.Enterprise({id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true})]
+
+ it 'loads hubs as an array', ->
+ Enterprise.index()
+ $httpBackend.flush()
+ expect(Enterprise.hub_enterprises).toEqual [new Enterprise.Enterprise({id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'})]
+
+ it 'collates all supplied products', ->
+ enterprises = Enterprise.index()
+ $httpBackend.flush()
+ expect(Enterprise.supplied_products).toEqual [1, 2, 3, 4, 5, 6]
+
+ it "finds supplied variants for an enterprise", ->
+ spyOn(Enterprise, 'variantsOf').and.returnValue(10)
+ Enterprise.index()
+ $httpBackend.flush()
+ expect(Enterprise.suppliedVariants(1)).toEqual [10, 10]
+
+ describe "finding the variants of a product", ->
+ it "returns the master for products without variants", ->
+ p =
+ master_id: 1
+ variants: []
+ expect(Enterprise.variantsOf(p)).toEqual [1]
+
+ it "returns the variant ids for products with variants", ->
+ p =
+ master_id: 1
+ variants: [{id: 2}, {id: 3}]
+ expect(Enterprise.variantsOf(p)).toEqual [2, 3]
+
+ it 'counts total variants supplied by an enterprise', ->
+ enterprise =
+ supplied_products: [
+ {variants: []},
+ {variants: []},
+ {variants: [{}, {}, {}]}
+ ]
+
+ expect(Enterprise.totalVariants(enterprise)).toEqual(5)
+
+ it 'returns zero when enterprise is null', ->
+ expect(Enterprise.totalVariants(null)).toEqual(0)
diff --git a/spec/javascripts/unit/admin/order_cycles/services/order_cycle_spec.js.coffee b/spec/javascripts/unit/admin/order_cycles/services/order_cycle_spec.js.coffee
new file mode 100644
index 0000000000..18f07406d8
--- /dev/null
+++ b/spec/javascripts/unit/admin/order_cycles/services/order_cycle_spec.js.coffee
@@ -0,0 +1,520 @@
+describe 'OrderCycle service', ->
+ OrderCycle = null
+ $httpBackend = null
+ $window = null
+
+ beforeEach ->
+ $window = {navigator: {userAgent: 'foo'}}
+
+ module 'admin.orderCycles', ($provide)->
+ $provide.value('$window', $window)
+ null
+
+ inject ($injector, _$httpBackend_)->
+ OrderCycle = $injector.get('OrderCycle')
+ $httpBackend = _$httpBackend_
+ $httpBackend.whenGET('/admin/order_cycles/123.json').respond
+ id: 123
+ name: 'Test Order Cycle'
+ coordinator_id: 456
+ coordinator_fees: []
+ exchanges: [
+ {sender_id: 1, receiver_id: 456, incoming: true}
+ {sender_id: 456, receiver_id: 2, incoming: false}
+ ]
+ $httpBackend.whenGET('/admin/order_cycles/new.json').respond
+ id: 123
+ name: 'New Order Cycle'
+ coordinator_id: 456
+ coordinator_fees: []
+ exchanges: []
+
+ it 'initialises order cycle', ->
+ expect(OrderCycle.order_cycle).toEqual {incoming_exchanges: [], outgoing_exchanges: []}
+
+ it 'counts selected variants in an exchange', ->
+ result = OrderCycle.exchangeSelectedVariants({variants: {1: true, 2: false, 3: true}})
+ expect(result).toEqual(2)
+
+ describe "fetching exchange ids", ->
+ it "gets enterprise ids as ints", ->
+ OrderCycle.order_cycle.incoming_exchanges = [
+ {enterprise_id: 1}
+ {enterprise_id: '2'}
+ ]
+ OrderCycle.order_cycle.outgoing_exchanges = [
+ {enterprise_id: 3}
+ {enterprise_id: '4'}
+ ]
+ expect(OrderCycle.exchangeIds('incoming')).toEqual [1, 2]
+
+ describe "checking for novel enterprises", ->
+ e1 = {id: 1}
+ e2 = {id: 2}
+
+ beforeEach ->
+ OrderCycle.order_cycle.incoming_exchanges = [{enterprise_id: 1}]
+ OrderCycle.order_cycle.outgoing_exchanges = [{enterprise_id: 1}]
+
+ it "detects novel suppliers", ->
+ expect(OrderCycle.novelSupplier(e1)).toBe false
+ expect(OrderCycle.novelSupplier(e2)).toBe true
+
+ it "detects novel suppliers with enterprise as string id", ->
+ expect(OrderCycle.novelSupplier('1')).toBe false
+ expect(OrderCycle.novelSupplier('2')).toBe true
+
+ it "detects novel distributors", ->
+ expect(OrderCycle.novelDistributor(e1)).toBe false
+ expect(OrderCycle.novelDistributor(e2)).toBe true
+
+ it "detects novel distributors with enterprise as string id", ->
+ expect(OrderCycle.novelDistributor('1')).toBe false
+ expect(OrderCycle.novelDistributor('2')).toBe true
+
+
+ describe 'fetching the direction for an exchange', ->
+ it 'returns "incoming" for incoming exchanges', ->
+ exchange = {id: 1}
+ OrderCycle.order_cycle.incoming_exchanges = [exchange]
+ OrderCycle.order_cycle.outgoing_exchanges = []
+ expect(OrderCycle.exchangeDirection(exchange)).toEqual 'incoming'
+
+ it 'returns "outgoing" for outgoing exchanges', ->
+ exchange = {id: 1}
+ OrderCycle.order_cycle.incoming_exchanges = []
+ OrderCycle.order_cycle.outgoing_exchanges = [exchange]
+ expect(OrderCycle.exchangeDirection(exchange)).toEqual 'outgoing'
+
+ describe "setting exchange variants", ->
+ describe "when I have permissions to edit the variants", ->
+ beforeEach ->
+ OrderCycle.order_cycle["editable_variants_for_outgoing_exchanges"] = { 1: [1, 2, 3] }
+
+ it "sets all variants to the provided value", ->
+ exchange = { enterprise_id: 1, incoming: false, variants: {2: false}}
+ OrderCycle.setExchangeVariants(exchange, [1, 2, 3], true)
+ expect(exchange.variants).toEqual {1: true, 2: true, 3: true}
+
+ describe "when I don't have permissions to edit the variants", ->
+ beforeEach ->
+ OrderCycle.order_cycle["editable_variants_for_outgoing_exchanges"] = { 1: [] }
+
+ it "does not change variants to the provided value", ->
+ exchange = { enterprise_id: 1, incoming: false, variants: {2: false}}
+ OrderCycle.setExchangeVariants(exchange, [1, 2, 3], true)
+ expect(exchange.variants).toEqual {2: false}
+
+ describe 'adding suppliers', ->
+ exchange = null
+
+ beforeEach ->
+ # Initialise OC
+ OrderCycle.new()
+ $httpBackend.flush()
+
+ it 'adds the supplier to incoming exchanges', ->
+ OrderCycle.addSupplier('123')
+ expect(OrderCycle.order_cycle.incoming_exchanges).toEqual [
+ {enterprise_id: '123', incoming: true, active: true, variants: {}, enterprise_fees: []}
+ ]
+
+ describe 'adding distributors', ->
+ exchange = null
+
+ beforeEach ->
+ # Initialise OC
+ OrderCycle.new()
+ $httpBackend.flush()
+
+ it 'adds the distributor to outgoing exchanges', ->
+ OrderCycle.addDistributor('123')
+ expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
+ {enterprise_id: '123', incoming: false, active: true, variants: {}, enterprise_fees: []}
+ ]
+
+ describe 'removing exchanges', ->
+ exchange = null
+
+ beforeEach ->
+ spyOn(OrderCycle, 'removeDistributionOfVariant')
+ exchange =
+ enterprise_id: '123'
+ active: true
+ incoming: false
+ variants: {1: true, 2: false, 3: true}
+ enterprise_fees: []
+
+ describe "removing incoming exchanges", ->
+ beforeEach ->
+ exchange.incoming = true
+ OrderCycle.order_cycle.incoming_exchanges = [exchange]
+
+ it 'removes the exchange', ->
+ OrderCycle.removeExchange(exchange)
+ expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
+
+ it 'removes distribution of all exchange variants', ->
+ OrderCycle.removeExchange(exchange)
+ expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('1')
+ expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalledWith('2')
+ expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('3')
+
+ describe "removing outgoing exchanges", ->
+ beforeEach ->
+ exchange.incoming = false
+ OrderCycle.order_cycle.outgoing_exchanges = [exchange]
+
+ it 'removes the exchange', ->
+ OrderCycle.removeExchange(exchange)
+ expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
+
+ it "does not remove distribution of any variants", ->
+ OrderCycle.removeExchange(exchange)
+ expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalled()
+
+ it 'adds coordinator fees', ->
+ # Initialise OC
+ OrderCycle.new()
+ $httpBackend.flush()
+ OrderCycle.addCoordinatorFee()
+ expect(OrderCycle.order_cycle.coordinator_fees).toEqual [{}]
+
+ describe 'removing coordinator fees', ->
+ it 'removes a coordinator fee by index', ->
+ OrderCycle.order_cycle.coordinator_fees = [
+ {id: 1}
+ {id: 2}
+ {id: 3}
+ ]
+ OrderCycle.removeCoordinatorFee(1)
+ expect(OrderCycle.order_cycle.coordinator_fees).toEqual [
+ {id: 1}
+ {id: 3}
+ ]
+
+ it 'adds exchange fees', ->
+ exchange = {enterprise_fees: []}
+ OrderCycle.addExchangeFee(exchange)
+ expect(exchange.enterprise_fees).toEqual [{}]
+
+ describe 'removing exchange fees', ->
+ it 'removes an exchange fee by index', ->
+ exchange =
+ enterprise_fees: [
+ {id: 1}
+ {id: 2}
+ {id: 3}
+ ]
+ OrderCycle.removeExchangeFee(exchange, 1)
+ expect(exchange.enterprise_fees).toEqual [
+ {id: 1}
+ {id: 3}
+ ]
+
+ it 'finds participating enterprise ids', ->
+ OrderCycle.order_cycle.incoming_exchanges = [
+ {enterprise_id: 1}
+ {enterprise_id: 2}
+ ]
+ OrderCycle.order_cycle.outgoing_exchanges = [
+ {enterprise_id: 2}
+ {enterprise_id: 3}
+ ]
+ expect(OrderCycle.participatingEnterpriseIds()).toEqual [1, 2, 3]
+
+ describe 'fetching all variants supplied on incoming exchanges', ->
+ it 'collects variants from incoming exchanges', ->
+ OrderCycle.order_cycle.incoming_exchanges = [
+ {variants: {1: true, 2: false}}
+ {variants: {3: false, 4: true}}
+ {variants: {5: true, 6: false}}
+ ]
+ expect(OrderCycle.incomingExchangesVariants()).toEqual [1, 4, 5]
+
+ describe 'checking whether a product is supplied to the order cycle', ->
+ product_master_present = product_variant_present = product_master_absent = product_variant_absent = null
+
+ beforeEach ->
+ product_master_present =
+ name: "Linseed (500g)"
+ master_id: 1
+ variants: []
+ product_variant_present =
+ name: "Linseed (500g)"
+ master_id: 2
+ variants: [{id: 3}, {id: 4}]
+ product_master_absent =
+ name: "Linseed (500g)"
+ master_id: 5
+ variants: []
+ product_variant_absent =
+ name: "Linseed (500g)"
+ master_id: 6
+ variants: [{id: 7}, {id: 8}]
+
+ spyOn(OrderCycle, 'incomingExchangesVariants').and.returnValue([1, 3])
+
+ it 'returns true for products whose master is supplied', ->
+ expect(OrderCycle.productSuppliedToOrderCycle(product_master_present)).toBeTruthy()
+
+ it 'returns true for products for whom a variant is supplied', ->
+ expect(OrderCycle.productSuppliedToOrderCycle(product_variant_present)).toBeTruthy()
+
+ it 'returns false for products whose master is not supplied', ->
+ expect(OrderCycle.productSuppliedToOrderCycle(product_master_absent)).toBeFalsy()
+
+ it 'returns false for products whose variants are not supplied', ->
+ expect(OrderCycle.productSuppliedToOrderCycle(product_variant_absent)).toBeFalsy()
+
+
+ describe 'checking whether a variant is supplied to the order cycle', ->
+ beforeEach ->
+ spyOn(OrderCycle, 'incomingExchangesVariants').and.returnValue([1, 3])
+
+ it 'returns true for variants that are supplied', ->
+ expect(OrderCycle.variantSuppliedToOrderCycle({id: 1})).toBeTruthy()
+
+ it 'returns false for variants that are not supplied', ->
+ expect(OrderCycle.variantSuppliedToOrderCycle({id: 999})).toBeFalsy()
+
+
+ describe 'remove all distribution of a variant', ->
+ it 'removes the variant from every outgoing exchange', ->
+ OrderCycle.order_cycle.outgoing_exchanges = [
+ {variants: {123: true, 234: true}}
+ {variants: {123: true, 333: true}}
+ ]
+ OrderCycle.removeDistributionOfVariant('123')
+ expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
+ {variants: {123: false, 234: true}}
+ {variants: {123: false, 333: true}}
+ ]
+
+ describe 'loading an order cycle, reporting loadedness', ->
+ it 'reports its loadedness', ->
+ expect(OrderCycle.loaded).toBe(false)
+ OrderCycle.load('123')
+ $httpBackend.flush()
+ expect(OrderCycle.loaded).toBe(true)
+
+ describe 'loading a new order cycle', ->
+ beforeEach ->
+ OrderCycle.new()
+ $httpBackend.flush()
+
+
+ it 'loads basic fields', ->
+ expect(OrderCycle.order_cycle.id).toEqual(123)
+ expect(OrderCycle.order_cycle.name).toEqual('New Order Cycle')
+ expect(OrderCycle.order_cycle.coordinator_id).toEqual(456)
+
+ it 'initialises the incoming and outgoing exchanges', ->
+ expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
+ expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
+
+ it 'removes the original exchanges array', ->
+ expect(OrderCycle.order_cycle.exchanges).toBeUndefined()
+
+ describe 'loading an existing order cycle', ->
+ beforeEach ->
+ OrderCycle.load('123')
+ $httpBackend.flush()
+
+ it 'loads basic fields', ->
+ expect(OrderCycle.order_cycle.id).toEqual(123)
+ expect(OrderCycle.order_cycle.name).toEqual('Test Order Cycle')
+ expect(OrderCycle.order_cycle.coordinator_id).toEqual(456)
+
+ it 'splits exchanges into incoming and outgoing', ->
+ expect(OrderCycle.order_cycle.incoming_exchanges).toEqual [
+ sender_id: 1
+ enterprise_id: 1
+ incoming: true
+ active: true
+ ]
+
+ expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
+ receiver_id: 2
+ enterprise_id: 2
+ incoming: false
+ active: true
+ ]
+
+ it 'removes the original exchanges array', ->
+ expect(OrderCycle.order_cycle.exchanges).toBeUndefined()
+
+ describe 'creating an order cycle', ->
+ beforeEach ->
+ spyOn(OrderCycle, 'confirmNoDistributors').and.returnValue true
+
+ it 'redirects to the destination page on success', ->
+ OrderCycle.order_cycle = 'this is the order cycle'
+ spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
+ $httpBackend.expectPOST('/admin/order_cycles.json', {
+ order_cycle: 'this is the submit data'
+ }).respond {success: true}
+
+ OrderCycle.create('/destination/page')
+ $httpBackend.flush()
+ expect($window.location).toEqual('/destination/page')
+
+ it 'does not redirect on error', ->
+ OrderCycle.order_cycle = 'this is the order cycle'
+ spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
+ $httpBackend.expectPOST('/admin/order_cycles.json', {
+ order_cycle: 'this is the submit data'
+ }).respond 400, { errors: [] }
+
+ OrderCycle.create('/destination/page')
+ $httpBackend.flush()
+ expect($window.location).toEqual(undefined)
+
+ describe 'updating an order cycle', ->
+ beforeEach ->
+ spyOn(OrderCycle, 'confirmNoDistributors').and.returnValue true
+
+ it 'redirects to the destination page on success', ->
+ form = jasmine.createSpyObj('order_cycle_form', ['$dirty', '$setPristine'])
+ OrderCycle.order_cycle = 'this is the order cycle'
+ spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
+ $httpBackend.expectPUT('/admin/order_cycles.json?reloading=1', {
+ order_cycle: 'this is the submit data'
+ }).respond {success: true}
+
+ OrderCycle.update('/destination/page', form)
+ $httpBackend.flush()
+ expect($window.location).toEqual('/destination/page')
+ expect(form.$setPristine.calls.count()).toBe 1
+
+ it 'does not redirect on error', ->
+ OrderCycle.order_cycle = 'this is the order cycle'
+ spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
+ $httpBackend.expectPUT('/admin/order_cycles.json?reloading=1', {
+ order_cycle: 'this is the submit data'
+ }).respond 400, { errors: [] }
+
+ OrderCycle.update('/destination/page')
+ $httpBackend.flush()
+ expect($window.location).toEqual(undefined)
+
+ describe 'preparing data for form submission', ->
+ it 'calls all the methods', ->
+ OrderCycle.order_cycle = {foo: 'bar'}
+ spyOn(OrderCycle, 'removeInactiveExchanges')
+ spyOn(OrderCycle, 'translateCoordinatorFees')
+ spyOn(OrderCycle, 'translateExchangeFees')
+ OrderCycle.dataForSubmit()
+ expect(OrderCycle.removeInactiveExchanges).toHaveBeenCalled()
+ expect(OrderCycle.translateCoordinatorFees).toHaveBeenCalled()
+ expect(OrderCycle.translateExchangeFees).toHaveBeenCalled()
+
+ it 'removes inactive exchanges', ->
+ data =
+ incoming_exchanges: [
+ {enterprise_id: "1", active: false}
+ {enterprise_id: "2", active: true}
+ {enterprise_id: "3", active: false}
+ ]
+ outgoing_exchanges: [
+ {enterprise_id: "4", active: true}
+ {enterprise_id: "5", active: false}
+ {enterprise_id: "6", active: true}
+ ]
+
+ data = OrderCycle.removeInactiveExchanges(data)
+
+ expect(data.incoming_exchanges).toEqual [
+ {enterprise_id: "2", active: true}
+ ]
+ expect(data.outgoing_exchanges).toEqual [
+ {enterprise_id: "4", active: true}
+ {enterprise_id: "6", active: true}
+ ]
+
+ it 'converts coordinator fees into a list of ids', ->
+ order_cycle =
+ coordinator_fees: [
+ {id: 1}
+ {id: 2}
+ ]
+
+ data = OrderCycle.translateCoordinatorFees(order_cycle)
+
+ expect(data.coordinator_fees).toBeUndefined()
+ expect(data.coordinator_fee_ids).toEqual [1, 2]
+
+ it "preserves original data when converting coordinator fees", ->
+ OrderCycle.order_cycle =
+ coordinator_fees: [
+ {id: 1}
+ {id: 2}
+ ]
+
+ data = OrderCycle.deepCopy()
+ data = OrderCycle.translateCoordinatorFees(data)
+
+ expect(OrderCycle.order_cycle.coordinator_fees).toEqual [{id: 1}, {id: 2}]
+ expect(OrderCycle.order_cycle.coordinator_fee_ids).toBeUndefined()
+
+ describe "converting exchange fees into a list of ids", ->
+ order_cycle = null
+ data = null
+
+ beforeEach ->
+ order_cycle =
+ incoming_exchanges: [
+ enterprise_fees: [
+ {id: 1}
+ {id: 2}
+ ]
+ ]
+ outgoing_exchanges: [
+ enterprise_fees: [
+ {id: 3}
+ {id: 4}
+ ]
+ ]
+ OrderCycle.order_cycle = order_cycle
+
+ data = OrderCycle.deepCopy()
+ data = OrderCycle.translateExchangeFees(data)
+
+ it 'converts exchange fees into a list of ids', ->
+ expect(data.incoming_exchanges[0].enterprise_fees).toBeUndefined()
+ expect(data.outgoing_exchanges[0].enterprise_fees).toBeUndefined()
+ expect(data.incoming_exchanges[0].enterprise_fee_ids).toEqual [1, 2]
+ expect(data.outgoing_exchanges[0].enterprise_fee_ids).toEqual [3, 4]
+
+ it "preserves original data when converting exchange fees", ->
+ expect(order_cycle.incoming_exchanges[0].enterprise_fees).toEqual [{id: 1}, {id: 2}]
+ expect(order_cycle.outgoing_exchanges[0].enterprise_fees).toEqual [{id: 3}, {id: 4}]
+ expect(order_cycle.incoming_exchanges[0].enterprise_fee_ids).toBeUndefined()
+ expect(order_cycle.outgoing_exchanges[0].enterprise_fee_ids).toBeUndefined()
+
+ describe "confirming when there are no distributors", ->
+ order_cycle_with_exchanges = order_cycle_without_exchanges = null
+
+ beforeEach ->
+ order_cycle_with_exchanges =
+ outgoing_exchanges: [{}]
+ order_cycle_without_exchanges =
+ outgoing_exchanges: []
+
+ it "returns true when there are distributors", ->
+ spyOn(window, 'confirm')
+ OrderCycle.order_cycle = order_cycle_with_exchanges
+ expect(OrderCycle.confirmNoDistributors()).toBe true
+ expect(window.confirm).not.toHaveBeenCalled()
+
+ it "returns true when there are no distributors but the user confirms", ->
+ spyOn(window, 'confirm').and.returnValue(true)
+ OrderCycle.order_cycle = order_cycle_without_exchanges
+ expect(OrderCycle.confirmNoDistributors()).toBe true
+ expect(window.confirm).toHaveBeenCalled()
+
+ it "returns false when there are no distributors and the user does not confirm", ->
+ spyOn(window, 'confirm').and.returnValue(false)
+ OrderCycle.order_cycle = order_cycle_without_exchanges
+ expect(OrderCycle.confirmNoDistributors()).toBe false
+ expect(window.confirm).toHaveBeenCalled()
diff --git a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee
index 131880ddc7..f8d124c110 100644
--- a/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee
+++ b/spec/javascripts/unit/darkswarm/services/cart_spec.js.coffee
@@ -145,11 +145,11 @@ describe 'Cart service', ->
expect(li.max_quantity).toEqual 0
it "resets the count on hand available", ->
- li = {variant: {id: 1, count_on_hand: 10}, quantity: 5}
+ li = {variant: {id: 1, on_hand: 10}, quantity: 5}
Cart.line_items = [li]
stockLevels = {1: {quantity: 0, max_quantity: 0, on_hand: 0}}
Cart.compareAndNotifyStockLevels stockLevels
- expect(li.variant.count_on_hand).toEqual 0
+ expect(li.variant.on_hand).toEqual 0
describe "when the quantity available is less than that requested", ->
it "reduces the quantity in the cart", ->
@@ -172,7 +172,7 @@ describe 'Cart service', ->
Cart.line_items = [li]
stockLevels = {1: {quantity: 5, on_hand: 6}}
Cart.compareAndNotifyStockLevels stockLevels
- expect(li.variant.count_on_hand).toEqual 6
+ expect(li.variant.on_hand).toEqual 6
describe "when the client-side quantity has been increased during the request", ->
it "does not reset the quantity", ->
diff --git a/spec/javascripts/unit/order_cycle_spec.js.coffee b/spec/javascripts/unit/order_cycle_spec.js.coffee
deleted file mode 100644
index 6c6f3440e6..0000000000
--- a/spec/javascripts/unit/order_cycle_spec.js.coffee
+++ /dev/null
@@ -1,968 +0,0 @@
-describe 'OrderCycle controllers', ->
-
- describe 'AdminCreateOrderCycleCtrl', ->
- ctrl = null
- scope = null
- event = null
- OrderCycle = null
- Enterprise = null
- EnterpriseFee = null
-
- beforeEach ->
- scope =
- order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty'])
- $watch: jasmine.createSpy('$watch')
- event =
- preventDefault: jasmine.createSpy('preventDefault')
- OrderCycle =
- exchangeSelectedVariants: jasmine.createSpy('exchangeSelectedVariants').and.returnValue('variants selected')
- productSuppliedToOrderCycle: jasmine.createSpy('productSuppliedToOrderCycle').and.returnValue('product supplied')
- variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').and.returnValue('variant supplied')
- exchangeDirection: jasmine.createSpy('exchangeDirection').and.returnValue('exchange direction')
- toggleProducts: jasmine.createSpy('toggleProducts')
- setExchangeVariants: jasmine.createSpy('setExchangeVariants')
- addSupplier: jasmine.createSpy('addSupplier')
- addDistributor: jasmine.createSpy('addDistributor')
- removeExchange: jasmine.createSpy('removeExchange')
- addCoordinatorFee: jasmine.createSpy('addCoordinatorFee')
- removeCoordinatorFee: jasmine.createSpy('removeCoordinatorFee')
- addExchangeFee: jasmine.createSpy('addExchangeFee')
- removeExchangeFee: jasmine.createSpy('removeExchangeFee')
- removeDistributionOfVariant: jasmine.createSpy('removeDistributionOfVariant')
- create: jasmine.createSpy('create')
- new: jasmine.createSpy('new').and.returnValue "my order cycle"
- Enterprise =
- index: jasmine.createSpy('index').and.returnValue('enterprises list')
- supplied_products: 'supplied products'
- suppliedVariants: jasmine.createSpy('suppliedVariants').and.returnValue('supplied variants')
- totalVariants: jasmine.createSpy('totalVariants').and.returnValue('variants total')
- EnterpriseFee =
- index: jasmine.createSpy('index').and.returnValue('enterprise fees list')
- forEnterprise: jasmine.createSpy('forEnterprise').and.returnValue('enterprise fees for enterprise')
- ocInstance = {}
-
- module('admin.orderCycles')
- inject ($controller) ->
- ctrl = $controller 'AdminCreateOrderCycleCtrl', {$scope: scope, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee, ocInstance: ocInstance}
-
-
- it 'Loads enterprises and supplied products', ->
- expect(Enterprise.index).toHaveBeenCalled()
- expect(scope.enterprises).toEqual('enterprises list')
- expect(scope.supplied_products).toEqual('supplied products')
-
- it 'Loads enterprise fees', ->
- expect(EnterpriseFee.index).toHaveBeenCalled()
- expect(scope.enterprise_fees).toEqual('enterprise fees list')
-
- it 'Loads order cycles', ->
- expect(scope.order_cycle).toEqual('my order cycle')
-
- describe 'Reporting when all resources are loaded', ->
- beforeEach inject (RequestMonitor) ->
- RequestMonitor.loading = false
- Enterprise.loaded = true
- EnterpriseFee.loaded = true
- OrderCycle.loaded = true
-
- it 'returns true when all resources are loaded', ->
- expect(scope.loaded()).toBe(true)
-
- it 'returns false otherwise', ->
- EnterpriseFee.loaded = false
- expect(scope.loaded()).toBe(false)
-
- it "delegates suppliedVariants to Enterprise", ->
- expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
- expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
-
- it 'Delegates exchangeSelectedVariants to OrderCycle', ->
- expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
- expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
-
- it "delegates setExchangeVariants to OrderCycle", ->
- scope.setExchangeVariants('exchange', 'variants', 'selected')
- expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
-
- it 'Delegates enterpriseTotalVariants to Enterprise', ->
- expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
- expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
-
- it 'Delegates productSuppliedToOrderCycle to OrderCycle', ->
- expect(scope.productSuppliedToOrderCycle('product')).toEqual('product supplied')
- expect(OrderCycle.productSuppliedToOrderCycle).toHaveBeenCalledWith('product')
-
- it 'Delegates variantSuppliedToOrderCycle to OrderCycle', ->
- expect(scope.variantSuppliedToOrderCycle('variant')).toEqual('variant supplied')
- expect(OrderCycle.variantSuppliedToOrderCycle).toHaveBeenCalledWith('variant')
-
- it 'Delegates exchangeDirection to OrderCycle', ->
- expect(scope.exchangeDirection('exchange')).toEqual('exchange direction')
- expect(OrderCycle.exchangeDirection).toHaveBeenCalledWith('exchange')
-
- it 'Finds enterprises participating in the order cycle that have fees', ->
- scope.enterprises =
- 1: {id: 1, name: 'Eaterprises'}
- 2: {id: 2, name: 'Pepper Tree Place'}
- 3: {id: 3, name: 'South East'}
- OrderCycle.participatingEnterpriseIds = jasmine.createSpy('participatingEnterpriseIds').and.returnValue([2])
- EnterpriseFee.enterprise_fees = [ {enterprise_id: 2} ] # Pepper Tree Place has a fee
- expect(scope.enterprisesWithFees()).toEqual([
- {id: 2, name: 'Pepper Tree Place'}
- ])
-
- it 'Delegates enterpriseFeesForEnterprise to EnterpriseFee', ->
- scope.enterpriseFeesForEnterprise('123')
- expect(EnterpriseFee.forEnterprise).toHaveBeenCalledWith(123)
-
- it 'Adds order cycle suppliers', ->
- scope.new_supplier_id = 'new supplier id'
- scope.addSupplier(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addSupplier).toHaveBeenCalledWith('new supplier id')
-
- it 'Adds order cycle distributors', ->
- scope.new_distributor_id = 'new distributor id'
- scope.addDistributor(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addDistributor).toHaveBeenCalledWith('new distributor id')
-
- it 'Removes order cycle exchanges', ->
- scope.removeExchange(event, 'exchange')
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeExchange).toHaveBeenCalledWith('exchange')
-
- it 'Adds coordinator fees', ->
- scope.addCoordinatorFee(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addCoordinatorFee).toHaveBeenCalled()
-
- it 'Removes coordinator fees', ->
- scope.removeCoordinatorFee(event, 0)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeCoordinatorFee).toHaveBeenCalledWith(0)
-
- it 'Adds exchange fees', ->
- scope.addExchangeFee(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addExchangeFee).toHaveBeenCalled()
-
- it 'Removes exchange fees', ->
- scope.removeExchangeFee(event, 'exchange', 0)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeExchangeFee).toHaveBeenCalledWith('exchange', 0)
-
- it 'Removes distribution of a variant', ->
- scope.removeDistributionOfVariant('variant')
- expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('variant')
-
- it 'Submits the order cycle via OrderCycle create', ->
- eventMock = {preventDefault: jasmine.createSpy()}
- scope.submit(eventMock,'/admin/order_cycles')
- expect(eventMock.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.create).toHaveBeenCalledWith('/admin/order_cycles')
-
- describe 'AdminEditOrderCycleCtrl', ->
- ctrl = null
- scope = null
- event = null
- location = null
- OrderCycle = null
- Enterprise = null
- EnterpriseFee = null
-
- beforeEach ->
- scope =
- order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty', '$setPristine'])
- $watch: jasmine.createSpy('$watch')
- event =
- preventDefault: jasmine.createSpy('preventDefault')
- location =
- absUrl: ->
- 'example.com/admin/order_cycles/27/edit'
- OrderCycle =
- load: jasmine.createSpy('load')
- exchangeSelectedVariants: jasmine.createSpy('exchangeSelectedVariants').and.returnValue('variants selected')
- productSuppliedToOrderCycle: jasmine.createSpy('productSuppliedToOrderCycle').and.returnValue('product supplied')
- variantSuppliedToOrderCycle: jasmine.createSpy('variantSuppliedToOrderCycle').and.returnValue('variant supplied')
- exchangeDirection: jasmine.createSpy('exchangeDirection').and.returnValue('exchange direction')
- toggleProducts: jasmine.createSpy('toggleProducts')
- setExchangeVariants: jasmine.createSpy('setExchangeVariants')
- addSupplier: jasmine.createSpy('addSupplier')
- addDistributor: jasmine.createSpy('addDistributor')
- removeExchange: jasmine.createSpy('removeExchange')
- addCoordinatorFee: jasmine.createSpy('addCoordinatorFee')
- removeCoordinatorFee: jasmine.createSpy('removeCoordinatorFee')
- addExchangeFee: jasmine.createSpy('addExchangeFee')
- removeExchangeFee: jasmine.createSpy('removeExchangeFee')
- removeDistributionOfVariant: jasmine.createSpy('removeDistributionOfVariant')
- update: jasmine.createSpy('update')
- Enterprise =
- index: jasmine.createSpy('index').and.returnValue('enterprises list')
- supplied_products: 'supplied products'
- suppliedVariants: jasmine.createSpy('suppliedVariants').and.returnValue('supplied variants')
- totalVariants: jasmine.createSpy('totalVariants').and.returnValue('variants total')
- EnterpriseFee =
- index: jasmine.createSpy('index').and.returnValue('enterprise fees list')
- forEnterprise: jasmine.createSpy('forEnterprise').and.returnValue('enterprise fees for enterprise')
-
- module('admin.orderCycles')
- inject ($controller) ->
- ctrl = $controller 'AdminEditOrderCycleCtrl', {$scope: scope, $location: location, OrderCycle: OrderCycle, Enterprise: Enterprise, EnterpriseFee: EnterpriseFee}
-
- it 'Loads enterprises and supplied products', ->
- expect(Enterprise.index).toHaveBeenCalled()
- expect(scope.enterprises).toEqual('enterprises list')
- expect(scope.supplied_products).toEqual('supplied products')
-
- it 'Loads enterprise fees', ->
- expect(EnterpriseFee.index).toHaveBeenCalled()
- expect(scope.enterprise_fees).toEqual('enterprise fees list')
-
- it 'Loads order cycles', ->
- expect(OrderCycle.load).toHaveBeenCalledWith('27')
-
- describe 'Reporting when all resources are loaded', ->
- beforeEach inject (RequestMonitor) ->
- RequestMonitor.loading = false
- Enterprise.loaded = true
- EnterpriseFee.loaded = true
- OrderCycle.loaded = true
-
- it 'returns true when all resources are loaded', ->
- expect(scope.loaded()).toBe(true)
-
- it 'returns false otherwise', ->
- EnterpriseFee.loaded = false
- expect(scope.loaded()).toBe(false)
-
- it "delegates suppliedVariants to Enterprise", ->
- expect(scope.suppliedVariants('enterprise_id')).toEqual('supplied variants')
- expect(Enterprise.suppliedVariants).toHaveBeenCalledWith('enterprise_id')
-
- it 'Delegates exchangeSelectedVariants to OrderCycle', ->
- expect(scope.exchangeSelectedVariants('exchange')).toEqual('variants selected')
- expect(OrderCycle.exchangeSelectedVariants).toHaveBeenCalledWith('exchange')
-
- it "delegates setExchangeVariants to OrderCycle", ->
- scope.setExchangeVariants('exchange', 'variants', 'selected')
- expect(OrderCycle.setExchangeVariants).toHaveBeenCalledWith('exchange', 'variants', 'selected')
-
- it 'Delegates totalVariants to Enterprise', ->
- expect(scope.enterpriseTotalVariants('enterprise')).toEqual('variants total')
- expect(Enterprise.totalVariants).toHaveBeenCalledWith('enterprise')
-
- it 'Delegates productSuppliedToOrderCycle to OrderCycle', ->
- expect(scope.productSuppliedToOrderCycle('product')).toEqual('product supplied')
- expect(OrderCycle.productSuppliedToOrderCycle).toHaveBeenCalledWith('product')
-
- it 'Delegates variantSuppliedToOrderCycle to OrderCycle', ->
- expect(scope.variantSuppliedToOrderCycle('variant')).toEqual('variant supplied')
- expect(OrderCycle.variantSuppliedToOrderCycle).toHaveBeenCalledWith('variant')
-
- it 'Delegates exchangeDirection to OrderCycle', ->
- expect(scope.exchangeDirection('exchange')).toEqual('exchange direction')
- expect(OrderCycle.exchangeDirection).toHaveBeenCalledWith('exchange')
-
- it 'Finds enterprises participating in the order cycle that have fees', ->
- scope.enterprises =
- 1: {id: 1, name: 'Eaterprises'}
- 2: {id: 2, name: 'Pepper Tree Place'}
- 3: {id: 3, name: 'South East'}
- OrderCycle.participatingEnterpriseIds = jasmine.createSpy('participatingEnterpriseIds').and.returnValue([2])
- EnterpriseFee.enterprise_fees = [ {enterprise_id: 2} ] # Pepper Tree Place has a fee
- expect(scope.enterprisesWithFees()).toEqual([
- {id: 2, name: 'Pepper Tree Place'}
- ])
-
- it 'Delegates enterpriseFeesForEnterprise to EnterpriseFee', ->
- scope.enterpriseFeesForEnterprise('123')
- expect(EnterpriseFee.forEnterprise).toHaveBeenCalledWith(123)
-
- it 'Adds order cycle suppliers', ->
- scope.new_supplier_id = 'new supplier id'
- scope.addSupplier(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addSupplier).toHaveBeenCalledWith('new supplier id')
-
- it 'Adds order cycle distributors', ->
- scope.new_distributor_id = 'new distributor id'
- scope.addDistributor(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addDistributor).toHaveBeenCalledWith('new distributor id')
-
- it 'Removes order cycle exchanges', ->
- scope.removeExchange(event, 'exchange')
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeExchange).toHaveBeenCalledWith('exchange')
- expect(scope.order_cycle_form.$dirty).toEqual true
-
- it 'Adds coordinator fees', ->
- scope.addCoordinatorFee(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addCoordinatorFee).toHaveBeenCalled()
-
- it 'Removes coordinator fees', ->
- scope.removeCoordinatorFee(event, 0)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeCoordinatorFee).toHaveBeenCalledWith(0)
- expect(scope.order_cycle_form.$dirty).toEqual true
-
- it 'Adds exchange fees', ->
- scope.addExchangeFee(event)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.addExchangeFee).toHaveBeenCalled()
-
- it 'Removes exchange fees', ->
- scope.removeExchangeFee(event, 'exchange', 0)
- expect(event.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.removeExchangeFee).toHaveBeenCalledWith('exchange', 0)
- expect(scope.order_cycle_form.$dirty).toEqual true
-
- it 'Removes distribution of a variant', ->
- scope.removeDistributionOfVariant('variant')
- expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('variant')
-
- it 'Submits the order cycle via OrderCycle update', ->
- eventMock = {preventDefault: jasmine.createSpy()}
- scope.submit(eventMock,'/admin/order_cycles')
- expect(eventMock.preventDefault).toHaveBeenCalled()
- expect(OrderCycle.update).toHaveBeenCalledWith('/admin/order_cycles', scope.order_cycle_form)
-
-
-describe 'OrderCycle services', ->
- describe 'Enterprise service', ->
- $httpBackend = null
- Enterprise = null
-
- beforeEach ->
- module 'admin.orderCycles'
- inject ($injector, _$httpBackend_)->
- Enterprise = $injector.get('Enterprise')
- $httpBackend = _$httpBackend_
- $httpBackend.whenGET('/admin/enterprises/for_order_cycle.json').respond [
- {id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true}
- {id: 2, name: 'Two', supplied_products: [3, 4]}
- {id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'}
- ]
-
- it 'loads enterprises as a hash', ->
- enterprises = Enterprise.index()
- $httpBackend.flush()
- expect(enterprises).toEqual
- 1: new Enterprise.Enterprise({id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true})
- 2: new Enterprise.Enterprise({id: 2, name: 'Two', supplied_products: [3, 4]})
- 3: new Enterprise.Enterprise({id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'})
-
- it 'reports its loadedness', ->
- expect(Enterprise.loaded).toBe(false)
- Enterprise.index()
- $httpBackend.flush()
- expect(Enterprise.loaded).toBe(true)
-
- it 'loads producers as an array', ->
- Enterprise.index()
- $httpBackend.flush()
- expect(Enterprise.producer_enterprises).toEqual [new Enterprise.Enterprise({id: 1, name: 'One', supplied_products: [1, 2], is_primary_producer: true})]
-
- it 'loads hubs as an array', ->
- Enterprise.index()
- $httpBackend.flush()
- expect(Enterprise.hub_enterprises).toEqual [new Enterprise.Enterprise({id: 3, name: 'Three', supplied_products: [5, 6], sells: 'any'})]
-
- it 'collates all supplied products', ->
- enterprises = Enterprise.index()
- $httpBackend.flush()
- expect(Enterprise.supplied_products).toEqual [1, 2, 3, 4, 5, 6]
-
- it "finds supplied variants for an enterprise", ->
- spyOn(Enterprise, 'variantsOf').and.returnValue(10)
- Enterprise.index()
- $httpBackend.flush()
- expect(Enterprise.suppliedVariants(1)).toEqual [10, 10]
-
- describe "finding the variants of a product", ->
- it "returns the master for products without variants", ->
- p =
- master_id: 1
- variants: []
- expect(Enterprise.variantsOf(p)).toEqual [1]
-
- it "returns the variant ids for products with variants", ->
- p =
- master_id: 1
- variants: [{id: 2}, {id: 3}]
- expect(Enterprise.variantsOf(p)).toEqual [2, 3]
-
- it 'counts total variants supplied by an enterprise', ->
- enterprise =
- supplied_products: [
- {variants: []},
- {variants: []},
- {variants: [{}, {}, {}]}
- ]
-
- expect(Enterprise.totalVariants(enterprise)).toEqual(5)
-
- it 'returns zero when enterprise is null', ->
- expect(Enterprise.totalVariants(null)).toEqual(0)
-
- describe 'EnterpriseFee service', ->
- $httpBackend = null
- EnterpriseFee = null
-
- beforeEach ->
- module 'admin.orderCycles'
- inject ($injector, _$httpBackend_)->
- EnterpriseFee = $injector.get('EnterpriseFee')
- $httpBackend = _$httpBackend_
- $httpBackend.whenGET('/admin/enterprise_fees/for_order_cycle.json').respond [
- {id: 1, name: "Yayfee", enterprise_id: 1}
- {id: 2, name: "FeeTwo", enterprise_id: 2}
- ]
-
- it 'loads enterprise fees', ->
- enterprise_fees = EnterpriseFee.index()
- $httpBackend.flush()
- expected_fees = [
- new EnterpriseFee.EnterpriseFee({id: 1, name: "Yayfee", enterprise_id: 1})
- new EnterpriseFee.EnterpriseFee({id: 2, name: "FeeTwo", enterprise_id: 2})
- ]
- for fee, i in enterprise_fees
- expect(fee.id).toEqual(expected_fees[i].id)
-
- it 'reports its loadedness', ->
- expect(EnterpriseFee.loaded).toBe(false)
- EnterpriseFee.index()
- $httpBackend.flush()
- expect(EnterpriseFee.loaded).toBe(true)
-
- it 'returns enterprise fees for an enterprise', ->
- all_enterprise_fees = EnterpriseFee.index()
- $httpBackend.flush()
- enterprise_fees = EnterpriseFee.forEnterprise(1)
- expect(enterprise_fees).toEqual [
- new EnterpriseFee.EnterpriseFee({id: 1, name: "Yayfee", enterprise_id: 1})
- ]
-
-
- describe 'OrderCycle service', ->
- OrderCycle = null
- $httpBackend = null
- $window = null
-
- beforeEach ->
- $window = {navigator: {userAgent: 'foo'}}
-
- module 'admin.orderCycles', ($provide)->
- $provide.value('$window', $window)
- null
-
- inject ($injector, _$httpBackend_)->
- OrderCycle = $injector.get('OrderCycle')
- $httpBackend = _$httpBackend_
- $httpBackend.whenGET('/admin/order_cycles/123.json').respond
- id: 123
- name: 'Test Order Cycle'
- coordinator_id: 456
- coordinator_fees: []
- exchanges: [
- {sender_id: 1, receiver_id: 456, incoming: true}
- {sender_id: 456, receiver_id: 2, incoming: false}
- ]
- $httpBackend.whenGET('/admin/order_cycles/new.json').respond
- id: 123
- name: 'New Order Cycle'
- coordinator_id: 456
- coordinator_fees: []
- exchanges: []
-
- it 'initialises order cycle', ->
- expect(OrderCycle.order_cycle).toEqual {incoming_exchanges: [], outgoing_exchanges: []}
-
- it 'counts selected variants in an exchange', ->
- result = OrderCycle.exchangeSelectedVariants({variants: {1: true, 2: false, 3: true}})
- expect(result).toEqual(2)
-
- describe "fetching exchange ids", ->
- it "gets enterprise ids as ints", ->
- OrderCycle.order_cycle.incoming_exchanges = [
- {enterprise_id: 1}
- {enterprise_id: '2'}
- ]
- OrderCycle.order_cycle.outgoing_exchanges = [
- {enterprise_id: 3}
- {enterprise_id: '4'}
- ]
- expect(OrderCycle.exchangeIds('incoming')).toEqual [1, 2]
-
- describe "checking for novel enterprises", ->
- e1 = {id: 1}
- e2 = {id: 2}
-
- beforeEach ->
- OrderCycle.order_cycle.incoming_exchanges = [{enterprise_id: 1}]
- OrderCycle.order_cycle.outgoing_exchanges = [{enterprise_id: 1}]
-
- it "detects novel suppliers", ->
- expect(OrderCycle.novelSupplier(e1)).toBe false
- expect(OrderCycle.novelSupplier(e2)).toBe true
-
- it "detects novel suppliers with enterprise as string id", ->
- expect(OrderCycle.novelSupplier('1')).toBe false
- expect(OrderCycle.novelSupplier('2')).toBe true
-
- it "detects novel distributors", ->
- expect(OrderCycle.novelDistributor(e1)).toBe false
- expect(OrderCycle.novelDistributor(e2)).toBe true
-
- it "detects novel distributors with enterprise as string id", ->
- expect(OrderCycle.novelDistributor('1')).toBe false
- expect(OrderCycle.novelDistributor('2')).toBe true
-
-
- describe 'fetching the direction for an exchange', ->
- it 'returns "incoming" for incoming exchanges', ->
- exchange = {id: 1}
- OrderCycle.order_cycle.incoming_exchanges = [exchange]
- OrderCycle.order_cycle.outgoing_exchanges = []
- expect(OrderCycle.exchangeDirection(exchange)).toEqual 'incoming'
-
- it 'returns "outgoing" for outgoing exchanges', ->
- exchange = {id: 1}
- OrderCycle.order_cycle.incoming_exchanges = []
- OrderCycle.order_cycle.outgoing_exchanges = [exchange]
- expect(OrderCycle.exchangeDirection(exchange)).toEqual 'outgoing'
-
- describe "setting exchange variants", ->
- describe "when I have permissions to edit the variants", ->
- beforeEach ->
- OrderCycle.order_cycle["editable_variants_for_outgoing_exchanges"] = { 1: [1, 2, 3] }
-
- it "sets all variants to the provided value", ->
- exchange = { enterprise_id: 1, incoming: false, variants: {2: false}}
- OrderCycle.setExchangeVariants(exchange, [1, 2, 3], true)
- expect(exchange.variants).toEqual {1: true, 2: true, 3: true}
-
- describe "when I don't have permissions to edit the variants", ->
- beforeEach ->
- OrderCycle.order_cycle["editable_variants_for_outgoing_exchanges"] = { 1: [] }
-
- it "does not change variants to the provided value", ->
- exchange = { enterprise_id: 1, incoming: false, variants: {2: false}}
- OrderCycle.setExchangeVariants(exchange, [1, 2, 3], true)
- expect(exchange.variants).toEqual {2: false}
-
- describe 'adding suppliers', ->
- exchange = null
-
- beforeEach ->
- # Initialise OC
- OrderCycle.new()
- $httpBackend.flush()
-
- it 'adds the supplier to incoming exchanges', ->
- OrderCycle.addSupplier('123')
- expect(OrderCycle.order_cycle.incoming_exchanges).toEqual [
- {enterprise_id: '123', incoming: true, active: true, variants: {}, enterprise_fees: []}
- ]
-
- describe 'adding distributors', ->
- exchange = null
-
- beforeEach ->
- # Initialise OC
- OrderCycle.new()
- $httpBackend.flush()
-
- it 'adds the distributor to outgoing exchanges', ->
- OrderCycle.addDistributor('123')
- expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
- {enterprise_id: '123', incoming: false, active: true, variants: {}, enterprise_fees: []}
- ]
-
- describe 'removing exchanges', ->
- exchange = null
-
- beforeEach ->
- spyOn(OrderCycle, 'removeDistributionOfVariant')
- exchange =
- enterprise_id: '123'
- active: true
- incoming: false
- variants: {1: true, 2: false, 3: true}
- enterprise_fees: []
-
- describe "removing incoming exchanges", ->
- beforeEach ->
- exchange.incoming = true
- OrderCycle.order_cycle.incoming_exchanges = [exchange]
-
- it 'removes the exchange', ->
- OrderCycle.removeExchange(exchange)
- expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
-
- it 'removes distribution of all exchange variants', ->
- OrderCycle.removeExchange(exchange)
- expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('1')
- expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalledWith('2')
- expect(OrderCycle.removeDistributionOfVariant).toHaveBeenCalledWith('3')
-
- describe "removing outgoing exchanges", ->
- beforeEach ->
- exchange.incoming = false
- OrderCycle.order_cycle.outgoing_exchanges = [exchange]
-
- it 'removes the exchange', ->
- OrderCycle.removeExchange(exchange)
- expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
-
- it "does not remove distribution of any variants", ->
- OrderCycle.removeExchange(exchange)
- expect(OrderCycle.removeDistributionOfVariant).not.toHaveBeenCalled()
-
- it 'adds coordinator fees', ->
- # Initialise OC
- OrderCycle.new()
- $httpBackend.flush()
- OrderCycle.addCoordinatorFee()
- expect(OrderCycle.order_cycle.coordinator_fees).toEqual [{}]
-
- describe 'removing coordinator fees', ->
- it 'removes a coordinator fee by index', ->
- OrderCycle.order_cycle.coordinator_fees = [
- {id: 1}
- {id: 2}
- {id: 3}
- ]
- OrderCycle.removeCoordinatorFee(1)
- expect(OrderCycle.order_cycle.coordinator_fees).toEqual [
- {id: 1}
- {id: 3}
- ]
-
- it 'adds exchange fees', ->
- exchange = {enterprise_fees: []}
- OrderCycle.addExchangeFee(exchange)
- expect(exchange.enterprise_fees).toEqual [{}]
-
- describe 'removing exchange fees', ->
- it 'removes an exchange fee by index', ->
- exchange =
- enterprise_fees: [
- {id: 1}
- {id: 2}
- {id: 3}
- ]
- OrderCycle.removeExchangeFee(exchange, 1)
- expect(exchange.enterprise_fees).toEqual [
- {id: 1}
- {id: 3}
- ]
-
- it 'finds participating enterprise ids', ->
- OrderCycle.order_cycle.incoming_exchanges = [
- {enterprise_id: 1}
- {enterprise_id: 2}
- ]
- OrderCycle.order_cycle.outgoing_exchanges = [
- {enterprise_id: 2}
- {enterprise_id: 3}
- ]
- expect(OrderCycle.participatingEnterpriseIds()).toEqual [1, 2, 3]
-
- describe 'fetching all variants supplied on incoming exchanges', ->
- it 'collects variants from incoming exchanges', ->
- OrderCycle.order_cycle.incoming_exchanges = [
- {variants: {1: true, 2: false}}
- {variants: {3: false, 4: true}}
- {variants: {5: true, 6: false}}
- ]
- expect(OrderCycle.incomingExchangesVariants()).toEqual [1, 4, 5]
-
- describe 'checking whether a product is supplied to the order cycle', ->
- product_master_present = product_variant_present = product_master_absent = product_variant_absent = null
-
- beforeEach ->
- product_master_present =
- name: "Linseed (500g)"
- master_id: 1
- variants: []
- product_variant_present =
- name: "Linseed (500g)"
- master_id: 2
- variants: [{id: 3}, {id: 4}]
- product_master_absent =
- name: "Linseed (500g)"
- master_id: 5
- variants: []
- product_variant_absent =
- name: "Linseed (500g)"
- master_id: 6
- variants: [{id: 7}, {id: 8}]
-
- spyOn(OrderCycle, 'incomingExchangesVariants').and.returnValue([1, 3])
-
- it 'returns true for products whose master is supplied', ->
- expect(OrderCycle.productSuppliedToOrderCycle(product_master_present)).toBeTruthy()
-
- it 'returns true for products for whom a variant is supplied', ->
- expect(OrderCycle.productSuppliedToOrderCycle(product_variant_present)).toBeTruthy()
-
- it 'returns false for products whose master is not supplied', ->
- expect(OrderCycle.productSuppliedToOrderCycle(product_master_absent)).toBeFalsy()
-
- it 'returns false for products whose variants are not supplied', ->
- expect(OrderCycle.productSuppliedToOrderCycle(product_variant_absent)).toBeFalsy()
-
-
- describe 'checking whether a variant is supplied to the order cycle', ->
- beforeEach ->
- spyOn(OrderCycle, 'incomingExchangesVariants').and.returnValue([1, 3])
-
- it 'returns true for variants that are supplied', ->
- expect(OrderCycle.variantSuppliedToOrderCycle({id: 1})).toBeTruthy()
-
- it 'returns false for variants that are not supplied', ->
- expect(OrderCycle.variantSuppliedToOrderCycle({id: 999})).toBeFalsy()
-
-
- describe 'remove all distribution of a variant', ->
- it 'removes the variant from every outgoing exchange', ->
- OrderCycle.order_cycle.outgoing_exchanges = [
- {variants: {123: true, 234: true}}
- {variants: {123: true, 333: true}}
- ]
- OrderCycle.removeDistributionOfVariant('123')
- expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
- {variants: {123: false, 234: true}}
- {variants: {123: false, 333: true}}
- ]
-
- describe 'loading an order cycle, reporting loadedness', ->
- it 'reports its loadedness', ->
- expect(OrderCycle.loaded).toBe(false)
- OrderCycle.load('123')
- $httpBackend.flush()
- expect(OrderCycle.loaded).toBe(true)
-
- describe 'loading a new order cycle', ->
- beforeEach ->
- OrderCycle.new()
- $httpBackend.flush()
-
-
- it 'loads basic fields', ->
- expect(OrderCycle.order_cycle.id).toEqual(123)
- expect(OrderCycle.order_cycle.name).toEqual('New Order Cycle')
- expect(OrderCycle.order_cycle.coordinator_id).toEqual(456)
-
- it 'initialises the incoming and outgoing exchanges', ->
- expect(OrderCycle.order_cycle.incoming_exchanges).toEqual []
- expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual []
-
- it 'removes the original exchanges array', ->
- expect(OrderCycle.order_cycle.exchanges).toBeUndefined()
-
- describe 'loading an existing order cycle', ->
- beforeEach ->
- OrderCycle.load('123')
- $httpBackend.flush()
-
- it 'loads basic fields', ->
- expect(OrderCycle.order_cycle.id).toEqual(123)
- expect(OrderCycle.order_cycle.name).toEqual('Test Order Cycle')
- expect(OrderCycle.order_cycle.coordinator_id).toEqual(456)
-
- it 'splits exchanges into incoming and outgoing', ->
- expect(OrderCycle.order_cycle.incoming_exchanges).toEqual [
- sender_id: 1
- enterprise_id: 1
- incoming: true
- active: true
- ]
-
- expect(OrderCycle.order_cycle.outgoing_exchanges).toEqual [
- receiver_id: 2
- enterprise_id: 2
- incoming: false
- active: true
- ]
-
- it 'removes the original exchanges array', ->
- expect(OrderCycle.order_cycle.exchanges).toBeUndefined()
-
- describe 'creating an order cycle', ->
- beforeEach ->
- spyOn(OrderCycle, 'confirmNoDistributors').and.returnValue true
-
- it 'redirects to the destination page on success', ->
- OrderCycle.order_cycle = 'this is the order cycle'
- spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
- $httpBackend.expectPOST('/admin/order_cycles.json', {
- order_cycle: 'this is the submit data'
- }).respond {success: true}
-
- OrderCycle.create('/destination/page')
- $httpBackend.flush()
- expect($window.location).toEqual('/destination/page')
-
- it 'does not redirect on error', ->
- OrderCycle.order_cycle = 'this is the order cycle'
- spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
- $httpBackend.expectPOST('/admin/order_cycles.json', {
- order_cycle: 'this is the submit data'
- }).respond 400, { errors: [] }
-
- OrderCycle.create('/destination/page')
- $httpBackend.flush()
- expect($window.location).toEqual(undefined)
-
- describe 'updating an order cycle', ->
- beforeEach ->
- spyOn(OrderCycle, 'confirmNoDistributors').and.returnValue true
-
- it 'redirects to the destination page on success', ->
- form = jasmine.createSpyObj('order_cycle_form', ['$dirty', '$setPristine'])
- OrderCycle.order_cycle = 'this is the order cycle'
- spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
- $httpBackend.expectPUT('/admin/order_cycles.json?reloading=1', {
- order_cycle: 'this is the submit data'
- }).respond {success: true}
-
- OrderCycle.update('/destination/page', form)
- $httpBackend.flush()
- expect($window.location).toEqual('/destination/page')
- expect(form.$setPristine.calls.count()).toBe 1
-
- it 'does not redirect on error', ->
- OrderCycle.order_cycle = 'this is the order cycle'
- spyOn(OrderCycle, 'dataForSubmit').and.returnValue('this is the submit data')
- $httpBackend.expectPUT('/admin/order_cycles.json?reloading=1', {
- order_cycle: 'this is the submit data'
- }).respond 400, { errors: [] }
-
- OrderCycle.update('/destination/page')
- $httpBackend.flush()
- expect($window.location).toEqual(undefined)
-
- describe 'preparing data for form submission', ->
- it 'calls all the methods', ->
- OrderCycle.order_cycle = {foo: 'bar'}
- spyOn(OrderCycle, 'removeInactiveExchanges')
- spyOn(OrderCycle, 'translateCoordinatorFees')
- spyOn(OrderCycle, 'translateExchangeFees')
- OrderCycle.dataForSubmit()
- expect(OrderCycle.removeInactiveExchanges).toHaveBeenCalled()
- expect(OrderCycle.translateCoordinatorFees).toHaveBeenCalled()
- expect(OrderCycle.translateExchangeFees).toHaveBeenCalled()
-
- it 'removes inactive exchanges', ->
- data =
- incoming_exchanges: [
- {enterprise_id: "1", active: false}
- {enterprise_id: "2", active: true}
- {enterprise_id: "3", active: false}
- ]
- outgoing_exchanges: [
- {enterprise_id: "4", active: true}
- {enterprise_id: "5", active: false}
- {enterprise_id: "6", active: true}
- ]
-
- data = OrderCycle.removeInactiveExchanges(data)
-
- expect(data.incoming_exchanges).toEqual [
- {enterprise_id: "2", active: true}
- ]
- expect(data.outgoing_exchanges).toEqual [
- {enterprise_id: "4", active: true}
- {enterprise_id: "6", active: true}
- ]
-
- it 'converts coordinator fees into a list of ids', ->
- order_cycle =
- coordinator_fees: [
- {id: 1}
- {id: 2}
- ]
-
- data = OrderCycle.translateCoordinatorFees(order_cycle)
-
- expect(data.coordinator_fees).toBeUndefined()
- expect(data.coordinator_fee_ids).toEqual [1, 2]
-
- it "preserves original data when converting coordinator fees", ->
- OrderCycle.order_cycle =
- coordinator_fees: [
- {id: 1}
- {id: 2}
- ]
-
- data = OrderCycle.deepCopy()
- data = OrderCycle.translateCoordinatorFees(data)
-
- expect(OrderCycle.order_cycle.coordinator_fees).toEqual [{id: 1}, {id: 2}]
- expect(OrderCycle.order_cycle.coordinator_fee_ids).toBeUndefined()
-
- describe "converting exchange fees into a list of ids", ->
- order_cycle = null
- data = null
-
- beforeEach ->
- order_cycle =
- incoming_exchanges: [
- enterprise_fees: [
- {id: 1}
- {id: 2}
- ]
- ]
- outgoing_exchanges: [
- enterprise_fees: [
- {id: 3}
- {id: 4}
- ]
- ]
- OrderCycle.order_cycle = order_cycle
-
- data = OrderCycle.deepCopy()
- data = OrderCycle.translateExchangeFees(data)
-
- it 'converts exchange fees into a list of ids', ->
- expect(data.incoming_exchanges[0].enterprise_fees).toBeUndefined()
- expect(data.outgoing_exchanges[0].enterprise_fees).toBeUndefined()
- expect(data.incoming_exchanges[0].enterprise_fee_ids).toEqual [1, 2]
- expect(data.outgoing_exchanges[0].enterprise_fee_ids).toEqual [3, 4]
-
- it "preserves original data when converting exchange fees", ->
- expect(order_cycle.incoming_exchanges[0].enterprise_fees).toEqual [{id: 1}, {id: 2}]
- expect(order_cycle.outgoing_exchanges[0].enterprise_fees).toEqual [{id: 3}, {id: 4}]
- expect(order_cycle.incoming_exchanges[0].enterprise_fee_ids).toBeUndefined()
- expect(order_cycle.outgoing_exchanges[0].enterprise_fee_ids).toBeUndefined()
-
- describe "confirming when there are no distributors", ->
- order_cycle_with_exchanges = order_cycle_without_exchanges = null
-
- beforeEach ->
- order_cycle_with_exchanges =
- outgoing_exchanges: [{}]
- order_cycle_without_exchanges =
- outgoing_exchanges: []
-
- it "returns true when there are distributors", ->
- spyOn(window, 'confirm')
- OrderCycle.order_cycle = order_cycle_with_exchanges
- expect(OrderCycle.confirmNoDistributors()).toBe true
- expect(window.confirm).not.toHaveBeenCalled()
-
- it "returns true when there are no distributors but the user confirms", ->
- spyOn(window, 'confirm').and.returnValue(true)
- OrderCycle.order_cycle = order_cycle_without_exchanges
- expect(OrderCycle.confirmNoDistributors()).toBe true
- expect(window.confirm).toHaveBeenCalled()
-
- it "returns false when there are no distributors and the user does not confirm", ->
- spyOn(window, 'confirm').and.returnValue(false)
- OrderCycle.order_cycle = order_cycle_without_exchanges
- expect(OrderCycle.confirmNoDistributors()).toBe false
- expect(window.confirm).toHaveBeenCalled()
diff --git a/spec/jobs/finalize_account_invoices_spec.rb b/spec/jobs/finalize_account_invoices_spec.rb
deleted file mode 100644
index a8b591395d..0000000000
--- a/spec/jobs/finalize_account_invoices_spec.rb
+++ /dev/null
@@ -1,216 +0,0 @@
-require 'spec_helper'
-
-def travel_to(time)
- around { |example| Timecop.travel(start_of_july + time) { example.run } }
-end
-
-
-xdescribe FinalizeAccountInvoices do
- let!(:year) { Time.zone.now.year }
-
- describe "unit specs" do
- let!(:finalizer) { FinalizeAccountInvoices.new }
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- describe "perform" do
- let!(:accounts_distributor) { create(:distributor_enterprise) }
-
- #Invoice from June
- let!(:account_invoice1) { create(:account_invoice, year: year, month: 6, order: create(:order, completed_at: nil))}
-
- # We don't care when it was completed, in the future or past
- let!(:account_invoice2) { create(:account_invoice, year: year, month: 6, order: create(:order, completed_at: start_of_july - 10.days))}
- let!(:account_invoice3) { create(:account_invoice, year: year, month: 6, order: create(:order, completed_at: start_of_july + 10.days))}
-
- # Invoices from July
- let!(:account_invoice4) { create(:account_invoice, year: year, month: 7, order: create(:order, completed_at: nil))}
- let!(:account_invoice5) { create(:account_invoice, year: year, month: 7, order: create(:order, completed_at: start_of_july + 10.days))}
-
- before do
- allow(Enterprise).to receive(:find_by_id) { accounts_distributor }
- allow(accounts_distributor).to receive(:payment_methods) { double(:payment_methods, find_by_id: true) }
- allow(accounts_distributor).to receive(:shipping_methods) { double(:shipping_methods, find_by_id: true) }
- allow(finalizer).to receive(:finalize)
- allow(Bugsnag).to receive(:notify)
- end
-
- context "when necessary global config setting have not been set" do
- travel_to(20.days)
-
- context "when accounts_distributor has been set" do
- before do
- allow(Enterprise).to receive(:find_by_id) { false }
- finalizer.perform
- end
-
- it "snags errors and doesn't run" do
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(finalizer).to_not have_received(:finalize)
- end
- end
-
- context "when default payment method has been set" do
- before do
- allow(accounts_distributor).to receive(:payment_methods) { double(:payment_methods, find_by_id: false) }
- finalizer.perform
- end
-
- it "snags errors and doesn't run" do
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(finalizer).to_not have_received(:finalize)
- end
- end
-
- context "when default shipping method has been set" do
- before do
- allow(accounts_distributor).to receive(:shipping_methods) { double(:shipping_methods, find_by_id: false) }
- finalizer.perform
- end
-
- it "snags errors and doesn't run" do
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(finalizer).to_not have_received(:finalize)
- end
- end
- end
-
- context "when necessary global config setting have been set" do
- context "and no date arguments are passed to the job" do
- travel_to(3.days)
-
- it "finalizes the uncompleted orders from account_invoices for the previous calendar month" do
- finalizer.perform
- expect(finalizer).to have_received(:finalize).with(account_invoice1.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice2.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice3.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice4.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice5.order)
- end
- end
-
- context "and a specific year and month are passed as arguments" do
- let!(:finalizer) { FinalizeAccountInvoices.new(year, 7) }
-
- before do
- allow(finalizer).to receive(:finalizer)
- end
-
- context "that ends in the past" do
- travel_to(1.month + 3.hours)
-
- it "finalizes the uncompleted orders from account_invoices for the specified calendar month" do
- finalizer.perform
- expect(finalizer).to_not have_received(:finalize).with(account_invoice1.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice2.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice3.order)
- expect(finalizer).to have_received(:finalize).with(account_invoice4.order)
- expect(finalizer).to_not have_received(:finalize).with(account_invoice5.order)
- end
- end
-
- context "that ends in the future" do
- travel_to 3.days
-
- it "does not finalize any orders" do
- finalizer.perform
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(finalizer).to_not have_received(:finalize)
- end
- end
- end
- end
- end
-
- describe "finalize" do
- let!(:pm) { create(:payment_method, name: "PM1") }
- let!(:sm) { create(:shipping_method, name: "ship1") }
- let!(:accounts_distributor) { create(:distributor_enterprise, payment_methods: [pm], shipping_methods: [sm]) }
- let!(:invoice_order) { create(:order, distributor: accounts_distributor) }
-
- before do
- Spree::Config.set({ accounts_distributor_id: accounts_distributor.id })
- Spree::Config.set({ default_accounts_payment_method_id: pm.id })
- Spree::Config.set({ default_accounts_shipping_method_id: sm.id })
- invoice_order.line_items.clear
- end
-
- it "creates payment, assigns shipping method and finalizes the order" do
- expect(invoice_order.completed_at).to be nil
- finalizer.finalize(invoice_order)
- expect(invoice_order.completed_at).to_not be nil
- expect(invoice_order.payments.count).to eq 1
- expect(invoice_order.payments.first.payment_method).to eq pm
- expect(invoice_order.shipping_method).to eq sm
- end
-
- it "does not send a confirmation email" do
- expect(invoice_order).to receive(:deliver_order_confirmation_email).and_call_original
- expect{finalizer.finalize(invoice_order)}.to_not enqueue_job ConfirmOrderJob
- end
-
- context "when errors exist on the order" do
- before do
- allow(invoice_order).to receive(:errors) { double(:errors, any?: true, full_messages: ["Error message 1", "Error message 2"]) }
- allow(Bugsnag).to receive(:notify)
- end
-
- it "Snags a bug and does not finalize the order" do
- finalizer.finalize(invoice_order)
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("FinalizeInvoiceError"), anything)
- expect(invoice_order).to_not be_completed
- end
- end
- end
- end
-
- describe "validation spec" do
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- let!(:updater) { UpdateAccountInvoices.new }
- let!(:finalizer) { FinalizeAccountInvoices.new }
-
- let!(:pm) { create(:payment_method, name: "Default Payment Method") }
- let!(:sm) { create(:shipping_method, name: "Default Shipping Method") }
- let!(:accounts_distributor) { create(:distributor_enterprise, payment_methods: [pm], shipping_methods: [sm]) }
-
- let!(:user) { create(:user) }
- let!(:billable_period1) { create(:billable_period, sells: 'any', owner: user, begins_at: start_of_july - 1.month, ends_at: start_of_july) }
- let!(:billable_period2) { create(:billable_period, owner: user, begins_at: start_of_july, ends_at: start_of_july + 10.days) }
- let!(:billable_period3) { create(:billable_period, owner: user, begins_at: start_of_july + 12.days, ends_at: start_of_july + 20.days) }
-
- before do
- sm.calculator.set_preference(:amount, 0); sm.calculator.save!
-
- Spree::Config.set({ accounts_distributor_id: accounts_distributor.id })
- Spree::Config.set({ default_accounts_payment_method_id: pm.id })
- Spree::Config.set({ default_accounts_shipping_method_id: sm.id })
-
- # Make sure that bills are > 0
- Spree::Config.set(:account_invoices_monthly_fixed, 5)
- Spree::Config.set(:account_invoices_monthly_rate, 0.02)
- Spree::Config.set(:account_invoices_monthly_cap, 50)
- Spree::Config.set(:minimum_billable_turnover, 0)
- end
-
- context "finalizing an invoice" do
- travel_to(3.hours)
-
- it "finalizes it" do
- # Create an invoice using the updater, to make sure we are using
- # an order as it would be when generated this way
- expect{updater.perform}.to change{Spree::Order.count}.from(0).to(1)
- invoice = user.orders.first
-
- # Finalize invoices
- finalizer.perform
- invoice.reload
-
- expect(invoice.completed_at).to_not be_nil
- expect(invoice.total).to eq billable_period1.bill.round(2)
- expect(invoice.payments.count).to eq 1
- expect(invoice.payments.first.amount).to eq billable_period1.bill.round(2)
- expect(invoice.state).to eq 'complete'
- end
- end
- end
-end
diff --git a/spec/jobs/subscription_confirm_job_spec.rb b/spec/jobs/subscription_confirm_job_spec.rb
index 0d71241503..64713518e3 100644
--- a/spec/jobs/subscription_confirm_job_spec.rb
+++ b/spec/jobs/subscription_confirm_job_spec.rb
@@ -58,6 +58,12 @@ xdescribe SubscriptionConfirmJob do
proxy_order.update_attributes!(confirmed_at: 1.second.ago)
expect(proxy_orders).to_not include proxy_order
end
+
+ it "ignores orders that have been cancelled" do
+ setup_email
+ proxy_order.order.cancel!
+ expect(proxy_orders).to_not include proxy_order
+ end
end
describe "performing the job" do
diff --git a/spec/jobs/subscription_placement_job_spec.rb b/spec/jobs/subscription_placement_job_spec.rb
index 685d6f4ded..a55bce0d00 100644
--- a/spec/jobs/subscription_placement_job_spec.rb
+++ b/spec/jobs/subscription_placement_job_spec.rb
@@ -76,9 +76,9 @@ describe SubscriptionPlacementJob do
context "and insufficient stock exists to fulfil the order for some items" do
before do
- variant1.update_attribute(:count_on_hand, 5)
- variant2.update_attribute(:count_on_hand, 2)
- variant3.update_attribute(:count_on_hand, 0)
+ variant1.update_attribute(:on_hand, 5)
+ variant2.update_attribute(:on_hand, 2)
+ variant3.update_attribute(:on_hand, 0)
end
xit "caps quantity at the stock level for stock-limited items, and reports the change" do
@@ -98,9 +98,9 @@ describe SubscriptionPlacementJob do
context "and insufficient stock exists to fulfil the order for some items" do
before do
- variant1.update_attribute(:count_on_hand, 5)
- variant2.update_attribute(:count_on_hand, 2)
- variant3.update_attribute(:count_on_hand, 0)
+ variant1.update_attribute(:on_hand, 5)
+ variant2.update_attribute(:on_hand, 2)
+ variant3.update_attribute(:on_hand, 0)
end
xit "sets quantity to 0 for unavailable items, and reports the change" do
diff --git a/spec/jobs/update_account_invoices_spec.rb b/spec/jobs/update_account_invoices_spec.rb
deleted file mode 100644
index abe65ec853..0000000000
--- a/spec/jobs/update_account_invoices_spec.rb
+++ /dev/null
@@ -1,448 +0,0 @@
-require 'spec_helper'
-
-def travel_to(time)
- around { |example| Timecop.travel(start_of_july + time) { example.run } }
-end
-
-xdescribe UpdateAccountInvoices do
- let(:year) { Time.zone.now.year }
-
- before do
- # Make sure that bills are > 0
- Spree::Config.set(:account_invoices_monthly_fixed, 5)
- Spree::Config.set(:account_invoices_monthly_rate, 0.02)
- Spree::Config.set(:account_invoices_monthly_cap, 50)
- Spree::Config.set(:minimum_billable_turnover, 0)
- end
-
- describe "units specs" do
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- let!(:updater) { UpdateAccountInvoices.new }
-
- let!(:user) { create(:user) }
- let!(:june_billable_period1) { create(:billable_period, owner: user, begins_at: start_of_july - 1.month, ends_at: start_of_july - 20.days) }
- let!(:june_billable_period2) { create(:billable_period, owner: user, begins_at: start_of_july - 20.days, ends_at: start_of_july - 10.days, turnover: 45, sells: "none" ) }
- let!(:june_billable_period3) { create(:billable_period, owner: user, begins_at: start_of_july - 10.days, ends_at: start_of_july - 1.days, turnover: 0, sells: "any" ) }
- let!(:july_billable_period1) { create(:billable_period, owner: user, begins_at: start_of_july, ends_at: start_of_july + 12.days) }
- let!(:july_billable_period2) { create(:billable_period, owner: user, begins_at: start_of_july + 12.days, ends_at: start_of_july + 20.days) }
- let!(:july_billable_period3) { create(:billable_period, owner: user, begins_at: start_of_july + 20.days, ends_at: start_of_july + 25.days, turnover: 45, sells: 'none') }
- let!(:july_billable_period4) { create(:billable_period, owner: user, begins_at: start_of_july + 25.days, ends_at: start_of_july + 28.days, turnover: 0, sells: 'any') }
- let(:june_account_invoice) { june_billable_period1.account_invoice }
- let(:july_account_invoice) { july_billable_period1.account_invoice }
-
- describe "perform" do
- let(:accounts_distributor) { double(:accounts_distributor) }
- before do
- allow(Enterprise).to receive(:find_by_id) { accounts_distributor }
- allow(updater).to receive(:update)
- allow(Bugsnag).to receive(:notify)
- end
-
- context "when necessary global config setting have not been set" do
- travel_to(20.days)
-
- context "when accounts_distributor has been set" do
- before do
- allow(Enterprise).to receive(:find_by_id) { false }
- updater.perform
- end
-
- it "snags errors and doesn't run" do
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(updater).to_not have_received(:update)
- end
- end
- end
-
- context "when necessary global config setting have been set" do
- context "on the first of the month" do
- travel_to(3.hours)
-
- it "updates invoices from the previous month" do
- updater.perform
- expect(updater).to have_received(:update).once
- .with(june_account_invoice)
- expect(updater).to_not have_received(:update)
- .with(july_account_invoice)
- end
- end
-
- context "on other days" do
- travel_to(20.days)
-
- it "updates invoices from the current month" do
- updater.perform
- expect(updater).to have_received(:update).once
- .with(july_account_invoice)
- end
- end
-
- context "when specfic a specific month (and year) are passed as arguments" do
- let!(:updater) { UpdateAccountInvoices.new(year, 7) }
-
- before do
- allow(updater).to receive(:update)
- end
-
- context "that just ended (in the past)" do
- travel_to(1.month)
-
- it "updates invoices from the previous month" do
- updater.perform
- expect(updater).to have_received(:update).once
- .with(july_account_invoice)
- end
- end
-
- context "that starts in the past and ends in the future (ie. current_month)" do
- travel_to 30.days
-
- it "updates invoices from that current month" do
- updater.perform
- expect(updater).to have_received(:update).once
- .with(july_account_invoice)
- end
- end
-
- context "that starts in the future" do
- travel_to(-1.days)
-
- it "snags an error and does not update invoices" do
- updater.perform
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("InvalidJobSettings"), anything)
- expect(updater).to_not have_received(:update)
- end
- end
- end
- end
- end
-
- describe "update" do
- before do
- allow(june_account_invoice).to receive(:save).and_call_original
- allow(july_account_invoice).to receive(:save).and_call_original
- allow(updater).to receive(:clean_up)
- allow(updater).to receive(:finalize)
- allow(Bugsnag).to receive(:notify)
- end
-
- context "where an order for the invoice already exists" do
- let!(:invoice_order) { create(:order, user: user) }
-
- before do
- expect(Spree::Order).to_not receive(:new)
- allow(june_account_invoice).to receive(:order) { invoice_order }
- end
-
- context "where the order is already complete" do
- before do
- allow(invoice_order).to receive(:complete?) { true }
- updater.update(june_account_invoice)
- end
-
- it "snags a bug" do
- expect(Bugsnag).to have_received(:notify)
- end
-
- it "does not save the order" do
- expect(june_account_invoice).to_not have_received(:save)
- end
-
- it "does not clean up the order" do
- expect(updater).to_not have_received(:clean_up).with(invoice_order, anything)
- end
- end
-
- context "where the order is not complete" do
- before do
- allow(invoice_order).to receive(:complete?) { false }
- june_billable_period1.enterprise.update_attributes(contact_name: "Firstname Lastname Something Else", phone: '12345')
- updater.update(june_account_invoice)
- end
-
- it "creates adjustments for each billing item where bill is not 0" do
- adjustments = invoice_order.adjustments
- expect(adjustments.map(&:source_id)).to eq [june_billable_period1.id, june_billable_period3.id]
- expect(adjustments.map(&:amount)).to eq [june_billable_period1.bill.round(2), june_billable_period3.bill.round(2)]
- expect(adjustments.map(&:label)).to eq [june_billable_period1.adjustment_label, june_billable_period3.adjustment_label]
- end
-
- it "assigns a addresses to the order" do
- expect(invoice_order.billing_address).to be_a Spree::Address
- expect(invoice_order.shipping_address).to be_a Spree::Address
- expect(invoice_order.shipping_address).to eq invoice_order.billing_address
- [:address1, :address2, :city, :zipcode, :state_id, :country_id].each do |attr|
- expect(invoice_order.billing_address[attr]).to eq june_billable_period1.enterprise.address[attr]
- end
- expect(invoice_order.billing_address.firstname).to eq "Firstname"
- expect(invoice_order.billing_address.lastname).to eq "Lastname Something Else"
- expect(invoice_order.billing_address.phone).to eq "12345"
- end
-
- it "saves the order" do
- expect(june_account_invoice).to have_received(:save)
- expect(june_account_invoice.order).to be_persisted
- end
-
- it "cleans up the order" do
- expect(updater).to have_received(:clean_up).with(invoice_order, anything).once
- end
- end
- end
-
- context "where an order for the invoice does not already exist" do
- let!(:accounts_distributor) { create(:distributor_enterprise) }
- before do
- Spree::Config.set({ accounts_distributor_id: accounts_distributor.id })
- updater.update(july_account_invoice)
- end
-
- it "creates adjustments for each billing item where bill is not 0" do
- adjustments = july_account_invoice.order.adjustments
- expect(adjustments.map(&:source_id)).to eq [july_billable_period1.id, july_billable_period2.id,july_billable_period4.id]
- expect(adjustments.map(&:amount)).to eq [july_billable_period1.bill.round(2), july_billable_period2.bill.round(2), july_billable_period4.bill.round(2)]
- expect(adjustments.map(&:label)).to eq [july_billable_period1.adjustment_label, july_billable_period2.adjustment_label, july_billable_period4.adjustment_label]
- end
-
- it "saves the order" do
- expect(july_account_invoice).to have_received(:save)
- expect(july_account_invoice.order).to be_persisted
- end
-
- it "cleans up order" do
- expect(updater).to have_received(:clean_up).with(july_account_invoice.order, anything).once
- end
- end
- end
-
- describe "clean_up" do
- let!(:invoice_order) { create(:order) }
- let!(:obsolete1) { create(:adjustment, adjustable: invoice_order) }
- let!(:obsolete2) { create(:adjustment, adjustable: invoice_order) }
- let!(:current1) { create(:adjustment, adjustable: invoice_order) }
- let!(:current2) { create(:adjustment, adjustable: invoice_order) }
-
- before do
- allow(invoice_order).to receive(:save)
- allow(invoice_order).to receive(:destroy)
- allow(Bugsnag).to receive(:notify)
- end
-
- context "when current adjustments are present" do
- let!(:current_adjustments) { [current1, current2] }
-
- context "and obsolete adjustments are present" do
- let!(:obsolete_adjustments) { [obsolete1, obsolete2] }
-
- before do
- allow(obsolete_adjustments).to receive(:destroy_all)
- allow(invoice_order).to receive(:adjustments) { double(:adjustments, where: obsolete_adjustments) }
- updater.clean_up(invoice_order, current_adjustments)
- end
-
- it "destroys obsolete adjustments and snags a bug" do
- expect(obsolete_adjustments).to have_received(:destroy_all)
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("Obsolete Adjustments"), anything)
- end
- end
-
- context "and obsolete adjustments are not present" do
- let!(:obsolete_adjustments) { [] }
-
- before do
- allow(invoice_order).to receive(:adjustments) { double(:adjustments, where: obsolete_adjustments) }
- updater.clean_up(invoice_order, current_adjustments)
- end
-
- it "has no bugs to snag" do
- expect(Bugsnag).to_not have_received(:notify)
- end
- end
- end
-
- context "when current adjustments are not present" do
- let!(:current_adjustments) { [] }
-
- context "and obsolete adjustments are present" do
- let!(:obsolete_adjustments) { [obsolete1, obsolete2] }
-
- before do
- allow(obsolete_adjustments).to receive(:destroy_all)
- allow(invoice_order).to receive(:adjustments) { double(:adjustments, where: obsolete_adjustments) }
- end
-
- it "destroys obsolete adjustments and snags a bug" do
- updater.clean_up(invoice_order, current_adjustments)
- expect(obsolete_adjustments).to have_received(:destroy_all)
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("Obsolete Adjustments"), anything)
- end
-
- context "when the order is not persisted" do
- before do
- allow(invoice_order).to receive(:persisted?) { false }
- end
-
- it "destroys the order" do
- updater.clean_up(invoice_order, current_adjustments)
- expect(invoice_order).to have_received(:destroy)
- end
- end
-
- context "when the order is persisted" do
- before do
- allow(invoice_order).to receive(:persisted?) { true }
- end
-
- it "snags a bug" do
- updater.clean_up(invoice_order, current_adjustments)
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("Empty Persisted Invoice"), anything)
- end
- end
- end
-
- context "and obsolete adjustments are not present" do
- let!(:obsolete_adjustments) { [] }
-
- before do
- allow(invoice_order).to receive(:adjustments) { double(:adjustments, where: obsolete_adjustments) }
- end
-
- it "has no bugs to snag" do
- expect(Bugsnag).to_not have_received(:notify).with(RuntimeError.new("Obsolete Adjustments"), anything)
- end
-
- context "when the order is not persisted" do
- before do
- allow(invoice_order).to receive(:persisted?) { false }
- end
-
- it "destroys the order" do
- updater.clean_up(invoice_order, current_adjustments)
- expect(invoice_order).to have_received(:destroy)
- end
- end
-
- context "when the order is persisted" do
- before do
- allow(invoice_order).to receive(:persisted?) { true }
- end
-
- it "snags a bug" do
- updater.clean_up(invoice_order, current_adjustments)
- expect(Bugsnag).to have_received(:notify).with(RuntimeError.new("Empty Persisted Invoice"), anything)
- end
- end
- end
- end
- end
- end
-
- describe "validation spec" do
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- let!(:updater) { UpdateAccountInvoices.new }
-
- let!(:accounts_distributor) { create(:distributor_enterprise) }
-
- let!(:user) { create(:user) }
- let!(:july_billable_period1) { create(:billable_period, sells: 'any', owner: user, begins_at: start_of_july - 1.month, ends_at: start_of_july) }
- let!(:july_billable_period2) { create(:billable_period, owner: user, begins_at: start_of_july, ends_at: start_of_july + 10.days) }
- let!(:july_billable_period3) { create(:billable_period, owner: user, begins_at: start_of_july + 12.days, ends_at: start_of_july + 20.days) }
- let!(:july_account_invoice) { july_billable_period2.account_invoice }
- let!(:august_account_invoice) { create(:account_invoice, user: user, year: july_account_invoice.year, month: 8)}
-
- before do
- Spree::Config.set({ accounts_distributor_id: accounts_distributor.id })
- july_billable_period2.enterprise.update_attributes(contact_name: 'Anna Karenina', phone: '3433523')
- end
-
- context "when no invoice_order currently exists" do
- context "when relevant billable periods exist" do
- travel_to(20.days)
-
- it "creates an invoice_order" do
- expect{updater.perform}.to change{Spree::Order.count}.from(0).to(1)
- invoice_order = july_account_invoice.reload.order
- expect(user.orders.first).to eq invoice_order
- expect(invoice_order.completed_at).to be_nil
- billable_adjustments = invoice_order.adjustments.where('source_type = (?)', 'BillablePeriod')
- expect(billable_adjustments.map(&:amount)).to eq [july_billable_period2.bill.round(2), july_billable_period3.bill.round(2)]
- expect(invoice_order.total).to eq july_billable_period2.bill.round(2) + july_billable_period3.bill.round(2)
- expect(invoice_order.payments.count).to eq 0
- expect(invoice_order.state).to eq 'cart'
- expect(invoice_order.bill_address).to be_a Spree::Address
- expect(invoice_order.ship_address).to be_a Spree::Address
- expect(invoice_order.shipping_address).to eq invoice_order.billing_address
- [:address1, :address2, :city, :zipcode, :state_id, :country_id].each do |attr|
- expect(invoice_order.billing_address[attr]).to eq july_billable_period2.enterprise.address[attr]
- end
- expect(invoice_order.billing_address.firstname).to eq "Anna"
- expect(invoice_order.billing_address.lastname).to eq "Karenina"
- expect(invoice_order.billing_address.phone).to eq "3433523"
- end
- end
-
- context "when no relevant billable periods exist" do
- travel_to(1.month + 5.days)
-
- it "does not create an order" do
- expect(updater).to receive(:update).with(august_account_invoice).and_call_original
- expect{updater.perform}.to_not change{Spree::Order.count}.from(0)
- end
- end
- end
-
- context "when an order already exists" do
- context "when relevant billable periods exist" do
- let!(:invoice_order) { create(:order, user: user, distributor: accounts_distributor, created_at: start_of_july) }
- let!(:billable_adjustment) { create(:adjustment, adjustable: invoice_order, source_type: 'BillablePeriod') }
-
- before do
- invoice_order.line_items.clear
- july_account_invoice.update_attribute(:order, invoice_order)
- end
-
- travel_to(20.days)
-
- it "updates the order, and clears any obsolete invoices" do
- expect{updater.perform}.to_not change{Spree::Order.count}
- invoice_order = user.orders.first
- expect(invoice_order.completed_at).to be_nil
- billable_adjustments = invoice_order.adjustments.where('source_type = (?)', 'BillablePeriod')
- expect(billable_adjustments).to_not include billable_adjustment
- expect(billable_adjustments.map(&:amount)).to eq [july_billable_period2.bill.round(2), july_billable_period3.bill.round(2)]
- expect(invoice_order.total).to eq july_billable_period2.bill.round(2) + july_billable_period3.bill.round(2)
- expect(invoice_order.payments.count).to eq 0
- expect(invoice_order.state).to eq 'cart'
- expect(invoice_order.bill_address).to be_a Spree::Address
- expect(invoice_order.ship_address).to be_a Spree::Address
- expect(invoice_order.shipping_address).to eq invoice_order.billing_address
- [:address1, :address2, :city, :zipcode, :state_id, :country_id].each do |attr|
- expect(invoice_order.billing_address[attr]).to eq july_billable_period2.enterprise.address[attr]
- end
- expect(invoice_order.billing_address.firstname).to eq "Anna"
- expect(invoice_order.billing_address.lastname).to eq "Karenina"
- expect(invoice_order.billing_address.phone).to eq "3433523"
- end
- end
-
- context "when no relevant billable periods exist" do
- let!(:invoice_order) { create(:order, user: user, distributor: accounts_distributor) }
-
- before do
- invoice_order.line_items.clear
- august_account_invoice.update_attribute(:order, invoice_order)
- end
-
- travel_to(1.month + 5.days)
-
- it "snags a bug" do
- expect(updater).to receive(:update).with(august_account_invoice).and_call_original
- expect(Bugsnag).to receive(:notify).with(RuntimeError.new("Empty Persisted Invoice"), anything)
- expect{updater.perform}.to_not change{Spree::Order.count}
- end
- end
- end
- end
-end
diff --git a/spec/jobs/update_billable_periods_spec.rb b/spec/jobs/update_billable_periods_spec.rb
deleted file mode 100644
index 1b461e7f2a..0000000000
--- a/spec/jobs/update_billable_periods_spec.rb
+++ /dev/null
@@ -1,725 +0,0 @@
-require 'spec_helper'
-
-def travel_to(time)
- around { |example| Timecop.travel(start_of_july + time) { example.run } }
-end
-
-describe UpdateBillablePeriods do
- let!(:year) { Time.zone.now.year }
-
- describe "unit specs" do
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- let!(:updater) { UpdateBillablePeriods.new }
-
- describe "perform", versioning: true do
- let!(:enterprise) { create(:supplier_enterprise, created_at: start_of_july - 1.month, sells: 'any') }
-
- context "when no date arguments are passed to the job" do
- before do
- expect(updater).to receive(:clean_up_untouched_billable_periods_for).once
- end
-
- context "on the first of the month" do
- travel_to(3.hours)
-
- it "processes the previous month" do
- expect(updater).to receive(:split_for_trial)
- .with(enterprise, start_of_july - 1.month, start_of_july, nil, nil)
- updater.perform
- end
- end
-
- context "on all other days" do
- travel_to(1.day + 3.hours)
-
- it "processes the current month up until previous midnight" do
- expect(updater).to receive(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 1.day, nil, nil)
- updater.perform
- end
- end
- end
-
- context "when a specfic year and month are passed as arguments" do
- let!(:updater) { UpdateBillablePeriods.new(year, 6) }
-
- before do
- allow(updater).to receive(:split_for_trial)
- end
-
- context "that ends in the past" do
- travel_to(3.hours)
-
- it "processes the month" do
- expect(updater).to receive(:split_for_trial)
- .with(enterprise, start_of_july - 1.month, start_of_july, nil, nil)
- updater.perform
- end
- end
-
- context "that starts in the past and ends in the future (ie. current month)" do
- travel_to(-3.days)
-
- it "processes the current month up to the previous midnight" do
- expect(updater).to receive(:split_for_trial)
- .with(enterprise, start_of_july - 1.month, start_of_july-3.days, nil, nil)
- updater.perform
- end
- end
-
- context "that starts in the future" do
- travel_to(-31.days)
-
- it "does not run" do
- expect(updater).to_not receive(:split_for_trial)
- updater.perform
- end
- end
- end
-
- context "when an enterprise is created before the beginning of the current month" do
- before do
- expect(updater).to receive(:clean_up_untouched_billable_periods_for).once
- end
-
- travel_to(28.days)
-
- context "when no alterations to sells or owner have been made during the current month" do
-
- it "begins at the start of the month" do
- expect(updater).to receive(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 28.days, nil, nil)
- updater.perform
- end
- end
-
- context "when sells has been changed within the current month" do
- before do
- Timecop.freeze(start_of_july + 10.days) do
- # NOTE: Sells is changed between when order1 and order2 are placed
- enterprise.update_attribute(:sells, 'own')
- end
- end
-
- travel_to(28.days)
-
- it "processes each sells period separately" do
- allow(updater).to receive(:split_for_trial).twice
- updater.perform
-
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise.versions.first.reify, start_of_july, start_of_july + 10.days, nil, nil)
-
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july + 10.days, start_of_july + 28.days, nil, nil)
- end
- end
-
- context "when owner has been changed within the current month" do
- let!(:new_owner) { create(:user) }
-
- before do
- Timecop.freeze(start_of_july + 10.days) do
- # NOTE: Sells is changed between when order1 and order2 are placed
- enterprise.update_attribute(:owner, new_owner)
- end
- end
-
- travel_to(28.days)
-
- it "processes each ownership period separately" do
- allow(updater).to receive(:split_for_trial).twice
- updater.perform
-
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise.versions.first.reify, start_of_july, start_of_july + 10.days, nil, nil)
-
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july + 10.days, start_of_july + 28.days, nil, nil)
- end
- end
-
- context "when some other attribute has been changed within the current month" do
- before do
- Timecop.freeze(start_of_july + 10.days) do
- # NOTE: Sells is changed between when order1 and order2 are placed
- enterprise.update_attribute(:name, 'Some New Name')
- end
- end
-
- travel_to(28.days)
-
- it "does not create a version, and so does not split the period" do
- expect(enterprise.versions).to eq []
- allow(updater).to receive(:split_for_trial).once
- updater.perform
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 28.days, nil, nil)
- end
- end
-
- context "where sells or owner_id were altered during the previous month (ie. June)" do
- let!(:new_owner) { create(:user) }
-
- before do
- Timecop.freeze(start_of_july - 20.days) do
- # NOTE: Sells is changed between when order1 and order2 are placed
- enterprise.update_attribute(:sells, 'own')
- end
- Timecop.freeze(start_of_july - 10.days) do
- # NOTE: Sells is changed between when order1 and order2 are placed
- enterprise.update_attribute(:owner, new_owner)
- end
- end
-
- travel_to(28.days)
-
- it "ignores those verions" do
- allow(updater).to receive(:split_for_trial).once
- updater.perform
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 28.days, nil, nil)
- end
- end
-
- context "where sells or owner_id were altered in the future" do
- let!(:new_owner) { create(:user) }
-
- before do
- Timecop.freeze(start_of_july + 17.days) do
- enterprise.update_attribute(:sells, 'own')
- end
- Timecop.freeze(start_of_july + 35.days) do
- enterprise.update_attribute(:owner, new_owner)
- end
- end
-
- travel_to(15.days)
-
- it "ignores those verions" do
- allow(updater).to receive(:split_for_trial).once
- updater.perform
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 15.days, nil, nil)
- end
- end
- end
-
- context "when an enterprise is created during the current month" do
- before do
- expect(updater).to receive(:clean_up_untouched_billable_periods_for).once
- enterprise.update_attribute(:created_at, start_of_july + 10.days)
- end
-
- travel_to(28.days)
-
- it "begins at the date the enterprise was created" do
- allow(updater).to receive(:split_for_trial).once
- updater.perform
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july + 10.days, start_of_july + 28.days, nil, nil)
- end
- end
-
- context "when an enterprise is created after the previous midnight" do
- before do
- expect(updater).to_not receive(:clean_up_untouched_billable_periods_for)
- enterprise.update_attribute(:created_at, start_of_july + 29.days)
- end
-
- travel_to(28.days)
-
- it "ignores the enterprise" do
- allow(updater).to receive(:split_for_trial)
- updater.perform
- expect(updater).to_not have_received(:split_for_trial)
- end
- end
-
- pending "when an enterprise is deleted during the current month" do
- before do
- expect(updater).to receive(:clean_up_untouched_billable_periods_for).once
- enterprise.update_attribute(:deleted_at, start_of_july + 20.days)
- end
-
- travel_to(28.days)
-
- it "ends at the date the enterprise was deleted" do
- allow(updater).to receive(:split_for_trial)
- updater.perform
- expect(updater).to have_received(:split_for_trial)
- .with(enterprise, start_of_july, start_of_july + 20.days, nil, nil)
- end
- end
- end
-
- describe "split_for_trial" do
- let!(:enterprise) { double(:enterprise) }
- let(:begins_at) { start_of_july }
- let(:ends_at) { begins_at + 30.days }
-
- context "when trial_start is nil" do
- let(:trial_start) { nil }
- let(:trial_expiry) { begins_at + 3.days }
-
- before do
- allow(updater).to receive(:update_billable_period).once
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the entire period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, ends_at, false)
- end
- end
-
- context "when trial_expiry is nil" do
- let(:trial_start) { begins_at + 3.days }
- let(:trial_expiry) { nil }
-
- before do
- allow(updater).to receive(:update_billable_period).once
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the entire period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, ends_at, false)
- end
- end
-
- context "when the trial begins before begins_at" do
- let(:trial_start) { begins_at - 10.days }
-
- context "and the trial ends before begins_at" do
- let(:trial_expiry) { begins_at - 5.days }
-
- before do
- allow(updater).to receive(:update_billable_period).once
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the entire period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, ends_at, false)
- end
- end
-
- context "and the trial ends after begins_at" do
- let(:trial_expiry) { begins_at + 5.days }
-
- before do
- allow(updater).to receive(:update_billable_period).twice
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the trial period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, trial_expiry, true)
- end
-
- it "calls update_billable_period once for the non-trial period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, trial_expiry, ends_at, false)
- end
- end
-
- context "and the trial ends after ends_at" do
- let(:trial_expiry) { ends_at + 5.days }
-
- before do
- allow(updater).to receive(:update_billable_period).once
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the entire (trial) period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, ends_at, true)
- end
- end
- end
-
- context "when the trial begins after begins_at" do
- let(:trial_start) { begins_at + 5.days }
-
- context "and the trial begins after ends_at" do
- let(:trial_start) { ends_at + 5.days }
- let(:trial_expiry) { ends_at + 10.days }
-
- before do
- allow(updater).to receive(:update_billable_period).once
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the entire period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, ends_at, false)
- end
- end
-
- context "and the trial ends before ends_at" do
- let(:trial_expiry) { ends_at - 2.days }
-
- before do
- allow(updater).to receive(:update_billable_period).exactly(3).times
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the non-trial period before the trial" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, trial_start, false)
- end
-
- it "calls update_billable_period once for the trial period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, trial_start, trial_expiry, true)
- end
-
- it "calls update_billable_period once for the non-trial period after the trial" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, trial_expiry, ends_at, false)
- end
- end
-
- context "and the trial ends after ends_at" do
- let(:trial_expiry) { ends_at + 5.days }
-
- before do
- allow(updater).to receive(:update_billable_period).twice
- updater.split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry)
- end
-
- it "calls update_billable_period once for the non-trial period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, begins_at, trial_start, false)
- end
-
- it "calls update_billable_period once for the trial period" do
- expect(updater).to have_received(:update_billable_period)
- .with(enterprise, trial_start, ends_at, true)
- end
- end
- end
- end
-
- describe "update_billable_period" do
- let!(:enterprise) { create(:enterprise, sells: 'any') }
-
- let!(:existing) { create(:billable_period, enterprise: enterprise, begins_at: start_of_july) }
-
- before do
- allow(Spree::Order).to receive(:where) { [
- double(:order, total: 10),
- double(:order, total: 20),
- double(:order, total: 30)
- ]
- }
- end
-
- context "when the account invoice is already_complete" do
- before do
- allow(BillablePeriod).to receive(:where) { [existing] }
- allow(existing.account_invoice).to receive(:order) { double(:order, complete?: true ) }
- allow(AccountInvoice).to receive(:find_or_create_by_user_id_and_year_and_month) { existing.account_invoice }
- end
-
- it "does not update the billing period, but changes updated_at by touching the billable period " do
- expect(existing).to_not receive(:update_attributes)
- expect(existing).to receive(:touch)
- expect(Bugsnag).to_not receive(:notify)
- expect{
- updater.update_billable_period(enterprise, start_of_july, start_of_july + 20.days, false)
- }.to_not change{ BillablePeriod.count }
- end
- end
-
- context "when arguments match both 'begins_at' and 'enterprise_id' of an existing billable period" do
- it "updates the existing billable period" do
- expect{
- updater.update_billable_period(enterprise, start_of_july, start_of_july + 20.days, false)
- }.to_not change{ BillablePeriod.count }
- existing.reload
- expect(existing.owner_id).to eq enterprise.owner_id
- expect(existing.ends_at).to eq start_of_july + 20.days
- expect(existing.sells).to eq enterprise.sells
- expect(existing.trial).to eq false
- expect(existing.turnover).to eq 60
- end
-
- context "when there is nothing to update" do
- before do
- Timecop.freeze(start_of_july + 3.days) {
- existing.update_attributes(
- begins_at: start_of_july,
- ends_at: start_of_july + 20.days,
- trial: false,
- sells: enterprise.sells,
- turnover: 60
- )
- }
- end
-
- it "changes updated_at anyway by touching the billable period" do
- Timecop.freeze(start_of_july + 10.days) {
- expect{
- updater.update_billable_period(enterprise, start_of_july, start_of_july + 20.days, false)
- }.to change{ existing.reload.updated_at }
- .from(start_of_july + 3.days)
- .to(start_of_july + 10.days)
- }
- end
- end
- end
-
- context "when 'begins_at' does not match an existing billable period" do
- before do
- expect{
- updater.update_billable_period(enterprise, start_of_july + 20.days, start_of_july + 30.days, false)
- }.to change{ BillablePeriod.count }.from(1).to(2)
- end
-
- it "creates a new existing billable period" do
- billable_period = BillablePeriod.last
- expect(billable_period.owner_id).to eq enterprise.owner_id
- expect(billable_period.ends_at).to eq start_of_july + 30.days
- expect(billable_period.sells).to eq enterprise.sells
- expect(billable_period.trial).to eq false
- expect(billable_period.turnover).to eq 60
- end
- end
-
- context "when 'enterprise_id' does not match an existing billable period" do
- let!(:new_enterprise) { create(:enterprise, sells: 'own') }
-
- before do
- expect{
- updater.update_billable_period(new_enterprise, start_of_july, start_of_july + 20.days, false)
- }.to change{ BillablePeriod.count }.from(1).to(2)
- end
-
- it "creates a new existing billable period" do
- billable_period = BillablePeriod.last
- expect(billable_period.owner_id).to eq new_enterprise.owner_id
- expect(billable_period.ends_at).to eq start_of_july + 20.days
- expect(billable_period.sells).to eq new_enterprise.sells
- expect(billable_period.trial).to eq false
- expect(billable_period.turnover).to eq 60
- end
- end
- end
-
- context "cleaning up untouched billable periods" do
- let(:job_start_time) { Time.zone.now }
- let(:enterprise) { create(:enterprise) }
- # Updated after start
- let!(:bp1) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time + 2.seconds, begins_at: start_of_july, ends_at: start_of_july + 5.days ) }
- let!(:bp2) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time + 2.seconds, begins_at: start_of_july + 5.days, ends_at: start_of_july + 10.days ) }
- # Updated before start
- let!(:bp3) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july, ends_at: start_of_july + 10.days ) }
- # Updated before start but begins after end_date
- let!(:bp4) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july + 10.days, ends_at: start_of_july + 15.days ) }
- # Updated before start but begins at end_date (ie. not before end_date, so should be ignored) EDGE CASE
- let!(:bp5) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july + 8.days, ends_at: start_of_july + 10.days ) }
- # Updated before start but ends before start_date
- let!(:bp6) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july - 10.days, ends_at: start_of_july - 5.days ) }
- # Updated before start but ends at start_date (ie. not after start_date, so should be ignored) EDGE CASE
- let!(:bp7) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july - 5.days, ends_at: start_of_july ) }
- # Updated before start, but order is already complete, so should not be deleted
- let!(:bp8) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july, ends_at: start_of_july + 10.days, account_invoice: create(:account_invoice, order: create(:order, state: 'complete', completed_at: 5.minutes.ago))) }
-
- before do
- allow(Bugsnag).to receive(:notify)
- allow(updater).to receive(:start_date) { start_of_july }
- allow(updater).to receive(:end_date) { start_of_july + 8.days }
- updater.clean_up_untouched_billable_periods_for(enterprise, job_start_time)
- end
-
- it "soft deletes untouched billable_periods" do
- expect(bp1.reload.deleted_at).to be_nil
- expect(bp2.reload.deleted_at).to be_nil
- expect(bp3.reload.deleted_at).to_not be_nil
- expect(bp4.reload.deleted_at).to be_nil
- expect(bp5.reload.deleted_at).to be_nil
- expect(bp6.reload.deleted_at).to be_nil
- expect(bp7.reload.deleted_at).to be_nil
- expect(bp8.reload.deleted_at).to be_nil
- end
-
- it "notifies bugsnag" do
- expect(Bugsnag).to have_received(:notify).once
- end
- end
- end
-
- describe "validation spec" do
- # Chose july to test with because June has 30 days and so is easy to calculate end date for shop trial
- let!(:year) { Time.zone.now.year }
- let!(:start_of_july) { Time.zone.local(year, 7) }
-
- let!(:enterprise) { create(:supplier_enterprise, sells: 'any') }
-
- let!(:original_owner) { enterprise.owner }
-
- let!(:new_owner) { create(:user) }
-
- let!(:account_invoice1) { create(:account_invoice, user: original_owner, year: year, month: 7)}
- let!(:account_invoice2) { create(:account_invoice, user: new_owner, year: year, month: 7)}
-
- # This BP was updated before the current run and so should be marked for deletion at the end of the run
- let!(:obsolete_bp) { create(:billable_period, enterprise: enterprise, updated_at: start_of_july + 10.days, begins_at: start_of_july + 6.5.days, ends_at: start_of_july + 10.days ) }
-
- # This one has an updated_at in the future (so that it doesn't get deleted)
- # It also has a begins_at date which matches a period that would otherwise be created,
- # and so it should be picked up and overwritten
- let!(:bp_to_overwrite) { create(:billable_period, enterprise: enterprise, updated_at: start_of_july + 21.days, begins_at: start_of_july + 10.days, ends_at: start_of_july + 15.days ) }
-
- let!(:order1) { create(:order, completed_at: start_of_july + 1.days, distributor: enterprise) }
- let!(:order2) { create(:order, completed_at: start_of_july + 3.days, distributor: enterprise) }
- let!(:order3) { create(:order, completed_at: start_of_july + 5.days, distributor: enterprise) }
- let!(:order4) { create(:order, completed_at: start_of_july + 7.days, distributor: enterprise) }
- let!(:order5) { create(:order, completed_at: start_of_july + 9.days, distributor: enterprise) }
- let!(:order6) { create(:order, completed_at: start_of_july + 11.days, distributor: enterprise) }
- let!(:order7) { create(:order, completed_at: start_of_july + 13.days, distributor: enterprise) }
- let!(:order8) { create(:order, completed_at: start_of_july + 15.days, distributor: enterprise) }
- let!(:order9) { create(:order, completed_at: start_of_july + 17.days, distributor: enterprise) }
- let!(:order10) { create(:order, completed_at: start_of_july + 19.days, distributor: enterprise) }
-
- before do
- order1.line_items = [ create(:line_item_with_shipment, price: 12.56, order: order1) ]
- order2.line_items = [ create(:line_item_with_shipment, price: 87.44, order: order2) ]
- order3.line_items = [ create(:line_item_with_shipment, price: 50.00, order: order3) ]
- order4.line_items = [ create(:line_item_with_shipment, price: 73.37, order: order4) ]
- order5.line_items = [ create(:line_item_with_shipment, price: 22.46, order: order5) ]
- order6.line_items = [ create(:line_item_with_shipment, price: 44.85, order: order6) ]
- order7.line_items = [ create(:line_item_with_shipment, price: 93.45, order: order7) ]
- order8.line_items = [ create(:line_item_with_shipment, price: 59.38, order: order8) ]
- order9.line_items = [ create(:line_item_with_shipment, price: 47.23, order: order9) ]
- order10.line_items = [ create(:line_item_with_shipment, price: 2.35, order: order10) ]
- [order1, order2, order3, order4, order5, order6, order7, order8, order9, order10].each(&:update!)
-
- allow(Enterprise).to receive(:where) { double(:enterprises, select: [enterprise]) }
- end
-
- context "super complex example", versioning: true do
- before do
- enterprise.update_attribute(:created_at, start_of_july + 2.days)
-
- Timecop.freeze(start_of_july + 4.days) { enterprise.update_attribute(:sells, 'own') }
-
- Timecop.freeze(start_of_july + 6.days) { enterprise.update_attribute(:owner, new_owner) }
-
- enterprise.update_attribute(:shop_trial_start_date, start_of_july + 8.days)
-
- Timecop.freeze(start_of_july + 10.days) { enterprise.update_attribute(:owner, original_owner) }
-
- Timecop.freeze(start_of_july + 12.days) { enterprise.update_attribute(:sells, 'any') }
-
- allow(enterprise).to receive(:shop_trial_expiry) { start_of_july + 14.days }
-
- Timecop.freeze(start_of_july + 16.days) { enterprise.update_attribute(:sells, 'own') }
-
- Timecop.freeze(start_of_july + 18.days) { enterprise.update_attribute(:owner, new_owner) }
- end
-
- travel_to(20.days)
-
- before do
- UpdateBillablePeriods.new.perform
- end
-
- let(:billable_periods) { BillablePeriod.order(:updated_at) }
-
- it "creates the correct billable periods and deleted obsolete ones" do
- expect(obsolete_bp.reload.deleted_at).to_not be_nil
-
- bp_to_overwrite.reload
-
- expect(bp_to_overwrite.sells).to eq 'own'
- expect(bp_to_overwrite.trial).to be true
- expect(bp_to_overwrite.owner).to eq original_owner
- expect(bp_to_overwrite.begins_at).to eq start_of_july + 10.days
- expect(bp_to_overwrite.ends_at).to eq start_of_july + 12.days
- expect(bp_to_overwrite.turnover).to eq order6.total
- expect(bp_to_overwrite.account_invoice).to eq account_invoice1
-
- expect(billable_periods.count).to eq 9
-
- expect(account_invoice1.billable_periods.sort).to eq billable_periods.sort.select{ |bp| bp.owner == original_owner }
- expect(account_invoice2.billable_periods.sort).to eq billable_periods.sort.select{ |bp| bp.owner == new_owner }
-
- expect(billable_periods.map(&:begins_at)).to eq [
- start_of_july + 2.days,
- start_of_july + 4.days,
- start_of_july + 6.days,
- start_of_july + 8.days,
- start_of_july + 10.days,
- start_of_july + 12.days,
- start_of_july + 14.days,
- start_of_july + 16.days,
- start_of_july + 18.days
- ]
-
- expect(billable_periods.map(&:ends_at)).to eq [
- start_of_july + 4.days,
- start_of_july + 6.days,
- start_of_july + 8.days,
- start_of_july + 10.days,
- start_of_july + 12.days,
- start_of_july + 14.days,
- start_of_july + 16.days,
- start_of_july + 18.days,
- start_of_july + 20.days
- ]
-
- expect(billable_periods.map(&:owner)).to eq [
- original_owner,
- original_owner,
- new_owner,
- new_owner,
- original_owner,
- original_owner,
- original_owner,
- original_owner,
- new_owner
- ]
-
- expect(billable_periods.map(&:sells)).to eq [
- 'any',
- 'own',
- 'own',
- 'own',
- 'own',
- 'any',
- 'any',
- 'own',
- 'own'
- ]
-
- expect(billable_periods.map(&:trial)).to eq [
- false,
- false,
- false,
- true,
- true,
- true,
- false,
- false,
- false
- ]
-
- expect(billable_periods.map(&:turnover)).to eq [
- order2.total,
- order3.total,
- order4.total,
- order5.total,
- order6.total,
- order7.total,
- order8.total,
- order9.total,
- order10.total
- ]
- end
- end
- end
-end
diff --git a/spec/lib/open_food_network/cached_products_renderer_spec.rb b/spec/lib/open_food_network/cached_products_renderer_spec.rb
index 8a3e72a775..6bff04dad2 100644
--- a/spec/lib/open_food_network/cached_products_renderer_spec.rb
+++ b/spec/lib/open_food_network/cached_products_renderer_spec.rb
@@ -5,22 +5,60 @@ module OpenFoodNetwork
describe CachedProductsRenderer do
let(:distributor) { double(:distributor, id: 123) }
let(:order_cycle) { double(:order_cycle, id: 456) }
- let(:cpr) { CachedProductsRenderer.new(distributor, order_cycle) }
+ let(:cached_products_renderer) { CachedProductsRenderer.new(distributor, order_cycle) }
+
+ # keeps global state unchanged
+ around do |example|
+ original_config = Spree::Config[:enable_products_cache?]
+ example.run
+ Spree::Config[:enable_products_cache?] = original_config
+ end
describe "#products_json" do
- context "when in testing / development" do
- let(:products_renderer) do
- double(ProductsRenderer, products_json: 'uncached products')
- end
+ let(:products_renderer) do
+ double(ProductsRenderer, products_json: 'uncached products')
+ end
+ before do
+ allow(ProductsRenderer)
+ .to receive(:new)
+ .with(distributor, order_cycle) { products_renderer }
+ end
+
+ context "products cache toggle" do
before do
- allow(ProductsRenderer)
- .to receive(:new)
- .with(distributor, order_cycle) { products_renderer }
+ allow(Rails.env).to receive(:production?) { true }
+ Rails.cache.write "products-json-#{distributor.id}-#{order_cycle.id}", 'products'
end
- it "returns uncaches products JSON" do
- expect(cpr.products_json).to eq 'uncached products'
+ context "disabled" do
+ before do
+ Spree::Config[:enable_products_cache?] = false
+ end
+
+ it "returns uncached products JSON" do
+ expect(cached_products_renderer.products_json).to eq 'uncached products'
+ end
+ end
+
+ context "enabled" do
+ before do
+ Spree::Config[:enable_products_cache?] = true
+ end
+
+ it "returns the cached JSON" do
+ expect(cached_products_renderer.products_json).to eq 'products'
+ end
+ end
+ end
+
+ context "when in testing / development" do
+ before do
+ allow(Rails.env).to receive(:production?) { false }
+ end
+
+ it "returns uncached products JSON" do
+ expect(cached_products_renderer.products_json).to eq 'uncached products'
end
end
@@ -30,10 +68,10 @@ module OpenFoodNetwork
end
describe "when the distribution is not set" do
- let(:cpr) { CachedProductsRenderer.new(nil, nil) }
+ let(:cached_products_renderer) { CachedProductsRenderer.new(nil, nil) }
it "raises an exception and returns no products" do
- expect { cpr.products_json }.to raise_error CachedProductsRenderer::NoProducts
+ expect { cached_products_renderer.products_json }.to raise_error CachedProductsRenderer::NoProducts
end
end
@@ -43,12 +81,12 @@ module OpenFoodNetwork
end
it "returns the cached JSON" do
- expect(cpr.products_json).to eq 'products'
+ expect(cached_products_renderer.products_json).to eq 'products'
end
it "raises an exception when there are no products" do
Rails.cache.write "products-json-#{distributor.id}-#{order_cycle.id}", nil
- expect { cpr.products_json }.to raise_error CachedProductsRenderer::NoProducts
+ expect { cached_products_renderer.products_json }.to raise_error CachedProductsRenderer::NoProducts
end
end
@@ -70,11 +108,11 @@ module OpenFoodNetwork
describe "when there are products" do
it "returns products as JSON" do
- expect(cpr.products_json).to eq 'fresh products'
+ expect(cached_products_renderer.products_json).to eq 'fresh products'
end
it "caches the JSON" do
- cpr.products_json
+ cached_products_renderer.products_json
expect(cached_json).to eq 'fresh products'
end
end
@@ -91,11 +129,11 @@ module OpenFoodNetwork
end
it "raises an error" do
- expect { cpr.products_json }.to raise_error CachedProductsRenderer::NoProducts
+ expect { cached_products_renderer.products_json }.to raise_error CachedProductsRenderer::NoProducts
end
it "caches the products as nil" do
- expect { cpr.products_json }.to raise_error CachedProductsRenderer::NoProducts
+ expect { cached_products_renderer.products_json }.to raise_error CachedProductsRenderer::NoProducts
expect(cache_present).to be
expect(cached_json).to be_nil
end
diff --git a/spec/lib/open_food_network/lettuce_share_report_spec.rb b/spec/lib/open_food_network/lettuce_share_report_spec.rb
index eb912f58c2..0ca330251c 100644
--- a/spec/lib/open_food_network/lettuce_share_report_spec.rb
+++ b/spec/lib/open_food_network/lettuce_share_report_spec.rb
@@ -50,7 +50,7 @@ module OpenFoodNetwork
end
it "only available items" do
- variant.count_on_hand = 0
+ variant.on_hand = 0
report.stub(:child_variants) { Spree::Variant.where(id: [variant, variant2, variant3, variant4]) }
report.table.count.should eq 3
end
diff --git a/spec/lib/open_food_network/products_renderer_spec.rb b/spec/lib/open_food_network/products_renderer_spec.rb
index a845dfecf5..330ad57062 100644
--- a/spec/lib/open_food_network/products_renderer_spec.rb
+++ b/spec/lib/open_food_network/products_renderer_spec.rb
@@ -50,7 +50,7 @@ module OpenFoodNetwork
it "doesn't return products not in stock" do
variant.update_attribute(:on_demand, false)
- variant.update_attribute(:count_on_hand, 0)
+ variant.update_attribute(:on_hand, 0)
pr.products_json.should_not include product.name
end
diff --git a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb
index 11bf218a1d..55ad5ba2df 100644
--- a/spec/lib/open_food_network/scope_variant_to_hub_spec.rb
+++ b/spec/lib/open_food_network/scope_variant_to_hub_spec.rb
@@ -39,12 +39,12 @@ module OpenFoodNetwork
it "returns the overridden stock level when one is present" do
vo
scoper.scope v
- v.count_on_hand.should == 2
+ v.on_hand.should == 2
end
it "returns the variant's stock level otherwise" do
scoper.scope v
- v.count_on_hand.should == 1
+ v.on_hand.should == 1
end
describe "overriding stock on an on_demand variant" do
@@ -82,13 +82,6 @@ module OpenFoodNetwork
context "without an on_demand set" do
before { vo.update_column(:on_demand, nil) }
- context "when count_on_hand is set" do
- it "returns false" do
- scoper.scope v
- expect(v.on_demand).to be false
- end
- end
-
context "when count_on_hand is not set" do
before { vo.update_column(:count_on_hand, nil) }
@@ -97,6 +90,13 @@ module OpenFoodNetwork
expect(v.on_demand).to be true
end
end
+
+ context "when count_on_hand is set" do
+ it "should return validation error on save" do
+ scoper.scope v
+ expect{ vo.save! }.to raise_error ActiveRecord::RecordInvalid
+ end
+ end
end
end
@@ -131,7 +131,7 @@ module OpenFoodNetwork
end
context "when variant out of stock" do
- before { v.count_on_hand = 0 }
+ before { v.on_hand = 0 }
it "returns true if VO in stock" do
scoper.scope v
@@ -153,7 +153,7 @@ module OpenFoodNetwork
end
it "returns false if variant out of stock" do
- v.count_on_hand = 0
+ v.on_hand = 0
scoper.scope v
expect(v.in_stock?).to eq(false)
end
diff --git a/spec/lib/open_food_network/xero_invoices_report_spec.rb b/spec/lib/open_food_network/xero_invoices_report_spec.rb
index e5ae74d8d0..d2a437d57f 100644
--- a/spec/lib/open_food_network/xero_invoices_report_spec.rb
+++ b/spec/lib/open_food_network/xero_invoices_report_spec.rb
@@ -31,7 +31,6 @@ module OpenFoodNetwork
allow(report).to receive(:shipping_summary_rows) { ['shipping'] }
allow(report).to receive(:payment_summary_rows) { ['payment'] }
allow(report).to receive(:admin_adjustment_summary_rows) { ['admin'] }
- allow(order).to receive(:account_invoice?) { false }
end
it "displays produce summary rows when summary report" do
@@ -46,22 +45,14 @@ module OpenFoodNetwork
it "displays fee summary rows when summary report" do
allow(report).to receive(:detail?) { false }
- allow(order).to receive(:account_invoice?) { true }
expect(summary_rows).to include 'fee'
end
- it "displays fee summary rows when this is not an account invoice" do
+ it "displays fee summary rows when detail report" do
allow(report).to receive(:detail?) { true }
- allow(order).to receive(:account_invoice?) { false }
expect(summary_rows).to include 'fee'
end
- it "does not display fee summary rows when this is a detail report for an account invoice" do
- allow(report).to receive(:detail?) { true }
- allow(order).to receive(:account_invoice?) { true }
- expect(summary_rows).not_to include 'fee'
- end
-
it "always displays shipping summary rows" do
expect(summary_rows).to include 'shipping'
end
@@ -76,24 +67,6 @@ module OpenFoodNetwork
end
end
- describe "finding account invoice adjustments" do
- let(:report) { XeroInvoicesReport.new user, initial_invoice_number: '', invoice_date: '', due_date: '', account_code: '' }
- let!(:order) { create(:order) }
- let(:billable_period) { create(:billable_period) }
- let(:shipping_method) { create(:shipping_method) }
- let!(:adj_invoice) { create(:adjustment, adjustable: order, label: 'Account invoice item', source: billable_period) }
- let!(:adj_shipping) { create(:adjustment, adjustable: order, label: "Shipping", originator: shipping_method) }
-
- it "returns BillablePeriod adjustments only" do
- expect(report.send(:account_invoice_adjustments, order)).to eq([adj_invoice])
- end
-
- it "excludes adjustments where the source is missing" do
- billable_period.destroy
- expect(report.send(:account_invoice_adjustments, order)).to be_empty
- end
- end
-
describe "generating invoice numbers" do
let(:order) { double(:order, number: 'R731032860') }
diff --git a/spec/models/billable_period_spec.rb b/spec/models/billable_period_spec.rb
deleted file mode 100644
index 7095080920..0000000000
--- a/spec/models/billable_period_spec.rb
+++ /dev/null
@@ -1,558 +0,0 @@
-require 'spec_helper'
-
-describe BillablePeriod, type: :model do
-
- require 'spec_helper'
-
- describe 'ensure_correct_adjustment' do
- let!(:start_of_july) { Time.zone.now.beginning_of_year + 6.months }
- let!(:user) { create(:user) }
- let!(:invoice) { create(:order, user: user) }
- let!(:subject) { create(:billable_period, owner: user, begins_at: start_of_july, ends_at: start_of_july + 12.days) }
-
- before do
- allow(subject).to receive(:bill) { 99 }
- allow(subject).to receive(:adjustment_label) { "Label for adjustment" }
- Spree::Config.set({ account_invoices_tax_rate: 0.1 })
- end
-
- context "when no adjustment currently exists" do
- it "creates an adjustment on the given order" do
- expect(invoice.total_tax).to eq 0.0
- expect(subject.adjustment).to be nil
- subject.ensure_correct_adjustment_for(invoice)
- expect(subject.adjustment).to be_a Spree::Adjustment
- expect(invoice.total_tax).to eq 9.0
- end
- end
- end
-
- describe "calculating monthly bills for enterprises with no turnover" do
- let!(:subject) { create(:billable_period, turnover: 0) }
-
- context "when no tax is charged" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
- it { expect(subject.bill).to eq 10 }
- end
-
- context "when no fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when minimum billable turnover is > zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 1) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when no fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
-
- context "when tax is charged" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.1) }
-
- context "when minimum billable turnover is zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
- it { expect(subject.bill).to eq 11 }
- end
-
- context "when no fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when minimum billable turnover is > zero" do
- before { Spree::Config.set(:minimum_billable_turnover, 1) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when no fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
-
- describe "calculating monthly bills for enterprises" do
- let!(:subject) { create(:billable_period, turnover: 100) }
-
- context "when no tax is charged" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0) }
-
- context "when no minimum billable turnover" do
- before { Spree::Config.set(:minimum_billable_turnover, 0) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 65) }
- it { expect(subject.bill).to eq 60 }
- end
-
- context "at a level lower than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 55 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 60 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 15) }
- it { expect(subject.bill).to eq 10 }
- end
-
- context "at a level lower than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 5) }
- it { expect(subject.bill).to eq 5 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 10 }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 50 }
- end
-
- context "at a level lower than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 45) }
- it { expect(subject.bill).to eq 45 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 50 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
-
- context "when turnover is above minimum billable turnover" do
- before { Spree::Config.set(:minimum_billable_turnover, 99) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 65) }
- it { expect(subject.bill).to eq 60 }
- end
-
- context "at a level lower than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 55 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 60 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 15) }
- it { expect(subject.bill).to eq 10 }
- end
-
- context "at a level lower than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 5) }
- it { expect(subject.bill).to eq 5 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 10 }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 50 }
- end
-
- context "at a level lower than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 45) }
- it { expect(subject.bill).to eq 45 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 50 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
-
- context "when turnover is below minimum billable turnover" do
- before { Spree::Config.set(:minimum_billable_turnover, 101) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 65) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 15) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 5) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 55) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 45) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
-
- context "when tax is charged" do
- before { Spree::Config.set(:account_invoices_tax_rate, 0.1) }
-
- context "when turnover is above minimum billable turnover" do
- before { Spree::Config.set(:minimum_billable_turnover, 99) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 61) }
- it { expect(subject.bill).to eq 66 }
- end
-
- context "at a level lower than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 59) }
- it {
- expect(subject.bill.to_f).to eq 64.9
- }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 66 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 11) }
- it { expect(subject.bill).to eq 11 }
- end
-
- context "at a level lower than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 9) }
- it { expect(subject.bill.to_f).to eq 9.9 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 11 }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 51) }
- it { expect(subject.bill).to eq 55 }
- end
-
- context "at a level lower than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 49) }
- it { expect(subject.bill.to_f).to eq 53.9 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 55 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
- end
- end
-
- context "when turnover is below minimum billable turnover" do
- before { Spree::Config.set(:minimum_billable_turnover, 101) }
-
- context "when a fixed cost is included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 10) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 61) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the fixed charge plus the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 59) }
- it {
- expect(subject.bill.to_f).to eq 0
- }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- context "at a level higher than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 11) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the fixed charge" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 9) }
- it { expect(subject.bill.to_f).to eq 0 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
-
- context "when a fixed cost is not included" do
- before { Spree::Config.set(:account_invoices_monthly_fixed, 0) }
-
- context "when a percentage of turnover is included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0.5) }
-
- context "when the bill is capped" do
- context "at a level higher than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 51) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "at a level lower than the product of the rate and turnover" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 49) }
- it { expect(subject.bill.to_f).to eq 0 }
- end
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
-
- context "when a percentage of turnover is not included" do
- before { Spree::Config.set(:account_invoices_monthly_rate, 0) }
-
- context "when the bill is capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 20) }
- it { expect(subject.bill).to eq 0 }
- end
-
- context "when the bill is not capped" do
- before { Spree::Config.set(:account_invoices_monthly_cap, 0) }
- it { expect(subject.bill).to eq 0 }
- end
- end
- end
- end
- end
-end
diff --git a/spec/models/concerns/variant_stock_spec.rb b/spec/models/concerns/variant_stock_spec.rb
index 50c89671e4..0c521ac3e6 100644
--- a/spec/models/concerns/variant_stock_spec.rb
+++ b/spec/models/concerns/variant_stock_spec.rb
@@ -18,15 +18,15 @@ describe VariantStock do
end
describe '#on_hand' do
- context 'when the variant is ordered on demand' do
+ context 'when the variant is on demand' do
before do
variant.stock_items.first.update_attribute(
:backorderable, true
)
end
- it 'returns infinite' do
- expect(variant.on_hand).to eq(Float::INFINITY)
+ it 'returns the total items in stock anyway' do
+ expect(variant.on_hand).to eq(variant.stock_items.sum(&:count_on_hand))
end
end
@@ -44,28 +44,27 @@ describe VariantStock do
end
end
- describe '#count_on_hand' do
- before { allow(variant).to receive(:total_on_hand) }
-
- it 'delegates to #total_on_hand' do
- variant.count_on_hand
- expect(variant).to have_received(:total_on_hand)
- end
- end
-
describe '#on_hand=' do
context 'when track_inventory_levels is set' do
before do
- allow(variant).to receive(:count_on_hand=)
allow(Spree::Config)
.to receive(:track_inventory_levels) { true }
end
- it 'delegates to #count_on_hand=' do
+ it 'sets the new level as the stock item\'s count_on_hand' do
variant.on_hand = 3
- expect(variant)
- .to have_received(:count_on_hand=).with(3)
+ unique_stock_item = variant.stock_items.first
+ expect(unique_stock_item.count_on_hand).to eq(3)
end
+
+ context 'when the variant has no stock item' do
+ let(:variant) { build(:variant) }
+
+ it 'raises' do
+ expect { variant.on_hand = 3 }
+ .to raise_error(StandardError)
+ end
+ end
end
context 'when track_inventory_levels is not set' do
@@ -81,27 +80,6 @@ describe VariantStock do
end
end
- describe '#count_on_hand=' do
- context 'when the variant has a stock item' do
- let(:variant) { create(:variant) }
-
- it 'sets the new level as the stock item\'s count_on_hand' do
- variant.count_on_hand = 3
- unique_stock_item = variant.stock_items.first
- expect(unique_stock_item.count_on_hand).to eq(3)
- end
- end
-
- context 'when the variant has no stock item' do
- let(:variant) { build(:variant) }
-
- it 'raises' do
- expect { variant.count_on_hand = 3 }
- .to raise_error(StandardError)
- end
- end
- end
-
describe '#on_demand' do
context 'when the variant has a stock item' do
let(:variant) { create(:variant) }
@@ -187,7 +165,7 @@ describe VariantStock do
end
context 'when variant out of stock' do
- before { variant.count_on_hand = 0 }
+ before { variant.on_hand = 0 }
it "returns true for zero" do
expect(variant.can_supply?(0)).to eq(true)
diff --git a/spec/models/order_cycle_spec.rb b/spec/models/order_cycle_spec.rb
index aec7f61cd8..16a024f1a3 100644
--- a/spec/models/order_cycle_spec.rb
+++ b/spec/models/order_cycle_spec.rb
@@ -523,20 +523,31 @@ describe OrderCycle do
let(:shop) { create(:enterprise) }
let(:user) { create(:user) }
let(:oc) { create(:order_cycle) }
- let!(:order1) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: oc) }
- let!(:order2) { create(:completed_order_with_totals, distributor: create(:enterprise), user: user, order_cycle: oc) }
- let!(:order3) { create(:completed_order_with_totals, distributor: shop, user: create(:user), order_cycle: oc) }
- let!(:order4) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: create(:order_cycle)) }
- let!(:order5) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: oc) }
+ let!(:order) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: oc) }
+ let!(:order_from_other_hub) { create(:completed_order_with_totals, distributor: create(:enterprise), user: user, order_cycle: oc) }
+ let!(:order_from_other_user) { create(:completed_order_with_totals, distributor: shop, user: create(:user), order_cycle: oc) }
+ let!(:order_from_other_oc) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: create(:order_cycle)) }
+ let!(:order_cancelled) { create(:completed_order_with_totals, distributor: shop, user: user, order_cycle: oc) }
before do
setup_email
end
- before { order5.cancel }
+ before { order_cancelled.cancel }
it "only returns items from non-cancelled orders in the OC, placed by the user at the shop" do
items = oc.items_bought_by_user(user, shop)
- expect(items).to match_array order1.reload.line_items
+ expect(items).to match_array order.reload.line_items
+ end
+
+ it "returns items with scoped variants" do
+ overridden_variant = order.line_items.first.variant
+ create(:variant_override, hub: shop, variant: overridden_variant, count_on_hand: 1000)
+
+ items = oc.items_bought_by_user(user, shop)
+
+ expect(items).to match_array order.reload.line_items
+ item_with_overridden_variant = items.find { |item| item.variant_id == overridden_variant.id }
+ expect(item_with_overridden_variant.variant.on_hand).to eq(1000)
end
end
end
diff --git a/spec/models/product_import/products_reset_strategy_spec.rb b/spec/models/product_import/products_reset_strategy_spec.rb
index c3aa64a00b..e44249e8a3 100644
--- a/spec/models/product_import/products_reset_strategy_spec.rb
+++ b/spec/models/product_import/products_reset_strategy_spec.rb
@@ -9,7 +9,7 @@ describe ProductImport::ProductsResetStrategy do
let(:enterprise) { product.supplier }
let(:variant) { product.variants.first }
- before { variant.count_on_hand = 2 }
+ before { variant.on_hand = 2 }
context 'when there are excluded_items_ids' do
let(:excluded_items_ids) { [variant.id] }
@@ -17,35 +17,35 @@ describe ProductImport::ProductsResetStrategy do
context 'and supplier_ids is []' do
let(:supplier_ids) { [] }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is nil' do
let(:supplier_ids) { nil }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is set' do
- it 'does not update the count_on_hand of the excluded items' do
+ it 'does not update the on_hand of the excluded items' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
- it 'updates the count_on_hand of the non-excluded items' do
+ it 'updates the on_hand of the non-excluded items' do
non_excluded_variant = create(
:variant,
product: variant.product
)
- non_excluded_variant.count_on_hand = 3
+ non_excluded_variant.on_hand = 3
products_reset.reset(supplier_ids)
- expect(non_excluded_variant.reload.count_on_hand).to eq(0)
+ expect(non_excluded_variant.reload.on_hand).to eq(0)
end
end
end
@@ -56,31 +56,31 @@ describe ProductImport::ProductsResetStrategy do
context 'and supplier_ids is []' do
let(:supplier_ids) { [] }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is nil' do
let(:supplier_ids) { nil }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is not nil' do
- it 'sets all count_on_hand to 0' do
+ it 'sets all on_hand to 0' do
updated_records_count = products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(0)
+ expect(variant.reload.on_hand).to eq(0)
expect(updated_records_count).to eq(1)
end
context 'and there is an unresetable variant' do
before do
- variant.stock_items = [] # this makes variant.count_on_hand raise an error
+ variant.stock_items = [] # this makes variant.on_hand raise an error
end
it 'returns correct number of resetted variants' do
@@ -96,24 +96,24 @@ describe ProductImport::ProductsResetStrategy do
context 'and supplier_ids is []' do
let(:supplier_ids) { [] }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is nil' do
let(:supplier_ids) { nil }
- it 'does not reset the variant.count_on_hand' do
+ it 'does not reset the variant.on_hand' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(2)
+ expect(variant.reload.on_hand).to eq(2)
end
end
context 'and supplier_ids is nil' do
- it 'sets all count_on_hand to 0' do
+ it 'sets all on_hand to 0' do
products_reset.reset(supplier_ids)
- expect(variant.reload.count_on_hand).to eq(0)
+ expect(variant.reload.on_hand).to eq(0)
end
end
end
diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb
index 305ba29138..952ca743b7 100644
--- a/spec/models/spree/order_spec.rb
+++ b/spec/models/spree/order_spec.rb
@@ -533,24 +533,6 @@ describe Spree::Order do
end
end
- describe "checking if an order is an account invoice" do
- let(:accounts_distributor) { create(:distributor_enterprise) }
- let(:order_account_invoice) { create(:order, distributor: accounts_distributor) }
- let(:order_general) { create(:order, distributor: create(:distributor_enterprise)) }
-
- before do
- Spree::Config.accounts_distributor_id = accounts_distributor.id
- end
-
- it "returns true when the order is distributed by the accounts distributor" do
- order_account_invoice.should be_account_invoice
- end
-
- it "returns false otherwise" do
- order_general.should_not be_account_invoice
- end
- end
-
describe "sending confirmation emails" do
let!(:distributor) { create(:distributor_enterprise) }
let!(:order) { create(:order, distributor: distributor) }
@@ -561,14 +543,6 @@ describe Spree::Order do
end.to enqueue_job ConfirmOrderJob
end
- it "does not send confirmation emails when distributor is the accounts_distributor" do
- Spree::Config.set({ accounts_distributor_id: distributor.id })
-
- expect do
- order.deliver_order_confirmation_email
- end.to_not enqueue_job ConfirmOrderJob
- end
-
it "does not send confirmation emails when the order belongs to a subscription" do
create(:proxy_order, order: order)
diff --git a/spec/models/spree/product_spec.rb b/spec/models/spree/product_spec.rb
index a060e34a09..d3678cda68 100644
--- a/spec/models/spree/product_spec.rb
+++ b/spec/models/spree/product_spec.rb
@@ -629,14 +629,14 @@ module Spree
describe "stock filtering" do
it "considers products that are on_demand as being in stock" do
product = create(:simple_product, on_demand: true)
- product.master.update_attribute(:count_on_hand, 0)
+ product.master.update_attribute(:on_hand, 0)
product.has_stock?.should == true
end
describe "finding products in stock for a particular distribution" do
it "returns on-demand products" do
p = create(:simple_product, on_demand: true)
- p.variants.first.update_attributes!(count_on_hand: 0, on_demand: true)
+ p.variants.first.update_attributes!(on_hand: 0, on_demand: true)
d = create(:distributor_enterprise)
oc = create(:simple_order_cycle, distributors: [d])
oc.exchanges.outgoing.first.variants << p.variants.first
@@ -647,7 +647,7 @@ module Spree
it "returns products with in-stock variants" do
p = create(:simple_product)
v = create(:variant, product: p)
- v.update_attribute(:count_on_hand, 1)
+ v.update_attribute(:on_hand, 1)
d = create(:distributor_enterprise)
oc = create(:simple_order_cycle, distributors: [d])
oc.exchanges.outgoing.first.variants << v
@@ -658,7 +658,7 @@ module Spree
it "returns products with on-demand variants" do
p = create(:simple_product)
v = create(:variant, product: p, on_demand: true)
- v.update_attribute(:count_on_hand, 0)
+ v.update_attribute(:on_hand, 0)
d = create(:distributor_enterprise)
oc = create(:simple_order_cycle, distributors: [d])
oc.exchanges.outgoing.first.variants << v
@@ -668,7 +668,7 @@ module Spree
it "does not return products that have stock not in the distribution" do
p = create(:simple_product)
- p.master.update_attribute(:count_on_hand, 1)
+ p.master.update_attribute(:on_hand, 1)
d = create(:distributor_enterprise)
oc = create(:simple_order_cycle, distributors: [d])
diff --git a/spec/requests/shop_spec.rb b/spec/requests/shop_spec.rb
index 359549fa41..c73e8bd099 100644
--- a/spec/requests/shop_spec.rb
+++ b/spec/requests/shop_spec.rb
@@ -23,15 +23,15 @@ describe "Shop API", type: :request do
before do
set_order order
- v61.update_attribute(:count_on_hand, 1)
+ v61.update_attribute(:on_hand, 1)
p6.destroy
- v71.update_attribute(:count_on_hand, 1)
- v41.update_attribute(:count_on_hand, 1)
- v42.update_attribute(:count_on_hand, 0)
- v43.update_attribute(:count_on_hand, 0)
- v51.update_attribute(:count_on_hand, 1)
- v52.update_attribute(:count_on_hand, 0)
- v71.update_attribute(:count_on_hand, 1)
+ v71.update_attribute(:on_hand, 1)
+ v41.update_attribute(:on_hand, 1)
+ v42.update_attribute(:on_hand, 0)
+ v43.update_attribute(:on_hand, 0)
+ v51.update_attribute(:on_hand, 1)
+ v52.update_attribute(:on_hand, 0)
+ v71.update_attribute(:on_hand, 1)
v71.update_attribute(:deleted_at, Time.zone.now)
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
exchange.update_attribute :pickup_time, "frogs"
diff --git a/spec/serializers/variant_serializer_spec.rb b/spec/serializers/variant_serializer_spec.rb
index 3c6aebf6a9..583412ff56 100644
--- a/spec/serializers/variant_serializer_spec.rb
+++ b/spec/serializers/variant_serializer_spec.rb
@@ -10,7 +10,7 @@ describe Api::VariantSerializer do
:id,
:name_to_display,
:is_master,
- :count_on_hand,
+ :on_hand,
:name_to_display,
:unit_to_display,
:unit_value,
diff --git a/spec/services/order_factory_spec.rb b/spec/services/order_factory_spec.rb
index 3755f69e8e..672ac0a780 100644
--- a/spec/services/order_factory_spec.rb
+++ b/spec/services/order_factory_spec.rb
@@ -55,7 +55,7 @@ describe OrderFactory do
context "when requested quantity is greater than available stock" do
context "when no override is present" do
before do
- variant1.update_attribute(:count_on_hand, 2)
+ variant1.update_attribute(:on_hand, 2)
attrs[:line_items].first[:quantity] = 5
end
diff --git a/spec/services/order_syncer_spec.rb b/spec/services/order_syncer_spec.rb
index e1ee400fc8..8645eb674e 100644
--- a/spec/services/order_syncer_spec.rb
+++ b/spec/services/order_syncer_spec.rb
@@ -292,7 +292,7 @@ describe OrderSyncer do
let(:sli) { subscription.subscription_line_items.first }
let(:variant) { sli.variant }
- before { variant.update_attribute(:count_on_hand, 2) }
+ before { variant.update_attribute(:on_hand, 2) }
context "when quantity is within available stock" do
let(:params) { { subscription_line_items_attributes: [{ id: sli.id, quantity: 2}] } }
@@ -327,7 +327,7 @@ describe OrderSyncer do
let(:syncer) { OrderSyncer.new(subscription) }
let(:changed_line_item) { order.line_items.find_by_variant_id(sli.variant_id) }
- before { variant.update_attribute(:count_on_hand, 3) }
+ before { variant.update_attribute(:on_hand, 3) }
context "when the changed line_item quantity matches the new quantity on the subscription line item" do
before { changed_line_item.update_attributes(quantity: 3) }
diff --git a/spec/services/variants_stock_levels_spec.rb b/spec/services/variants_stock_levels_spec.rb
index a7e788d657..f4a77d7018 100644
--- a/spec/services/variants_stock_levels_spec.rb
+++ b/spec/services/variants_stock_levels_spec.rb
@@ -12,39 +12,39 @@ describe VariantsStockLevels do
let(:variant_stock_levels) { VariantsStockLevels.new }
before do
- variant_in_the_order.count_on_hand = 4
- variant_not_in_the_order.count_on_hand = 2
+ variant_in_the_order.on_hand = 4
+ variant_not_in_the_order.on_hand = 2
order.reload
end
- it "returns a hash with variant id, quantity, max_quantity and stock on hand" do
+ it "returns a hash with variant id, quantity, max_quantity, on hand and on demand" do
expect(variant_stock_levels.call(order, [variant_in_the_order.id])).to eq(
- variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4 }
+ variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4, on_demand: false }
)
end
it "includes all line items, even when the variant_id is not specified" do
expect(variant_stock_levels.call(order, [])).to eq(
- variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4 }
+ variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4, on_demand: false }
)
end
it "includes an empty quantity entry for variants that aren't in the order" do
variant_ids = [variant_in_the_order.id, variant_not_in_the_order.id]
expect(variant_stock_levels.call(order, variant_ids)).to eq(
- variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4 },
- variant_not_in_the_order.id => { quantity: 0, max_quantity: 0, on_hand: 2 }
+ variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 4, on_demand: false },
+ variant_not_in_the_order.id => { quantity: 0, max_quantity: 0, on_hand: 2, on_demand: false }
)
end
- describe "encoding Infinity" do
+ describe "when variant is on_demand" do
let!(:variant_in_the_order) { create(:variant, on_demand: true) }
- before { variant_in_the_order.count_on_hand = 0 }
+ before { variant_in_the_order.on_hand = 0 }
- it "encodes Infinity as a large, finite integer" do
+ it "includes the actual on_hand value and on_demand: true" do
expect(variant_stock_levels.call(order, [variant_in_the_order.id])).to eq(
- variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 2147483647 }
+ variant_in_the_order.id => { quantity: 2, max_quantity: 3, on_hand: 0, on_demand: true }
)
end
end
diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb
index 912c19e445..52ffc306ac 100644
--- a/spec/support/request/web_helper.rb
+++ b/spec/support/request/web_helper.rb
@@ -152,8 +152,23 @@ module WebHelper
page.driver.browser.switch_to.alert.accept
end
+ def angular_http_requests_finished(controller=nil)
+ page.evaluate_script("#{angular_scope(controller)}.injector().get('$http').pendingRequests.length == 0")
+ end
+
+ def request_monitor_finished(controller=nil)
+ page.evaluate_script("#{angular_scope(controller)}.scope().RequestMonitor.loading == false")
+ end
+
private
+ # Takes an optional angular controller name eg: "LineItemsCtrl",
+ # otherwise finds the first object in the DOM with an angular scope
+ def angular_scope(controller=nil)
+ element = controller ? "[ng-controller=#{controller}]" : '.ng-scope'
+ "angular.element(document.querySelector('#{element}'))"
+ end
+
def wait_for_ajax
wait_until { page.evaluate_script("$.active") == 0 }
end
diff --git a/vendor/assets/javascripts/jquery-ui-timepicker-addon.js b/vendor/assets/javascripts/jquery-ui-timepicker-addon.js
new file mode 100644
index 0000000000..d37bc02b48
--- /dev/null
+++ b/vendor/assets/javascripts/jquery-ui-timepicker-addon.js
@@ -0,0 +1,2291 @@
+/*! jQuery Timepicker Addon - v1.6.3 - 2016-04-20
+* http://trentrichardson.com/examples/timepicker
+* Copyright (c) 2016 Trent Richardson; Licensed MIT */
+(function (factory) {
+ if (typeof define === 'function' && define.amd) {
+ define(['jquery', 'jquery-ui'], factory);
+ } else {
+ factory(jQuery);
+ }
+}(function ($) {
+
+ /*
+ * Lets not redefine timepicker, Prevent "Uncaught RangeError: Maximum call stack size exceeded"
+ */
+ $.ui.timepicker = $.ui.timepicker || {};
+ if ($.ui.timepicker.version) {
+ return;
+ }
+
+ /*
+ * Extend jQueryUI, get it started with our version number
+ */
+ $.extend($.ui, {
+ timepicker: {
+ version: "1.6.3"
+ }
+ });
+
+ /*
+ * Timepicker manager.
+ * Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+ * Settings for (groups of) time pickers are maintained in an instance object,
+ * allowing multiple different settings on the same page.
+ */
+ var Timepicker = function () {
+ this.regional = []; // Available regional settings, indexed by language code
+ this.regional[''] = { // Default regional settings
+ currentText: 'Now',
+ closeText: 'Done',
+ amNames: ['AM', 'A'],
+ pmNames: ['PM', 'P'],
+ timeFormat: 'HH:mm',
+ timeSuffix: '',
+ timeOnlyTitle: 'Choose Time',
+ timeText: 'Time',
+ hourText: 'Hour',
+ minuteText: 'Minute',
+ secondText: 'Second',
+ millisecText: 'Millisecond',
+ microsecText: 'Microsecond',
+ timezoneText: 'Time Zone',
+ isRTL: false
+ };
+ this._defaults = { // Global defaults for all the datetime picker instances
+ showButtonPanel: true,
+ timeOnly: false,
+ timeOnlyShowDate: false,
+ showHour: null,
+ showMinute: null,
+ showSecond: null,
+ showMillisec: null,
+ showMicrosec: null,
+ showTimezone: null,
+ showTime: true,
+ stepHour: 1,
+ stepMinute: 1,
+ stepSecond: 1,
+ stepMillisec: 1,
+ stepMicrosec: 1,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMin: 0,
+ minuteMin: 0,
+ secondMin: 0,
+ millisecMin: 0,
+ microsecMin: 0,
+ hourMax: 23,
+ minuteMax: 59,
+ secondMax: 59,
+ millisecMax: 999,
+ microsecMax: 999,
+ minDateTime: null,
+ maxDateTime: null,
+ maxTime: null,
+ minTime: null,
+ onSelect: null,
+ hourGrid: 0,
+ minuteGrid: 0,
+ secondGrid: 0,
+ millisecGrid: 0,
+ microsecGrid: 0,
+ alwaysSetTime: true,
+ separator: ' ',
+ altFieldTimeOnly: true,
+ altTimeFormat: null,
+ altSeparator: null,
+ altTimeSuffix: null,
+ altRedirectFocus: true,
+ pickerTimeFormat: null,
+ pickerTimeSuffix: null,
+ showTimepicker: true,
+ timezoneList: null,
+ addSliderAccess: false,
+ sliderAccessArgs: null,
+ controlType: 'slider',
+ oneLine: false,
+ defaultValue: null,
+ parse: 'strict',
+ afterInject: null
+ };
+ $.extend(this._defaults, this.regional['']);
+ };
+
+ $.extend(Timepicker.prototype, {
+ $input: null,
+ $altInput: null,
+ $timeObj: null,
+ inst: null,
+ hour_slider: null,
+ minute_slider: null,
+ second_slider: null,
+ millisec_slider: null,
+ microsec_slider: null,
+ timezone_select: null,
+ maxTime: null,
+ minTime: null,
+ hour: 0,
+ minute: 0,
+ second: 0,
+ millisec: 0,
+ microsec: 0,
+ timezone: null,
+ hourMinOriginal: null,
+ minuteMinOriginal: null,
+ secondMinOriginal: null,
+ millisecMinOriginal: null,
+ microsecMinOriginal: null,
+ hourMaxOriginal: null,
+ minuteMaxOriginal: null,
+ secondMaxOriginal: null,
+ millisecMaxOriginal: null,
+ microsecMaxOriginal: null,
+ ampm: '',
+ formattedDate: '',
+ formattedTime: '',
+ formattedDateTime: '',
+ timezoneList: null,
+ units: ['hour', 'minute', 'second', 'millisec', 'microsec'],
+ support: {},
+ control: null,
+
+ /*
+ * Override the default settings for all instances of the time picker.
+ * @param {Object} settings object - the new settings to use as defaults (anonymous object)
+ * @return {Object} the manager object
+ */
+ setDefaults: function (settings) {
+ extendRemove(this._defaults, settings || {});
+ return this;
+ },
+
+ /*
+ * Create a new Timepicker instance
+ */
+ _newInst: function ($input, opts) {
+ var tp_inst = new Timepicker(),
+ inlineSettings = {},
+ fns = {},
+ overrides, i;
+
+ for (var attrName in this._defaults) {
+ if (this._defaults.hasOwnProperty(attrName)) {
+ var attrValue = $input.attr('time:' + attrName);
+ if (attrValue) {
+ try {
+ inlineSettings[attrName] = eval(attrValue);
+ } catch (err) {
+ inlineSettings[attrName] = attrValue;
+ }
+ }
+ }
+ }
+
+ overrides = {
+ beforeShow: function (input, dp_inst) {
+ if ($.isFunction(tp_inst._defaults.evnts.beforeShow)) {
+ return tp_inst._defaults.evnts.beforeShow.call($input[0], input, dp_inst, tp_inst);
+ }
+ },
+ onChangeMonthYear: function (year, month, dp_inst) {
+ // Update the time as well : this prevents the time from disappearing from the $input field.
+ // tp_inst._updateDateTime(dp_inst);
+ if ($.isFunction(tp_inst._defaults.evnts.onChangeMonthYear)) {
+ tp_inst._defaults.evnts.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+ }
+ },
+ onClose: function (dateText, dp_inst) {
+ if (tp_inst.timeDefined === true && $input.val() !== '') {
+ tp_inst._updateDateTime(dp_inst);
+ }
+ if ($.isFunction(tp_inst._defaults.evnts.onClose)) {
+ tp_inst._defaults.evnts.onClose.call($input[0], dateText, dp_inst, tp_inst);
+ }
+ }
+ };
+ for (i in overrides) {
+ if (overrides.hasOwnProperty(i)) {
+ fns[i] = opts[i] || this._defaults[i] || null;
+ }
+ }
+
+ tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, opts, overrides, {
+ evnts: fns,
+ timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+ });
+ tp_inst.amNames = $.map(tp_inst._defaults.amNames, function (val) {
+ return val.toUpperCase();
+ });
+ tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function (val) {
+ return val.toUpperCase();
+ });
+
+ // detect which units are supported
+ tp_inst.support = detectSupport(
+ tp_inst._defaults.timeFormat +
+ (tp_inst._defaults.pickerTimeFormat ? tp_inst._defaults.pickerTimeFormat : '') +
+ (tp_inst._defaults.altTimeFormat ? tp_inst._defaults.altTimeFormat : ''));
+
+ // controlType is string - key to our this._controls
+ if (typeof(tp_inst._defaults.controlType) === 'string') {
+ if (tp_inst._defaults.controlType === 'slider' && typeof($.ui.slider) === 'undefined') {
+ tp_inst._defaults.controlType = 'select';
+ }
+ tp_inst.control = tp_inst._controls[tp_inst._defaults.controlType];
+ }
+ // controlType is an object and must implement create, options, value methods
+ else {
+ tp_inst.control = tp_inst._defaults.controlType;
+ }
+
+ // prep the timezone options
+ var timezoneList = [-720, -660, -600, -570, -540, -480, -420, -360, -300, -270, -240, -210, -180, -120, -60,
+ 0, 60, 120, 180, 210, 240, 270, 300, 330, 345, 360, 390, 420, 480, 525, 540, 570, 600, 630, 660, 690, 720, 765, 780, 840];
+ if (tp_inst._defaults.timezoneList !== null) {
+ timezoneList = tp_inst._defaults.timezoneList;
+ }
+ var tzl = timezoneList.length, tzi = 0, tzv = null;
+ if (tzl > 0 && typeof timezoneList[0] !== 'object') {
+ for (; tzi < tzl; tzi++) {
+ tzv = timezoneList[tzi];
+ timezoneList[tzi] = { value: tzv, label: $.timepicker.timezoneOffsetString(tzv, tp_inst.support.iso8601) };
+ }
+ }
+ tp_inst._defaults.timezoneList = timezoneList;
+
+ // set the default units
+ tp_inst.timezone = tp_inst._defaults.timezone !== null ? $.timepicker.timezoneOffsetNumber(tp_inst._defaults.timezone) :
+ ((new Date()).getTimezoneOffset() * -1);
+ tp_inst.hour = tp_inst._defaults.hour < tp_inst._defaults.hourMin ? tp_inst._defaults.hourMin :
+ tp_inst._defaults.hour > tp_inst._defaults.hourMax ? tp_inst._defaults.hourMax : tp_inst._defaults.hour;
+ tp_inst.minute = tp_inst._defaults.minute < tp_inst._defaults.minuteMin ? tp_inst._defaults.minuteMin :
+ tp_inst._defaults.minute > tp_inst._defaults.minuteMax ? tp_inst._defaults.minuteMax : tp_inst._defaults.minute;
+ tp_inst.second = tp_inst._defaults.second < tp_inst._defaults.secondMin ? tp_inst._defaults.secondMin :
+ tp_inst._defaults.second > tp_inst._defaults.secondMax ? tp_inst._defaults.secondMax : tp_inst._defaults.second;
+ tp_inst.millisec = tp_inst._defaults.millisec < tp_inst._defaults.millisecMin ? tp_inst._defaults.millisecMin :
+ tp_inst._defaults.millisec > tp_inst._defaults.millisecMax ? tp_inst._defaults.millisecMax : tp_inst._defaults.millisec;
+ tp_inst.microsec = tp_inst._defaults.microsec < tp_inst._defaults.microsecMin ? tp_inst._defaults.microsecMin :
+ tp_inst._defaults.microsec > tp_inst._defaults.microsecMax ? tp_inst._defaults.microsecMax : tp_inst._defaults.microsec;
+ tp_inst.ampm = '';
+ tp_inst.$input = $input;
+
+ if (tp_inst._defaults.altField) {
+ tp_inst.$altInput = $(tp_inst._defaults.altField);
+ if (tp_inst._defaults.altRedirectFocus === true) {
+ tp_inst.$altInput.css({
+ cursor: 'pointer'
+ }).focus(function () {
+ $input.trigger("focus");
+ });
+ }
+ }
+
+ if (tp_inst._defaults.minDate === 0 || tp_inst._defaults.minDateTime === 0) {
+ tp_inst._defaults.minDate = new Date();
+ }
+ if (tp_inst._defaults.maxDate === 0 || tp_inst._defaults.maxDateTime === 0) {
+ tp_inst._defaults.maxDate = new Date();
+ }
+
+ // datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+ if (tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date) {
+ tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+ }
+ if (tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date) {
+ tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+ }
+ if (tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date) {
+ tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+ }
+ if (tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date) {
+ tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+ }
+ tp_inst.$input.bind('focus', function () {
+ tp_inst._onFocus();
+ });
+
+ return tp_inst;
+ },
+
+ /*
+ * add our sliders to the calendar
+ */
+ _addTimePicker: function (dp_inst) {
+ var currDT = $.trim((this.$altInput && this._defaults.altFieldTimeOnly) ? this.$input.val() + ' ' + this.$altInput.val() : this.$input.val());
+
+ this.timeDefined = this._parseTime(currDT);
+ this._limitMinMaxDateTime(dp_inst, false);
+ this._injectTimePicker();
+ this._afterInject();
+ },
+
+ /*
+ * parse the time string from input value or _setTime
+ */
+ _parseTime: function (timeString, withDate) {
+ if (!this.inst) {
+ this.inst = $.datepicker._getInst(this.$input[0]);
+ }
+
+ if (withDate || !this._defaults.timeOnly) {
+ var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+ try {
+ var parseRes = parseDateTimeInternal(dp_dateFormat, this._defaults.timeFormat, timeString, $.datepicker._getFormatConfig(this.inst), this._defaults);
+ if (!parseRes.timeObj) {
+ return false;
+ }
+ $.extend(this, parseRes.timeObj);
+ } catch (err) {
+ $.timepicker.log("Error parsing the date/time string: " + err +
+ "\ndate/time string = " + timeString +
+ "\ntimeFormat = " + this._defaults.timeFormat +
+ "\ndateFormat = " + dp_dateFormat);
+ return false;
+ }
+ return true;
+ } else {
+ var timeObj = $.datepicker.parseTime(this._defaults.timeFormat, timeString, this._defaults);
+ if (!timeObj) {
+ return false;
+ }
+ $.extend(this, timeObj);
+ return true;
+ }
+ },
+
+ /*
+ * Handle callback option after injecting timepicker
+ */
+ _afterInject: function() {
+ var o = this.inst.settings;
+ if ($.isFunction(o.afterInject)) {
+ o.afterInject.call(this);
+ }
+ },
+
+ /*
+ * generate and inject html for timepicker into ui datepicker
+ */
+ _injectTimePicker: function () {
+ var $dp = this.inst.dpDiv,
+ o = this.inst.settings,
+ tp_inst = this,
+ litem = '',
+ uitem = '',
+ show = null,
+ max = {},
+ gridSize = {},
+ size = null,
+ i = 0,
+ l = 0;
+
+ // Prevent displaying twice
+ if ($dp.find("div.ui-timepicker-div").length === 0 && o.showTimepicker) {
+ var noDisplay = ' ui_tpicker_unit_hide',
+ html = '
' + '
' + o.timeText + '
' +
+ '';
+
+ // Create the markup
+ for (i = 0, l = this.units.length; i < l; i++) {
+ litem = this.units[i];
+ uitem = litem.substr(0, 1).toUpperCase() + litem.substr(1);
+ show = o['show' + uitem] !== null ? o['show' + uitem] : this.support[litem];
+
+ // Added by Peter Medeiros:
+ // - Figure out what the hour/minute/second max should be based on the step values.
+ // - Example: if stepMinute is 15, then minMax is 45.
+ max[litem] = parseInt((o[litem + 'Max'] - ((o[litem + 'Max'] - o[litem + 'Min']) % o['step' + uitem])), 10);
+ gridSize[litem] = 0;
+
+ html += '
' + o[litem + 'Text'] + '
' +
+ '
';
+
+ if (show && o[litem + 'Grid'] > 0) {
+ html += '
';
+
+ if (litem === 'hour') {
+ for (var h = o[litem + 'Min']; h <= max[litem]; h += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ var tmph = $.datepicker.formatTime(this.support.ampm ? 'hht' : 'HH', {hour: h}, o);
+ html += '
' + tmph + '
';
+ }
+ }
+ else {
+ for (var m = o[litem + 'Min']; m <= max[litem]; m += parseInt(o[litem + 'Grid'], 10)) {
+ gridSize[litem]++;
+ html += '