From 1fba998b9eaedfde6ab5ce7f85bf1f29e3887560 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Thu, 28 May 2020 19:04:18 +0100 Subject: [PATCH 001/261] Drop Blockenspiel and use :rules/:columns methods instead of :organise/:summary_columns DSL. For https://github.com/openfoodfoundation/openfoodnetwork/issues/3231 --- Gemfile | 1 - Gemfile.lock | 2 - .../reports/bulk_coop_allocation_report.rb | 77 ++++++++--------- .../reports/bulk_coop_report.rb | 86 +++++++++---------- .../reports/bulk_coop_supplier_report.rb | 76 ++++++++-------- lib/open_food_network/reports/report.rb | 10 --- lib/open_food_network/reports/row.rb | 2 - lib/open_food_network/reports/rule.rb | 11 --- .../open_food_network/reports/report_spec.rb | 83 ------------------ .../open_food_network/reports/rule_spec.rb | 18 ---- 10 files changed, 117 insertions(+), 249 deletions(-) diff --git a/Gemfile b/Gemfile index c2d772e8d3..861e193b16 100644 --- a/Gemfile +++ b/Gemfile @@ -65,7 +65,6 @@ gem 'unicorn' gem "active_model_serializers", "0.8.4" gem 'acts-as-taggable-on', '~> 3.4' gem 'angularjs-file-upload-rails', '~> 2.4.1' -gem 'blockenspiel' gem 'custom_error_message', github: 'jeremydurham/custom-err-msg' gem 'dalli' gem 'diffy' diff --git a/Gemfile.lock b/Gemfile.lock index 12760634af..dc1aa80cf5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -146,7 +146,6 @@ GEM bcrypt (3.1.13) bcrypt-ruby (3.1.5) bcrypt (>= 3.1.3) - blockenspiel (0.5.0) bugsnag (6.13.1) concurrent-ruby (~> 1.0) builder (3.0.4) @@ -698,7 +697,6 @@ DEPENDENCIES atomic awesome_print aws-sdk - blockenspiel bugsnag byebug (~> 11.0.0) capybara (>= 2.18.0) diff --git a/lib/open_food_network/reports/bulk_coop_allocation_report.rb b/lib/open_food_network/reports/bulk_coop_allocation_report.rb index f132e642df..c8b05c30a0 100644 --- a/lib/open_food_network/reports/bulk_coop_allocation_report.rb +++ b/lib/open_food_network/reports/bulk_coop_allocation_report.rb @@ -18,47 +18,46 @@ module OpenFoodNetwork::Reports ] end - organise do - group(&:product) - sort(&:name) - - summary_row do - column { |_lis| I18n.t('admin.reports.total') } - column { |lis| product_name(lis) } - column { |lis| group_buy_unit_size_f(lis) } - column { |_lis| "" } - column { |_lis| "" } - column { |_lis| "" } - column { |_lis| "" } - column { |lis| total_amount(lis) } - column { |lis| total_available(lis) } - column { |lis| remainder(lis) } - column { |lis| max_quantity_excess(lis) } - end - - organise do - group(&:full_name) - sort { |full_name| full_name } - - organise do - group(&:order) - sort(&:to_s) - end - end + def rules + [ + { + group_by: proc { |line_item| line_item.product }, + sort_by: proc { |product| product.name }, + summary_columns: [ + proc { |_lis| I18n.t('admin.reports.total') }, + proc { |lis| product_name(lis) }, + proc { |lis| group_buy_unit_size_f(lis) }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |lis| total_amount(lis) }, + proc { |lis| total_available(lis) }, + proc { |lis| remainder(lis) }, + proc { |lis| max_quantity_excess(lis) } + ] + }, + { + group_by: proc { |line_item| line_item.order }, + sort_by: proc { |order| order.to_s } + } + ] end - columns do - column { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname } - column { |lis| lis.first.product.name } - column { |lis| lis.first.product.group_buy_unit_size || 0.0 } - column { |lis| lis.first.full_name } - column { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value } - column { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit } - column { |lis| lis.first.weight_from_unit_value || 0 } - column { |lis| total_amount(lis) } - column { |_lis| "" } - column { |_lis| "" } - column { |_lis| "" } + def columns + [ + proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, + proc { |lis| lis.first.product.name }, + proc { |lis| lis.first.product.group_buy_unit_size || 0.0 }, + proc { |lis| lis.first.full_name }, + proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value }, + proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit }, + proc { |lis| lis.first.weight_from_unit_value || 0 }, + proc { |lis| total_amount(lis) }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |_lis| "" } + ] end end end diff --git a/lib/open_food_network/reports/bulk_coop_report.rb b/lib/open_food_network/reports/bulk_coop_report.rb index 0bbefcab35..a82605d634 100644 --- a/lib/open_food_network/reports/bulk_coop_report.rb +++ b/lib/open_food_network/reports/bulk_coop_report.rb @@ -4,63 +4,61 @@ module OpenFoodNetwork::Reports class BulkCoopReport < Report private - class << self - def supplier_name(lis) - lis.first.variant.product.supplier.name - end + def supplier_name(lis) + lis.first.variant.product.supplier.name + end - def product_name(lis) - lis.first.variant.product.name - end + def product_name(lis) + lis.first.variant.product.name + end - def group_buy_unit_size(lis) - (lis.first.variant.product.group_buy_unit_size || 0.0) / - (lis.first.product.variant_unit_scale || 1) - end + def group_buy_unit_size(lis) + (lis.first.variant.product.group_buy_unit_size || 0.0) / + (lis.first.product.variant_unit_scale || 1) + end - def group_buy_unit_size_f(lis) - group_buy_unit_size(lis) - end + def group_buy_unit_size_f(lis) + group_buy_unit_size(lis) + end - def total_amount(lis) - lis.sum { |li| scaled_final_weight_volume(li) } - end + def total_amount(lis) + lis.sum { |li| scaled_final_weight_volume(li) } + end - def units_required(lis) - if group_buy_unit_size(lis).zero? - 0 - else - ( total_amount(lis) / group_buy_unit_size(lis) ).ceil - end + def units_required(lis) + if group_buy_unit_size(lis).zero? + 0 + else + ( total_amount(lis) / group_buy_unit_size(lis) ).ceil end + end - def total_available(lis) - units_required(lis) * group_buy_unit_size(lis) - end + def total_available(lis) + units_required(lis) * group_buy_unit_size(lis) + end - def remainder(lis) - remainder = total_available(lis) - total_amount(lis) - remainder >= 0 ? remainder : '' - end + def remainder(lis) + remainder = total_available(lis) - total_amount(lis) + remainder >= 0 ? remainder : '' + end - def max_quantity_excess(lis) - max_quantity_amount(lis) - total_amount(lis) - end + def max_quantity_excess(lis) + max_quantity_amount(lis) - total_amount(lis) + end - def max_quantity_amount(lis) - lis.sum do |li| - max_quantity = [li.max_quantity || 0, li.quantity || 0].max - max_quantity * scaled_unit_value(li.variant) - end + def max_quantity_amount(lis) + lis.sum do |li| + max_quantity = [li.max_quantity || 0, li.quantity || 0].max + max_quantity * scaled_unit_value(li.variant) end + end - def scaled_final_weight_volume(li) - (li.final_weight_volume || 0) / (li.product.variant_unit_scale || 1) - end + def scaled_final_weight_volume(li) + (li.final_weight_volume || 0) / (li.product.variant_unit_scale || 1) + end - def scaled_unit_value(v) - (v.unit_value || 0) / (v.product.variant_unit_scale || 1) - end + def scaled_unit_value(v) + (v.unit_value || 0) / (v.product.variant_unit_scale || 1) end end end diff --git a/lib/open_food_network/reports/bulk_coop_supplier_report.rb b/lib/open_food_network/reports/bulk_coop_supplier_report.rb index ae4ed3da37..9ed4f7e175 100644 --- a/lib/open_food_network/reports/bulk_coop_supplier_report.rb +++ b/lib/open_food_network/reports/bulk_coop_supplier_report.rb @@ -18,47 +18,45 @@ module OpenFoodNetwork::Reports ] end - organise do - group { |li| li.product.supplier } - sort(&:name) - - organise do - group(&:product) - sort(&:name) - - summary_row do - column { |lis| supplier_name(lis) } - column { |lis| product_name(lis) } - column { |lis| group_buy_unit_size_f(lis) } - column { |_lis| "" } - column { |_lis| "" } - column { |_lis| "" } - column { |_lis| "" } - column { |lis| total_amount(lis) } - column { |lis| units_required(lis) } - column { |lis| remainder(lis) } - column { |lis| max_quantity_excess(lis) } - end - - organise do - group(&:full_name) - sort { |full_name| full_name } - end - end + def rules + [ + { group_by: proc { |line_item| line_item.product.supplier }, + sort_by: proc { |supplier| supplier.name } }, + { group_by: proc { |line_item| line_item.product }, + sort_by: proc { |product| product.name }, + summary_columns: [ + proc { |lis| supplier_name(lis) }, + proc { |lis| product_name(lis) }, + proc { |lis| group_buy_unit_size_f(lis) }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |lis| total_amount(lis) }, + proc { |lis| units_required(lis) }, + proc { |lis| remainder(lis) }, + proc { |lis| max_quantity_excess(lis) } + ] + }, + { group_by: proc { |line_item| line_item.full_name }, + sort_by: proc { |full_name| full_name } } + ] end - columns do - column { |lis| supplier_name(lis) } - column { |lis| product_name(lis) } - column { |lis| group_buy_unit_size_f(lis) } - column { |lis| lis.first.full_name } - column { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value } - column { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit } - column { |lis| lis.first.weight_from_unit_value || 0 } - column { |lis| total_amount(lis) } - column { |_lis| '' } - column { |_lis| '' } - column { |_lis| '' } + def columns + [ + proc { |lis| supplier_name(lis) }, + proc { |lis| product_name(lis) }, + proc { |lis| group_buy_unit_size_f(lis) }, + proc { |lis| lis.first.full_name }, + proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value }, + proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit }, + proc { |lis| lis.first.weight_from_unit_value || 0 }, + proc { |lis| total_amount(lis) }, + proc { |_lis| '' }, + proc { |_lis| '' }, + proc { |_lis| '' } + ] end end end diff --git a/lib/open_food_network/reports/report.rb b/lib/open_food_network/reports/report.rb index 2933b7cec6..2c4e5900f2 100644 --- a/lib/open_food_network/reports/report.rb +++ b/lib/open_food_network/reports/report.rb @@ -31,15 +31,5 @@ module OpenFoodNetwork::Reports def self.header(*columns) self._header = columns end - - def self.columns(&block) - self._columns = Row.new - Blockenspiel.invoke block, _columns - end - - def self.organise(&block) - self._rules_head = Rule.new - Blockenspiel.invoke block, _rules_head - end end end diff --git a/lib/open_food_network/reports/row.rb b/lib/open_food_network/reports/row.rb index 01c8dd192e..35b4bffe33 100644 --- a/lib/open_food_network/reports/row.rb +++ b/lib/open_food_network/reports/row.rb @@ -1,7 +1,5 @@ module OpenFoodNetwork::Reports class Row - include Blockenspiel::DSL - def initialize @columns = [] end diff --git a/lib/open_food_network/reports/rule.rb b/lib/open_food_network/reports/rule.rb index 372c52b249..cfb8b7e67f 100644 --- a/lib/open_food_network/reports/rule.rb +++ b/lib/open_food_network/reports/rule.rb @@ -2,7 +2,6 @@ require 'open_food_network/reports/row' module OpenFoodNetwork::Reports class Rule - include Blockenspiel::DSL attr_reader :next def group(&block) @@ -13,16 +12,6 @@ module OpenFoodNetwork::Reports @sort = block end - def summary_row(&block) - @summary_row = Row.new - Blockenspiel.invoke block, @summary_row - end - - def organise(&block) - @next = Rule.new - Blockenspiel.invoke block, @next - end - def to_h h = { group_by: @group, sort_by: @sort } h[:summary_columns] = @summary_row.to_a if @summary_row diff --git a/spec/lib/open_food_network/reports/report_spec.rb b/spec/lib/open_food_network/reports/report_spec.rb index 64baf06ba6..86e76bcec5 100644 --- a/spec/lib/open_food_network/reports/report_spec.rb +++ b/spec/lib/open_food_network/reports/report_spec.rb @@ -1,98 +1,15 @@ require 'open_food_network/reports/report' module OpenFoodNetwork::Reports - P1 = proc { |o| o[:one] } - P2 = proc { |o| o[:two] } - P3 = proc { |o| o[:three] } - P4 = proc { |o| o[:four] } - class TestReport < Report header 'One', 'Two', 'Three', 'Four' - - columns do - column(&P1) - column(&P2) - column(&P3) - column(&P4) - end - - organise do - group(&P1) - sort(&P2) - - organise do - group(&P3) - sort(&P4) - - summary_row do - column(&P1) - column(&P4) - end - end - end - end - - class HelperReport < Report - columns do - column { |o| my_helper(o) } - end - - private - - def self.my_helper(o) - o[:one] - end end describe Report do let(:report) { TestReport.new } - let(:helper_report) { HelperReport.new } - let(:rules_head) { TestReport._rules_head } - let(:data) { { one: 1, two: 2, three: 3, four: 4 } } it "returns the header" do expect(report.header).to eq(%w(One Two Three Four)) end - - it "returns columns as an array of procs" do - expect(report.columns[0].call(data)).to eq(1) - expect(report.columns[1].call(data)).to eq(2) - expect(report.columns[2].call(data)).to eq(3) - expect(report.columns[3].call(data)).to eq(4) - end - - it "supports helpers when outputting columns" do - expect(helper_report.columns[0].call(data)).to eq(1) - end - - describe "rules" do - let(:group_by) { rules_head.to_h[:group_by] } - let(:sort_by) { rules_head.to_h[:sort_by] } - let(:next_group_by) { rules_head.next.to_h[:group_by] } - let(:next_sort_by) { rules_head.next.to_h[:sort_by] } - let(:next_summary_columns) { rules_head.next.to_h[:summary_columns] } - - it "constructs the head of the rules list" do - expect(group_by.call(data)).to eq(1) - expect(sort_by.call(data)).to eq(2) - end - - it "constructs nested rules" do - expect(next_group_by.call(data)).to eq(3) - expect(next_sort_by.call(data)).to eq(4) - end - - it "constructs summary columns for rules" do - expect(next_summary_columns[0].call(data)).to eq(1) - expect(next_summary_columns[1].call(data)).to eq(4) - end - end - - describe "outputting rules" do - it "outputs the rules" do - expect(report.rules).to eq([{ group_by: P1, sort_by: P2 }, - { group_by: P3, sort_by: P4, summary_columns: [P1, P4] }]) - end - end end end diff --git a/spec/lib/open_food_network/reports/rule_spec.rb b/spec/lib/open_food_network/reports/rule_spec.rb index d800f6e818..eae5b26045 100644 --- a/spec/lib/open_food_network/reports/rule_spec.rb +++ b/spec/lib/open_food_network/reports/rule_spec.rb @@ -17,23 +17,5 @@ module OpenFoodNetwork::Reports rule.sort(&proc) expect(rule.to_h).to eq(group_by: nil, sort_by: proc) end - - it "can define a nested rule" do - rule.organise(&proc) - expect(rule.next).to be_a Rule - end - - it "can define a summary row and return it in a hash" do - rule.summary_row do - column {} - column {} - column {} - end - - expect(rule.to_h[:summary_columns].count).to eq(3) - expect(rule.to_h[:summary_columns][0]).to be_a Proc - expect(rule.to_h[:summary_columns][1]).to be_a Proc - expect(rule.to_h[:summary_columns][2]).to be_a Proc - end end end From d02f64da064f5725b46730856de6c7873ac45036 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 29 May 2020 10:55:55 +0100 Subject: [PATCH 002/261] Define bulk coop report summary row and columns with lists of method names instead of Procs. --- .../spree/admin/reports_controller.rb | 2 +- lib/open_food_network/bulk_coop_report.rb | 164 ++++++++++++++++-- lib/open_food_network/order_grouper.rb | 27 ++- .../reports/bulk_coop_allocation_report.rb | 48 +++-- .../reports/bulk_coop_report.rb | 64 ------- .../reports/bulk_coop_supplier_report.rb | 48 +++-- 6 files changed, 217 insertions(+), 136 deletions(-) delete mode 100644 lib/open_food_network/reports/bulk_coop_report.rb diff --git a/app/controllers/spree/admin/reports_controller.rb b/app/controllers/spree/admin/reports_controller.rb index 9583fe7134..6fd19ae734 100644 --- a/app/controllers/spree/admin/reports_controller.rb +++ b/app/controllers/spree/admin/reports_controller.rb @@ -260,7 +260,7 @@ module Spree end def order_grouper_table - order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns + order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns, @report order_grouper.table(@report.table_items) end diff --git a/lib/open_food_network/bulk_coop_report.rb b/lib/open_food_network/bulk_coop_report.rb index 019dcddbb7..74802dbbe2 100644 --- a/lib/open_food_network/bulk_coop_report.rb +++ b/lib/open_food_network/bulk_coop_report.rb @@ -96,26 +96,32 @@ module OpenFoodNetwork when "bulk_coop_allocation" @allocation_report.columns when "bulk_coop_packing_sheets" - [proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, - proc { |lis| lis.first.product.name }, - proc { |lis| lis.first.full_name }, - proc { |lis| lis.sum(&:quantity) }] + [ + :order_billing_address_name, + :product_name, + :full_name, + :total_quantity + ] when "bulk_coop_customer_payments" - [proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, - proc { |lis| lis.first.order.completed_at.to_s }, - proc { |lis| lis.map(&:order).uniq.sum(&:total) }, - proc { |lis| lis.map(&:order).uniq.sum(&:outstanding_balance) }, - proc { |lis| lis.map(&:order).uniq.sum(&:payment_total) }] + [ + :order_billing_address_name, + :order_completed_at, + :customer_payments_total_cost, + :customer_payments_amount_owed, + :customer_payments_amount_paid + ] else - [proc { |lis| lis.first.product.supplier.name }, - proc { |lis| lis.first.product.name }, - proc { |lis| lis.first.product.group_buy_unit_size || 0.0 }, - proc { |lis| lis.first.full_name }, - proc { |lis| lis.first.weight_from_unit_value || 0 }, - proc { |lis| lis.sum(&:quantity) }, - proc { |lis| lis.sum { |li| li.max_quantity || 0 } }, - proc { |_lis| "" }, - proc { |_lis| "" }] + [ + :product_supplier_name, + :product_name, + :product_group_buy_unit_size, + :full_name, + :weight_from_unit_value, + :total_quantity, + :total_max_quantity, + :empty_cell, + :empty_cell + ] end end @@ -134,5 +140,127 @@ module OpenFoodNetwork def report_line_items @report_line_items ||= Reports::LineItems.new(order_permissions, @params) end + + def customer_payments_total_cost(line_items) + line_items.map(&:order).uniq.sum(&:total) + end + + def customer_payments_amount_owed(line_items) + line_items.map(&:order).uniq.sum(&:outstanding_balance) + end + + def customer_payments_amount_paid(line_items) + line_items.map(&:order).uniq.sum(&:payment_total) + end + + def empty_cell(line_items) + "" + end + + def full_name(line_items) + line_items.first.full_name + end + + def group_buy_unit_size(line_items) + (line_items.first.variant.product.group_buy_unit_size || 0.0) / + (line_items.first.product.variant_unit_scale || 1) + end + + def max_quantity_excess(line_items) + max_quantity_amount(line_items) - total_amount(line_items) + end + + def max_quantity_amount(line_items) + line_items.sum do |line_item| + max_quantity = [line_item.max_quantity || 0, line_item.quantity || 0].max + max_quantity * scaled_unit_value(line_item.variant) + end + end + + def option_value_value(line_items) + OpenFoodNetwork::OptionValueNamer.new(line_items.first).value + end + + def option_value_unit(line_items) + OpenFoodNetwork::OptionValueNamer.new(line_items.first).unit + end + + def order_billing_address_name(line_items) + billing_address = line_items.first.order.bill_address + billing_address.firstname + " " + billing_address.lastname + end + + def order_completed_at(line_items) + line_items.first.order.completed_at.to_s + end + + def product_group_buy_unit_size(line_items) + line_items.first.product.group_buy_unit_size || 0.0 + end + + def product_name(line_items) + line_items.first.product.name + end + + def product_supplier_name(line_items) + line_items.first.product.supplier.name + end + + def remainder(line_items) + remainder = total_available(line_items) - total_amount(line_items) + remainder >= 0 ? remainder : '' + end + + def scaled_final_weight_volume(li) + (li.final_weight_volume || 0) / (li.product.variant_unit_scale || 1) + end + + def scaled_unit_value(v) + (v.unit_value || 0) / (v.product.variant_unit_scale || 1) + end + + def total_amount(line_items) + line_items.sum { |li| scaled_final_weight_volume(li) } + end + + def total_available(line_items) + units_required(line_items) * group_buy_unit_size(line_items) + end + + def total_max_quantity(line_items) + line_items.sum { |line_item| line_item.max_quantity || 0 } + end + + def total_quantity(line_items) + line_items.sum(&:quantity) + end + + def total_label(line_items) + I18n.t('admin.reports.total') + end + + def units_required(line_items) + if group_buy_unit_size(line_items).zero? + 0 + else + ( total_amount(line_items) / group_buy_unit_size(line_items) ).ceil + end + end + + def variant_product_group_buy_unit_size_f(line_items) + group_buy_unit_size(line_items) + end + + def variant_product_name(line_items) + line_items.first.variant.product.name + end + + def variant_product_supplier_name(line_items) + line_items.first.variant.product.supplier.name + end + + def weight_from_unit_value(line_items) + line_items.first.weight_from_unit_value || 0 + end end end diff --git a/lib/open_food_network/order_grouper.rb b/lib/open_food_network/order_grouper.rb index 5b792bd5d4..b4e4861a79 100644 --- a/lib/open_food_network/order_grouper.rb +++ b/lib/open_food_network/order_grouper.rb @@ -1,8 +1,9 @@ module OpenFoodNetwork class OrderGrouper - def initialize(rules, column_constructors) + def initialize(rules, column_constructors, report=nil) @rules = rules @column_constructors = column_constructors + @report = report end def build_tree(items, remaining_rules) @@ -38,11 +39,11 @@ module OpenFoodNetwork def build_table(groups) rows = [] if is_leaf_node(groups) - rows << @column_constructors.map { |column_constructor| column_constructor.call(groups) } + rows << build_row(groups) else groups.each do |key, group| if key == :summary_row - rows << group[:columns].map { |cols| cols.call(group[:items]) } + rows << build_summary_row(group[:columns], group[:items]) else build_table(group).each { |g| rows << g } end @@ -59,6 +60,26 @@ module OpenFoodNetwork private + def build_cell(column_constructor, items) + if column_constructor.is_a?(Symbol) + @report.send(column_constructor, items) + else + column_constructor.call(items) + end + end + + def build_row(groups) + @column_constructors.map do |column_constructor| + build_cell(column_constructor, groups) + end + end + + def build_summary_row(summary_row_column_constructors, items) + summary_row_column_constructors.map do |summary_row_column_constructor| + build_cell(summary_row_column_constructor, items) + end + end + def is_leaf_node(node) node.is_a? Array end diff --git a/lib/open_food_network/reports/bulk_coop_allocation_report.rb b/lib/open_food_network/reports/bulk_coop_allocation_report.rb index c8b05c30a0..316648dbf6 100644 --- a/lib/open_food_network/reports/bulk_coop_allocation_report.rb +++ b/lib/open_food_network/reports/bulk_coop_allocation_report.rb @@ -1,7 +1,5 @@ -require 'open_food_network/reports/bulk_coop_report' - module OpenFoodNetwork::Reports - class BulkCoopAllocationReport < BulkCoopReport + class BulkCoopAllocationReport def header [ I18n.t(:report_header_customer), @@ -24,17 +22,17 @@ module OpenFoodNetwork::Reports group_by: proc { |line_item| line_item.product }, sort_by: proc { |product| product.name }, summary_columns: [ - proc { |_lis| I18n.t('admin.reports.total') }, - proc { |lis| product_name(lis) }, - proc { |lis| group_buy_unit_size_f(lis) }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |lis| total_amount(lis) }, - proc { |lis| total_available(lis) }, - proc { |lis| remainder(lis) }, - proc { |lis| max_quantity_excess(lis) } + :total_label, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :empty_cell, + :empty_cell, + :empty_cell, + :empty_cell, + :total_amount, + :total_available, + :remainder, + :max_quantity_excess ] }, { @@ -46,17 +44,17 @@ module OpenFoodNetwork::Reports def columns [ - proc { |lis| lis.first.order.bill_address.firstname + " " + lis.first.order.bill_address.lastname }, - proc { |lis| lis.first.product.name }, - proc { |lis| lis.first.product.group_buy_unit_size || 0.0 }, - proc { |lis| lis.first.full_name }, - proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value }, - proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit }, - proc { |lis| lis.first.weight_from_unit_value || 0 }, - proc { |lis| total_amount(lis) }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |_lis| "" } + :order_billing_address_name, + :product_name, + :product_group_buy_unit_size, + :full_name, + :option_value_value, + :option_value_unit, + :weight_from_unit_value, + :total_amount, + :empty_cell, + :empty_cell, + :empty_cell ] end end diff --git a/lib/open_food_network/reports/bulk_coop_report.rb b/lib/open_food_network/reports/bulk_coop_report.rb deleted file mode 100644 index a82605d634..0000000000 --- a/lib/open_food_network/reports/bulk_coop_report.rb +++ /dev/null @@ -1,64 +0,0 @@ -require 'open_food_network/reports/report' - -module OpenFoodNetwork::Reports - class BulkCoopReport < Report - private - - def supplier_name(lis) - lis.first.variant.product.supplier.name - end - - def product_name(lis) - lis.first.variant.product.name - end - - def group_buy_unit_size(lis) - (lis.first.variant.product.group_buy_unit_size || 0.0) / - (lis.first.product.variant_unit_scale || 1) - end - - def group_buy_unit_size_f(lis) - group_buy_unit_size(lis) - end - - def total_amount(lis) - lis.sum { |li| scaled_final_weight_volume(li) } - end - - def units_required(lis) - if group_buy_unit_size(lis).zero? - 0 - else - ( total_amount(lis) / group_buy_unit_size(lis) ).ceil - end - end - - def total_available(lis) - units_required(lis) * group_buy_unit_size(lis) - end - - def remainder(lis) - remainder = total_available(lis) - total_amount(lis) - remainder >= 0 ? remainder : '' - end - - def max_quantity_excess(lis) - max_quantity_amount(lis) - total_amount(lis) - end - - def max_quantity_amount(lis) - lis.sum do |li| - max_quantity = [li.max_quantity || 0, li.quantity || 0].max - max_quantity * scaled_unit_value(li.variant) - end - end - - def scaled_final_weight_volume(li) - (li.final_weight_volume || 0) / (li.product.variant_unit_scale || 1) - end - - def scaled_unit_value(v) - (v.unit_value || 0) / (v.product.variant_unit_scale || 1) - end - end -end diff --git a/lib/open_food_network/reports/bulk_coop_supplier_report.rb b/lib/open_food_network/reports/bulk_coop_supplier_report.rb index 9ed4f7e175..0c1c86e3b2 100644 --- a/lib/open_food_network/reports/bulk_coop_supplier_report.rb +++ b/lib/open_food_network/reports/bulk_coop_supplier_report.rb @@ -1,7 +1,5 @@ -require 'open_food_network/reports/bulk_coop_report' - module OpenFoodNetwork::Reports - class BulkCoopSupplierReport < BulkCoopReport + class BulkCoopSupplierReport def header [ I18n.t(:report_header_supplier), @@ -25,17 +23,17 @@ module OpenFoodNetwork::Reports { group_by: proc { |line_item| line_item.product }, sort_by: proc { |product| product.name }, summary_columns: [ - proc { |lis| supplier_name(lis) }, - proc { |lis| product_name(lis) }, - proc { |lis| group_buy_unit_size_f(lis) }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |lis| total_amount(lis) }, - proc { |lis| units_required(lis) }, - proc { |lis| remainder(lis) }, - proc { |lis| max_quantity_excess(lis) } + :variant_product_supplier_name, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :empty_cell, + :empty_cell, + :empty_cell, + :empty_cell, + :total_amount, + :units_required, + :remainder, + :max_quantity_excess ] }, { group_by: proc { |line_item| line_item.full_name }, @@ -45,17 +43,17 @@ module OpenFoodNetwork::Reports def columns [ - proc { |lis| supplier_name(lis) }, - proc { |lis| product_name(lis) }, - proc { |lis| group_buy_unit_size_f(lis) }, - proc { |lis| lis.first.full_name }, - proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).value }, - proc { |lis| OpenFoodNetwork::OptionValueNamer.new(lis.first).unit }, - proc { |lis| lis.first.weight_from_unit_value || 0 }, - proc { |lis| total_amount(lis) }, - proc { |_lis| '' }, - proc { |_lis| '' }, - proc { |_lis| '' } + :variant_product_supplier_name, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :full_name, + :option_value_value, + :option_value_unit, + :weight_from_unit_value, + :total_amount, + :empty_cell, + :empty_cell, + :empty_cell ] end end From d436d18d19c0233093995b82b508451d394d09fd Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 10:13:06 +0100 Subject: [PATCH 003/261] Fix code climate violations in removal of Blockenspiel dependency. --- lib/open_food_network/bulk_coop_report.rb | 12 ++++++------ lib/open_food_network/order_grouper.rb | 4 ++-- .../reports/bulk_coop_allocation_report.rb | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/open_food_network/bulk_coop_report.rb b/lib/open_food_network/bulk_coop_report.rb index 74802dbbe2..9eb8cf07c6 100644 --- a/lib/open_food_network/bulk_coop_report.rb +++ b/lib/open_food_network/bulk_coop_report.rb @@ -153,7 +153,7 @@ module OpenFoodNetwork line_items.map(&:order).uniq.sum(&:payment_total) end - def empty_cell(line_items) + def empty_cell(*) "" end @@ -211,12 +211,12 @@ module OpenFoodNetwork remainder >= 0 ? remainder : '' end - def scaled_final_weight_volume(li) - (li.final_weight_volume || 0) / (li.product.variant_unit_scale || 1) + def scaled_final_weight_volume(line_item) + (line_item.final_weight_volume || 0) / (line_item.product.variant_unit_scale || 1) end - def scaled_unit_value(v) - (v.unit_value || 0) / (v.product.variant_unit_scale || 1) + def scaled_unit_value(variant) + (variant.unit_value || 0) / (variant.product.variant_unit_scale || 1) end def total_amount(line_items) @@ -235,7 +235,7 @@ module OpenFoodNetwork line_items.sum(&:quantity) end - def total_label(line_items) + def total_label(*) I18n.t('admin.reports.total') end diff --git a/lib/open_food_network/order_grouper.rb b/lib/open_food_network/order_grouper.rb index b4e4861a79..8d810254d5 100644 --- a/lib/open_food_network/order_grouper.rb +++ b/lib/open_food_network/order_grouper.rb @@ -1,6 +1,6 @@ module OpenFoodNetwork class OrderGrouper - def initialize(rules, column_constructors, report=nil) + def initialize(rules, column_constructors, report = nil) @rules = rules @column_constructors = column_constructors @report = report @@ -62,7 +62,7 @@ module OpenFoodNetwork def build_cell(column_constructor, items) if column_constructor.is_a?(Symbol) - @report.send(column_constructor, items) + @report.__send__(column_constructor, items) else column_constructor.call(items) end diff --git a/lib/open_food_network/reports/bulk_coop_allocation_report.rb b/lib/open_food_network/reports/bulk_coop_allocation_report.rb index 316648dbf6..bcc068c0c5 100644 --- a/lib/open_food_network/reports/bulk_coop_allocation_report.rb +++ b/lib/open_food_network/reports/bulk_coop_allocation_report.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OpenFoodNetwork::Reports class BulkCoopAllocationReport def header From 406309c577d7fe702bd79701d544cca38ab172da Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 16:43:38 +0100 Subject: [PATCH 004/261] Move BulkCoop reports out of deprecated lib/ directory into OrderManagement engine. The BulkCoop reports are not generated the same way as the EnterpriseFeeSummary report is generated yet so that may need to be updated. --- .../spree/admin/reports_controller.rb | 8 +- .../spree/admin/reports/bulk_coop.html.haml | 19 -- .../reports/bulk_coop_controller.rb | 64 ++++ .../reports/bulk_coop/authorizer.rb | 16 + .../bulk_coop/bulk_coop_allocation_report.rb | 67 +++++ .../reports/bulk_coop/bulk_coop_report.rb | 275 ++++++++++++++++++ .../bulk_coop/bulk_coop_supplier_report.rb | 64 ++++ .../reports/bulk_coop/parameters.rb | 55 ++++ .../reports/bulk_coop/permissions.rb | 11 + .../bulk_coop/renderers/csv_renderer.rb | 30 ++ .../bulk_coop/renderers/html_renderer.rb | 22 ++ .../reports/bulk_coop/report_service.rb | 27 ++ .../enterprise_fee_summary/authorizer.rb | 13 - .../app/services/reports/authorizer.rb | 15 + .../reports/bulk_coop/_filters.html.haml | 31 ++ .../reports/bulk_coop/_report.html.haml | 20 ++ .../reports/bulk_coop/create.html.haml | 2 + .../reports/bulk_coop/new.html.haml | 1 + engines/order_management/config/routes.rb | 1 + lib/open_food_network/bulk_coop_report.rb | 266 ----------------- .../reports/bulk_coop_allocation_report.rb | 63 ---- .../reports/bulk_coop_supplier_report.rb | 60 ---- 22 files changed, 707 insertions(+), 423 deletions(-) delete mode 100644 app/views/spree/admin/reports/bulk_coop.html.haml create mode 100644 engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_allocation_report.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb create mode 100644 engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb create mode 100644 engines/order_management/app/views/order_management/reports/bulk_coop/_filters.html.haml create mode 100644 engines/order_management/app/views/order_management/reports/bulk_coop/_report.html.haml create mode 100644 engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml create mode 100644 engines/order_management/app/views/order_management/reports/bulk_coop/new.html.haml delete mode 100644 lib/open_food_network/bulk_coop_report.rb delete mode 100644 lib/open_food_network/reports/bulk_coop_allocation_report.rb delete mode 100644 lib/open_food_network/reports/bulk_coop_supplier_report.rb diff --git a/app/controllers/spree/admin/reports_controller.rb b/app/controllers/spree/admin/reports_controller.rb index 6fd19ae734..ce3ec90c57 100644 --- a/app/controllers/spree/admin/reports_controller.rb +++ b/app/controllers/spree/admin/reports_controller.rb @@ -12,7 +12,6 @@ require 'open_food_network/order_cycle_management_report' require 'open_food_network/packing_report' require 'open_food_network/sales_tax_report' require 'open_food_network/xero_invoices_report' -require 'open_food_network/bulk_coop_report' require 'open_food_network/payments_report' require 'open_food_network/orders_and_fulfillments_report' @@ -21,6 +20,11 @@ module Spree class ReportsController < Spree::Admin::BaseController include Spree::ReportsHelper + ORDER_MANAGEMENT_ENGINE_REPORTS = [ + :bulk_coop, + :enterprise_fee_summary + ] + helper_method :render_content? before_filter :cache_search_state @@ -309,7 +313,7 @@ module Spree # List of reports that have been moved to the Order Management engine def report_in_order_management_engine?(report) - report == :enterprise_fee_summary + ORDER_MANAGEMENT_ENGINE_REPORTS.include?(report) end def timestamp diff --git a/app/views/spree/admin/reports/bulk_coop.html.haml b/app/views/spree/admin/reports/bulk_coop.html.haml deleted file mode 100644 index c644e8dd6e..0000000000 --- a/app/views/spree/admin/reports/bulk_coop.html.haml +++ /dev/null @@ -1,19 +0,0 @@ -= form_for @report.search, :url => spree.bulk_coop_admin_reports_path do |f| - = render 'date_range_form', f: f - - .row - .four.columns.alpha - = label_tag nil, t(:report_distributor) - = f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => t(:all)}, {:class => "select2 fullwidth"}) - = label_tag nil, t(:report_type) - %br - = select_tag(:report_type, options_for_select([:bulk_coop_supplier_report, :bulk_coop_allocation, :bulk_coop_packing_sheets, :bulk_coop_customer_payments].map{ |e| [t(".#{e}"), e] }, @report_type)) - %br - %br - = check_box_tag :csv - = label_tag :csv, t(:report_customers_csv) - %br - %br - = button t(:search) - -= render "table", id: "listing_orders", msg_option: t(:search) diff --git a/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb b/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb new file mode 100644 index 0000000000..26397e40bf --- /dev/null +++ b/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb @@ -0,0 +1,64 @@ +module OrderManagement + module Reports + class BulkCoopController < Spree::Admin::BaseController + before_filter :load_report_parameters + before_filter :load_permissions + + def new; end + + def create + return respond_to_invalid_parameters unless @report_parameters.valid? + + @report_parameters.authorize!(@permissions) + + @report = report_klass::ReportService.new(@permissions, params[:report], spree_current_user) + renderer.render(self) + rescue ::Reports::Authorizer::ParameterNotAllowedError => e + flash[:error] = e.message + render_report_form + end + + private + + def respond_to_invalid_parameters + flash[:error] = I18n.t("invalid_filter_parameters", scope: i18n_scope) + render_report_form + end + + def i18n_scope + "order_management.reports.enterprise_fee_summary" + end + + def render_report_form + render action: :new + end + + def report_klass + OrderManagement::Reports::BulkCoop + end + + def load_report_parameters + @report_parameters = report_klass::Parameters.new(params[:report] || {}) + end + + def load_permissions + @permissions = report_klass::Permissions.new(spree_current_user) + end + + def report_renderer_klass + case params[:report_format] + when "csv" + report_klass::Renderers::CsvRenderer + when nil, "", "html" + report_klass::Renderers::HtmlRenderer + else + raise Reports::UnsupportedReportFormatException + end + end + + def renderer + @renderer ||= report_renderer_klass.new(@report) + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb new file mode 100644 index 0000000000..39562e6da2 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb @@ -0,0 +1,16 @@ +module OrderManagement + module Reports + module BulkCoop + class Authorizer < ::Reports::Authorizer + def self.parameter_not_allowed_error_message + i18n_scope = "order_management.reports.enterprise_fee_summary" + I18n.t("parameter_not_allowed_error", scope: i18n_scope) + end + + def authorize! + require_ids_allowed(parameters.distributor_ids, permissions.allowed_distributors) + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_allocation_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_allocation_report.rb new file mode 100644 index 0000000000..9513f51e9b --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_allocation_report.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module OrderManagement + module Reports + module BulkCoop + class BulkCoopAllocationReport + def header + [ + I18n.t(:report_header_customer), + I18n.t(:report_header_product), + I18n.t(:report_header_bulk_unit_size), + I18n.t(:report_header_variant), + I18n.t(:report_header_variant_value), + I18n.t(:report_header_variant_unit), + I18n.t(:report_header_weight), + I18n.t(:report_header_sum_total), + I18n.t(:report_header_total_available), + I18n.t(:report_header_unallocated), + I18n.t(:report_header_max_quantity_excess), + ] + end + + def rules + [ + { + group_by: proc { |line_item| line_item.product }, + sort_by: proc { |product| product.name }, + summary_columns: [ + :total_label, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :empty_cell, + :empty_cell, + :empty_cell, + :empty_cell, + :total_amount, + :total_available, + :remainder, + :max_quantity_excess + ] + }, + { + group_by: proc { |line_item| line_item.order }, + sort_by: proc { |order| order.to_s } + } + ] + end + + def columns + [ + :order_billing_address_name, + :product_name, + :product_group_buy_unit_size, + :full_name, + :option_value_value, + :option_value_unit, + :weight_from_unit_value, + :total_amount, + :empty_cell, + :empty_cell, + :empty_cell + ] + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb new file mode 100644 index 0000000000..3d776c31f5 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb @@ -0,0 +1,275 @@ +require "open_food_network/reports/line_items" + +module OrderManagement + module Reports + module BulkCoop + class BulkCoopReport + REPORT_TYPES = [ + :bulk_coop_supplier_report, + :bulk_coop_allocation, + :bulk_coop_packing_sheets, + :bulk_coop_customer_payments + ] + + attr_reader :params + def initialize(user, params = {}, render_table = false) + @params = params + @user = user + @render_table = render_table + + @supplier_report = BulkCoopSupplierReport.new + @allocation_report = BulkCoopAllocationReport.new + end + + def header + case params[:report_type] + when "bulk_coop_supplier_report" + @supplier_report.header + when "bulk_coop_allocation" + @allocation_report.header + when "bulk_coop_packing_sheets" + [I18n.t(:report_header_customer), + I18n.t(:report_header_product), + I18n.t(:report_header_variant), + I18n.t(:report_header_sum_total)] + when "bulk_coop_customer_payments" + [I18n.t(:report_header_customer), + I18n.t(:report_header_date_of_order), + I18n.t(:report_header_total_cost), + I18n.t(:report_header_amount_owing), + I18n.t(:report_header_amount_paid)] + else + [I18n.t(:report_header_supplier), + I18n.t(:report_header_product), + I18n.t(:report_header_product), + I18n.t(:report_header_bulk_unit_size), + I18n.t(:report_header_variant), + I18n.t(:report_header_weight), + I18n.t(:report_header_sum_total), + I18n.t(:report_header_sum_max_total), + I18n.t(:report_header_units_required), + I18n.t(:report_header_remainder)] + end + end + + def search + report_line_items.orders + end + + def table_items + return [] unless @render_table + report_line_items.list(line_item_includes) + end + + def rules + case params[:report_type] + when "bulk_coop_supplier_report" + @supplier_report.rules + when "bulk_coop_allocation" + @allocation_report.rules + when "bulk_coop_packing_sheets" + [{ group_by: proc { |li| li.product }, + sort_by: proc { |product| product.name } }, + { group_by: proc { |li| li.full_name }, + sort_by: proc { |full_name| full_name } }, + { group_by: proc { |li| li.order }, + sort_by: proc { |order| order.to_s } }] + when "bulk_coop_customer_payments" + [{ group_by: proc { |li| li.order }, + sort_by: proc { |order| order.completed_at } }] + else + [{ group_by: proc { |li| li.product.supplier }, + sort_by: proc { |supplier| supplier.name } }, + { group_by: proc { |li| li.product }, + sort_by: proc { |product| product.name }, + summary_columns: [proc { |lis| lis.first.product.supplier.name }, + proc { |lis| lis.first.product.name }, + proc { |lis| lis.first.product.group_buy_unit_size || 0.0 }, + proc { |_lis| "" }, + proc { |_lis| "" }, + proc { |lis| lis.sum { |li| li.quantity * (li.weight_from_unit_value || 0) } }, + proc { |lis| lis.sum { |li| (li.max_quantity || 0) * (li.weight_from_unit_value || 0) } }, + proc { |lis| ( (lis.first.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } / lis.first.product.group_buy_unit_size ) ).floor }, + proc { |lis| lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } - ( ( (lis.first.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } / lis.first.product.group_buy_unit_size ) ).floor * (lis.first.product.group_buy_unit_size || 0) ) }] }, + { group_by: proc { |li| li.full_name }, + sort_by: proc { |full_name| full_name } }] + end + end + + def columns + case params[:report_type] + when "bulk_coop_supplier_report" + @supplier_report.columns + when "bulk_coop_allocation" + @allocation_report.columns + when "bulk_coop_packing_sheets" + [ + :order_billing_address_name, + :product_name, + :full_name, + :total_quantity + ] + when "bulk_coop_customer_payments" + [ + :order_billing_address_name, + :order_completed_at, + :customer_payments_total_cost, + :customer_payments_amount_owed, + :customer_payments_amount_paid + ] + else + [ + :product_supplier_name, + :product_name, + :product_group_buy_unit_size, + :full_name, + :weight_from_unit_value, + :total_quantity, + :total_max_quantity, + :empty_cell, + :empty_cell + ] + end + end + + private + + def line_item_includes + [{ order: [:bill_address], + variant: [{ option_values: :option_type }, { product: :supplier }] }] + end + + def order_permissions + return @order_permissions unless @order_permissions.nil? + @order_permissions = ::Permissions::Order.new(@user, @params[:q]) + end + + def report_line_items + @report_line_items ||= OpenFoodNetwork::Reports::LineItems.new(order_permissions, @params) + end + + def customer_payments_total_cost(line_items) + line_items.map(&:order).uniq.sum(&:total) + end + + def customer_payments_amount_owed(line_items) + line_items.map(&:order).uniq.sum(&:outstanding_balance) + end + + def customer_payments_amount_paid(line_items) + line_items.map(&:order).uniq.sum(&:payment_total) + end + + def empty_cell(*) + "" + end + + def full_name(line_items) + line_items.first.full_name + end + + def group_buy_unit_size(line_items) + (line_items.first.variant.product.group_buy_unit_size || 0.0) / + (line_items.first.product.variant_unit_scale || 1) + end + + def max_quantity_excess(line_items) + max_quantity_amount(line_items) - total_amount(line_items) + end + + def max_quantity_amount(line_items) + line_items.sum do |line_item| + max_quantity = [line_item.max_quantity || 0, line_item.quantity || 0].max + max_quantity * scaled_unit_value(line_item.variant) + end + end + + def option_value_value(line_items) + OpenFoodNetwork::OptionValueNamer.new(line_items.first).value + end + + def option_value_unit(line_items) + OpenFoodNetwork::OptionValueNamer.new(line_items.first).unit + end + + def order_billing_address_name(line_items) + billing_address = line_items.first.order.bill_address + billing_address.firstname + " " + billing_address.lastname + end + + def order_completed_at(line_items) + line_items.first.order.completed_at.to_s + end + + def product_group_buy_unit_size(line_items) + line_items.first.product.group_buy_unit_size || 0.0 + end + + def product_name(line_items) + line_items.first.product.name + end + + def product_supplier_name(line_items) + line_items.first.product.supplier.name + end + + def remainder(line_items) + remainder = total_available(line_items) - total_amount(line_items) + remainder >= 0 ? remainder : '' + end + + def scaled_final_weight_volume(line_item) + (line_item.final_weight_volume || 0) / (line_item.product.variant_unit_scale || 1) + end + + def scaled_unit_value(variant) + (variant.unit_value || 0) / (variant.product.variant_unit_scale || 1) + end + + def total_amount(line_items) + line_items.sum { |li| scaled_final_weight_volume(li) } + end + + def total_available(line_items) + units_required(line_items) * group_buy_unit_size(line_items) + end + + def total_max_quantity(line_items) + line_items.sum { |line_item| line_item.max_quantity || 0 } + end + + def total_quantity(line_items) + line_items.sum(&:quantity) + end + + def total_label(*) + I18n.t('admin.reports.total') + end + + def units_required(line_items) + if group_buy_unit_size(line_items).zero? + 0 + else + ( total_amount(line_items) / group_buy_unit_size(line_items) ).ceil + end + end + + def variant_product_group_buy_unit_size_f(line_items) + group_buy_unit_size(line_items) + end + + def variant_product_name(line_items) + line_items.first.variant.product.name + end + + def variant_product_supplier_name(line_items) + line_items.first.variant.product.supplier.name + end + + def weight_from_unit_value(line_items) + line_items.first.weight_from_unit_value || 0 + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb new file mode 100644 index 0000000000..076a0a63c9 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb @@ -0,0 +1,64 @@ +module OrderManagement + module Reports + module BulkCoop + class BulkCoopSupplierReport + def header + [ + I18n.t(:report_header_supplier), + I18n.t(:report_header_product), + I18n.t(:report_header_bulk_unit_size), + I18n.t(:report_header_variant), + I18n.t(:report_header_variant_value), + I18n.t(:report_header_variant_unit), + I18n.t(:report_header_weight), + I18n.t(:report_header_sum_total), + I18n.t(:report_header_units_required), + I18n.t(:report_header_unallocated), + I18n.t(:report_header_max_quantity_excess), + ] + end + + def rules + [ + { group_by: proc { |line_item| line_item.product.supplier }, + sort_by: proc { |supplier| supplier.name } }, + { group_by: proc { |line_item| line_item.product }, + sort_by: proc { |product| product.name }, + summary_columns: [ + :variant_product_supplier_name, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :empty_cell, + :empty_cell, + :empty_cell, + :empty_cell, + :total_amount, + :units_required, + :remainder, + :max_quantity_excess + ] + }, + { group_by: proc { |line_item| line_item.full_name }, + sort_by: proc { |full_name| full_name } } + ] + end + + def columns + [ + :variant_product_supplier_name, + :variant_product_name, + :variant_product_group_buy_unit_size_f, + :full_name, + :option_value_value, + :option_value_unit, + :weight_from_unit_value, + :total_amount, + :empty_cell, + :empty_cell, + :empty_cell + ] + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb new file mode 100644 index 0000000000..16ed31a744 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb @@ -0,0 +1,55 @@ +module OrderManagement + module Reports + module BulkCoop + class Parameters < ::Reports::Parameters::Base + extend ActiveModel::Naming + extend ActiveModel::Translation + include ActiveModel::Validations + + attr_accessor :start_at, :end_at, :distributor_ids, :report_type + + before_validation :cleanup_arrays + + validates :start_at, :end_at, date_time_string: true + validates :distributor_ids, integer_array: true + validates_inclusion_of :report_type, in: OrderManagement::Reports::BulkCoop::BulkCoopReport::REPORT_TYPES.map(&:to_s) + + validate :require_valid_datetime_range + + def self.date_end_before_start_error_message + i18n_scope = "order_management.reports.enterprise_fee_summary" + I18n.t("date_end_before_start_error", scope: i18n_scope) + end + + def initialize(attributes = {}) + self.distributor_ids = [] + + super(attributes) + end + + def authorize!(permissions) + authorizer = Authorizer.new(self, permissions) + authorizer.authorize! + end + + protected + + def require_valid_datetime_range + return if start_at.blank? || end_at.blank? + + error_message = self.class.date_end_before_start_error_message + errors.add(:end_at, error_message) unless start_at < end_at + end + + # Remove the blank strings that Rails multiple selects add by default to + # make sure that blank lists are still submitted to the server as arrays + # instead of nil. + # + # https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-select + def cleanup_arrays + distributor_ids.reject!(&:blank?) + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb new file mode 100644 index 0000000000..23eb0aaca0 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb @@ -0,0 +1,11 @@ +module OrderManagement + module Reports + module BulkCoop + class Permissions < ::Reports::Permissions + def allowed_distributors + @allowed_distributors ||= Enterprise.is_distributor.managed_by(user) + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb new file mode 100644 index 0000000000..ca19e0a873 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb @@ -0,0 +1,30 @@ +module OrderManagement + module Reports + module BulkCoop + module Renderers + class CsvRenderer < ::Reports::Renderers::Base + def render(context) + context.send_data(generate, filename: filename) + end + + def generate + CSV.generate do |csv| + csv << report_data.header + + report_data.list.each do |data| + csv << data + end + end + end + + private + + def filename + timestamp = Time.zone.now.strftime("%Y%m%d") + "#{report_data.parameters[:report_type]}_#{timestamp}.csv" + end + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb new file mode 100644 index 0000000000..edbda863e1 --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb @@ -0,0 +1,22 @@ +module OrderManagement + module Reports + module BulkCoop + module Renderers + class HtmlRenderer < ::Reports::Renderers::Base + def render(context) + context.instance_variable_set :@renderer, self + context.render(action: :create, renderer: self) + end + + def header + report_data.header + end + + def data_rows + report_data.list + end + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb new file mode 100644 index 0000000000..c74e40934e --- /dev/null +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb @@ -0,0 +1,27 @@ +require 'open_food_network/order_grouper' + +module OrderManagement + module Reports + module BulkCoop + class ReportService + attr_accessor :permissions, :parameters, :user + + def initialize(permissions, parameters, user) + @permissions = permissions + @parameters = parameters + @user = user + @report = BulkCoopReport.new(user, parameters, true) + end + + def header + @report.header + end + + def list + order_grouper = OpenFoodNetwork::OrderGrouper.new @report.rules, @report.columns, @report + order_grouper.table(@report.table_items) + end + end + end + end +end diff --git a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/authorizer.rb b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/authorizer.rb index e129905dc6..51b1393630 100644 --- a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/authorizer.rb +++ b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/authorizer.rb @@ -2,11 +2,6 @@ module OrderManagement module Reports module EnterpriseFeeSummary class Authorizer < ::Reports::Authorizer - def self.parameter_not_allowed_error_message - i18n_scope = "order_management.reports.enterprise_fee_summary" - I18n.t("parameter_not_allowed_error", scope: i18n_scope) - end - def authorize! authorize_by_distribution! authorize_by_fee! @@ -25,14 +20,6 @@ module OrderManagement require_ids_allowed(parameters.shipping_method_ids, permissions.allowed_shipping_methods) require_ids_allowed(parameters.payment_method_ids, permissions.allowed_payment_methods) end - - def require_ids_allowed(array, allowed_objects) - error_klass = ::Reports::Authorizer::ParameterNotAllowedError - error_message = self.class.parameter_not_allowed_error_message - ids_allowed = (array - allowed_objects.map(&:id).map(&:to_s)).blank? - - raise error_klass, error_message unless ids_allowed - end end end end diff --git a/engines/order_management/app/services/reports/authorizer.rb b/engines/order_management/app/services/reports/authorizer.rb index 279952249a..5871e7e395 100644 --- a/engines/order_management/app/services/reports/authorizer.rb +++ b/engines/order_management/app/services/reports/authorizer.rb @@ -8,5 +8,20 @@ module Reports @parameters = parameters @permissions = permissions end + + def self.parameter_not_allowed_error_message + i18n_scope = "order_management.reports.shared" + I18n.t("parameter_not_allowed_error", scope: i18n_scope) + end + + private + + def require_ids_allowed(array, allowed_objects) + error_klass = ::Reports::Authorizer::ParameterNotAllowedError + error_message = self.class.parameter_not_allowed_error_message + ids_allowed = (array - allowed_objects.map(&:id).map(&:to_s)).blank? + + raise error_klass, error_message unless ids_allowed + end end end diff --git a/engines/order_management/app/views/order_management/reports/bulk_coop/_filters.html.haml b/engines/order_management/app/views/order_management/reports/bulk_coop/_filters.html.haml new file mode 100644 index 0000000000..012d910070 --- /dev/null +++ b/engines/order_management/app/views/order_management/reports/bulk_coop/_filters.html.haml @@ -0,0 +1,31 @@ += form_for @report_parameters, as: :report, url: main_app.order_management_reports_bulk_coop_path, method: :post do |f| + .row.date-range-filter + .sixteen.columns.alpha + = label_tag nil, t(".date_range") + %br + + = f.label :start_at, class: "inline" + = f.text_field :start_at, class: "datetimepicker datepicker-from" + + %span.range-divider + %i.icon-arrow-right + + = f.text_field :end_at, class: "datetimepicker datepicker-to" + = f.label :end_at, class: "inline" + + .row + .sixteen.columns.alpha + = f.label :distributor_ids + = f.collection_select(:distributor_ids, @permissions.allowed_distributors, :id, :name, {}, {class: "select2 fullwidth", multiple: true}) + + .row + .sixteen.columns.alpha + = f.label :report_type + = f.collection_select(:report_type, OrderManagement::Reports::BulkCoop::BulkCoopReport::REPORT_TYPES.map { |report_type| [t(".#{report_type}"), report_type] }, :last, :first, {}, {class: "select2 fullwidth", multiple: false}) + + .row + .sixteen.columns.alpha + = check_box_tag :report_format, "csv", false, id: "report_format_csv" + = label_tag :report_format_csv, t(".report_format_csv") + + = button t(".generate_report") diff --git a/engines/order_management/app/views/order_management/reports/bulk_coop/_report.html.haml b/engines/order_management/app/views/order_management/reports/bulk_coop/_report.html.haml new file mode 100644 index 0000000000..c4e2e5fc76 --- /dev/null +++ b/engines/order_management/app/views/order_management/reports/bulk_coop/_report.html.haml @@ -0,0 +1,20 @@ +- if @report.present? + %table#bulk_coop_report.report__table + %thead + %tr + - @renderer.header.each do |heading| + %th= heading + + %tbody + - @renderer.data_rows.each do |row| + %tr + - row.each do |cell_value| + %td= cell_value + + - if @renderer.data_rows.empty? + %tr + %td{colspan: @renderer.header.length}= t('.none') +- else + %p.report__message + = t(".select_and_search") + diff --git a/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml b/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml new file mode 100644 index 0000000000..6d8f0c79ab --- /dev/null +++ b/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml @@ -0,0 +1,2 @@ += render "filters" += render "report" diff --git a/engines/order_management/app/views/order_management/reports/bulk_coop/new.html.haml b/engines/order_management/app/views/order_management/reports/bulk_coop/new.html.haml new file mode 100644 index 0000000000..790853ca1f --- /dev/null +++ b/engines/order_management/app/views/order_management/reports/bulk_coop/new.html.haml @@ -0,0 +1 @@ += render "filters" diff --git a/engines/order_management/config/routes.rb b/engines/order_management/config/routes.rb index 79706c635a..405219634b 100644 --- a/engines/order_management/config/routes.rb +++ b/engines/order_management/config/routes.rb @@ -1,6 +1,7 @@ Openfoodnetwork::Application.routes.prepend do namespace :order_management do namespace :reports do + resource :bulk_coop, only: [:new, :create], controller: :bulk_coop resource :enterprise_fee_summary, only: [:new, :create] end end diff --git a/lib/open_food_network/bulk_coop_report.rb b/lib/open_food_network/bulk_coop_report.rb deleted file mode 100644 index 9eb8cf07c6..0000000000 --- a/lib/open_food_network/bulk_coop_report.rb +++ /dev/null @@ -1,266 +0,0 @@ -require 'open_food_network/reports/bulk_coop_supplier_report' -require 'open_food_network/reports/bulk_coop_allocation_report' -require "open_food_network/reports/line_items" - -module OpenFoodNetwork - class BulkCoopReport - attr_reader :params - def initialize(user, params = {}, render_table = false) - @params = params - @user = user - @render_table = render_table - - @supplier_report = Reports::BulkCoopSupplierReport.new - @allocation_report = Reports::BulkCoopAllocationReport.new - end - - def header - case params[:report_type] - when "bulk_coop_supplier_report" - @supplier_report.header - when "bulk_coop_allocation" - @allocation_report.header - when "bulk_coop_packing_sheets" - [I18n.t(:report_header_customer), - I18n.t(:report_header_product), - I18n.t(:report_header_variant), - I18n.t(:report_header_sum_total)] - when "bulk_coop_customer_payments" - [I18n.t(:report_header_customer), - I18n.t(:report_header_date_of_order), - I18n.t(:report_header_total_cost), - I18n.t(:report_header_amount_owing), - I18n.t(:report_header_amount_paid)] - else - [I18n.t(:report_header_supplier), - I18n.t(:report_header_product), - I18n.t(:report_header_product), - I18n.t(:report_header_bulk_unit_size), - I18n.t(:report_header_variant), - I18n.t(:report_header_weight), - I18n.t(:report_header_sum_total), - I18n.t(:report_header_sum_max_total), - I18n.t(:report_header_units_required), - I18n.t(:report_header_remainder)] - end - end - - def search - report_line_items.orders - end - - def table_items - return [] unless @render_table - report_line_items.list(line_item_includes) - end - - def rules - case params[:report_type] - when "bulk_coop_supplier_report" - @supplier_report.rules - when "bulk_coop_allocation" - @allocation_report.rules - when "bulk_coop_packing_sheets" - [{ group_by: proc { |li| li.product }, - sort_by: proc { |product| product.name } }, - { group_by: proc { |li| li.full_name }, - sort_by: proc { |full_name| full_name } }, - { group_by: proc { |li| li.order }, - sort_by: proc { |order| order.to_s } }] - when "bulk_coop_customer_payments" - [{ group_by: proc { |li| li.order }, - sort_by: proc { |order| order.completed_at } }] - else - [{ group_by: proc { |li| li.product.supplier }, - sort_by: proc { |supplier| supplier.name } }, - { group_by: proc { |li| li.product }, - sort_by: proc { |product| product.name }, - summary_columns: [proc { |lis| lis.first.product.supplier.name }, - proc { |lis| lis.first.product.name }, - proc { |lis| lis.first.product.group_buy_unit_size || 0.0 }, - proc { |_lis| "" }, - proc { |_lis| "" }, - proc { |lis| lis.sum { |li| li.quantity * (li.weight_from_unit_value || 0) } }, - proc { |lis| lis.sum { |li| (li.max_quantity || 0) * (li.weight_from_unit_value || 0) } }, - proc { |lis| ( (lis.first.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } / lis.first.product.group_buy_unit_size ) ).floor }, - proc { |lis| lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } - ( ( (lis.first.product.group_buy_unit_size || 0).zero? ? 0 : ( lis.sum { |li| [li.max_quantity || 0, li.quantity || 0].max * (li.weight_from_unit_value || 0) } / lis.first.product.group_buy_unit_size ) ).floor * (lis.first.product.group_buy_unit_size || 0) ) }] }, - { group_by: proc { |li| li.full_name }, - sort_by: proc { |full_name| full_name } }] - end - end - - def columns - case params[:report_type] - when "bulk_coop_supplier_report" - @supplier_report.columns - when "bulk_coop_allocation" - @allocation_report.columns - when "bulk_coop_packing_sheets" - [ - :order_billing_address_name, - :product_name, - :full_name, - :total_quantity - ] - when "bulk_coop_customer_payments" - [ - :order_billing_address_name, - :order_completed_at, - :customer_payments_total_cost, - :customer_payments_amount_owed, - :customer_payments_amount_paid - ] - else - [ - :product_supplier_name, - :product_name, - :product_group_buy_unit_size, - :full_name, - :weight_from_unit_value, - :total_quantity, - :total_max_quantity, - :empty_cell, - :empty_cell - ] - end - end - - private - - def line_item_includes - [{ order: [:bill_address], - variant: [{ option_values: :option_type }, { product: :supplier }] }] - end - - def order_permissions - return @order_permissions unless @order_permissions.nil? - @order_permissions = ::Permissions::Order.new(@user, @params[:q]) - end - - def report_line_items - @report_line_items ||= Reports::LineItems.new(order_permissions, @params) - end - - def customer_payments_total_cost(line_items) - line_items.map(&:order).uniq.sum(&:total) - end - - def customer_payments_amount_owed(line_items) - line_items.map(&:order).uniq.sum(&:outstanding_balance) - end - - def customer_payments_amount_paid(line_items) - line_items.map(&:order).uniq.sum(&:payment_total) - end - - def empty_cell(*) - "" - end - - def full_name(line_items) - line_items.first.full_name - end - - def group_buy_unit_size(line_items) - (line_items.first.variant.product.group_buy_unit_size || 0.0) / - (line_items.first.product.variant_unit_scale || 1) - end - - def max_quantity_excess(line_items) - max_quantity_amount(line_items) - total_amount(line_items) - end - - def max_quantity_amount(line_items) - line_items.sum do |line_item| - max_quantity = [line_item.max_quantity || 0, line_item.quantity || 0].max - max_quantity * scaled_unit_value(line_item.variant) - end - end - - def option_value_value(line_items) - OpenFoodNetwork::OptionValueNamer.new(line_items.first).value - end - - def option_value_unit(line_items) - OpenFoodNetwork::OptionValueNamer.new(line_items.first).unit - end - - def order_billing_address_name(line_items) - billing_address = line_items.first.order.bill_address - billing_address.firstname + " " + billing_address.lastname - end - - def order_completed_at(line_items) - line_items.first.order.completed_at.to_s - end - - def product_group_buy_unit_size(line_items) - line_items.first.product.group_buy_unit_size || 0.0 - end - - def product_name(line_items) - line_items.first.product.name - end - - def product_supplier_name(line_items) - line_items.first.product.supplier.name - end - - def remainder(line_items) - remainder = total_available(line_items) - total_amount(line_items) - remainder >= 0 ? remainder : '' - end - - def scaled_final_weight_volume(line_item) - (line_item.final_weight_volume || 0) / (line_item.product.variant_unit_scale || 1) - end - - def scaled_unit_value(variant) - (variant.unit_value || 0) / (variant.product.variant_unit_scale || 1) - end - - def total_amount(line_items) - line_items.sum { |li| scaled_final_weight_volume(li) } - end - - def total_available(line_items) - units_required(line_items) * group_buy_unit_size(line_items) - end - - def total_max_quantity(line_items) - line_items.sum { |line_item| line_item.max_quantity || 0 } - end - - def total_quantity(line_items) - line_items.sum(&:quantity) - end - - def total_label(*) - I18n.t('admin.reports.total') - end - - def units_required(line_items) - if group_buy_unit_size(line_items).zero? - 0 - else - ( total_amount(line_items) / group_buy_unit_size(line_items) ).ceil - end - end - - def variant_product_group_buy_unit_size_f(line_items) - group_buy_unit_size(line_items) - end - - def variant_product_name(line_items) - line_items.first.variant.product.name - end - - def variant_product_supplier_name(line_items) - line_items.first.variant.product.supplier.name - end - - def weight_from_unit_value(line_items) - line_items.first.weight_from_unit_value || 0 - end - end -end diff --git a/lib/open_food_network/reports/bulk_coop_allocation_report.rb b/lib/open_food_network/reports/bulk_coop_allocation_report.rb deleted file mode 100644 index bcc068c0c5..0000000000 --- a/lib/open_food_network/reports/bulk_coop_allocation_report.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module OpenFoodNetwork::Reports - class BulkCoopAllocationReport - def header - [ - I18n.t(:report_header_customer), - I18n.t(:report_header_product), - I18n.t(:report_header_bulk_unit_size), - I18n.t(:report_header_variant), - I18n.t(:report_header_variant_value), - I18n.t(:report_header_variant_unit), - I18n.t(:report_header_weight), - I18n.t(:report_header_sum_total), - I18n.t(:report_header_total_available), - I18n.t(:report_header_unallocated), - I18n.t(:report_header_max_quantity_excess), - ] - end - - def rules - [ - { - group_by: proc { |line_item| line_item.product }, - sort_by: proc { |product| product.name }, - summary_columns: [ - :total_label, - :variant_product_name, - :variant_product_group_buy_unit_size_f, - :empty_cell, - :empty_cell, - :empty_cell, - :empty_cell, - :total_amount, - :total_available, - :remainder, - :max_quantity_excess - ] - }, - { - group_by: proc { |line_item| line_item.order }, - sort_by: proc { |order| order.to_s } - } - ] - end - - def columns - [ - :order_billing_address_name, - :product_name, - :product_group_buy_unit_size, - :full_name, - :option_value_value, - :option_value_unit, - :weight_from_unit_value, - :total_amount, - :empty_cell, - :empty_cell, - :empty_cell - ] - end - end -end diff --git a/lib/open_food_network/reports/bulk_coop_supplier_report.rb b/lib/open_food_network/reports/bulk_coop_supplier_report.rb deleted file mode 100644 index 0c1c86e3b2..0000000000 --- a/lib/open_food_network/reports/bulk_coop_supplier_report.rb +++ /dev/null @@ -1,60 +0,0 @@ -module OpenFoodNetwork::Reports - class BulkCoopSupplierReport - def header - [ - I18n.t(:report_header_supplier), - I18n.t(:report_header_product), - I18n.t(:report_header_bulk_unit_size), - I18n.t(:report_header_variant), - I18n.t(:report_header_variant_value), - I18n.t(:report_header_variant_unit), - I18n.t(:report_header_weight), - I18n.t(:report_header_sum_total), - I18n.t(:report_header_units_required), - I18n.t(:report_header_unallocated), - I18n.t(:report_header_max_quantity_excess), - ] - end - - def rules - [ - { group_by: proc { |line_item| line_item.product.supplier }, - sort_by: proc { |supplier| supplier.name } }, - { group_by: proc { |line_item| line_item.product }, - sort_by: proc { |product| product.name }, - summary_columns: [ - :variant_product_supplier_name, - :variant_product_name, - :variant_product_group_buy_unit_size_f, - :empty_cell, - :empty_cell, - :empty_cell, - :empty_cell, - :total_amount, - :units_required, - :remainder, - :max_quantity_excess - ] - }, - { group_by: proc { |line_item| line_item.full_name }, - sort_by: proc { |full_name| full_name } } - ] - end - - def columns - [ - :variant_product_supplier_name, - :variant_product_name, - :variant_product_group_buy_unit_size_f, - :full_name, - :option_value_value, - :option_value_unit, - :weight_from_unit_value, - :total_amount, - :empty_cell, - :empty_cell, - :empty_cell - ] - end - end -end From 9172606780806734217691428067b95e71b36a93 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 16:51:43 +0100 Subject: [PATCH 005/261] Allow the order management report partial to be reused on different reports. --- .../reports/{enterprise_fee_summaries => }/_report.html.haml | 0 .../views/order_management/reports/bulk_coop/create.html.haml | 2 +- .../reports/enterprise_fee_summaries/create.html.haml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename engines/order_management/app/views/order_management/reports/{enterprise_fee_summaries => }/_report.html.haml (100%) diff --git a/engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/_report.html.haml b/engines/order_management/app/views/order_management/reports/_report.html.haml similarity index 100% rename from engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/_report.html.haml rename to engines/order_management/app/views/order_management/reports/_report.html.haml diff --git a/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml b/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml index 6d8f0c79ab..06938dd67d 100644 --- a/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml +++ b/engines/order_management/app/views/order_management/reports/bulk_coop/create.html.haml @@ -1,2 +1,2 @@ = render "filters" -= render "report" += render "order_management/reports/report" diff --git a/engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/create.html.haml b/engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/create.html.haml index 6d8f0c79ab..06938dd67d 100644 --- a/engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/create.html.haml +++ b/engines/order_management/app/views/order_management/reports/enterprise_fee_summaries/create.html.haml @@ -1,2 +1,2 @@ = render "filters" -= render "report" += render "order_management/reports/report" From e58852289ffa44069374424f282137f596bb143c Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 16:58:56 +0100 Subject: [PATCH 006/261] Move the :require_valid_datetime_range method to OrderManagement::Reports::Parameters::Base so it can be reused on multiple reports. --- config/locales/en.yml | 5 +++-- .../reports/bulk_coop/parameters.rb | 12 ------------ .../reports/enterprise_fee_summary/parameters.rb | 12 ------------ .../app/services/reports/parameters/base.rb | 14 ++++++++++++++ 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 1aee3bfa2c..ef9dfe332d 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2827,6 +2827,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using order_management: reports: + base: + 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." enterprise_fee_summaries: filters: date_range: "Date Range" @@ -2836,8 +2839,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using none: "None" select_and_search: "Select filters and click on GENERATE REPORT to access your data." 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" diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb index 16ed31a744..5fe2b0e5fb 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb @@ -16,11 +16,6 @@ module OrderManagement validate :require_valid_datetime_range - def self.date_end_before_start_error_message - i18n_scope = "order_management.reports.enterprise_fee_summary" - I18n.t("date_end_before_start_error", scope: i18n_scope) - end - def initialize(attributes = {}) self.distributor_ids = [] @@ -34,13 +29,6 @@ module OrderManagement protected - def require_valid_datetime_range - return if start_at.blank? || end_at.blank? - - error_message = self.class.date_end_before_start_error_message - errors.add(:end_at, error_message) unless start_at < end_at - end - # Remove the blank strings that Rails multiple selects add by default to # make sure that blank lists are still submitted to the server as arrays # instead of nil. diff --git a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/parameters.rb b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/parameters.rb index cc12d9be1f..938feeea75 100644 --- a/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/parameters.rb +++ b/engines/order_management/app/services/order_management/reports/enterprise_fee_summary/parameters.rb @@ -19,11 +19,6 @@ module OrderManagement validate :require_valid_datetime_range - def self.date_end_before_start_error_message - i18n_scope = "order_management.reports.enterprise_fee_summary" - I18n.t("date_end_before_start_error", scope: i18n_scope) - end - def initialize(attributes = {}) self.distributor_ids = [] self.producer_ids = [] @@ -42,13 +37,6 @@ module OrderManagement protected - def require_valid_datetime_range - return if start_at.blank? || end_at.blank? - - error_message = self.class.date_end_before_start_error_message - errors.add(:end_at, error_message) unless start_at < end_at - end - # Remove the blank strings that Rails multiple selects add by default to # make sure that blank lists are still submitted to the server as arrays # instead of nil. diff --git a/engines/order_management/app/services/reports/parameters/base.rb b/engines/order_management/app/services/reports/parameters/base.rb index 8debc06b1d..c25a2e9969 100644 --- a/engines/order_management/app/services/reports/parameters/base.rb +++ b/engines/order_management/app/services/reports/parameters/base.rb @@ -12,8 +12,22 @@ module Reports end end + def self.date_end_before_start_error_message + i18n_scope = "order_management.reports.base" + I18n.t("date_end_before_start_error", scope: i18n_scope) + end + # The parameters are never persisted. def to_key; end + + protected + + def require_valid_datetime_range + return if start_at.blank? || end_at.blank? + + error_message = self.class.date_end_before_start_error_message + errors.add(:end_at, error_message) unless start_at < end_at + end end end end From bafa8beab361b745a5df48d977ebb6e69452e4b1 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 17:05:26 +0100 Subject: [PATCH 007/261] Use :parameter_not_allowed_error_message to from base Reports::Authorizer. --- .../order_management/reports/bulk_coop/authorizer.rb | 5 ----- engines/order_management/app/services/reports/authorizer.rb | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb index 39562e6da2..98e499d3c1 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb @@ -2,11 +2,6 @@ module OrderManagement module Reports module BulkCoop class Authorizer < ::Reports::Authorizer - def self.parameter_not_allowed_error_message - i18n_scope = "order_management.reports.enterprise_fee_summary" - I18n.t("parameter_not_allowed_error", scope: i18n_scope) - end - def authorize! require_ids_allowed(parameters.distributor_ids, permissions.allowed_distributors) end diff --git a/engines/order_management/app/services/reports/authorizer.rb b/engines/order_management/app/services/reports/authorizer.rb index 5871e7e395..3fd3d2fc4f 100644 --- a/engines/order_management/app/services/reports/authorizer.rb +++ b/engines/order_management/app/services/reports/authorizer.rb @@ -10,7 +10,7 @@ module Reports end def self.parameter_not_allowed_error_message - i18n_scope = "order_management.reports.shared" + i18n_scope = "order_management.reports.base" I18n.t("parameter_not_allowed_error", scope: i18n_scope) end From f90969134d5191e379865bf639bc77c9afd33e4c Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Fri, 5 Jun 2020 20:03:17 +0100 Subject: [PATCH 008/261] Fix a couple of Rubocop violations. --- .../order_management/reports/bulk_coop/bulk_coop_report.rb | 3 ++- .../services/order_management/reports/bulk_coop/parameters.rb | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb index 3d776c31f5..67229fdbc4 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb @@ -9,7 +9,7 @@ module OrderManagement :bulk_coop_allocation, :bulk_coop_packing_sheets, :bulk_coop_customer_payments - ] + ].freeze attr_reader :params def initialize(user, params = {}, render_table = false) @@ -141,6 +141,7 @@ module OrderManagement def order_permissions return @order_permissions unless @order_permissions.nil? + @order_permissions = ::Permissions::Order.new(@user, @params[:q]) end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb index 5fe2b0e5fb..7de25375e4 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb @@ -12,7 +12,7 @@ module OrderManagement validates :start_at, :end_at, date_time_string: true validates :distributor_ids, integer_array: true - validates_inclusion_of :report_type, in: OrderManagement::Reports::BulkCoop::BulkCoopReport::REPORT_TYPES.map(&:to_s) + validates_inclusion_of :report_type, in: BulkCoopReport::REPORT_TYPES.map(&:to_s) validate :require_valid_datetime_range From f08b83711566880dfe73a92ac00b596685ff96f3 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 13 Jun 2020 11:49:26 +0100 Subject: [PATCH 009/261] Make enter submit the search form in products list --- .../javascripts/admin/bulk_product_update.js.coffee | 4 ++++ .../admin/directives/enter_to_submit.js.coffee | 8 ++++++++ app/views/spree/admin/products/index/_filters.html.haml | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/admin/directives/enter_to_submit.js.coffee diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index 94939f3f91..cb434ebe7a 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -64,6 +64,10 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout RequestMonitor.load(BulkProducts.fetch(params).$promise).then -> $scope.resetProducts() + # Used by directive enterToSubmit + $scope.submit = -> + $scope.fetchProducts() + removeClearedValues = -> delete $scope.producerFilter if $scope.producerFilter == "0" delete $scope.categoryFilter if $scope.categoryFilter == "0" diff --git a/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee b/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee new file mode 100644 index 0000000000..913c6167f0 --- /dev/null +++ b/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee @@ -0,0 +1,8 @@ +angular.module("ofn.admin").directive "enterToSubmit", -> + restrict: 'A' + + link: (scope, element, attrs) -> + element.bind "keypress", (event) -> + return if event.which != 13 + + scope.submit() diff --git a/app/views/spree/admin/products/index/_filters.html.haml b/app/views/spree/admin/products/index/_filters.html.haml index 5aeaf5e4f9..71fc902792 100644 --- a/app/views/spree/admin/products/index/_filters.html.haml +++ b/app/views/spree/admin/products/index/_filters.html.haml @@ -5,7 +5,7 @@ .quick_search.three.columns.alpha %label{ for: 'quick_filter' } %br - %input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search') } + %input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "enter-to-submit" => "" } .one.columns   .filter_select.three.columns %label{ for: 'producer_filter' }= t 'producer' From 1740879261b5c6b002e36f940c5db01a8b63abb8 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 13 Jun 2020 12:07:25 +0100 Subject: [PATCH 010/261] Revert directive and just use ng-kkeypress --- .../javascripts/admin/bulk_product_update.js.coffee | 4 ---- .../admin/directives/enter_to_submit.js.coffee | 8 -------- app/views/spree/admin/products/index/_filters.html.haml | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 app/assets/javascripts/admin/directives/enter_to_submit.js.coffee diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee index cb434ebe7a..94939f3f91 100644 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ b/app/assets/javascripts/admin/bulk_product_update.js.coffee @@ -64,10 +64,6 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout RequestMonitor.load(BulkProducts.fetch(params).$promise).then -> $scope.resetProducts() - # Used by directive enterToSubmit - $scope.submit = -> - $scope.fetchProducts() - removeClearedValues = -> delete $scope.producerFilter if $scope.producerFilter == "0" delete $scope.categoryFilter if $scope.categoryFilter == "0" diff --git a/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee b/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee deleted file mode 100644 index 913c6167f0..0000000000 --- a/app/assets/javascripts/admin/directives/enter_to_submit.js.coffee +++ /dev/null @@ -1,8 +0,0 @@ -angular.module("ofn.admin").directive "enterToSubmit", -> - restrict: 'A' - - link: (scope, element, attrs) -> - element.bind "keypress", (event) -> - return if event.which != 13 - - scope.submit() diff --git a/app/views/spree/admin/products/index/_filters.html.haml b/app/views/spree/admin/products/index/_filters.html.haml index 71fc902792..0e7d47543d 100644 --- a/app/views/spree/admin/products/index/_filters.html.haml +++ b/app/views/spree/admin/products/index/_filters.html.haml @@ -5,7 +5,7 @@ .quick_search.three.columns.alpha %label{ for: 'quick_filter' } %br - %input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "enter-to-submit" => "" } + %input.quick-search.fullwidth{ ng: {model: 'query'}, name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress" => "$event.keyCode === 13 && fetchProducts()" } .one.columns   .filter_select.three.columns %label{ for: 'producer_filter' }= t 'producer' From e6e4b6f95cd18a78907bc98fc935e757dbb23f05 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 13 Jun 2020 12:08:13 +0100 Subject: [PATCH 011/261] Add keypress events to text input fields on orders search page --- app/views/spree/admin/orders/_filters.html.haml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/spree/admin/orders/_filters.html.haml b/app/views/spree/admin/orders/_filters.html.haml index 63c65fd488..e06d3ad5c6 100644 --- a/app/views/spree/admin/orders/_filters.html.haml +++ b/app/views/spree/admin/orders/_filters.html.haml @@ -16,17 +16,17 @@ .four.columns .field = label_tag nil, t(:order_number) - = text_field_tag "q[number_cont]", nil, 'ng-model' => 'q.number_cont' + = text_field_tag "q[number_cont]", nil, "ng-model" => "q.number_cont", "ng-keypress" => "$event.keyCode === 13 && fetchResults()" .field = label_tag nil, t(:email) - = email_field_tag "q[email_cont", nil, 'ng-model' => 'q.email_cont' + = email_field_tag "q[email_cont", nil, "ng-model" => "q.email_cont", "ng-keypress" => "$event.keyCode === 13 && fetchResults()" .four.columns .field = label_tag nil, t(:first_name_begins_with) - = text_field_tag "q[bill_address_firstname_start]", nil, size: 25, 'ng-model' => 'q.bill_address_firstname_start' + = text_field_tag "q[bill_address_firstname_start]", nil, size: 25, "ng-model" => "q.bill_address_firstname_start", "ng-keypress" => "$event.keyCode === 13 && fetchResults()" .field = label_tag nil, t(:last_name_begins_with) - = text_field_tag "q[bill_address_lastname_start]", nil, size: 25, 'ng-model' => 'q.bill_address_lastname_start' + = text_field_tag "q[bill_address_lastname_start]", nil, size: 25, "ng-model" => "q.bill_address_lastname_start", "ng-keypress" => "$event.keyCode === 13 && fetchResults()" .omega.four.columns .field.checkbox %label From ed82c7e3db199c0b4d76b3ea9a6b37ad4a66e75a Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 12:51:29 +0100 Subject: [PATCH 012/261] BulkCoopReport has been moved to the engines/order_management so move it's spec there too. --- .../bulk_coop/bulk_coop_report_spec.rb | 95 ++++++++++++++++++ .../bulk_coop_report_spec.rb | 98 ------------------- 2 files changed, 95 insertions(+), 98 deletions(-) create mode 100644 engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb delete mode 100644 spec/lib/open_food_network/bulk_coop_report_spec.rb diff --git a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb new file mode 100644 index 0000000000..46f774a576 --- /dev/null +++ b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +include AuthenticationWorkflow + +describe OrderManagement::Reports::BulkCoop::BulkCoopReport do + describe "fetching orders" do + let(:d1) { create(:distributor_enterprise) } + let(:oc1) { create(:simple_order_cycle) } + let(:o1) { create(:order, completed_at: 1.day.ago, order_cycle: oc1, distributor: d1) } + let(:li1) { build(:line_item_with_shipment) } + + before { o1.line_items << li1 } + + context "as a site admin" do + let(:user) { create(:admin_user) } + subject { OrderManagement::Reports::BulkCoop::BulkCoopReport.new user, {}, true } + + it "fetches completed orders" do + o2 = create(:order) + o2.line_items << build(:line_item) + expect(subject.table_items).to eq([li1]) + end + + it "does not show cancelled orders" do + o2 = create(:order, state: "canceled", completed_at: 1.day.ago) + o2.line_items << build(:line_item_with_shipment) + expect(subject.table_items).to eq([li1]) + end + end + + context "as a manager of a supplier" do + let!(:user) { create(:user) } + subject { OrderManagement::Reports::BulkCoop::BulkCoopReport.new user, {}, true } + + let(:s1) { create(:supplier_enterprise) } + + before do + s1.enterprise_roles.create!(user: user) + end + + context "that has granted P-OC to the distributor" do + let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } + let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } + + before do + o2.line_items << li2 + create(:enterprise_relationship, parent: s1, child: d1, permissions_list: [:add_to_order_cycle]) + end + + it "shows line items supplied by my producers, with names hidden" do + expect(subject.table_items).to eq([li2]) + expect(subject.table_items.first.order.bill_address.firstname).to eq("HIDDEN") + end + end + + context "that has not granted P-OC to the distributor" do + let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } + let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } + + before do + o2.line_items << li2 + end + + it "does not show line items supplied by my producers" do + expect(subject.table_items).to eq([]) + end + end + end + + context "as a manager of a distributor" do + let!(:user) { create(:user) } + subject { PackingReport.new user, {}, true } + + before do + d1.enterprise_roles.create!(user: user) + end + + it "only shows line items distributed by enterprises managed by the current user" do + d2 = create(:distributor_enterprise) + d2.enterprise_roles.create!(user: create(:user)) + o2 = create(:order, distributor: d2, completed_at: 1.day.ago) + o2.line_items << build(:line_item_with_shipment) + expect(subject.table_items).to eq([li1]) + end + + it "only shows the selected order cycle" do + oc2 = create(:simple_order_cycle) + o2 = create(:order, distributor: d1, order_cycle: oc2) + o2.line_items << build(:line_item) + allow(subject).to receive(:params).and_return(order_cycle_id_in: oc1.id) + expect(subject.table_items).to eq([li1]) + end + end + end +end diff --git a/spec/lib/open_food_network/bulk_coop_report_spec.rb b/spec/lib/open_food_network/bulk_coop_report_spec.rb deleted file mode 100644 index 5b43ba0283..0000000000 --- a/spec/lib/open_food_network/bulk_coop_report_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'spec_helper' -require 'open_food_network/bulk_coop_report' - -include AuthenticationWorkflow - -module OpenFoodNetwork - describe BulkCoopReport do - describe "fetching orders" do - let(:d1) { create(:distributor_enterprise) } - let(:oc1) { create(:simple_order_cycle) } - let(:o1) { create(:order, completed_at: 1.day.ago, order_cycle: oc1, distributor: d1) } - let(:li1) { build(:line_item_with_shipment) } - - before { o1.line_items << li1 } - - context "as a site admin" do - let(:user) { create(:admin_user) } - subject { BulkCoopReport.new user, {}, true } - - it "fetches completed orders" do - o2 = create(:order) - o2.line_items << build(:line_item) - expect(subject.table_items).to eq([li1]) - end - - it "does not show cancelled orders" do - o2 = create(:order, state: "canceled", completed_at: 1.day.ago) - o2.line_items << build(:line_item_with_shipment) - expect(subject.table_items).to eq([li1]) - end - end - - context "as a manager of a supplier" do - let!(:user) { create(:user) } - subject { BulkCoopReport.new user, {}, true } - - let(:s1) { create(:supplier_enterprise) } - - before do - s1.enterprise_roles.create!(user: user) - end - - context "that has granted P-OC to the distributor" do - let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } - let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } - - before do - o2.line_items << li2 - create(:enterprise_relationship, parent: s1, child: d1, permissions_list: [:add_to_order_cycle]) - end - - it "shows line items supplied by my producers, with names hidden" do - expect(subject.table_items).to eq([li2]) - expect(subject.table_items.first.order.bill_address.firstname).to eq("HIDDEN") - end - end - - context "that has not granted P-OC to the distributor" do - let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } - let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } - - before do - o2.line_items << li2 - end - - it "does not show line items supplied by my producers" do - expect(subject.table_items).to eq([]) - end - end - end - - context "as a manager of a distributor" do - let!(:user) { create(:user) } - subject { PackingReport.new user, {}, true } - - before do - d1.enterprise_roles.create!(user: user) - end - - it "only shows line items distributed by enterprises managed by the current user" do - d2 = create(:distributor_enterprise) - d2.enterprise_roles.create!(user: create(:user)) - o2 = create(:order, distributor: d2, completed_at: 1.day.ago) - o2.line_items << build(:line_item_with_shipment) - expect(subject.table_items).to eq([li1]) - end - - it "only shows the selected order cycle" do - oc2 = create(:simple_order_cycle) - o2 = create(:order, distributor: d1, order_cycle: oc2) - o2.line_items << build(:line_item) - allow(subject).to receive(:params).and_return(order_cycle_id_in: oc1.id) - expect(subject.table_items).to eq([li1]) - end - end - end - end -end From bfc6daf07689649afb0e411c79ea889e26f03d5f Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 12:57:14 +0100 Subject: [PATCH 013/261] Remove duplicate PackingReport tests from the BulkCoopReport spec. These tests already exist in spec/lib/open_food_network/packing_report_spec.rb:72 --- .../bulk_coop/bulk_coop_report_spec.rb | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb index 46f774a576..cc8d874cc1 100644 --- a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb +++ b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb @@ -66,30 +66,5 @@ describe OrderManagement::Reports::BulkCoop::BulkCoopReport do end end end - - context "as a manager of a distributor" do - let!(:user) { create(:user) } - subject { PackingReport.new user, {}, true } - - before do - d1.enterprise_roles.create!(user: user) - end - - it "only shows line items distributed by enterprises managed by the current user" do - d2 = create(:distributor_enterprise) - d2.enterprise_roles.create!(user: create(:user)) - o2 = create(:order, distributor: d2, completed_at: 1.day.ago) - o2.line_items << build(:line_item_with_shipment) - expect(subject.table_items).to eq([li1]) - end - - it "only shows the selected order cycle" do - oc2 = create(:simple_order_cycle) - o2 = create(:order, distributor: d1, order_cycle: oc2) - o2.line_items << build(:line_item) - allow(subject).to receive(:params).and_return(order_cycle_id_in: oc1.id) - expect(subject.table_items).to eq([li1]) - end - end end end From 293e8949a998fc4626fda0eeccc0865347c81e56 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 12:59:23 +0100 Subject: [PATCH 014/261] Remove unused AuthenticationWorkflow module from the BulkCoopReport specs. --- .../order_management/reports/bulk_coop/bulk_coop_report_spec.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb index cc8d874cc1..9cd9629c74 100644 --- a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb +++ b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb @@ -1,7 +1,5 @@ require 'spec_helper' -include AuthenticationWorkflow - describe OrderManagement::Reports::BulkCoop::BulkCoopReport do describe "fetching orders" do let(:d1) { create(:distributor_enterprise) } From 6dbb6f3f09941d28dd9689cb0655a36196e0711f Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 13:09:09 +0100 Subject: [PATCH 015/261] Add an underscore before unused method arguments rather than an empty splat operator so it's easier to understand what is being passed in. --- .../order_management/reports/bulk_coop/bulk_coop_report.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb index 67229fdbc4..c31c3edfc3 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb @@ -161,7 +161,7 @@ module OrderManagement line_items.map(&:order).uniq.sum(&:payment_total) end - def empty_cell(*) + def empty_cell(_line_items) "" end @@ -243,7 +243,7 @@ module OrderManagement line_items.sum(&:quantity) end - def total_label(*) + def total_label(_line_items) I18n.t('admin.reports.total') end From bcf79ef8032741ec19bc239f23632a8e33600e2c Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 13:27:44 +0100 Subject: [PATCH 016/261] Fix code climate violations related to removing blockenspiel. --- app/controllers/spree/admin/reports_controller.rb | 2 +- .../order_management/reports/bulk_coop_controller.rb | 2 ++ .../order_management/reports/bulk_coop/authorizer.rb | 2 ++ .../order_management/reports/bulk_coop/bulk_coop_report.rb | 3 +++ .../reports/bulk_coop/bulk_coop_supplier_report.rb | 5 +++-- .../order_management/reports/bulk_coop/parameters.rb | 2 ++ .../order_management/reports/bulk_coop/permissions.rb | 2 ++ .../reports/bulk_coop/renderers/csv_renderer.rb | 2 ++ .../reports/bulk_coop/renderers/html_renderer.rb | 2 ++ .../order_management/reports/bulk_coop/report_service.rb | 2 ++ .../reports/bulk_coop/bulk_coop_report_spec.rb | 2 ++ 11 files changed, 23 insertions(+), 3 deletions(-) diff --git a/app/controllers/spree/admin/reports_controller.rb b/app/controllers/spree/admin/reports_controller.rb index ce3ec90c57..e8878308de 100644 --- a/app/controllers/spree/admin/reports_controller.rb +++ b/app/controllers/spree/admin/reports_controller.rb @@ -23,7 +23,7 @@ module Spree ORDER_MANAGEMENT_ENGINE_REPORTS = [ :bulk_coop, :enterprise_fee_summary - ] + ].freeze helper_method :render_content? diff --git a/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb b/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb index 26397e40bf..5a308fbdab 100644 --- a/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb +++ b/engines/order_management/app/controllers/order_management/reports/bulk_coop_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports class BulkCoopController < Spree::Admin::BaseController diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb index 98e499d3c1..b0e398e0a0 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/authorizer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb index c31c3edfc3..8adaef7f33 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_report.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "open_food_network/reports/line_items" module OrderManagement @@ -58,6 +60,7 @@ module OrderManagement def table_items return [] unless @render_table + report_line_items.list(line_item_includes) end diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb index 076a0a63c9..0f57c58f6a 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/bulk_coop_supplier_report.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop @@ -36,8 +38,7 @@ module OrderManagement :units_required, :remainder, :max_quantity_excess - ] - }, + ] }, { group_by: proc { |line_item| line_item.full_name }, sort_by: proc { |full_name| full_name } } ] diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb index 7de25375e4..2f5a48d296 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb index 23eb0aaca0..ca2a38467c 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/permissions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb index ca19e0a873..f848edbe71 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/csv_renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb index edbda863e1..03f7934e06 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/renderers/html_renderer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module OrderManagement module Reports module BulkCoop diff --git a/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb b/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb index c74e40934e..ac7f965218 100644 --- a/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb +++ b/engines/order_management/app/services/order_management/reports/bulk_coop/report_service.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'open_food_network/order_grouper' module OrderManagement diff --git a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb index 9cd9629c74..4378eb5b9b 100644 --- a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb +++ b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe OrderManagement::Reports::BulkCoop::BulkCoopReport do From 3abcb5b23c0cfc6f40675d584cb5bd5a559e54c2 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 15:37:44 +0100 Subject: [PATCH 017/261] Don't move the :parameter_not_allowed_error translation to a different scope yet. It will make it harder to merge and deploy this PR if every translation locale file has to be updated too. --- config/locales/en.yml | 5 ++--- engines/order_management/app/services/reports/authorizer.rb | 2 +- .../order_management/app/services/reports/parameters/base.rb | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index ef9dfe332d..1aee3bfa2c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -2827,9 +2827,6 @@ See the %{link} to find out more about %{sitename}'s features and to start using order_management: reports: - base: - 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." enterprise_fee_summaries: filters: date_range: "Date Range" @@ -2839,6 +2836,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using none: "None" select_and_search: "Select filters and click on GENERATE REPORT to access your data." 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" diff --git a/engines/order_management/app/services/reports/authorizer.rb b/engines/order_management/app/services/reports/authorizer.rb index 3fd3d2fc4f..1f232b0160 100644 --- a/engines/order_management/app/services/reports/authorizer.rb +++ b/engines/order_management/app/services/reports/authorizer.rb @@ -10,7 +10,7 @@ module Reports end def self.parameter_not_allowed_error_message - i18n_scope = "order_management.reports.base" + i18n_scope = "order_management.reports.enterprise_fee_summary" I18n.t("parameter_not_allowed_error", scope: i18n_scope) end diff --git a/engines/order_management/app/services/reports/parameters/base.rb b/engines/order_management/app/services/reports/parameters/base.rb index c25a2e9969..31148fd47c 100644 --- a/engines/order_management/app/services/reports/parameters/base.rb +++ b/engines/order_management/app/services/reports/parameters/base.rb @@ -13,7 +13,7 @@ module Reports end def self.date_end_before_start_error_message - i18n_scope = "order_management.reports.base" + i18n_scope = "order_management.reports.enterprise_fee_summary" I18n.t("date_end_before_start_error", scope: i18n_scope) end From c1e57fcc128f9c060d0bb5c2e1f1e3fa8ed27926 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 15:41:09 +0100 Subject: [PATCH 018/261] Adjust CanCan ability to reflect that the bulk coop report now runs from the order management engine. --- app/models/spree/ability_decorator.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index dccfd4d756..baac52a54d 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -185,9 +185,10 @@ class AbilityDecorator can [:admin, :index, :guide, :import, :save, :save_data, :validate_data, :reset_absent_products], ProductImport::ProductImporter # Reports page - can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, + can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :packing], Spree::Admin::ReportsController + add_bulk_coop_abilities add_enterprise_fee_summary_abilities end @@ -267,6 +268,7 @@ class AbilityDecorator can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :xero_invoices], Spree::Admin::ReportsController + add_bulk_coop_abilities add_enterprise_fee_summary_abilities can [:create], Customer @@ -291,6 +293,13 @@ class AbilityDecorator end end + def add_bulk_coop_abilities + # Reveal the report link in spree/admin/reports#index + can [:bulk_coop], Spree::Admin::ReportsController + # Allow direct access to the report resource + can [:admin, :new, :create], :bulk_coop + end + def add_enterprise_fee_summary_abilities # Reveal the report link in spree/admin/reports#index can [:enterprise_fee_summary], Spree::Admin::ReportsController From ba126d5afc7f72857973096046b682a82cf19793 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 15:42:26 +0100 Subject: [PATCH 019/261] Move the bulk coop controller specs to the order management engine. Also deleting old :bulk_coop_report action from the Spree::Admin::ReportsController. --- .../spree/admin/reports_controller.rb | 13 --- .../reports/bulk_coop_controller_spec.rb | 95 +++++++++++++++++++ .../spree/admin/reports_controller_spec.rb | 37 -------- 3 files changed, 95 insertions(+), 50 deletions(-) create mode 100644 engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb diff --git a/app/controllers/spree/admin/reports_controller.rb b/app/controllers/spree/admin/reports_controller.rb index e8878308de..a931606ed0 100644 --- a/app/controllers/spree/admin/reports_controller.rb +++ b/app/controllers/spree/admin/reports_controller.rb @@ -95,19 +95,6 @@ module Spree render_report(@report.header, @report.table, params[:csv], "sales_tax.csv") end - def bulk_coop - # -- Prepare form options - @distributors = my_distributors - @report_type = params[:report_type] - - # -- Build Report with Order Grouper - @report = OpenFoodNetwork::BulkCoopReport.new spree_current_user, params, render_content? - @table = order_grouper_table - csv_file_name = "bulk_coop_#{params[:report_type]}_#{timestamp}.csv" - - render_report(@report.header, @table, params[:csv], csv_file_name) - end - def payments # -- Prepare Form Options @distributors = my_distributors diff --git a/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb b/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb new file mode 100644 index 0000000000..e292325ff8 --- /dev/null +++ b/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb @@ -0,0 +1,95 @@ +require "spec_helper" + +describe OrderManagement::Reports::BulkCoopController, type: :controller do + let(:report_klass) { OrderManagement::Reports::BulkCoop } + + let!(:distributor) { create(:distributor_enterprise) } + + let(:current_user) { distributor.owner } + + before do + allow(controller).to receive(:spree_current_user) { current_user } + end + + describe "#new" do + it "renders the report form" do + get :new + + expect(response).to be_success + expect(response).to render_template(new_template_path) + end + end + + describe "#create" do + context "when the parameters are valid" do + it "sends the generated report in the correct format" do + post :create, report: { + start_at: "2018-10-09 07:30:00", + report_type: "bulk_coop_supplier_report" + }, report_format: "csv" + + expect(response).to be_success + expect(response.body).not_to be_blank + expect(response.header["Content-Type"]).to eq("text/csv") + end + end + + context "when the parameters are invalid" do + it "renders the report form with an error" do + post :create, report: { + start_at: "invalid_date", + report_type: "bulk_coop_supplier_report" + }, report_format: "csv" + + expect(flash[:error]).to eq(I18n.t("invalid_filter_parameters", scope: i18n_scope)) + expect(response).to render_template(new_template_path) + end + end + + context "when some parameters are now allowed" do + let!(:distributor) { create(:distributor_enterprise) } + let!(:other_distributor) { create(:distributor_enterprise) } + + let(:current_user) { distributor.owner } + + it "renders the report form with an error" do + post :create, report: { + distributor_ids: [other_distributor.id], + report_type: "bulk_coop_supplier_report" + }, report_format: "csv" + + expect(flash[:error]).to eq(report_klass::Authorizer.parameter_not_allowed_error_message) + expect(response).to render_template(new_template_path) + end + end + + describe "filtering results based on permissions" do + let!(:distributor) { create(:distributor_enterprise) } + let!(:other_distributor) { create(:distributor_enterprise) } + + let(:current_user) { distributor.owner } + + it "applies permissions to report" do + post :create, report: {}, report_format: "csv" + + expect(assigns(:permissions).allowed_distributors.to_a).to eq([distributor]) + end + end + end + + private + + def default_report_params + { + report_type: "bulk_coop_supplier_report" + } + end + + def i18n_scope + "order_management.reports.enterprise_fee_summary" + end + + def new_template_path + "order_management/reports/bulk_coop/new" + end +end diff --git a/spec/controllers/spree/admin/reports_controller_spec.rb b/spec/controllers/spree/admin/reports_controller_spec.rb index e339e09fd1..9c4e2d65ff 100644 --- a/spec/controllers/spree/admin/reports_controller_spec.rb +++ b/spec/controllers/spree/admin/reports_controller_spec.rb @@ -93,18 +93,6 @@ describe Spree::Admin::ReportsController, type: :controller do end end - describe 'Bulk Coop' do - let!(:present_objects) { [orderA1, orderA2, orderB1, orderB2] } - - it "only shows orders that I have access to" do - spree_post :bulk_coop, q: {} - - expect(resulting_orders).to include(orderA1, orderB1) - expect(resulting_orders).not_to include(orderA2) - expect(resulting_orders).not_to include(orderB2) - end - end - describe 'Payments' do let!(:present_objects) { [orderA1, orderA2, orderB1, orderB2] } @@ -156,31 +144,6 @@ describe Spree::Admin::ReportsController, type: :controller do end end - describe 'Bulk Coop' do - context "where I have granted P-OC to the distributor" do - let!(:present_objects) { [orderA1, orderA2] } - - before do - create(:enterprise_relationship, parent: supplier1, child: distributor1, permissions_list: [:add_to_order_cycle]) - end - - it "only shows product line items that I am supplying" do - spree_post :bulk_coop, q: {} - - expect(resulting_products).to include product1 - expect(resulting_products).not_to include product2, product3 - end - end - - context "where I have not granted P-OC to the distributor" do - it "shows product line items that I am supplying" do - spree_post :bulk_coop - - expect(resulting_products).not_to include product1, product2, product3 - end - end - end - describe 'Orders & Fulfillment' do let!(:present_objects) { [orderA1, orderA2] } From fdf0d923667395a7ccb70b67d7c764bc63ab7524 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 15:52:42 +0100 Subject: [PATCH 020/261] Move feature spec for bulk coop report to the order management engine. --- .../order_management/reports/bulk_coop_spec.rb | 17 +++++++++++++++++ spec/features/admin/reports_spec.rb | 9 --------- 2 files changed, 17 insertions(+), 9 deletions(-) create mode 100644 engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb diff --git a/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb new file mode 100644 index 0000000000..90d3599628 --- /dev/null +++ b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb @@ -0,0 +1,17 @@ +require "spec_helper" + +feature "bulk coop" do + include AuthenticationWorkflow + include WebHelper + + scenario "bulk co-op report" do + quick_login_as_admin + visit spree.admin_reports_path + click_link 'Bulk Co-Op' + click_button 'Generate Report' + + expect(page).to have_content 'Supplier' + end +end + + diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 97b677ed98..5ebd118fd7 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -155,15 +155,6 @@ feature ' expect(page).to have_content 'Order date' end - scenario "bulk co-op report" do - quick_login_as_admin - visit spree.admin_reports_path - click_link 'Bulk Co-Op' - click_button 'Search' - - expect(page).to have_content 'Supplier' - end - scenario "payments reports" do quick_login_as_admin visit spree.admin_reports_path From 0ef3a7e24f614d6670cb4d8445aae1c0eaf93e8d Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 16:23:11 +0100 Subject: [PATCH 021/261] Fix some more code climate violations for bulk coop specs which have been moved to the order management engine. --- .../reports/bulk_coop_controller_spec.rb | 2 ++ .../reports/bulk_coop_spec.rb | 4 ++-- .../bulk_coop/bulk_coop_report_spec.rb | 21 ++++++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb b/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb index e292325ff8..4476edd9cf 100644 --- a/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb +++ b/engines/order_management/spec/controllers/order_management/reports/bulk_coop_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" describe OrderManagement::Reports::BulkCoopController, type: :controller do diff --git a/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb index 90d3599628..29caf17a15 100644 --- a/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb +++ b/engines/order_management/spec/features/order_management/reports/bulk_coop_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "spec_helper" feature "bulk coop" do @@ -13,5 +15,3 @@ feature "bulk coop" do expect(page).to have_content 'Supplier' end end - - diff --git a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb index 4378eb5b9b..8f45355ee6 100644 --- a/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb +++ b/engines/order_management/spec/services/order_management/reports/bulk_coop/bulk_coop_report_spec.rb @@ -39,12 +39,18 @@ describe OrderManagement::Reports::BulkCoop::BulkCoopReport do end context "that has granted P-OC to the distributor" do - let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } - let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } + let(:o2) do + create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), + ship_address: create(:address)) + end + let(:li2) do + build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) + end before do o2.line_items << li2 - create(:enterprise_relationship, parent: s1, child: d1, permissions_list: [:add_to_order_cycle]) + create(:enterprise_relationship, parent: s1, child: d1, + permissions_list: [:add_to_order_cycle]) end it "shows line items supplied by my producers, with names hidden" do @@ -54,8 +60,13 @@ describe OrderManagement::Reports::BulkCoop::BulkCoopReport do end context "that has not granted P-OC to the distributor" do - let(:o2) { create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), ship_address: create(:address)) } - let(:li2) { build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) } + let(:o2) do + create(:order, distributor: d1, completed_at: 1.day.ago, bill_address: create(:address), + ship_address: create(:address)) + end + let(:li2) do + build(:line_item_with_shipment, product: create(:simple_product, supplier: s1)) + end before do o2.line_items << li2 From 430e5ea9cc43ae0e7f72cdf7b20597f465e13712 Mon Sep 17 00:00:00 2001 From: Cillian O'Ruanaidh Date: Sat, 13 Jun 2020 16:57:43 +0100 Subject: [PATCH 022/261] Permission to view :bulk_coop report is now added in the #add_bulk_coop_abilities method. --- app/models/spree/ability_decorator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index baac52a54d..f416a9d53f 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -265,7 +265,7 @@ class AbilityDecorator end # Reports page - can [:admin, :index, :customers, :group_buys, :bulk_coop, :sales_tax, :payments, + can [:admin, :index, :customers, :group_buys, :sales_tax, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management, :xero_invoices], Spree::Admin::ReportsController add_bulk_coop_abilities From 9c643447c263bf72c143a805f573d97cc61e5a86 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2020 19:15:45 +0000 Subject: [PATCH 023/261] Bump ransack from 1.2.3 to 1.8.10 Bumps [ransack](https://github.com/activerecord-hackery/ransack) from 1.2.3 to 1.8.10. - [Release notes](https://github.com/activerecord-hackery/ransack/releases) - [Changelog](https://github.com/activerecord-hackery/ransack/blob/master/CHANGELOG.md) - [Commits](https://github.com/activerecord-hackery/ransack/compare/v1.2.3...v1.8.10) Signed-off-by: dependabot-preview[bot] --- Gemfile | 2 +- Gemfile.lock | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Gemfile b/Gemfile index 03db94f8a4..f11fa66851 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,7 @@ gem 'httparty', '~> 0.11' # For checking alerts. gem 'json', '>= 1.7.7' gem 'money', '5.1.1' gem 'paranoia', '~> 2.0' -gem 'ransack', '~> 1.2.3' +gem 'ransack', '~> 1.8.10' gem 'state_machine', '1.2.0' gem 'stringex', '~> 1.5.1' diff --git a/Gemfile.lock b/Gemfile.lock index ea173868b8..5832c55da1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -500,8 +500,6 @@ GEM paypal-sdk-merchant (1.106.1) paypal-sdk-core (~> 0.2.3) pg (0.21.0) - polyamorous (1.0.0) - activerecord (>= 3.0) power_assert (1.2.0) pry (0.12.2) coderay (~> 1.1.0) @@ -540,12 +538,11 @@ GEM rainbow (3.0.0) raindrops (0.19.1) rake (13.0.1) - ransack (1.2.3) - actionpack (>= 3.0) - activerecord (>= 3.0) - activesupport (>= 3.0) + ransack (1.8.10) + actionpack (>= 3.0, < 5.2) + activerecord (>= 3.0, < 5.2) + activesupport (>= 3.0, < 5.2) i18n - polyamorous (~> 1.0.0) rb-fsevent (0.10.3) rb-inotify (0.10.1) ffi (~> 1.0) @@ -776,7 +773,7 @@ DEPENDENCIES rails (~> 4.0.13) rails-i18n (~> 4.0) rails_safe_tasks (~> 1.0) - ransack (~> 1.2.3) + ransack (~> 1.8.10) redcarpet roadie-rails (~> 1.3.0) roo (~> 2.8.3) From 27fb3f156cd9859d2f36fc37c39485e144725dda Mon Sep 17 00:00:00 2001 From: Fatih Orhan Date: Thu, 18 Jun 2020 20:36:50 +0300 Subject: [PATCH 024/261] Update sell.html.haml --- app/views/home/sell.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/home/sell.html.haml b/app/views/home/sell.html.haml index 5238fd4cd8..ad0740979e 100644 --- a/app/views/home/sell.html.haml +++ b/app/views/home/sell.html.haml @@ -18,7 +18,7 @@ %h3= t :sell_producers %p = t :sell_producers_detail - %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) + %a{href: ContentConfig.user_guide_link}= t(:sell_user_guide) %a.button.transparent{href: signup_producers_path} = t :register_title @@ -26,7 +26,7 @@ %h3= t :sell_hubs %p = t :sell_hubs_detail - %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) + %a{href: ContentConfig.user_guide_link}= t(:sell_user_guide) %a.button.transparent{href: signup_shops_path} = t :register_title @@ -34,7 +34,7 @@ %h3= t :sell_groups %p = t :sell_groups_detail - %a{href: "https://openfoodnetwork.org/user-guide/"}= t(:sell_user_guide) + %a{href: ContentConfig.user_guide_link}= t(:sell_user_guide) %a.button.transparent{href: signup_groups_path} = t :register_title From 573f7b1087f485f607cfd98815fcbdea60462114 Mon Sep 17 00:00:00 2001 From: Eduardo Date: Thu, 18 Jun 2020 19:55:06 -0300 Subject: [PATCH 025/261] make shop links on the producers page open in new tab --- app/views/producers/_fat.html.haml | 4 ++-- app/views/producers/_skinny.html.haml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/producers/_fat.html.haml b/app/views/producers/_fat.html.haml index 9b4e3b68b6..7712d43629 100644 --- a/app/views/producers/_fat.html.haml +++ b/app/views/producers/_fat.html.haml @@ -79,8 +79,8 @@ .row.cta-container .columns.small-12 %a.cta-hub{"ng-repeat" => "hub in producer.hubs | orderBy:'-active'", - "ng-href" => "{{::hub.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined }}", - "ng-class" => "::{primary: hub.active, secondary: !hub.active}"} + "ng-href" => "{{::hub.path}}", "ng-attr-target" => "_blank", + "ng-class" => "::{primary: hub.active, secondary: !hub.active}", "target" => "_blank"} %i.ofn-i_068-shop-reversed{"ng-if" => "::hub.active"} %i.ofn-i_068-shop-reversed{"ng-if" => "::!hub.active"} .hub-name{"ng-bind" => "::hub.name"} diff --git a/app/views/producers/_skinny.html.haml b/app/views/producers/_skinny.html.haml index 6e05619d07..8664537362 100644 --- a/app/views/producers/_skinny.html.haml +++ b/app/views/producers/_skinny.html.haml @@ -3,7 +3,7 @@ %span{"ng-if" => "::producer.is_distributor" } .row.vertical-align-middle .columns.small-12 - %a.is_distributor{"ng-href" => "{{::producer.path}}", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}", "data-is-link" => "true"} + %a.is_distributor{"ng-href" => "{{::producer.path}}", "ng-attr-target" => "_blank", "data-is-link" => "true", "target" => "_blank"} %i{ng: {class: "::producer.producer_icon_font"}} %span.margin-top %strong{"ng-bind" => "::producer.name"} From f36e08a163b6da8399a919a0093e489ab0d71de2 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 19 Jun 2020 16:13:18 +0200 Subject: [PATCH 026/261] Rename *.css.scss to *.scss This fixes the following deprecation warning ``` DEPRECATION WARNING: Extra .css in SCSS file is unnecessary. Rename /usr/src/app/app/assets/stylesheets/darkswarm/variables.css.scss to /usr/src/app/app/assets/stylesheets/darkswar m/variables.scss. (called from _app_views_layouts_darkswarm_html_haml___3990351141569700945_46957256630860 at /usr/src/app/app/views/layouts/darkswarm.html.haml:18) (...) ``` --- .../admin/{advanced_settings.css.scss => advanced_settings.scss} | 0 app/assets/stylesheets/admin/{alert.css.scss => alert.scss} | 0 .../stylesheets/admin/{animations.css.scss => animations.scss} | 0 .../admin/{change_type_form.css.scss => change_type_form.scss} | 0 .../admin/components/{alert-box.css.scss => alert-box.scss} | 0 .../admin/components/{alert_row.css.scss => alert_row.scss} | 0 .../admin/components/{dialogs.css.scss => dialogs.scss} | 0 .../stylesheets/admin/components/{input.css.scss => input.scss} | 0 .../admin/components/{ng-cloak.css.scss => ng-cloak.scss} | 0 .../admin/components/{page_actions.css.scss => page_actions.scss} | 0 .../admin/components/{simple_modal.css.scss => simple_modal.scss} | 0 ...{stripe_connect_button.css.scss => stripe_connect_button.scss} | 0 .../components/{table_loading.css.scss => table_loading.scss} | 0 .../admin/components/{timepicker.css.scss => timepicker.scss} | 0 .../admin/components/{tooltip.css.scss => tooltip.scss} | 0 .../components/{wizard_progress.css.scss => wizard_progress.scss} | 0 .../stylesheets/admin/{customers.css.scss => customers.scss} | 0 .../{dashboard-single-ent.css.scss => dashboard-single-ent.scss} | 0 .../admin/{dashboard_item.css.scss => dashboard_item.scss} | 0 .../stylesheets/admin/{datepicker.css.scss => datepicker.scss} | 0 app/assets/stylesheets/admin/{dialog.css.scss => dialog.scss} | 0 app/assets/stylesheets/admin/{disabled.css.scss => disabled.scss} | 0 app/assets/stylesheets/admin/{dropdown.css.scss => dropdown.scss} | 0 .../{enterprise_console.css.scss => enterprise_console.scss} | 0 ...erprise_index_panels.css.scss => enterprise_index_panels.scss} | 0 .../stylesheets/admin/{enterprises.css.scss => enterprises.scss} | 0 .../{filters_and_controls.css.scss => filters_and_controls.scss} | 0 app/assets/stylesheets/admin/{icons.css.scss => icons.scss} | 0 .../{index_panel_buttons.css.scss => index_panel_buttons.scss} | 0 .../admin/{index_panels.css.scss => index_panels.scss} | 0 app/assets/stylesheets/admin/{modals.css.scss => modals.scss} | 0 app/assets/stylesheets/admin/{offsets.css.scss => offsets.scss} | 0 .../admin/{openfoodnetwork.css.scss => openfoodnetwork.scss} | 0 app/assets/stylesheets/admin/{orders.css.scss => orders.scss} | 0 .../pages/{subscription_form.css.scss => subscription_form.scss} | 0 ...scription_line_items.css.scss => subscription_line_items.scss} | 0 .../{subscription_review.css.scss => subscription_review.scss} | 0 .../admin/{product_import.css.scss => product_import.scss} | 0 app/assets/stylesheets/admin/{products.css.scss => products.scss} | 0 .../admin/{relationships.css.scss => relationships.scss} | 0 app/assets/stylesheets/admin/{reports.css.scss => reports.scss} | 0 app/assets/stylesheets/admin/{select2.css.scss => select2.scss} | 0 .../stylesheets/admin/{side_menu.css.scss => side_menu.scss} | 0 .../admin/{sidebar-item.css.scss => sidebar-item.scss} | 0 app/assets/stylesheets/admin/{tables.css.scss => tables.scss} | 0 .../stylesheets/admin/{tag_rules.css.scss => tag_rules.scss} | 0 .../stylesheets/admin/{typography.css.scss => typography.scss} | 0 .../stylesheets/admin/{validation.css.scss => validation.scss} | 0 .../stylesheets/admin/{variables.css.scss => variables.scss} | 0 .../admin/{variant_overrides.css.scss => variant_overrides.scss} | 0 app/assets/stylesheets/admin/{welcome.css.scss => welcome.scss} | 0 .../darkswarm/{_shop-filters.css.scss => _shop-filters.scss} | 0 .../darkswarm/{_shop-inputs.css.scss => _shop-inputs.scss} | 0 .../darkswarm/{_shop-modals.css.scss => _shop-modals.scss} | 0 .../{_shop-navigation.css.scss => _shop-navigation.scss} | 0 .../darkswarm/{_shop-popovers.css.scss => _shop-popovers.scss} | 0 .../{_shop-product-rows.css.scss => _shop-product-rows.scss} | 0 .../{_shop-product-thumb.css.scss => _shop-product-thumb.scss} | 0 .../{_shop-taxon-flag.css.scss => _shop-taxon-flag.scss} | 0 .../stylesheets/darkswarm/{account.css.scss => account.scss} | 0 .../darkswarm/{active_table.css.scss => active_table.scss} | 0 .../{active_table_search.css.scss => active_table_search.scss} | 0 .../stylesheets/darkswarm/{angular.css.scss => angular.scss} | 0 .../stylesheets/darkswarm/base/{colors.css.scss => colors.scss} | 0 .../stylesheets/darkswarm/{branding.css.scss => branding.scss} | 0 .../darkswarm/{cart-dropdown.css.scss => cart-dropdown.scss} | 0 .../stylesheets/darkswarm/{cart-page.css.scss => cart-page.scss} | 0 .../stylesheets/darkswarm/{checkout.css.scss => checkout.scss} | 0 .../darkswarm/{collapsible.css.scss => collapsible.scss} | 0 .../{distributor_header.css.scss => distributor_header.scss} | 0 .../{embedded_shopfront.css.scss => embedded_shopfront.scss} | 0 .../{expanding-sidebar.css.scss => expanding-sidebar.scss} | 0 app/assets/stylesheets/darkswarm/{forms.css.scss => forms.scss} | 0 app/assets/stylesheets/darkswarm/{groups.css.scss => groups.scss} | 0 .../darkswarm/{help-modal.css.scss => help-modal.scss} | 0 .../darkswarm/{home_panes.css.scss => home_panes.scss} | 0 .../darkswarm/{home_tagline.css.scss => home_tagline.scss} | 0 .../stylesheets/darkswarm/{hub_node.css.scss => hub_node.scss} | 0 app/assets/stylesheets/darkswarm/{hubs.css.scss => hubs.scss} | 0 app/assets/stylesheets/darkswarm/{images.css.scss => images.scss} | 0 .../darkswarm/layout/{offcanvas.css.scss => offcanvas.scss} | 0 app/assets/stylesheets/darkswarm/{lists.css.scss => lists.scss} | 0 app/assets/stylesheets/darkswarm/{map.css.scss => map.scss} | 0 app/assets/stylesheets/darkswarm/{menu.css.scss => menu.scss} | 0 .../{modal-enterprises.css.scss => modal-enterprises.scss} | 0 app/assets/stylesheets/darkswarm/{modals.css.scss => modals.scss} | 0 .../stylesheets/darkswarm/{overrides.css.scss => overrides.scss} | 0 .../darkswarm/{page_alert.css.scss => page_alert.scss} | 0 .../darkswarm/pages/{login_modal.css.scss => login_modal.scss} | 0 .../darkswarm/{producer_node.css.scss => producer_node.scss} | 0 .../stylesheets/darkswarm/{producers.css.scss => producers.scss} | 0 .../darkswarm/{product_table.css.scss => product_table.scss} | 0 .../darkswarm/{registration.css.scss => registration.scss} | 0 app/assets/stylesheets/darkswarm/{shop.css.scss => shop.scss} | 0 .../darkswarm/{shop_search.css.scss => shop_search.scss} | 0 .../stylesheets/darkswarm/{shop_tabs.css.scss => shop_tabs.scss} | 0 .../stylesheets/darkswarm/{sidebar.css.scss => sidebar.scss} | 0 app/assets/stylesheets/darkswarm/{signup.css.scss => signup.scss} | 0 .../darkswarm/{stripe-elements.css.scss => stripe-elements.scss} | 0 app/assets/stylesheets/darkswarm/{style.css.scss => style.scss} | 0 app/assets/stylesheets/darkswarm/{tables.css.scss => tables.scss} | 0 app/assets/stylesheets/darkswarm/{tabset.css.scss => tabset.scss} | 0 app/assets/stylesheets/darkswarm/{taxons.css.scss => taxons.scss} | 0 .../darkswarm/{typography.css.scss => typography.scss} | 0 app/assets/stylesheets/darkswarm/{ui.css.scss => ui.scss} | 0 .../stylesheets/darkswarm/{variables.css.scss => variables.scss} | 0 app/assets/stylesheets/mail/{email.css.scss => email.scss} | 0 engines/web/app/assets/stylesheets/web/{all.css.scss => all.scss} | 0 .../web/pages/{cookies_banner.css.scss => cookies_banner.scss} | 0 .../{cookies_policy_modal.css.scss => cookies_policy_modal.scss} | 0 110 files changed, 0 insertions(+), 0 deletions(-) rename app/assets/stylesheets/admin/{advanced_settings.css.scss => advanced_settings.scss} (100%) rename app/assets/stylesheets/admin/{alert.css.scss => alert.scss} (100%) rename app/assets/stylesheets/admin/{animations.css.scss => animations.scss} (100%) rename app/assets/stylesheets/admin/{change_type_form.css.scss => change_type_form.scss} (100%) rename app/assets/stylesheets/admin/components/{alert-box.css.scss => alert-box.scss} (100%) rename app/assets/stylesheets/admin/components/{alert_row.css.scss => alert_row.scss} (100%) rename app/assets/stylesheets/admin/components/{dialogs.css.scss => dialogs.scss} (100%) rename app/assets/stylesheets/admin/components/{input.css.scss => input.scss} (100%) rename app/assets/stylesheets/admin/components/{ng-cloak.css.scss => ng-cloak.scss} (100%) rename app/assets/stylesheets/admin/components/{page_actions.css.scss => page_actions.scss} (100%) rename app/assets/stylesheets/admin/components/{simple_modal.css.scss => simple_modal.scss} (100%) rename app/assets/stylesheets/admin/components/{stripe_connect_button.css.scss => stripe_connect_button.scss} (100%) rename app/assets/stylesheets/admin/components/{table_loading.css.scss => table_loading.scss} (100%) rename app/assets/stylesheets/admin/components/{timepicker.css.scss => timepicker.scss} (100%) rename app/assets/stylesheets/admin/components/{tooltip.css.scss => tooltip.scss} (100%) rename app/assets/stylesheets/admin/components/{wizard_progress.css.scss => wizard_progress.scss} (100%) rename app/assets/stylesheets/admin/{customers.css.scss => customers.scss} (100%) rename app/assets/stylesheets/admin/{dashboard-single-ent.css.scss => dashboard-single-ent.scss} (100%) rename app/assets/stylesheets/admin/{dashboard_item.css.scss => dashboard_item.scss} (100%) rename app/assets/stylesheets/admin/{datepicker.css.scss => datepicker.scss} (100%) rename app/assets/stylesheets/admin/{dialog.css.scss => dialog.scss} (100%) rename app/assets/stylesheets/admin/{disabled.css.scss => disabled.scss} (100%) rename app/assets/stylesheets/admin/{dropdown.css.scss => dropdown.scss} (100%) rename app/assets/stylesheets/admin/{enterprise_console.css.scss => enterprise_console.scss} (100%) rename app/assets/stylesheets/admin/{enterprise_index_panels.css.scss => enterprise_index_panels.scss} (100%) rename app/assets/stylesheets/admin/{enterprises.css.scss => enterprises.scss} (100%) rename app/assets/stylesheets/admin/{filters_and_controls.css.scss => filters_and_controls.scss} (100%) rename app/assets/stylesheets/admin/{icons.css.scss => icons.scss} (100%) rename app/assets/stylesheets/admin/{index_panel_buttons.css.scss => index_panel_buttons.scss} (100%) rename app/assets/stylesheets/admin/{index_panels.css.scss => index_panels.scss} (100%) rename app/assets/stylesheets/admin/{modals.css.scss => modals.scss} (100%) rename app/assets/stylesheets/admin/{offsets.css.scss => offsets.scss} (100%) rename app/assets/stylesheets/admin/{openfoodnetwork.css.scss => openfoodnetwork.scss} (100%) rename app/assets/stylesheets/admin/{orders.css.scss => orders.scss} (100%) rename app/assets/stylesheets/admin/pages/{subscription_form.css.scss => subscription_form.scss} (100%) rename app/assets/stylesheets/admin/pages/{subscription_line_items.css.scss => subscription_line_items.scss} (100%) rename app/assets/stylesheets/admin/pages/{subscription_review.css.scss => subscription_review.scss} (100%) rename app/assets/stylesheets/admin/{product_import.css.scss => product_import.scss} (100%) rename app/assets/stylesheets/admin/{products.css.scss => products.scss} (100%) rename app/assets/stylesheets/admin/{relationships.css.scss => relationships.scss} (100%) rename app/assets/stylesheets/admin/{reports.css.scss => reports.scss} (100%) rename app/assets/stylesheets/admin/{select2.css.scss => select2.scss} (100%) rename app/assets/stylesheets/admin/{side_menu.css.scss => side_menu.scss} (100%) rename app/assets/stylesheets/admin/{sidebar-item.css.scss => sidebar-item.scss} (100%) rename app/assets/stylesheets/admin/{tables.css.scss => tables.scss} (100%) rename app/assets/stylesheets/admin/{tag_rules.css.scss => tag_rules.scss} (100%) rename app/assets/stylesheets/admin/{typography.css.scss => typography.scss} (100%) rename app/assets/stylesheets/admin/{validation.css.scss => validation.scss} (100%) rename app/assets/stylesheets/admin/{variables.css.scss => variables.scss} (100%) rename app/assets/stylesheets/admin/{variant_overrides.css.scss => variant_overrides.scss} (100%) rename app/assets/stylesheets/admin/{welcome.css.scss => welcome.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-filters.css.scss => _shop-filters.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-inputs.css.scss => _shop-inputs.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-modals.css.scss => _shop-modals.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-navigation.css.scss => _shop-navigation.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-popovers.css.scss => _shop-popovers.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-product-rows.css.scss => _shop-product-rows.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-product-thumb.css.scss => _shop-product-thumb.scss} (100%) rename app/assets/stylesheets/darkswarm/{_shop-taxon-flag.css.scss => _shop-taxon-flag.scss} (100%) rename app/assets/stylesheets/darkswarm/{account.css.scss => account.scss} (100%) rename app/assets/stylesheets/darkswarm/{active_table.css.scss => active_table.scss} (100%) rename app/assets/stylesheets/darkswarm/{active_table_search.css.scss => active_table_search.scss} (100%) rename app/assets/stylesheets/darkswarm/{angular.css.scss => angular.scss} (100%) rename app/assets/stylesheets/darkswarm/base/{colors.css.scss => colors.scss} (100%) rename app/assets/stylesheets/darkswarm/{branding.css.scss => branding.scss} (100%) rename app/assets/stylesheets/darkswarm/{cart-dropdown.css.scss => cart-dropdown.scss} (100%) rename app/assets/stylesheets/darkswarm/{cart-page.css.scss => cart-page.scss} (100%) rename app/assets/stylesheets/darkswarm/{checkout.css.scss => checkout.scss} (100%) rename app/assets/stylesheets/darkswarm/{collapsible.css.scss => collapsible.scss} (100%) rename app/assets/stylesheets/darkswarm/{distributor_header.css.scss => distributor_header.scss} (100%) rename app/assets/stylesheets/darkswarm/{embedded_shopfront.css.scss => embedded_shopfront.scss} (100%) rename app/assets/stylesheets/darkswarm/{expanding-sidebar.css.scss => expanding-sidebar.scss} (100%) rename app/assets/stylesheets/darkswarm/{forms.css.scss => forms.scss} (100%) rename app/assets/stylesheets/darkswarm/{groups.css.scss => groups.scss} (100%) rename app/assets/stylesheets/darkswarm/{help-modal.css.scss => help-modal.scss} (100%) rename app/assets/stylesheets/darkswarm/{home_panes.css.scss => home_panes.scss} (100%) rename app/assets/stylesheets/darkswarm/{home_tagline.css.scss => home_tagline.scss} (100%) rename app/assets/stylesheets/darkswarm/{hub_node.css.scss => hub_node.scss} (100%) rename app/assets/stylesheets/darkswarm/{hubs.css.scss => hubs.scss} (100%) rename app/assets/stylesheets/darkswarm/{images.css.scss => images.scss} (100%) rename app/assets/stylesheets/darkswarm/layout/{offcanvas.css.scss => offcanvas.scss} (100%) rename app/assets/stylesheets/darkswarm/{lists.css.scss => lists.scss} (100%) rename app/assets/stylesheets/darkswarm/{map.css.scss => map.scss} (100%) rename app/assets/stylesheets/darkswarm/{menu.css.scss => menu.scss} (100%) rename app/assets/stylesheets/darkswarm/{modal-enterprises.css.scss => modal-enterprises.scss} (100%) rename app/assets/stylesheets/darkswarm/{modals.css.scss => modals.scss} (100%) rename app/assets/stylesheets/darkswarm/{overrides.css.scss => overrides.scss} (100%) rename app/assets/stylesheets/darkswarm/{page_alert.css.scss => page_alert.scss} (100%) rename app/assets/stylesheets/darkswarm/pages/{login_modal.css.scss => login_modal.scss} (100%) rename app/assets/stylesheets/darkswarm/{producer_node.css.scss => producer_node.scss} (100%) rename app/assets/stylesheets/darkswarm/{producers.css.scss => producers.scss} (100%) rename app/assets/stylesheets/darkswarm/{product_table.css.scss => product_table.scss} (100%) rename app/assets/stylesheets/darkswarm/{registration.css.scss => registration.scss} (100%) rename app/assets/stylesheets/darkswarm/{shop.css.scss => shop.scss} (100%) rename app/assets/stylesheets/darkswarm/{shop_search.css.scss => shop_search.scss} (100%) rename app/assets/stylesheets/darkswarm/{shop_tabs.css.scss => shop_tabs.scss} (100%) rename app/assets/stylesheets/darkswarm/{sidebar.css.scss => sidebar.scss} (100%) rename app/assets/stylesheets/darkswarm/{signup.css.scss => signup.scss} (100%) rename app/assets/stylesheets/darkswarm/{stripe-elements.css.scss => stripe-elements.scss} (100%) rename app/assets/stylesheets/darkswarm/{style.css.scss => style.scss} (100%) rename app/assets/stylesheets/darkswarm/{tables.css.scss => tables.scss} (100%) rename app/assets/stylesheets/darkswarm/{tabset.css.scss => tabset.scss} (100%) rename app/assets/stylesheets/darkswarm/{taxons.css.scss => taxons.scss} (100%) rename app/assets/stylesheets/darkswarm/{typography.css.scss => typography.scss} (100%) rename app/assets/stylesheets/darkswarm/{ui.css.scss => ui.scss} (100%) rename app/assets/stylesheets/darkswarm/{variables.css.scss => variables.scss} (100%) rename app/assets/stylesheets/mail/{email.css.scss => email.scss} (100%) rename engines/web/app/assets/stylesheets/web/{all.css.scss => all.scss} (100%) rename engines/web/app/assets/stylesheets/web/pages/{cookies_banner.css.scss => cookies_banner.scss} (100%) rename engines/web/app/assets/stylesheets/web/pages/{cookies_policy_modal.css.scss => cookies_policy_modal.scss} (100%) diff --git a/app/assets/stylesheets/admin/advanced_settings.css.scss b/app/assets/stylesheets/admin/advanced_settings.scss similarity index 100% rename from app/assets/stylesheets/admin/advanced_settings.css.scss rename to app/assets/stylesheets/admin/advanced_settings.scss diff --git a/app/assets/stylesheets/admin/alert.css.scss b/app/assets/stylesheets/admin/alert.scss similarity index 100% rename from app/assets/stylesheets/admin/alert.css.scss rename to app/assets/stylesheets/admin/alert.scss diff --git a/app/assets/stylesheets/admin/animations.css.scss b/app/assets/stylesheets/admin/animations.scss similarity index 100% rename from app/assets/stylesheets/admin/animations.css.scss rename to app/assets/stylesheets/admin/animations.scss diff --git a/app/assets/stylesheets/admin/change_type_form.css.scss b/app/assets/stylesheets/admin/change_type_form.scss similarity index 100% rename from app/assets/stylesheets/admin/change_type_form.css.scss rename to app/assets/stylesheets/admin/change_type_form.scss diff --git a/app/assets/stylesheets/admin/components/alert-box.css.scss b/app/assets/stylesheets/admin/components/alert-box.scss similarity index 100% rename from app/assets/stylesheets/admin/components/alert-box.css.scss rename to app/assets/stylesheets/admin/components/alert-box.scss diff --git a/app/assets/stylesheets/admin/components/alert_row.css.scss b/app/assets/stylesheets/admin/components/alert_row.scss similarity index 100% rename from app/assets/stylesheets/admin/components/alert_row.css.scss rename to app/assets/stylesheets/admin/components/alert_row.scss diff --git a/app/assets/stylesheets/admin/components/dialogs.css.scss b/app/assets/stylesheets/admin/components/dialogs.scss similarity index 100% rename from app/assets/stylesheets/admin/components/dialogs.css.scss rename to app/assets/stylesheets/admin/components/dialogs.scss diff --git a/app/assets/stylesheets/admin/components/input.css.scss b/app/assets/stylesheets/admin/components/input.scss similarity index 100% rename from app/assets/stylesheets/admin/components/input.css.scss rename to app/assets/stylesheets/admin/components/input.scss diff --git a/app/assets/stylesheets/admin/components/ng-cloak.css.scss b/app/assets/stylesheets/admin/components/ng-cloak.scss similarity index 100% rename from app/assets/stylesheets/admin/components/ng-cloak.css.scss rename to app/assets/stylesheets/admin/components/ng-cloak.scss diff --git a/app/assets/stylesheets/admin/components/page_actions.css.scss b/app/assets/stylesheets/admin/components/page_actions.scss similarity index 100% rename from app/assets/stylesheets/admin/components/page_actions.css.scss rename to app/assets/stylesheets/admin/components/page_actions.scss diff --git a/app/assets/stylesheets/admin/components/simple_modal.css.scss b/app/assets/stylesheets/admin/components/simple_modal.scss similarity index 100% rename from app/assets/stylesheets/admin/components/simple_modal.css.scss rename to app/assets/stylesheets/admin/components/simple_modal.scss diff --git a/app/assets/stylesheets/admin/components/stripe_connect_button.css.scss b/app/assets/stylesheets/admin/components/stripe_connect_button.scss similarity index 100% rename from app/assets/stylesheets/admin/components/stripe_connect_button.css.scss rename to app/assets/stylesheets/admin/components/stripe_connect_button.scss diff --git a/app/assets/stylesheets/admin/components/table_loading.css.scss b/app/assets/stylesheets/admin/components/table_loading.scss similarity index 100% rename from app/assets/stylesheets/admin/components/table_loading.css.scss rename to app/assets/stylesheets/admin/components/table_loading.scss diff --git a/app/assets/stylesheets/admin/components/timepicker.css.scss b/app/assets/stylesheets/admin/components/timepicker.scss similarity index 100% rename from app/assets/stylesheets/admin/components/timepicker.css.scss rename to app/assets/stylesheets/admin/components/timepicker.scss diff --git a/app/assets/stylesheets/admin/components/tooltip.css.scss b/app/assets/stylesheets/admin/components/tooltip.scss similarity index 100% rename from app/assets/stylesheets/admin/components/tooltip.css.scss rename to app/assets/stylesheets/admin/components/tooltip.scss diff --git a/app/assets/stylesheets/admin/components/wizard_progress.css.scss b/app/assets/stylesheets/admin/components/wizard_progress.scss similarity index 100% rename from app/assets/stylesheets/admin/components/wizard_progress.css.scss rename to app/assets/stylesheets/admin/components/wizard_progress.scss diff --git a/app/assets/stylesheets/admin/customers.css.scss b/app/assets/stylesheets/admin/customers.scss similarity index 100% rename from app/assets/stylesheets/admin/customers.css.scss rename to app/assets/stylesheets/admin/customers.scss diff --git a/app/assets/stylesheets/admin/dashboard-single-ent.css.scss b/app/assets/stylesheets/admin/dashboard-single-ent.scss similarity index 100% rename from app/assets/stylesheets/admin/dashboard-single-ent.css.scss rename to app/assets/stylesheets/admin/dashboard-single-ent.scss diff --git a/app/assets/stylesheets/admin/dashboard_item.css.scss b/app/assets/stylesheets/admin/dashboard_item.scss similarity index 100% rename from app/assets/stylesheets/admin/dashboard_item.css.scss rename to app/assets/stylesheets/admin/dashboard_item.scss diff --git a/app/assets/stylesheets/admin/datepicker.css.scss b/app/assets/stylesheets/admin/datepicker.scss similarity index 100% rename from app/assets/stylesheets/admin/datepicker.css.scss rename to app/assets/stylesheets/admin/datepicker.scss diff --git a/app/assets/stylesheets/admin/dialog.css.scss b/app/assets/stylesheets/admin/dialog.scss similarity index 100% rename from app/assets/stylesheets/admin/dialog.css.scss rename to app/assets/stylesheets/admin/dialog.scss diff --git a/app/assets/stylesheets/admin/disabled.css.scss b/app/assets/stylesheets/admin/disabled.scss similarity index 100% rename from app/assets/stylesheets/admin/disabled.css.scss rename to app/assets/stylesheets/admin/disabled.scss diff --git a/app/assets/stylesheets/admin/dropdown.css.scss b/app/assets/stylesheets/admin/dropdown.scss similarity index 100% rename from app/assets/stylesheets/admin/dropdown.css.scss rename to app/assets/stylesheets/admin/dropdown.scss diff --git a/app/assets/stylesheets/admin/enterprise_console.css.scss b/app/assets/stylesheets/admin/enterprise_console.scss similarity index 100% rename from app/assets/stylesheets/admin/enterprise_console.css.scss rename to app/assets/stylesheets/admin/enterprise_console.scss diff --git a/app/assets/stylesheets/admin/enterprise_index_panels.css.scss b/app/assets/stylesheets/admin/enterprise_index_panels.scss similarity index 100% rename from app/assets/stylesheets/admin/enterprise_index_panels.css.scss rename to app/assets/stylesheets/admin/enterprise_index_panels.scss diff --git a/app/assets/stylesheets/admin/enterprises.css.scss b/app/assets/stylesheets/admin/enterprises.scss similarity index 100% rename from app/assets/stylesheets/admin/enterprises.css.scss rename to app/assets/stylesheets/admin/enterprises.scss diff --git a/app/assets/stylesheets/admin/filters_and_controls.css.scss b/app/assets/stylesheets/admin/filters_and_controls.scss similarity index 100% rename from app/assets/stylesheets/admin/filters_and_controls.css.scss rename to app/assets/stylesheets/admin/filters_and_controls.scss diff --git a/app/assets/stylesheets/admin/icons.css.scss b/app/assets/stylesheets/admin/icons.scss similarity index 100% rename from app/assets/stylesheets/admin/icons.css.scss rename to app/assets/stylesheets/admin/icons.scss diff --git a/app/assets/stylesheets/admin/index_panel_buttons.css.scss b/app/assets/stylesheets/admin/index_panel_buttons.scss similarity index 100% rename from app/assets/stylesheets/admin/index_panel_buttons.css.scss rename to app/assets/stylesheets/admin/index_panel_buttons.scss diff --git a/app/assets/stylesheets/admin/index_panels.css.scss b/app/assets/stylesheets/admin/index_panels.scss similarity index 100% rename from app/assets/stylesheets/admin/index_panels.css.scss rename to app/assets/stylesheets/admin/index_panels.scss diff --git a/app/assets/stylesheets/admin/modals.css.scss b/app/assets/stylesheets/admin/modals.scss similarity index 100% rename from app/assets/stylesheets/admin/modals.css.scss rename to app/assets/stylesheets/admin/modals.scss diff --git a/app/assets/stylesheets/admin/offsets.css.scss b/app/assets/stylesheets/admin/offsets.scss similarity index 100% rename from app/assets/stylesheets/admin/offsets.css.scss rename to app/assets/stylesheets/admin/offsets.scss diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.scss similarity index 100% rename from app/assets/stylesheets/admin/openfoodnetwork.css.scss rename to app/assets/stylesheets/admin/openfoodnetwork.scss diff --git a/app/assets/stylesheets/admin/orders.css.scss b/app/assets/stylesheets/admin/orders.scss similarity index 100% rename from app/assets/stylesheets/admin/orders.css.scss rename to app/assets/stylesheets/admin/orders.scss diff --git a/app/assets/stylesheets/admin/pages/subscription_form.css.scss b/app/assets/stylesheets/admin/pages/subscription_form.scss similarity index 100% rename from app/assets/stylesheets/admin/pages/subscription_form.css.scss rename to app/assets/stylesheets/admin/pages/subscription_form.scss diff --git a/app/assets/stylesheets/admin/pages/subscription_line_items.css.scss b/app/assets/stylesheets/admin/pages/subscription_line_items.scss similarity index 100% rename from app/assets/stylesheets/admin/pages/subscription_line_items.css.scss rename to app/assets/stylesheets/admin/pages/subscription_line_items.scss diff --git a/app/assets/stylesheets/admin/pages/subscription_review.css.scss b/app/assets/stylesheets/admin/pages/subscription_review.scss similarity index 100% rename from app/assets/stylesheets/admin/pages/subscription_review.css.scss rename to app/assets/stylesheets/admin/pages/subscription_review.scss diff --git a/app/assets/stylesheets/admin/product_import.css.scss b/app/assets/stylesheets/admin/product_import.scss similarity index 100% rename from app/assets/stylesheets/admin/product_import.css.scss rename to app/assets/stylesheets/admin/product_import.scss diff --git a/app/assets/stylesheets/admin/products.css.scss b/app/assets/stylesheets/admin/products.scss similarity index 100% rename from app/assets/stylesheets/admin/products.css.scss rename to app/assets/stylesheets/admin/products.scss diff --git a/app/assets/stylesheets/admin/relationships.css.scss b/app/assets/stylesheets/admin/relationships.scss similarity index 100% rename from app/assets/stylesheets/admin/relationships.css.scss rename to app/assets/stylesheets/admin/relationships.scss diff --git a/app/assets/stylesheets/admin/reports.css.scss b/app/assets/stylesheets/admin/reports.scss similarity index 100% rename from app/assets/stylesheets/admin/reports.css.scss rename to app/assets/stylesheets/admin/reports.scss diff --git a/app/assets/stylesheets/admin/select2.css.scss b/app/assets/stylesheets/admin/select2.scss similarity index 100% rename from app/assets/stylesheets/admin/select2.css.scss rename to app/assets/stylesheets/admin/select2.scss diff --git a/app/assets/stylesheets/admin/side_menu.css.scss b/app/assets/stylesheets/admin/side_menu.scss similarity index 100% rename from app/assets/stylesheets/admin/side_menu.css.scss rename to app/assets/stylesheets/admin/side_menu.scss diff --git a/app/assets/stylesheets/admin/sidebar-item.css.scss b/app/assets/stylesheets/admin/sidebar-item.scss similarity index 100% rename from app/assets/stylesheets/admin/sidebar-item.css.scss rename to app/assets/stylesheets/admin/sidebar-item.scss diff --git a/app/assets/stylesheets/admin/tables.css.scss b/app/assets/stylesheets/admin/tables.scss similarity index 100% rename from app/assets/stylesheets/admin/tables.css.scss rename to app/assets/stylesheets/admin/tables.scss diff --git a/app/assets/stylesheets/admin/tag_rules.css.scss b/app/assets/stylesheets/admin/tag_rules.scss similarity index 100% rename from app/assets/stylesheets/admin/tag_rules.css.scss rename to app/assets/stylesheets/admin/tag_rules.scss diff --git a/app/assets/stylesheets/admin/typography.css.scss b/app/assets/stylesheets/admin/typography.scss similarity index 100% rename from app/assets/stylesheets/admin/typography.css.scss rename to app/assets/stylesheets/admin/typography.scss diff --git a/app/assets/stylesheets/admin/validation.css.scss b/app/assets/stylesheets/admin/validation.scss similarity index 100% rename from app/assets/stylesheets/admin/validation.css.scss rename to app/assets/stylesheets/admin/validation.scss diff --git a/app/assets/stylesheets/admin/variables.css.scss b/app/assets/stylesheets/admin/variables.scss similarity index 100% rename from app/assets/stylesheets/admin/variables.css.scss rename to app/assets/stylesheets/admin/variables.scss diff --git a/app/assets/stylesheets/admin/variant_overrides.css.scss b/app/assets/stylesheets/admin/variant_overrides.scss similarity index 100% rename from app/assets/stylesheets/admin/variant_overrides.css.scss rename to app/assets/stylesheets/admin/variant_overrides.scss diff --git a/app/assets/stylesheets/admin/welcome.css.scss b/app/assets/stylesheets/admin/welcome.scss similarity index 100% rename from app/assets/stylesheets/admin/welcome.css.scss rename to app/assets/stylesheets/admin/welcome.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-filters.css.scss b/app/assets/stylesheets/darkswarm/_shop-filters.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-filters.css.scss rename to app/assets/stylesheets/darkswarm/_shop-filters.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-inputs.css.scss b/app/assets/stylesheets/darkswarm/_shop-inputs.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-inputs.css.scss rename to app/assets/stylesheets/darkswarm/_shop-inputs.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-modals.css.scss b/app/assets/stylesheets/darkswarm/_shop-modals.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-modals.css.scss rename to app/assets/stylesheets/darkswarm/_shop-modals.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-navigation.css.scss b/app/assets/stylesheets/darkswarm/_shop-navigation.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-navigation.css.scss rename to app/assets/stylesheets/darkswarm/_shop-navigation.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-popovers.css.scss b/app/assets/stylesheets/darkswarm/_shop-popovers.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-popovers.css.scss rename to app/assets/stylesheets/darkswarm/_shop-popovers.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-product-rows.css.scss b/app/assets/stylesheets/darkswarm/_shop-product-rows.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-product-rows.css.scss rename to app/assets/stylesheets/darkswarm/_shop-product-rows.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-product-thumb.css.scss b/app/assets/stylesheets/darkswarm/_shop-product-thumb.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-product-thumb.css.scss rename to app/assets/stylesheets/darkswarm/_shop-product-thumb.scss diff --git a/app/assets/stylesheets/darkswarm/_shop-taxon-flag.css.scss b/app/assets/stylesheets/darkswarm/_shop-taxon-flag.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/_shop-taxon-flag.css.scss rename to app/assets/stylesheets/darkswarm/_shop-taxon-flag.scss diff --git a/app/assets/stylesheets/darkswarm/account.css.scss b/app/assets/stylesheets/darkswarm/account.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/account.css.scss rename to app/assets/stylesheets/darkswarm/account.scss diff --git a/app/assets/stylesheets/darkswarm/active_table.css.scss b/app/assets/stylesheets/darkswarm/active_table.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/active_table.css.scss rename to app/assets/stylesheets/darkswarm/active_table.scss diff --git a/app/assets/stylesheets/darkswarm/active_table_search.css.scss b/app/assets/stylesheets/darkswarm/active_table_search.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/active_table_search.css.scss rename to app/assets/stylesheets/darkswarm/active_table_search.scss diff --git a/app/assets/stylesheets/darkswarm/angular.css.scss b/app/assets/stylesheets/darkswarm/angular.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/angular.css.scss rename to app/assets/stylesheets/darkswarm/angular.scss diff --git a/app/assets/stylesheets/darkswarm/base/colors.css.scss b/app/assets/stylesheets/darkswarm/base/colors.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/base/colors.css.scss rename to app/assets/stylesheets/darkswarm/base/colors.scss diff --git a/app/assets/stylesheets/darkswarm/branding.css.scss b/app/assets/stylesheets/darkswarm/branding.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/branding.css.scss rename to app/assets/stylesheets/darkswarm/branding.scss diff --git a/app/assets/stylesheets/darkswarm/cart-dropdown.css.scss b/app/assets/stylesheets/darkswarm/cart-dropdown.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/cart-dropdown.css.scss rename to app/assets/stylesheets/darkswarm/cart-dropdown.scss diff --git a/app/assets/stylesheets/darkswarm/cart-page.css.scss b/app/assets/stylesheets/darkswarm/cart-page.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/cart-page.css.scss rename to app/assets/stylesheets/darkswarm/cart-page.scss diff --git a/app/assets/stylesheets/darkswarm/checkout.css.scss b/app/assets/stylesheets/darkswarm/checkout.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/checkout.css.scss rename to app/assets/stylesheets/darkswarm/checkout.scss diff --git a/app/assets/stylesheets/darkswarm/collapsible.css.scss b/app/assets/stylesheets/darkswarm/collapsible.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/collapsible.css.scss rename to app/assets/stylesheets/darkswarm/collapsible.scss diff --git a/app/assets/stylesheets/darkswarm/distributor_header.css.scss b/app/assets/stylesheets/darkswarm/distributor_header.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/distributor_header.css.scss rename to app/assets/stylesheets/darkswarm/distributor_header.scss diff --git a/app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss b/app/assets/stylesheets/darkswarm/embedded_shopfront.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/embedded_shopfront.css.scss rename to app/assets/stylesheets/darkswarm/embedded_shopfront.scss diff --git a/app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss b/app/assets/stylesheets/darkswarm/expanding-sidebar.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/expanding-sidebar.css.scss rename to app/assets/stylesheets/darkswarm/expanding-sidebar.scss diff --git a/app/assets/stylesheets/darkswarm/forms.css.scss b/app/assets/stylesheets/darkswarm/forms.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/forms.css.scss rename to app/assets/stylesheets/darkswarm/forms.scss diff --git a/app/assets/stylesheets/darkswarm/groups.css.scss b/app/assets/stylesheets/darkswarm/groups.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/groups.css.scss rename to app/assets/stylesheets/darkswarm/groups.scss diff --git a/app/assets/stylesheets/darkswarm/help-modal.css.scss b/app/assets/stylesheets/darkswarm/help-modal.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/help-modal.css.scss rename to app/assets/stylesheets/darkswarm/help-modal.scss diff --git a/app/assets/stylesheets/darkswarm/home_panes.css.scss b/app/assets/stylesheets/darkswarm/home_panes.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/home_panes.css.scss rename to app/assets/stylesheets/darkswarm/home_panes.scss diff --git a/app/assets/stylesheets/darkswarm/home_tagline.css.scss b/app/assets/stylesheets/darkswarm/home_tagline.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/home_tagline.css.scss rename to app/assets/stylesheets/darkswarm/home_tagline.scss diff --git a/app/assets/stylesheets/darkswarm/hub_node.css.scss b/app/assets/stylesheets/darkswarm/hub_node.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/hub_node.css.scss rename to app/assets/stylesheets/darkswarm/hub_node.scss diff --git a/app/assets/stylesheets/darkswarm/hubs.css.scss b/app/assets/stylesheets/darkswarm/hubs.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/hubs.css.scss rename to app/assets/stylesheets/darkswarm/hubs.scss diff --git a/app/assets/stylesheets/darkswarm/images.css.scss b/app/assets/stylesheets/darkswarm/images.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/images.css.scss rename to app/assets/stylesheets/darkswarm/images.scss diff --git a/app/assets/stylesheets/darkswarm/layout/offcanvas.css.scss b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/layout/offcanvas.css.scss rename to app/assets/stylesheets/darkswarm/layout/offcanvas.scss diff --git a/app/assets/stylesheets/darkswarm/lists.css.scss b/app/assets/stylesheets/darkswarm/lists.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/lists.css.scss rename to app/assets/stylesheets/darkswarm/lists.scss diff --git a/app/assets/stylesheets/darkswarm/map.css.scss b/app/assets/stylesheets/darkswarm/map.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/map.css.scss rename to app/assets/stylesheets/darkswarm/map.scss diff --git a/app/assets/stylesheets/darkswarm/menu.css.scss b/app/assets/stylesheets/darkswarm/menu.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/menu.css.scss rename to app/assets/stylesheets/darkswarm/menu.scss diff --git a/app/assets/stylesheets/darkswarm/modal-enterprises.css.scss b/app/assets/stylesheets/darkswarm/modal-enterprises.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/modal-enterprises.css.scss rename to app/assets/stylesheets/darkswarm/modal-enterprises.scss diff --git a/app/assets/stylesheets/darkswarm/modals.css.scss b/app/assets/stylesheets/darkswarm/modals.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/modals.css.scss rename to app/assets/stylesheets/darkswarm/modals.scss diff --git a/app/assets/stylesheets/darkswarm/overrides.css.scss b/app/assets/stylesheets/darkswarm/overrides.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/overrides.css.scss rename to app/assets/stylesheets/darkswarm/overrides.scss diff --git a/app/assets/stylesheets/darkswarm/page_alert.css.scss b/app/assets/stylesheets/darkswarm/page_alert.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/page_alert.css.scss rename to app/assets/stylesheets/darkswarm/page_alert.scss diff --git a/app/assets/stylesheets/darkswarm/pages/login_modal.css.scss b/app/assets/stylesheets/darkswarm/pages/login_modal.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/pages/login_modal.css.scss rename to app/assets/stylesheets/darkswarm/pages/login_modal.scss diff --git a/app/assets/stylesheets/darkswarm/producer_node.css.scss b/app/assets/stylesheets/darkswarm/producer_node.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/producer_node.css.scss rename to app/assets/stylesheets/darkswarm/producer_node.scss diff --git a/app/assets/stylesheets/darkswarm/producers.css.scss b/app/assets/stylesheets/darkswarm/producers.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/producers.css.scss rename to app/assets/stylesheets/darkswarm/producers.scss diff --git a/app/assets/stylesheets/darkswarm/product_table.css.scss b/app/assets/stylesheets/darkswarm/product_table.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/product_table.css.scss rename to app/assets/stylesheets/darkswarm/product_table.scss diff --git a/app/assets/stylesheets/darkswarm/registration.css.scss b/app/assets/stylesheets/darkswarm/registration.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/registration.css.scss rename to app/assets/stylesheets/darkswarm/registration.scss diff --git a/app/assets/stylesheets/darkswarm/shop.css.scss b/app/assets/stylesheets/darkswarm/shop.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/shop.css.scss rename to app/assets/stylesheets/darkswarm/shop.scss diff --git a/app/assets/stylesheets/darkswarm/shop_search.css.scss b/app/assets/stylesheets/darkswarm/shop_search.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/shop_search.css.scss rename to app/assets/stylesheets/darkswarm/shop_search.scss diff --git a/app/assets/stylesheets/darkswarm/shop_tabs.css.scss b/app/assets/stylesheets/darkswarm/shop_tabs.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/shop_tabs.css.scss rename to app/assets/stylesheets/darkswarm/shop_tabs.scss diff --git a/app/assets/stylesheets/darkswarm/sidebar.css.scss b/app/assets/stylesheets/darkswarm/sidebar.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/sidebar.css.scss rename to app/assets/stylesheets/darkswarm/sidebar.scss diff --git a/app/assets/stylesheets/darkswarm/signup.css.scss b/app/assets/stylesheets/darkswarm/signup.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/signup.css.scss rename to app/assets/stylesheets/darkswarm/signup.scss diff --git a/app/assets/stylesheets/darkswarm/stripe-elements.css.scss b/app/assets/stylesheets/darkswarm/stripe-elements.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/stripe-elements.css.scss rename to app/assets/stylesheets/darkswarm/stripe-elements.scss diff --git a/app/assets/stylesheets/darkswarm/style.css.scss b/app/assets/stylesheets/darkswarm/style.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/style.css.scss rename to app/assets/stylesheets/darkswarm/style.scss diff --git a/app/assets/stylesheets/darkswarm/tables.css.scss b/app/assets/stylesheets/darkswarm/tables.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/tables.css.scss rename to app/assets/stylesheets/darkswarm/tables.scss diff --git a/app/assets/stylesheets/darkswarm/tabset.css.scss b/app/assets/stylesheets/darkswarm/tabset.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/tabset.css.scss rename to app/assets/stylesheets/darkswarm/tabset.scss diff --git a/app/assets/stylesheets/darkswarm/taxons.css.scss b/app/assets/stylesheets/darkswarm/taxons.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/taxons.css.scss rename to app/assets/stylesheets/darkswarm/taxons.scss diff --git a/app/assets/stylesheets/darkswarm/typography.css.scss b/app/assets/stylesheets/darkswarm/typography.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/typography.css.scss rename to app/assets/stylesheets/darkswarm/typography.scss diff --git a/app/assets/stylesheets/darkswarm/ui.css.scss b/app/assets/stylesheets/darkswarm/ui.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/ui.css.scss rename to app/assets/stylesheets/darkswarm/ui.scss diff --git a/app/assets/stylesheets/darkswarm/variables.css.scss b/app/assets/stylesheets/darkswarm/variables.scss similarity index 100% rename from app/assets/stylesheets/darkswarm/variables.css.scss rename to app/assets/stylesheets/darkswarm/variables.scss diff --git a/app/assets/stylesheets/mail/email.css.scss b/app/assets/stylesheets/mail/email.scss similarity index 100% rename from app/assets/stylesheets/mail/email.css.scss rename to app/assets/stylesheets/mail/email.scss diff --git a/engines/web/app/assets/stylesheets/web/all.css.scss b/engines/web/app/assets/stylesheets/web/all.scss similarity index 100% rename from engines/web/app/assets/stylesheets/web/all.css.scss rename to engines/web/app/assets/stylesheets/web/all.scss diff --git a/engines/web/app/assets/stylesheets/web/pages/cookies_banner.css.scss b/engines/web/app/assets/stylesheets/web/pages/cookies_banner.scss similarity index 100% rename from engines/web/app/assets/stylesheets/web/pages/cookies_banner.css.scss rename to engines/web/app/assets/stylesheets/web/pages/cookies_banner.scss diff --git a/engines/web/app/assets/stylesheets/web/pages/cookies_policy_modal.css.scss b/engines/web/app/assets/stylesheets/web/pages/cookies_policy_modal.scss similarity index 100% rename from engines/web/app/assets/stylesheets/web/pages/cookies_policy_modal.css.scss rename to engines/web/app/assets/stylesheets/web/pages/cookies_policy_modal.scss From 923b905a9c4c1d6692c4777b8bd1e44f812e35f8 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Tue, 23 Jun 2020 22:30:53 +1000 Subject: [PATCH 027/261] Updating translations for config/locales/en_GB.yml --- config/locales/en_GB.yml | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 5d928e780f..9fe8406cd5 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -370,7 +370,10 @@ en_GB: title: "Matomo Settings" matomo_url: "Matomo URL" matomo_site_id: "Matomo Site ID" + matomo_tag_manager_url: "Matomo Tag Manager URL" + info_html: "Matomo is a Web and Mobile Analytics application. 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." + config_instructions_tag_manager_html: "Setting the Matomo Tag Manager URL enables Matomo Tag Manager. This tool allows you to set up analytics events. The Matomo Tag Manager URL is copied from the Install Code section of Matomo Tag Manager. Ensure you select the right container and environment as these options change the URL." customers: index: new_customer: "New Customer" @@ -476,6 +479,7 @@ en_GB: 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}" + malformed_csv: "Product Import found CSV was incorrectly formatted: %{error_message}" index: notice: "Notice" beta_notice: "This feature is still in beta: you may experience some errors while using it. Please don't hesitate to contact support." @@ -1143,13 +1147,18 @@ en_GB: menu: cart: cart: "Basket" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit basket" + items_in_cart_singular: "%{num} item in your basket" + items_in_cart_plural: "%{num} items in your basket" + close: "Close" + cart_empty: "Your basket is empty" + take_me_shopping: "Take me shopping!" signed_in: profile: "Profile" mobile_menu: cart: "Basket" - joyride: - checkout: "Checkout now" - already_ordered_products: "Already ordered in this order cycle" register_call: selling_on_ofn: "Interested in selling through the Open Food Network?" register: "Register here" @@ -2817,6 +2826,12 @@ en_GB: void: "Void" login: "Login" password: "Password" + signature: "Signature" + solution: "Solution" + landing_page: "Landing Page" + server: "Server" + test_mode: "Test Mode" + logourl: "Logo url" configurations: "Configurations" general_settings: "General Settings" site_name: "Site Name" @@ -2933,6 +2948,12 @@ en_GB: options: "Options" actions: update: "Update" + shared: + error_messages: + errors_prohibited_this_record_from_being_saved: + one: "1 error prohibited this record from being saved:" + other: "%{count} errors prohibited this record from being saved:" + there_were_problems_with_the_following_fields: "There were problems with the following fields" errors: messages: blank: "can't be blank" @@ -3102,9 +3123,11 @@ en_GB: display: "Display" active: "Active" both: "Both" + front_end: "Checkout only" back_end: "Back office only" active_yes: "Yes" active_no: "No" + no_payment_methods_found: "No payment methods found" new: new_payment_method: "New Payment Method" back_to_payment_methods_list: "Back To Payment Methods List" @@ -3134,8 +3157,10 @@ en_GB: active_yes: "Yes" active_no: "No" both: "Both Checkout and Back office" + front_end: "Checkout only" back_end: "Back office only" tags: "Tags" + deactivation_warning: "De-activating a payment method can make the payment method disappear from your list. Alternatively, you can hide a payment method from the checkout page by setting the option 'Display' to 'back office only'." providers: provider: "Provider" payments: @@ -3306,6 +3331,14 @@ en_GB: invalid: invalid order_mailer: cancel_email: + customer_greeting: "Dear %{name}," + instructions_html: "Your order with %{distributor} has been CANCELED. Please retain this cancellation information for your records." + dont_cancel: "If you have changed your mind or don't wish to cancel this order please contact %{email}" + order_summary_canceled_html: "Order Summary #%{number} [CANCELED]" + details: "Here are the details of what you ordered:" + unpaid_order: "Your order was unpaid so no refund has been made" + paid_order: "Your order was paid so %{distributor} has refunded the full amount" + credit_order: "Your order was paid so your account has been credited" subject: "Cancellation of Order" confirm_email: subject: "Order Confirmation" From 99096eee2d5524c8525ed06ccbed8e1745865e97 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Wed, 24 Jun 2020 01:41:21 +1000 Subject: [PATCH 028/261] Updating translations for config/locales/ca.yml --- config/locales/ca.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 55204a9c95..91d5b762cf 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -1150,13 +1150,18 @@ ca: menu: cart: cart: "Cistella" + cart_sidebar: + checkout: "Realitza la comanda" + edit_cart: "Edita la cistella" + items_in_cart_singular: "%{num} item a la teva cistella" + items_in_cart_plural: "%{num} item a la teva cistella" + close: "Tanca" + cart_empty: "La teva cistella és buida" + take_me_shopping: "Porta’m de compres!" signed_in: profile: "Perfil" mobile_menu: cart: "Cistella" - joyride: - checkout: "Validar ara" - already_ordered_products: "Ja està demanat en aquest cicle de comanda" register_call: selling_on_ofn: "Estàs interessat en formar part d'Open Food Network?" register: "Registra't aquí" From 8b79d41b81a1706bd4ad2487491d79e6913deeec Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 10 Jun 2020 16:29:07 +1000 Subject: [PATCH 029/261] Update orders swagger spec and fix api_key access to orders endpoint --- app/controllers/api/orders_controller.rb | 2 +- swagger.yaml | 53 +++++++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/app/controllers/api/orders_controller.rb b/app/controllers/api/orders_controller.rb index c011db44ec..7339af3c61 100644 --- a/app/controllers/api/orders_controller.rb +++ b/app/controllers/api/orders_controller.rb @@ -8,7 +8,7 @@ module Api def index authorize! :admin, Spree::Order - search_results = SearchOrders.new(params, spree_current_user) + search_results = SearchOrders.new(params, current_api_user) render json: { orders: serialized_orders(search_results.orders), diff --git a/swagger.yaml b/swagger.yaml index 838f09f2d4..0aed7ded9e 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -342,9 +342,60 @@ paths: /orders: get: - description: Gets all Orders. + description: Gets all Orders. Use combinations of parameters to filter your query. For example /api/orders?q[completed_at_gt]=2020_02_02&q[completed_at_lt]=2020_02_10 returns orders between 2nd and 10th February 2020. tags: - orders + parameters: + - in: query + name: q[distributor_id_eq] + schema: + type: string + style: deepObject + description: Query orders for a specific distributor id. + required: false + - in: query + name: q[completed_at_gt] + schema: + type: string + style: deepObject + description: Query orders completed after a date. + required: false + - in: query + name: q[completed_at_lt] + schema: + type: string + style: deepObject + description: Query orders completed before a date. + required: false + - in: query + name: q[state_eq] + schema: + type: string + style: deepObject + description: Query orders by order state, eg 'cart', 'complete'. + required: false + - in: query + name: q[payment_state_eq] + schema: + type: string + style: deepObject + description: Query orders by order payment_state, eg 'balance_due', 'paid', 'failed'. + required: false + - in: query + name: q[email_cont] + schema: + type: string + style: deepObject + description: Query orders where the order email contains a string. + required: false + - in: query + name: q[order_cycle_id_eq] + schema: + type: string + style: deepObject + description: Query orders for a specific order_cycle id. + required: false + responses: '200': description: successful operation From 9e19d79337cb0f2f95fc3f1e7e4475e568f85987 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 10 Jun 2020 17:05:25 +1000 Subject: [PATCH 030/261] Add more detail on the ransack based queries in the description --- swagger.yaml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/swagger.yaml b/swagger.yaml index 0aed7ded9e..9f4accc980 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -342,7 +342,10 @@ paths: /orders: get: - description: Gets all Orders. Use combinations of parameters to filter your query. For example /api/orders?q[completed_at_gt]=2020_02_02&q[completed_at_lt]=2020_02_10 returns orders between 2nd and 10th February 2020. + description: > + Gets all Orders. Use combinations of parameters to filter your query. + For example /api/orders?q[completed_at_gt]=2020_02_02&q[completed_at_lt]=2020_02_10 returns orders between 2nd and 10th February 2020. + Query parameters are generated for the '#/components/schemas/Order_Concise' model with [Ransack](https://github.com/activerecord-hackery/ransack#search-matchers) search matchers tags: - orders parameters: From e619ae621c9b3c08bbaf1fd35095baf52dcb8edd Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Fri, 5 Jun 2020 10:15:35 +1000 Subject: [PATCH 031/261] Add rswag and coverage for orders endpoint Add coverage for core orders endpoint queries (WIP) --- Gemfile | 3 +- Gemfile.lock | 18 ++++- config/initializers/rswag-ui.rb | 14 ++++ config/initializers/rswag_api.rb | 14 ++++ config/routes.rb | 4 + spec/requests/api/orders_spec.rb | 130 ++++++++++++++++++++++++++++++ spec/swagger_helper.rb | 72 +++++++++++++++++ swagger/v1/swagger.yaml | 131 +++++++++++++++++++++++++++++++ 8 files changed, 384 insertions(+), 2 deletions(-) create mode 100644 config/initializers/rswag-ui.rb create mode 100644 config/initializers/rswag_api.rb create mode 100644 spec/requests/api/orders_spec.rb create mode 100644 spec/swagger_helper.rb create mode 100644 swagger/v1/swagger.yaml diff --git a/Gemfile b/Gemfile index eb3e367894..2cc566eeaa 100644 --- a/Gemfile +++ b/Gemfile @@ -145,6 +145,7 @@ group :test, :development do gem 'letter_opener', '>= 1.4.1' gem 'rspec-rails', ">= 3.5.2" gem 'rspec-retry' + gem 'rswag', "2.2.0" gem 'selenium-webdriver' gem 'shoulda-matchers' gem 'timecop' @@ -165,7 +166,7 @@ group :development do gem "newrelic_rpm", "~> 3.0" gem "pry", "~> 0.12.0" # pry 0.13 is not compatible with pry-byebug 3.7 gem 'pry-byebug', '~> 3.7.0' # 3.8 requires ruby 2.4 - gem 'rubocop' + gem 'rubocop', '0.81' gem 'rubocop-rails' gem 'spring' gem 'spring-commands-rspec' diff --git a/Gemfile.lock b/Gemfile.lock index 02b4c3433b..77da7e9485 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -434,6 +434,8 @@ GEM jquery-ui-rails (4.2.1) railties (>= 3.2.16) json (1.8.6) + json-schema (2.8.1) + addressable (>= 2.4) json_spec (1.1.5) multi_json (~> 1.0) rspec (>= 2.0, < 4.0) @@ -590,6 +592,19 @@ GEM rspec-retry (0.6.2) rspec-core (> 3.3) rspec-support (3.9.2) + rswag (2.2.0) + rswag-api (= 2.2.0) + rswag-specs (= 2.2.0) + rswag-ui (= 2.2.0) + rswag-api (2.2.0) + railties (>= 3.1, < 6.1) + rswag-specs (2.2.0) + activesupport (>= 3.1, < 6.1) + json-schema (~> 2.2) + railties (>= 3.1, < 6.1) + rswag-ui (2.2.0) + actionpack (>= 3.1, < 6.1) + railties (>= 3.1, < 6.1) rubocop (0.81.0) jaro_winkler (~> 1.5.1) parallel (~> 1.10) @@ -780,7 +795,8 @@ DEPENDENCIES roo (~> 2.8.3) rspec-rails (>= 3.5.2) rspec-retry - rubocop + rswag (= 2.2.0) + rubocop (= 0.81) rubocop-rails sass sass-rails diff --git a/config/initializers/rswag-ui.rb b/config/initializers/rswag-ui.rb new file mode 100644 index 0000000000..0b9a4ab179 --- /dev/null +++ b/config/initializers/rswag-ui.rb @@ -0,0 +1,14 @@ +Rswag::Ui.configure do |c| + + # List the Swagger endpoints that you want to be documented through the swagger-ui + # The first parameter is the path (absolute or relative to the UI host) to the corresponding + # endpoint and the second is a title that will be displayed in the document selector + # NOTE: If you're using rspec-api to expose Swagger files (under swagger_root) as JSON or YAML endpoints, + # then the list below should correspond to the relative paths for those endpoints + + c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs' + + # Add Basic Auth in case your API is private + # c.basic_auth_enabled = true + # c.basic_auth_credentials 'username', 'password' +end diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb new file mode 100644 index 0000000000..5f3ddc40f1 --- /dev/null +++ b/config/initializers/rswag_api.rb @@ -0,0 +1,14 @@ +Rswag::Api.configure do |c| + + # Specify a root folder where Swagger JSON files are located + # This is used by the Swagger middleware to serve requests for API descriptions + # NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure + # that it's configured to generate files in the same folder + c.swagger_root = Rails.root.to_s + '/swagger' + + # Inject a lamda function to alter the returned Swagger prior to serialization + # The function will have access to the rack env for the current request + # For example, you could leverage this to dynamically assign the "host" property + # + #c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } +end diff --git a/config/routes.rb b/config/routes.rb index 877ca407d3..9fcf21bef8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,8 @@ Openfoodnetwork::Application.routes.draw do + mount Rswag::Ui::Engine => '/api-docs' + + mount Rswag::Api::Engine => '/api-docs' + root :to => 'home#index' # Redirects from old URLs avoid server errors and helps search engines diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb new file mode 100644 index 0000000000..fe85260382 --- /dev/null +++ b/spec/requests/api/orders_spec.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +require 'swagger_helper' + +describe 'api/orders', type: :request do + path '/api/orders' do + get('list orders') do + tags 'Orders' + # type should be replaced with swagger 3.01 valid schema: {type: string} when rswag #317 is resoved: + # https://github.com/rswag/rswag/pull/319 + parameter name: 'X-Spree-Token', in: :header, type: :string + parameter name: 'q[distributor_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific distributor id." + parameter name: 'q[completed_at_gt]', in: :query, type: :string, required: false, description: "Query orders completed after a date." + parameter name: 'q[completed_at_lt]', in: :query, type: :string, required: false, description: "Query orders completed before a date." + parameter name: 'q[state_eq]', in: :query, type: :string, required: false, description: "Query orders by order state, eg 'cart', 'complete'." + parameter name: 'q[payment_state_eq]', in: :query, type: :string, required: false, description: "Query orders by order payment_state, eg 'balance_due', 'paid', 'failed'." + parameter name: 'q[email_cont]', in: :query, type: :string, required: false, description: "Query orders where the order email contains a string." + parameter name: 'q[order_cycle_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific order_cycle id." + + response(200, 'get orders') do + # Adds model metadata for Swagger UI. Ideally we'd be able to just add: + # schema '$ref' => '#/components/schemas/Order_Concise' + # Which would also validate the response in the test, this is an open + # issue with rswag: https://github.com/rswag/rswag/issues/268 + metadata[:response][:content] = { "application/json": { + schema: {'$ref' => '#/components/schemas/Order_Concise'} + } + } + context "when there are four orders with different properties set" do + let(:order_dist_1) { create(:order_with_distributor, email: "specific_name@example.com") } + let(:order_dist_2) { create(:order_with_distributor) } + let(:order_dist_1_complete) { create(:order, distributor: order_dist_1.distributor, state: 'complete', completed_at: Time.zone.today - 7.days) } + let(:order_dist_1_credit_owed) { create(:order, distributor: order_dist_1.distributor, state: 'complete', payment_state: 'credit_owed', completed_at: Time.zone.today) } + + let(:user) { order_dist_1.distributor.owner } + let(:'X-Spree-Token') do + user.generate_spree_api_key! + user.spree_api_key + end + + context "and there are no query parameters" do + + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 4 + end + end + + context "and queried by distributor id" do + let(:'q[distributor_id_eq]') { order_dist_2.distributor.id } + + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_2.id + end + end + + context "and queried within a date range" do + let(:'q[completed_at_gt]') { Time.zone.today - 7.days - 1.second } + let(:'q[completed_at_lt]') { Time.zone.today - 6.days } + + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_1_complete.id + end + end + + context "and queried by complete state" do + let(:'q[state_eq]') { "complete" } + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_1_complete.id + end + end + + context "and queried by credit_owed payment_state" do + let(:'q[payment_state_eq]') { "credit_owed" } + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_1_credit_owed.id + end + end + + context "and queried by buyer email contains a specific string" do + let(:'q[email_cont]') { order_dist_1.email.split("@").first } + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_1_credit_owed.id + end + end + + context "and queried by a specific order_cycle" do + let(:'q[order_cycle_id_eq]') { order_dist_2.order_cycle.id } + run_test! do |response| + expect(response).to have_http_status(200) + + data = JSON.parse(response.body) + orders = data["orders"] + expect(orders.size).to eq 1 + expect(orders.first["id"]).to eq order_dist_2.id + end + end + end + end + end + end +end diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb new file mode 100644 index 0000000000..cca08655f6 --- /dev/null +++ b/spec/swagger_helper.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.configure do |config| + config.swagger_root = Rails.root.join('swagger').to_s + config.swagger_docs = { + 'v1/swagger.yaml' => { + openapi: '3.0.1', + info: { + title: 'The Open Food Network', + description: 'Some endpoints are public and require no authorization; others require authorization. Talk to us to get your credentials set up. Check out our repo! https://github.com/openfoodfoundation/openfoodnetwork', + version: '0.1', + }, + components: { + securitySchemes: { + api_key: { + type: :apiKey, + name: 'X-Spree-Token', + in: :header + } + }, + schemas: { + Order_Concise: { + type: 'object', + properties: { + id: { type: 'integer' }, + number: { type: 'string' }, + full_name: { type: 'string' }, + email: { type: 'string' }, + phone: { type: 'string' }, + completed_at: { type: 'string' }, + display_total: { type: 'string' }, + show_path: { type: 'string' }, + edit_path: { type: 'string' }, + state: { type: 'string' }, + payment_state: { type: 'string' }, + shipment_state: { type: 'string' }, + payments_path: { type: 'string' }, + shipments_path: { type: 'string' }, + ship_path: { type: 'string' }, + ready_to_ship: { type: 'string' }, + created_at: { type: 'string' }, + distributor_name: { type: 'string' }, + special_instructions: { type: 'string' }, + payment_capture_path: { type: 'string' }, + distributor: { + type: 'object', + properties: { + id: { type: 'integer' } + } + }, + order_cycle: { + type: 'object', + properties: { + id: { type: 'integer' } + } + } + } + } + } + }, + paths: {}, + servers: [ + { + url: 'https://staging.katuma.org/api' + } + ] + } + } + config.swagger_format = :yaml +end diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml new file mode 100644 index 0000000000..739e210e86 --- /dev/null +++ b/swagger/v1/swagger.yaml @@ -0,0 +1,131 @@ +--- +openapi: 3.0.1 +info: + title: The Open Food Network + description: Some endpoints are public and require no authorization; others require + authorization. Talk to us to get your credentials set up. Check out our repo! + https://github.com/openfoodfoundation/openfoodnetwork + version: '0.1' +components: + securitySchemes: + api_key: + type: apiKey + name: X-Spree-Token + in: header + schemas: + Order_Concise: + type: object + properties: + id: + type: integer + number: + type: string + full_name: + type: string + email: + type: string + phone: + type: string + completed_at: + type: string + display_total: + type: string + show_path: + type: string + edit_path: + type: string + state: + type: string + payment_state: + type: string + shipment_state: + type: string + payments_path: + type: string + shipments_path: + type: string + ship_path: + type: string + ready_to_ship: + type: string + created_at: + type: string + distributor_name: + type: string + special_instructions: + type: string + payment_capture_path: + type: string + distributor: + type: object + properties: + id: + type: integer + order_cycle: + type: object + properties: + id: + type: integer +paths: + "/api/orders": + get: + summary: list orders + tags: + - Orders + parameters: + - name: X-Spree-Token + in: header + schema: + type: string + - name: q[distributor_id_eq] + in: query + schema: + type: string + style: deepObject + description: Query orders for a specific distributor id. + - name: q[completed_at_gt] + in: query + schema: + type: string + style: deepObject + description: Query orders completed after a date. + - name: q[completed_at_lt] + in: query + schema: + type: string + style: deepObject + description: Query orders completed before a date. + - name: q[state_eq] + in: query + schema: + type: string + style: deepObject + description: Query orders by order state, eg 'cart', 'complete'. + - name: q[payment_state_eq] + in: query + schema: + type: string + style: deepObject + description: Query orders by order payment_state, eg 'balance_due', 'paid', + 'failed'. + - name: q[email_cont] + in: query + schema: + type: string + style: deepObject + description: Query orders where the order email contains a string. + - name: q[order_cycle_id_eq] + in: query + schema: + type: string + style: deepObject + description: Query orders for a specific order_cycle id. + responses: + '200': + description: get orders + content: + application/json: + schema: + "$ref": "#/components/schemas/Order_Concise" +servers: +- url: https://staging.katuma.org/api From b59dbebba6b40a55d479124baacf670a68e1338f Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 17 Jun 2020 12:42:39 +1000 Subject: [PATCH 032/261] Revert Gemfile change to specific version of rubocop Turns out it wasn't necessary. I thought it was needed to install a compatible version of rswag --- Gemfile | 4 ++-- Gemfile.lock | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 2cc566eeaa..cba7513c0a 100644 --- a/Gemfile +++ b/Gemfile @@ -145,7 +145,7 @@ group :test, :development do gem 'letter_opener', '>= 1.4.1' gem 'rspec-rails', ">= 3.5.2" gem 'rspec-retry' - gem 'rswag', "2.2.0" + gem 'rswag' gem 'selenium-webdriver' gem 'shoulda-matchers' gem 'timecop' @@ -166,7 +166,7 @@ group :development do gem "newrelic_rpm", "~> 3.0" gem "pry", "~> 0.12.0" # pry 0.13 is not compatible with pry-byebug 3.7 gem 'pry-byebug', '~> 3.7.0' # 3.8 requires ruby 2.4 - gem 'rubocop', '0.81' + gem 'rubocop' gem 'rubocop-rails' gem 'spring' gem 'spring-commands-rspec' diff --git a/Gemfile.lock b/Gemfile.lock index 77da7e9485..d156e3c981 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -795,8 +795,8 @@ DEPENDENCIES roo (~> 2.8.3) rspec-rails (>= 3.5.2) rspec-retry - rswag (= 2.2.0) - rubocop (= 0.81) + rswag + rubocop rubocop-rails sass sass-rails From 9541dbf49524bd5228a5c59c9592c0c140aa6e2b Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 24 Jun 2020 15:15:18 +1000 Subject: [PATCH 033/261] Fix order api spec and add incomplete generated swagger.yml --- spec/requests/api/orders_spec.rb | 33 ++++++++++++++--------- spec/swagger_helper.rb | 4 ++- swagger/v1/swagger.yaml | 45 ++++++++++++++------------------ 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/spec/requests/api/orders_spec.rb b/spec/requests/api/orders_spec.rb index fe85260382..b282b4045a 100644 --- a/spec/requests/api/orders_spec.rb +++ b/spec/requests/api/orders_spec.rb @@ -6,7 +6,7 @@ describe 'api/orders', type: :request do path '/api/orders' do get('list orders') do tags 'Orders' - # type should be replaced with swagger 3.01 valid schema: {type: string} when rswag #317 is resoved: + # type should be replaced with swagger 3.01 valid schema: {type: string} when rswag #317 is resolved: # https://github.com/rswag/rswag/pull/319 parameter name: 'X-Spree-Token', in: :header, type: :string parameter name: 'q[distributor_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific distributor id." @@ -16,22 +16,23 @@ describe 'api/orders', type: :request do parameter name: 'q[payment_state_eq]', in: :query, type: :string, required: false, description: "Query orders by order payment_state, eg 'balance_due', 'paid', 'failed'." parameter name: 'q[email_cont]', in: :query, type: :string, required: false, description: "Query orders where the order email contains a string." parameter name: 'q[order_cycle_id_eq]', in: :query, type: :string, required: false, description: "Query orders for a specific order_cycle id." - + response(200, 'get orders') do # Adds model metadata for Swagger UI. Ideally we'd be able to just add: # schema '$ref' => '#/components/schemas/Order_Concise' # Which would also validate the response in the test, this is an open # issue with rswag: https://github.com/rswag/rswag/issues/268 - metadata[:response][:content] = { "application/json": { + metadata[:response][:content] = { + "application/json": { schema: {'$ref' => '#/components/schemas/Order_Concise'} } } context "when there are four orders with different properties set" do - let(:order_dist_1) { create(:order_with_distributor, email: "specific_name@example.com") } - let(:order_dist_2) { create(:order_with_distributor) } - let(:order_dist_1_complete) { create(:order, distributor: order_dist_1.distributor, state: 'complete', completed_at: Time.zone.today - 7.days) } - let(:order_dist_1_credit_owed) { create(:order, distributor: order_dist_1.distributor, state: 'complete', payment_state: 'credit_owed', completed_at: Time.zone.today) } - + let!(:order_dist_1) { create(:order_with_distributor, email: "specific_name@example.com") } + let!(:order_dist_2) { create(:order_with_totals_and_distribution) } + let!(:order_dist_1_complete) { create(:order, distributor: order_dist_1.distributor, state: 'complete', completed_at: Time.zone.today - 7.days) } + let!(:order_dist_1_credit_owed) { create(:order, distributor: order_dist_1.distributor, payment_state: 'credit_owed', completed_at: Time.zone.today) } + let(:user) { order_dist_1.distributor.owner } let(:'X-Spree-Token') do user.generate_spree_api_key! @@ -39,7 +40,6 @@ describe 'api/orders', type: :request do end context "and there are no query parameters" do - run_test! do |response| expect(response).to have_http_status(200) @@ -52,6 +52,8 @@ describe 'api/orders', type: :request do context "and queried by distributor id" do let(:'q[distributor_id_eq]') { order_dist_2.distributor.id } + before { order_dist_2.distributor.update_attributes owner: user } + run_test! do |response| expect(response).to have_http_status(200) @@ -75,7 +77,7 @@ describe 'api/orders', type: :request do expect(orders.first["id"]).to eq order_dist_1_complete.id end end - + context "and queried by complete state" do let(:'q[state_eq]') { "complete" } run_test! do |response| @@ -108,12 +110,17 @@ describe 'api/orders', type: :request do data = JSON.parse(response.body) orders = data["orders"] expect(orders.size).to eq 1 - expect(orders.first["id"]).to eq order_dist_1_credit_owed.id + expect(orders.first["id"]).to eq order_dist_1.id end end - + context "and queried by a specific order_cycle" do - let(:'q[order_cycle_id_eq]') { order_dist_2.order_cycle.id } + let(:'q[order_cycle_id_eq]') { + order_dist_2.order_cycle.id + } + + before { order_dist_2.distributor.update_attributes owner: user } + run_test! do |response| expect(response).to have_http_status(200) diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index cca08655f6..0bf64f9ced 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -9,7 +9,9 @@ RSpec.configure do |config| openapi: '3.0.1', info: { title: 'The Open Food Network', - description: 'Some endpoints are public and require no authorization; others require authorization. Talk to us to get your credentials set up. Check out our repo! https://github.com/openfoodfoundation/openfoodnetwork', + description: 'This spec is auto generated using the rswag gem. It is incomplete and not yet valid for openapi 3.0.1. Do not publish this. \ +Some endpoints are public and require no authorization; others require authorization. Talk to us to get your credentials set up. \ +Check out our repo! https://github.com/openfoodfoundation/openfoodnetwork', version: '0.1', }, components: { diff --git a/swagger/v1/swagger.yaml b/swagger/v1/swagger.yaml index 739e210e86..88d54ed960 100644 --- a/swagger/v1/swagger.yaml +++ b/swagger/v1/swagger.yaml @@ -2,9 +2,10 @@ openapi: 3.0.1 info: title: The Open Food Network - description: Some endpoints are public and require no authorization; others require - authorization. Talk to us to get your credentials set up. Check out our repo! - https://github.com/openfoodfoundation/openfoodnetwork + description: |- + This spec is auto generated using the rswag gem. It is incomplete and not yet valid for openapi 3.0.1. Do not publish this. \ + Some endpoints are public and require no authorization; others require authorization. Talk to us to get your credentials set up. \ + Check out our repo! https://github.com/openfoodfoundation/openfoodnetwork version: '0.1' components: securitySchemes: @@ -75,50 +76,42 @@ paths: parameters: - name: X-Spree-Token in: header - schema: - type: string + type: string - name: q[distributor_id_eq] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders for a specific distributor id. - name: q[completed_at_gt] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders completed after a date. - name: q[completed_at_lt] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders completed before a date. - name: q[state_eq] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders by order state, eg 'cart', 'complete'. - name: q[payment_state_eq] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders by order payment_state, eg 'balance_due', 'paid', 'failed'. - name: q[email_cont] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders where the order email contains a string. - name: q[order_cycle_id_eq] in: query - schema: - type: string - style: deepObject + type: string + required: false description: Query orders for a specific order_cycle id. responses: '200': From 3d2a0d4d6764765a7258c4dba60c1d91e50a4041 Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 24 Jun 2020 15:51:08 +1000 Subject: [PATCH 034/261] Remove UI and API engine as we will not host the swagger spec right now --- config/initializers/rswag-ui.rb | 14 -------------- config/initializers/rswag_api.rb | 14 -------------- config/routes.rb | 3 --- 3 files changed, 31 deletions(-) delete mode 100644 config/initializers/rswag-ui.rb delete mode 100644 config/initializers/rswag_api.rb diff --git a/config/initializers/rswag-ui.rb b/config/initializers/rswag-ui.rb deleted file mode 100644 index 0b9a4ab179..0000000000 --- a/config/initializers/rswag-ui.rb +++ /dev/null @@ -1,14 +0,0 @@ -Rswag::Ui.configure do |c| - - # List the Swagger endpoints that you want to be documented through the swagger-ui - # The first parameter is the path (absolute or relative to the UI host) to the corresponding - # endpoint and the second is a title that will be displayed in the document selector - # NOTE: If you're using rspec-api to expose Swagger files (under swagger_root) as JSON or YAML endpoints, - # then the list below should correspond to the relative paths for those endpoints - - c.swagger_endpoint '/api-docs/v1/swagger.yaml', 'API V1 Docs' - - # Add Basic Auth in case your API is private - # c.basic_auth_enabled = true - # c.basic_auth_credentials 'username', 'password' -end diff --git a/config/initializers/rswag_api.rb b/config/initializers/rswag_api.rb deleted file mode 100644 index 5f3ddc40f1..0000000000 --- a/config/initializers/rswag_api.rb +++ /dev/null @@ -1,14 +0,0 @@ -Rswag::Api.configure do |c| - - # Specify a root folder where Swagger JSON files are located - # This is used by the Swagger middleware to serve requests for API descriptions - # NOTE: If you're using rswag-specs to generate Swagger, you'll need to ensure - # that it's configured to generate files in the same folder - c.swagger_root = Rails.root.to_s + '/swagger' - - # Inject a lamda function to alter the returned Swagger prior to serialization - # The function will have access to the rack env for the current request - # For example, you could leverage this to dynamically assign the "host" property - # - #c.swagger_filter = lambda { |swagger, env| swagger['host'] = env['HTTP_HOST'] } -end diff --git a/config/routes.rb b/config/routes.rb index 9fcf21bef8..ef3380ea79 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,4 @@ Openfoodnetwork::Application.routes.draw do - mount Rswag::Ui::Engine => '/api-docs' - - mount Rswag::Api::Engine => '/api-docs' root :to => 'home#index' From 8d4a9cba21b50d3d48626711ae96503f878fe1f6 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Wed, 24 Jun 2020 23:33:12 +1000 Subject: [PATCH 035/261] Updating translations for config/locales/nb.yml --- config/locales/nb.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/config/locales/nb.yml b/config/locales/nb.yml index bf8f4cba79..cfa66bd401 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -1147,13 +1147,18 @@ nb: menu: cart: cart: "Handlekurv" + cart_sidebar: + checkout: "Kassen" + edit_cart: "Rediger handlevogn" + items_in_cart_singular: "%{num} vare i handlekurven" + items_in_cart_plural: "%{num} varer i handlekurven" + close: "Lukk" + cart_empty: "Handlekurven din er tom" + take_me_shopping: "Ta meg shopping!" signed_in: profile: "Profil" mobile_menu: cart: "Handlekurv" - joyride: - checkout: "Sjekk ut nå" - already_ordered_products: "Allerede bestilt i denne bestillingssyklusen" register_call: selling_on_ofn: "Interessert i å bli med i Open Food Network?" register: "Registrer her" From 0e711832fdff9f91ac2e70b9c1038d60cb1961e8 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:13:21 +0800 Subject: [PATCH 036/261] Bring Spree::StockItem code from spree_core into the app --- app/models/spree/stock_item.rb | 52 +++++++++++++++++++ spec/models/spree/stock_item_spec.rb | 74 ++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 app/models/spree/stock_item.rb create mode 100644 spec/models/spree/stock_item_spec.rb diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb new file mode 100644 index 0000000000..9dc322b447 --- /dev/null +++ b/app/models/spree/stock_item.rb @@ -0,0 +1,52 @@ +module Spree + class StockItem < ActiveRecord::Base + belongs_to :stock_location, class_name: 'Spree::StockLocation' + belongs_to :variant, class_name: 'Spree::Variant' + has_many :stock_movements, dependent: :destroy + + validates_presence_of :stock_location, :variant + validates_uniqueness_of :variant_id, scope: :stock_location_id + + attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id + + delegate :weight, to: :variant + + def backordered_inventory_units + Spree::InventoryUnit.backordered_for_stock_item(self) + end + + def variant_name + variant.name + end + + def adjust_count_on_hand(value) + self.with_lock do + self.count_on_hand = self.count_on_hand + value + process_backorders if in_stock? + + self.save! + end + end + + def in_stock? + self.count_on_hand > 0 + end + + # Tells whether it's available to be included in a shipment + def available? + self.in_stock? || self.backorderable? + end + + private + def count_on_hand=(value) + write_attribute(:count_on_hand, value) + end + + def process_backorders + backordered_inventory_units.each do |unit| + return unless in_stock? + unit.fill_backorder + end + end + end +end diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb new file mode 100644 index 0000000000..da10d44efa --- /dev/null +++ b/spec/models/spree/stock_item_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe Spree::StockItem do + let(:stock_location) { create(:stock_location_with_items) } + + subject { stock_location.stock_items.order(:id).first } + + it 'maintains the count on hand for a variant' do + subject.count_on_hand.should eq 10 + end + + it "can return the stock item's variant's name" do + subject.variant_name.should == subject.variant.name + end + + context "available to be included in shipment" do + context "has stock" do + it { subject.should be_available } + end + + context "backorderable" do + before { subject.backorderable = true } + it { subject.should be_available } + end + + context "no stock and not backorderable" do + before do + subject.backorderable = false + subject.stub(count_on_hand: 0) + end + + it { subject.should_not be_available } + end + end + + context "adjust count_on_hand" do + let!(:current_on_hand) { subject.count_on_hand } + + it 'is updated pessimistically' do + copy = Spree::StockItem.find(subject.id) + + subject.adjust_count_on_hand(5) + subject.count_on_hand.should eq(current_on_hand + 5) + + copy.count_on_hand.should eq(current_on_hand) + copy.adjust_count_on_hand(5) + copy.count_on_hand.should eq(current_on_hand + 10) + end + + context "item out of stock (by two items)" do + let(:inventory_unit) { double('InventoryUnit') } + let(:inventory_unit_2) { double('InventoryUnit2') } + + before { subject.adjust_count_on_hand(- (current_on_hand + 2)) } + + it "doesn't process backorders" do + subject.should_not_receive(:backordered_inventory_units) + subject.adjust_count_on_hand(1) + end + + context "adds new items" do + before { subject.stub(:backordered_inventory_units => [inventory_unit, inventory_unit_2]) } + + it "fills existing backorders" do + inventory_unit.should_receive(:fill_backorder) + inventory_unit_2.should_receive(:fill_backorder) + + subject.adjust_count_on_hand(3) + subject.count_on_hand.should == 1 + end + end + end + end +end From 84d973d383d816b2760a4c0c4bf926875a341cae Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:19:24 +0800 Subject: [PATCH 037/261] Specify RSpec.describe in StockItem spec file --- spec/models/spree/stock_item_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index da10d44efa..2e6b757a71 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Spree::StockItem do +RSpec.describe Spree::StockItem do let(:stock_location) { create(:stock_location_with_items) } subject { stock_location.stock_items.order(:id).first } From b78311870065f63246831d30dbf1ad91ea9c292d Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:40:13 +0800 Subject: [PATCH 038/261] Auto-correct violationso of Rubocop Style/RedundantSelf --- app/models/spree/stock_item.rb | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 9dc322b447..70bb741e8d 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -20,21 +20,21 @@ module Spree end def adjust_count_on_hand(value) - self.with_lock do - self.count_on_hand = self.count_on_hand + value + with_lock do + self.count_on_hand = count_on_hand + value process_backorders if in_stock? - self.save! + save! end end def in_stock? - self.count_on_hand > 0 + count_on_hand > 0 end # Tells whether it's available to be included in a shipment def available? - self.in_stock? || self.backorderable? + in_stock? || backorderable? end private From 0fd66f9a558caccfa639a864c636261bf17a0962 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:44:07 +0800 Subject: [PATCH 039/261] Auto-correct violationso of Rubocop Style/* --- app/models/spree/stock_item.rb | 1 + spec/models/spree/stock_item_spec.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 70bb741e8d..d1c9faa983 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Spree class StockItem < ActiveRecord::Base belongs_to :stock_location, class_name: 'Spree::StockLocation' diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index 2e6b757a71..f58a0bd09c 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true require 'spec_helper' RSpec.describe Spree::StockItem do @@ -59,7 +60,7 @@ RSpec.describe Spree::StockItem do end context "adds new items" do - before { subject.stub(:backordered_inventory_units => [inventory_unit, inventory_unit_2]) } + before { subject.stub(backordered_inventory_units: [inventory_unit, inventory_unit_2]) } it "fills existing backorders" do inventory_unit.should_receive(:fill_backorder) From d1725014c4495481c83e9dd0b88febbd1b150e4e Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:44:23 +0800 Subject: [PATCH 040/261] Auto-correct violationso of Rubocop Layout/* --- app/models/spree/stock_item.rb | 19 +++++++++++-------- spec/models/spree/stock_item_spec.rb | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index d1c9faa983..29ec2401fa 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + module Spree class StockItem < ActiveRecord::Base belongs_to :stock_location, class_name: 'Spree::StockLocation' @@ -39,15 +40,17 @@ module Spree end private - def count_on_hand=(value) - write_attribute(:count_on_hand, value) - end - def process_backorders - backordered_inventory_units.each do |unit| - return unless in_stock? - unit.fill_backorder - end + def count_on_hand=(value) + write_attribute(:count_on_hand, value) + end + + def process_backorders + backordered_inventory_units.each do |unit| + return unless in_stock? + + unit.fill_backorder end + end end end diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index f58a0bd09c..c59416371d 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + require 'spec_helper' RSpec.describe Spree::StockItem do From 22c0693bebdf65346f11ab914db87b35a1166fe5 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:45:52 +0800 Subject: [PATCH 041/261] Address violation of Rubocop Style/NumericPredicate --- app/models/spree/stock_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 29ec2401fa..5c9f390567 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -31,7 +31,7 @@ module Spree end def in_stock? - count_on_hand > 0 + count_on_hand.positive? end # Tells whether it's available to be included in a shipment From 1e8543dfe7a9a1c420fc0011a1012a064d8daf97 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:50:57 +0800 Subject: [PATCH 042/261] Address violation of Rubocop Rails/ReadWriteAttribute --- app/models/spree/stock_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 5c9f390567..47bbf14fbd 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -42,7 +42,7 @@ module Spree private def count_on_hand=(value) - write_attribute(:count_on_hand, value) + self[:count_on_hand] = value end def process_backorders From 2acf61fd0f08ab8424c3d8422c469d82cc1dc226 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:54:50 +0800 Subject: [PATCH 043/261] Address violation of Rubocop Rails/Delegate --- app/models/spree/stock_item.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 47bbf14fbd..44aa72f422 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -17,9 +17,7 @@ module Spree Spree::InventoryUnit.backordered_for_stock_item(self) end - def variant_name - variant.name - end + delegate :name, to: :variant, prefix: true def adjust_count_on_hand(value) with_lock do From bc530b92b540bf2639872f8832633230c35e85eb Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 04:55:42 +0800 Subject: [PATCH 044/261] Address violation of Rubocop Rails/Validation: --- app/models/spree/stock_item.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 44aa72f422..47c311b205 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -6,8 +6,8 @@ module Spree belongs_to :variant, class_name: 'Spree::Variant' has_many :stock_movements, dependent: :destroy - validates_presence_of :stock_location, :variant - validates_uniqueness_of :variant_id, scope: :stock_location_id + validates :stock_location, :variant, presence: true + validates :variant_id, uniqueness: { scope: :stock_location_id } attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id From 0a1cb71ee4f8b64c52ade2a98d73563e2f524460 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 05:00:52 +0800 Subject: [PATCH 045/261] Ignore Rails/UniqueValidationWithoutIndex for unique index of StockItem#stock_location --- app/models/spree/stock_item.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 47c311b205..9eca73d0c8 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -7,7 +7,9 @@ module Spree has_many :stock_movements, dependent: :destroy validates :stock_location, :variant, presence: true + # rubocop:disable Rails/UniqueValidationWithoutIndex validates :variant_id, uniqueness: { scope: :stock_location_id } + # rubocop:enable Rails/UniqueValidationWithoutIndex attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id From fb20f220c04f83f938fee31f7023d9c8e01b88e7 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 05:16:58 +0800 Subject: [PATCH 046/261] Use break instead of return in StockItem#process_backorders We are not using the return value of this method anywhere. --- app/models/spree/stock_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index 9eca73d0c8..b3e14969eb 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -47,7 +47,7 @@ module Spree def process_backorders backordered_inventory_units.each do |unit| - return unless in_stock? + break unless in_stock? unit.fill_backorder end From 13ecf0ec73ba49782fe1a92e1c186196c14598fb Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 15:20:20 +0800 Subject: [PATCH 047/261] Update specs for StockItem with transpec --- spec/models/spree/stock_item_spec.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index c59416371d..ce5c7fafd0 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -8,30 +8,30 @@ RSpec.describe Spree::StockItem do subject { stock_location.stock_items.order(:id).first } it 'maintains the count on hand for a variant' do - subject.count_on_hand.should eq 10 + expect(subject.count_on_hand).to eq 10 end it "can return the stock item's variant's name" do - subject.variant_name.should == subject.variant.name + expect(subject.variant_name).to eq(subject.variant.name) end context "available to be included in shipment" do context "has stock" do - it { subject.should be_available } + it { expect(subject).to be_available } end context "backorderable" do before { subject.backorderable = true } - it { subject.should be_available } + it { expect(subject).to be_available } end context "no stock and not backorderable" do before do subject.backorderable = false - subject.stub(count_on_hand: 0) + allow(subject).to receive_messages(count_on_hand: 0) end - it { subject.should_not be_available } + it { expect(subject).not_to be_available } end end @@ -42,11 +42,11 @@ RSpec.describe Spree::StockItem do copy = Spree::StockItem.find(subject.id) subject.adjust_count_on_hand(5) - subject.count_on_hand.should eq(current_on_hand + 5) + expect(subject.count_on_hand).to eq(current_on_hand + 5) - copy.count_on_hand.should eq(current_on_hand) + expect(copy.count_on_hand).to eq(current_on_hand) copy.adjust_count_on_hand(5) - copy.count_on_hand.should eq(current_on_hand + 10) + expect(copy.count_on_hand).to eq(current_on_hand + 10) end context "item out of stock (by two items)" do @@ -56,19 +56,19 @@ RSpec.describe Spree::StockItem do before { subject.adjust_count_on_hand(- (current_on_hand + 2)) } it "doesn't process backorders" do - subject.should_not_receive(:backordered_inventory_units) + expect(subject).not_to receive(:backordered_inventory_units) subject.adjust_count_on_hand(1) end context "adds new items" do - before { subject.stub(backordered_inventory_units: [inventory_unit, inventory_unit_2]) } + before { allow(subject).to receive_messages(backordered_inventory_units: [inventory_unit, inventory_unit_2]) } it "fills existing backorders" do - inventory_unit.should_receive(:fill_backorder) - inventory_unit_2.should_receive(:fill_backorder) + expect(inventory_unit).to receive(:fill_backorder) + expect(inventory_unit_2).to receive(:fill_backorder) subject.adjust_count_on_hand(3) - subject.count_on_hand.should == 1 + expect(subject.count_on_hand).to eq(1) end end end From 774b3720d5853a408de6b890add2df54981bec71 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Thu, 14 May 2020 15:23:31 +0800 Subject: [PATCH 048/261] Update stock item count on hand in Spree core specs --- spec/models/spree/stock_item_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index ce5c7fafd0..679af05f90 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Spree::StockItem do subject { stock_location.stock_items.order(:id).first } it 'maintains the count on hand for a variant' do - expect(subject.count_on_hand).to eq 10 + expect(subject.count_on_hand).to eq 15 end it "can return the stock item's variant's name" do From e53913756c17f90d3405af8258c15c8a66fba028 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Tue, 12 May 2020 15:09:53 +0800 Subject: [PATCH 049/261] Add lock_version to Spree::StockItem --- db/migrate/20200512070717_add_lock_version_to_stock_items.rb | 5 +++++ db/schema.rb | 1 + 2 files changed, 6 insertions(+) create mode 100644 db/migrate/20200512070717_add_lock_version_to_stock_items.rb diff --git a/db/migrate/20200512070717_add_lock_version_to_stock_items.rb b/db/migrate/20200512070717_add_lock_version_to_stock_items.rb new file mode 100644 index 0000000000..416a43f62e --- /dev/null +++ b/db/migrate/20200512070717_add_lock_version_to_stock_items.rb @@ -0,0 +1,5 @@ +class AddLockVersionToStockItems < ActiveRecord::Migration + def change + add_column :spree_stock_items, :lock_version, :integer, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index d166fdfd3c..d153eec8ef 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -899,6 +899,7 @@ ActiveRecord::Schema.define(version: 20200623140437) do t.datetime "updated_at" t.boolean "backorderable", default: false t.datetime "deleted_at" + t.integer "lock_version", default: 0 end add_index "spree_stock_items", ["stock_location_id", "variant_id"], name: "stock_item_by_loc_and_var_id", using: :btree From 4694f1b21a67467738e83859aa2ed537b4850dac Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Tue, 12 May 2020 15:28:26 +0800 Subject: [PATCH 050/261] Require count on hand in non backorderable StockItem to be positive or zero Fix setting of count on hand in line item specs --- app/models/spree/stock_item.rb | 1 + spec/models/spree/line_item_spec.rb | 4 ++-- spec/models/spree/stock_item_spec.rb | 32 +++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index b3e14969eb..f71df2b942 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -10,6 +10,7 @@ module Spree # rubocop:disable Rails/UniqueValidationWithoutIndex validates :variant_id, uniqueness: { scope: :stock_location_id } # rubocop:enable Rails/UniqueValidationWithoutIndex + validates :count_on_hand, numericality: { greater_than_or_equal_to: 0, unless: :backorderable? } attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id diff --git a/spec/models/spree/line_item_spec.rb b/spec/models/spree/line_item_spec.rb index ca4a5353d9..ff00240aaf 100644 --- a/spec/models/spree/line_item_spec.rb +++ b/spec/models/spree/line_item_spec.rb @@ -97,7 +97,7 @@ module Spree end it "caps at zero when stock is negative" do - v.update! on_hand: -2 + v.__send__(:stock_item).update_column(:count_on_hand, -2) li.cap_quantity_at_stock! expect(li.reload.quantity).to eq 0 end @@ -123,7 +123,7 @@ module Spree before { vo.update(count_on_hand: -3) } it "caps at zero" do - v.update(on_hand: -2) + v.__send__(:stock_item).update_column(:count_on_hand, -2) li.cap_quantity_at_stock! expect(li.reload.quantity).to eq 0 end diff --git a/spec/models/spree/stock_item_spec.rb b/spec/models/spree/stock_item_spec.rb index 679af05f90..9c9b233986 100644 --- a/spec/models/spree/stock_item_spec.rb +++ b/spec/models/spree/stock_item_spec.rb @@ -7,6 +7,33 @@ RSpec.describe Spree::StockItem do subject { stock_location.stock_items.order(:id).first } + describe "validation" do + let(:stock_item) { stock_location.stock_items.first } + + it "requires count_on_hand to be positive if not backorderable" do + stock_item.backorderable = false + + stock_item.__send__(:count_on_hand=, 1) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, 0) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, -1) + expect(stock_item.valid?).to eq(false) + end + + it "allows count_on_hand to be negative if backorderable" do + stock_item.backorderable = true + + stock_item.__send__(:count_on_hand=, 1) + expect(stock_item.valid?).to eq(true) + + stock_item.__send__(:count_on_hand=, -1) + expect(stock_item.valid?).to eq(true) + end + end + it 'maintains the count on hand for a variant' do expect(subject.count_on_hand).to eq 15 end @@ -53,7 +80,10 @@ RSpec.describe Spree::StockItem do let(:inventory_unit) { double('InventoryUnit') } let(:inventory_unit_2) { double('InventoryUnit2') } - before { subject.adjust_count_on_hand(- (current_on_hand + 2)) } + before do + allow(subject).to receive(:backorderable?).and_return(true) + subject.adjust_count_on_hand(- (current_on_hand + 2)) + end it "doesn't process backorders" do expect(subject).not_to receive(:backordered_inventory_units) From 20fd3c2642d2abdc262d6dff3d88c1c6c5be6e72 Mon Sep 17 00:00:00 2001 From: Kristina Lim Date: Fri, 15 May 2020 01:56:34 +0800 Subject: [PATCH 051/261] Reset negative count on hand in existing non backorderable stock items --- ...korderable_count_on_hand_in_stock_items.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb diff --git a/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb b/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb new file mode 100644 index 0000000000..c57730c99a --- /dev/null +++ b/db/migrate/20200514174526_reset_negative_nonbackorderable_count_on_hand_in_stock_items.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class ResetNegativeNonbackorderableCountOnHandInStockItems < ActiveRecord::Migration + module Spree + class StockItem < ActiveRecord::Base + self.table_name = "spree_stock_items" + end + end + + def up + Spree::StockItem.where(backorderable: false) + .where("count_on_hand < 0") + .update_all(count_on_hand: 0) + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end From e12e50aa84b5621bbb2e71ca06206fc4368402c0 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 22 Jun 2020 17:55:54 +0100 Subject: [PATCH 052/261] Move rubocop exception to rubocop todo --- .rubocop_todo.yml | 7 +++++++ app/models/spree/stock_item.rb | 2 -- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 753aaee48e..a0c6a0b30c 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -363,6 +363,13 @@ Rails/UniqueValidationWithoutIndex: - 'app/models/customer.rb' - 'app/models/exchange.rb' +# Offense count: 2 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/UniqueValidationWithoutIndex: + Exclude: + - 'app/models/spree/stock_item.rb' + # Offense count: 1 # Configuration parameters: Environments. # Environments: development, test, production diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index f71df2b942..cf86103453 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -7,9 +7,7 @@ module Spree has_many :stock_movements, dependent: :destroy validates :stock_location, :variant, presence: true - # rubocop:disable Rails/UniqueValidationWithoutIndex validates :variant_id, uniqueness: { scope: :stock_location_id } - # rubocop:enable Rails/UniqueValidationWithoutIndex validates :count_on_hand, numericality: { greater_than_or_equal_to: 0, unless: :backorderable? } attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id From 34207fc20ffbd5a5463366e573daf4fd06d4ff3d Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 22 Jun 2020 18:19:05 +0100 Subject: [PATCH 053/261] Bring changes to stock_item from spree 2.1, the previous version was from spree 2.0.4 --- app/models/spree/stock_item.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/models/spree/stock_item.rb b/app/models/spree/stock_item.rb index cf86103453..e6df19b03a 100644 --- a/app/models/spree/stock_item.rb +++ b/app/models/spree/stock_item.rb @@ -2,24 +2,23 @@ module Spree class StockItem < ActiveRecord::Base + acts_as_paranoid + belongs_to :stock_location, class_name: 'Spree::StockLocation' belongs_to :variant, class_name: 'Spree::Variant' has_many :stock_movements, dependent: :destroy validates :stock_location, :variant, presence: true - validates :variant_id, uniqueness: { scope: :stock_location_id } + validates :variant_id, uniqueness: { scope: [:stock_location_id, :deleted_at] } validates :count_on_hand, numericality: { greater_than_or_equal_to: 0, unless: :backorderable? } - attr_accessible :count_on_hand, :variant, :stock_location, :backorderable, :variant_id - delegate :weight, to: :variant + delegate :name, to: :variant, prefix: true def backordered_inventory_units Spree::InventoryUnit.backordered_for_stock_item(self) end - delegate :name, to: :variant, prefix: true - def adjust_count_on_hand(value) with_lock do self.count_on_hand = count_on_hand + value @@ -38,6 +37,10 @@ module Spree in_stock? || backorderable? end + def variant + Spree::Variant.unscoped { super } + end + private def count_on_hand=(value) From ba50491c6d2e6699368aea68259fc99c3089597a Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 22 Jun 2020 19:28:28 +0100 Subject: [PATCH 054/261] Restructure the spec a little --- .../checkout_controller_concurrency_spec.rb | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/controllers/checkout_controller_concurrency_spec.rb b/spec/controllers/checkout_controller_concurrency_spec.rb index 51eefe98ae..266f9a4fbe 100644 --- a/spec/controllers/checkout_controller_concurrency_spec.rb +++ b/spec/controllers/checkout_controller_concurrency_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' # This is the first example of testing concurrency in the Open Food Network. @@ -15,6 +17,20 @@ describe CheckoutController, concurrency: true, type: :controller do let(:payment_method) { create(:payment_method, distributors: [distributor]) } let(:breakpoint) { Mutex.new } + let(:address_params) { address.attributes.except("id") } + let(:order_params) { + { + "payments_attributes" => [ + { + "payment_method_id" => payment_method.id, + "amount" => order.total + } + ], + "bill_address_attributes" => address_params, + "ship_address_attributes" => address_params, + } + } + before do # Create a valid order ready for checkout: create(:shipping_method, distributors: [distributor]) @@ -26,7 +42,9 @@ describe CheckoutController, concurrency: true, type: :controller do allow(controller).to receive(:spree_current_user).and_return(order.user) allow(controller).to receive(:current_distributor).and_return(order.distributor) allow(controller).to receive(:current_order_cycle).and_return(order.order_cycle) + end + it "handles two concurrent orders successfully" do # New threads start running straight away. The breakpoint is after loading # the order and before advancing the order's state and making payments. breakpoint.lock @@ -36,21 +54,6 @@ describe CheckoutController, concurrency: true, type: :controller do # I did not find out how to call the original code otherwise. ActiveSupport::Notifications.instrument("spree.checkout.update") end - end - - it "waits for concurrent checkouts" do - # Basic data the user submits during checkout: - address_params = address.attributes.except("id") - order_params = { - "payments_attributes" => [ - { - "payment_method_id" => payment_method.id, - "amount" => order.total - } - ], - "bill_address_attributes" => address_params, - "ship_address_attributes" => address_params, - } # Starting two checkout threads. The controller code will determine if # these two threads are synchronised correctly or run into a race condition. From 54ce5d8c0fb0f1648821333ec24ad66abe75d070 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Thu, 25 Jun 2020 09:15:11 +1000 Subject: [PATCH 055/261] Updating translations for config/locales/en_CA.yml --- config/locales/en_CA.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index 8af92b5472..70e0cacc68 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -479,6 +479,7 @@ en_CA: 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}" + malformed_csv: "Product Import encountered a malformed CSV: %{error_message}" index: notice: "Notice" beta_notice: "This feature is still in beta: you may experience some errors while using it. Please don't hesitate to contact support." @@ -1146,13 +1147,18 @@ en_CA: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit cart" + items_in_cart_singular: "%{num}item in your cart" + items_in_cart_plural: "%{num}items in your cart" + close: "Close" + cart_empty: "Your cart is empty" + take_me_shopping: "Take me shopping!" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" From 0b48a53c2f043ec549f1633ad446ef40d3afbcf0 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Thu, 25 Jun 2020 16:02:01 +1000 Subject: [PATCH 056/261] Updating translations for config/locales/tr.yml --- config/locales/tr.yml | 140 ++++++++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 87598248e1..d94a87fd02 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -78,7 +78,7 @@ tr: charges_not_allowed: "^ Bu müşteri tarafından kredi kartı ücretlendirme kabul edilmemektedir." no_default_card: "^ Bu müşteri için kayıtlı kart bulunmuyor" shipping_method: - not_available_to_shop: "%{shop} için kullanıma uygun değil" + not_available_to_shop: "%{shop} için müsait değil" devise: confirmations: send_instructions: "Birkaç dakika içinde, hesabınızı nasıl doğrulayacağınız ile ilgili talimatları içeren bir e-posta alacaksınız." @@ -183,7 +183,7 @@ tr: home: "AGA" title: Açık Gıda Ağı welcome_to: 'Hoşgeldiniz' - site_meta_description: "Açık Gıda Ağı, yerel, bağımsız, adil ve temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." + site_meta_description: "Açık Gıda Ağı, bağımsız, adil ve temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dayanışma ve şeffaflığı destekler." search_by_name: Üretici adına veya konuma göre arama yapın... producers_join: Bağımsız gıda üreticileri! Açık Gıda Ağı sizler için kullanıma açıldı. charges_sales_tax: KDV Uyguluyor mu? @@ -206,7 +206,7 @@ tr: ongoing: Devam eden bill_address: Fatura Adresi ship_address: Teslimat Adresi - sort_order_cycles_on_shopfront_by: "SİPARİŞ DÖNEMLERİNİ MAĞAZAMDA ŞUNA GÖRE SIRALA" + sort_order_cycles_on_shopfront_by: "SİPARİŞ DÖNEMLERİNİ DÜKKANIMDA ŞUNA GÖRE SIRALA" required_fields: Zorunlu alanlar yıldız ile belirtilmiştir select_continue: Seç ve Devam Et remove: Kaldır @@ -237,7 +237,7 @@ tr: admin_and_handling: Yönetici & İşlemler profile: Profil supplier_only: Sadece Tedarikçi - has_shopfront: MAĞAZASı Var + has_shopfront: DÜKKANI VAR weight: Ağırlık volume: Hacim items: Kalemler @@ -302,7 +302,7 @@ tr: schedule: Takvim shipping: Teslimat shipping_method: Teslimat Yöntemi - shop: Tezgah + shop: Dükkan sku: Stok Kodu status_state: Durum tags: Etiketler @@ -337,8 +337,8 @@ tr: unsaved_confirm_leave: "Kaydedilmemiş değişiklikler var. Kaydetmeden devam etmek istiyor musunuz?" unsaved_changes: "Kaydedilmemiş değişiklikleriniz var" shopfront_settings: - embedded_shopfront_settings: "YERLEŞTİRİLMİŞ MAĞAZA AYARLARI" - enable_embedded_shopfronts: "YERLEŞTİRİLMİŞ MAĞAZALARI ETKİNLEŞTİR" + embedded_shopfront_settings: "YERLEŞTİRİLMİŞ DÜKKAN AYARLARI" + enable_embedded_shopfronts: "YERLEŞTİRİLMİŞ DÜKKANLARI ETKİNLEŞTİR" embedded_shopfronts_whitelist: "Beyaz Listedeki harici Domain'ler" number_localization: number_localization_settings: "Numara Yerelleştirme Ayarları" @@ -441,7 +441,7 @@ tr: upload_an_image: Görsel yükleyin seo: product_search_keywords: "Ürün araması için anahtar kelimeler" - product_search_tip: "Pazarlarda ürünlerinizin aranmasına yardımcı olacak kelimeler yazın. Her bir anahtar kelimeyi ayırmak için boşluk kullanın." + product_search_tip: "Pazaryerinde ürünlerinizin aranmasına yardımcı olacak kelimeler yazın. Her bir anahtar kelimeyi ayırmak için boşluk kullanın." SEO_keywords: "Arama Motoru Anahtar Kelimeleri" seo_tip: "Ürünlerinizi internet üzerinde aramanıza yardımcı olacak kelimeler yazın. Her bir anahtar kelimeyi ayırmak için boşluk kullanın." search: "Ara" @@ -566,7 +566,7 @@ tr: add: Ekle hide: Sakla import_date: Aktarıldı - select_a_shop: Bir Mağaza Seçin + select_a_shop: Bir Dükkan Seçin review_now: Şimdi İncele new_products_alert_message: Stoklarınıza eklemek için %{new_product_count} yeni ürün var. currently_empty: Stoklarınız şu anda boş @@ -576,7 +576,7 @@ tr: no_new_products: Stoklara eklenecek yeni ürün yok no_matching_new_products: Arama kriterlerinize uyan yeni ürün yok inventory_powertip: Burası sizin ürün envanteriniz, stok takip merkeziniz. Ürün eklemek için menüdeki 'Yeni Ürün' butonun tıklayın. - hidden_powertip: Bu ürünler stoklarınızda gizlendi ve mağazanızda görünür olmayacak. Stoklarınıza ürün eklemek için 'Ekle' butonuna tıklayabilirsiniz. + hidden_powertip: Bu ürünler stoklarınızda gizlendi ve dükkanınızda görünür olmayacak. Stoklarınıza ürün eklemek için 'Ekle' butonuna tıklayabilirsiniz. new_powertip: Bu ürünler stoklarınıza eklenmeye hazır. Stoğunuza ürün eklemek için 'Ekle'yi veya tezgahınızda gizlemek için 'Gizle'yi tıklayın. İstediğiniz zaman fikrinizi değiştirebilirsiniz! controls: back_to_my_inventory: Stoklarıma geri dön @@ -657,8 +657,8 @@ tr: ürünün satış listenize eklenmeden önce Stok listenize eklenip eklenmemesi gerektiğini seçebilirsiniz. Eğer ürünlerinizi yönetmek için Stok sistemini kullanmıyorsanız 'tavsiye edilen' seçeneği ile devam etmeniz gerekir. - preferred_product_selection_from_inventory_only_yes: MAĞAZANIZA YENİ ÜRÜNLER EKLENEBİLİR (ÖNERİLİR) - preferred_product_selection_from_inventory_only_no: Yeni ürünler mağazanıza eklemeden önce Stok listesine girilmelidir + preferred_product_selection_from_inventory_only_yes: DÜKKANINIZA YENİ ÜRÜNLER EKLENEBİLİR (ÖNERİLİR) + preferred_product_selection_from_inventory_only_no: Yeni ürünler dükkanınıza eklemeden önce Stok listesine girilmelidir payment_methods: name: Ad applies: Uygulanma? @@ -680,14 +680,14 @@ tr: own: KENDİ ÜRÜNLERİ sells: NE SATIYOR sells_tip: "Hiç - İşletme müşterilere doğrudan satış yapmaz.
Kendi - İşletme müşterilerine kendi ürünlerini satar.
Hepsi - İşletme kendi ürünlerini veya diğer işletmelerin ürünlerini satabilir.
" - visible_in_search: Haritada görünsün mü? + visible_in_search: ARAMADA GÖRÜNÜR MÜ? visible_in_search_tip: Sitede arama yapılırken bu işletmenin müşteriler tarafından görünür olup olmayacağını belirler. - visible: Görünür - not_visible: Gizli + visible: GÖRÜNÜR + not_visible: GİZLİ permalink: Bağlantı Adı (boşluk yok) - permalink_tip: "Bağlantı adı, mağazanızın bağlantı URL'sini oluşturmak için kullanılır: %{link}sectiginiz-ad/tezgah" - link_to_front: Mağaza linkiniz - link_to_front_tip: Açık Gıda Ağı’ndaki mağazanıza doğrudan bağlantı linki + permalink_tip: "Bağlantı adı, mağazanızın bağlantı URL'sini oluşturmak için kullanılır: %{link}sectiginiz-ad/dükkan" + link_to_front: Dükkan linkiniz + link_to_front_tip: Açık Gıda Ağı’ndaki dükkanınıza doğrudan bağlantı linki ofn_uid: AGA KN ofn_uid_tip: Açık Gıda Ağı'na kayıtlı işletmenize özel tanımlanan kimlik numarası shipping_methods: @@ -698,8 +698,8 @@ tr: create_one_button: "Şimdi Oluştur" no_method_yet: "Henüz herhangi bir teslimat yönteminiz yok." shop_preferences: - shopfront_requires_login: "MAĞAZANIZ HERKESE AÇIK MI?" - shopfront_requires_login_tip: "Mağazanızın yalnızca üyelerinize mi yoksa herkese mi açık olduğunu seçin." + shopfront_requires_login: "DÜKKANINIZ HERKESE AÇIK MI?" + shopfront_requires_login_tip: "Dükkanınızın yalnızca üyelerinize mi yoksa herkese mi açık olduğunu seçin." shopfront_requires_login_false: "Herkese açık" shopfront_requires_login_true: "Yalnızca kayıtlı müşteriler tarafından görülebilir" recommend_require_login: "Siparişlerin değiştirilebileceği durumlarda kullanıcıların oturum açmasını öneriyoruz." @@ -715,19 +715,20 @@ tr: enable_subscriptions_tip: "Üyelik işlevselliği etkinleştirilsin mi?" enable_subscriptions_false: "Kapalı" enable_subscriptions_true: "Etkin" - shopfront_message: "MAĞAZA MESAJINIZ" + shopfront_message: "DÜKKAN MESAJINIZ" shopfront_message_placeholder: > - Müşterilerinize merhaba diyebilir, tezgahınız ve alışveriş şartlarınız + Müşterilerinize merhaba diyebilir, dükkanınız ve alışveriş şartlarınız ile ilgili bilgi verebilirsiniz. Yazdıklarınız, müşteriler mağazanızı ziyaret ettiğinde görünür olacak. shopfront_message_link_tooltip: "Bağlantı ekle/düzenle" shopfront_message_link_prompt: "Lütfen eklemek için bir URL girin" - shopfront_closed_message: "KAPALI MAĞAZA MESAJI" + shopfront_closed_message: "KAPALI DÜKKAN MESAJI" shopfront_closed_message_placeholder: > Mağazanızın neden satışa kapalı olduğunu ve ne zaman açılacağını müşterilerinize - açıklayan bir mesaj yazın. Bu mesaj, açık sipariş döneminiz olmadığında - sizi ziyaret edenler tarafından görülecek. - shopfront_category_ordering: "MAĞAZA KATEGORİ SIRALAMASI" + açıklayan bir mesaj yazın. Bu mesaj, açık bir sipariş döneminiz olmadığında + sizi ziyaret edenler tarafından görülecek. (örn. neden kapalı olduğunu + ve ne zaman açılacağını belirtebilirsiniz) + shopfront_category_ordering: "DÜKKAN KATEGORİ SIRALAMASI" open_date: "Açılış Tarihi" close_date: "Kapanış Tarih" social: @@ -788,7 +789,7 @@ tr: name: Ad role: Görev sells: NE SATIYOR - visible: Haritada görünür mü? + visible: GÖRÜNÜR MÜ? owner: Sahip producer: ÜRETİCİ change_type_form: @@ -796,10 +797,10 @@ tr: connect_ofn: AGA üzerinden bağlan always_free: HER ZAMAN ÜCRETSİZ producer_description_text: Ürünlerinizi Açık Gıda Ağı'na yükleyin. Böylece ürünleriniz pazar hesapları üzerinden satışa sunulabilir. - producer_shop: ÜRETİCİ TEZGAHI + producer_shop: ÜRETİCİ DÜKKANI sell_your_produce: Kendi ürününü sat - producer_shop_description_text: Açık Gıda Ağı üzerinden açtığınız bireysel mağazanız ile ürünlerinizi doğrudan müşterilere ulaştırabilirsiniz. - producer_shop_description_text2: Üretici Tezgahı sadece sizin ürünleriniz içindir. Üretiminiz haricindeki ürünleri satabilmek için lütfen 'Üretici Pazarı' seçeneğini seçin. + producer_shop_description_text: Açık Gıda Ağı üzerinden açtığınız bireysel dükkanınız ile ürünlerinizi doğrudan müşterilere ulaştırabilirsiniz. + producer_shop_description_text2: Üretici Dükkanı sadece sizin ürünleriniz içindir. Üretiminiz haricindeki ürünleri satabilmek için lütfen 'Üretici Pazarı' seçeneğini seçin. producer_hub: ÜRETİCİ PAZARI producer_hub_text: Kendi ürünleriniz ile beraber başkalarının ürünlerini de satın producer_hub_description_text: İşletmeniz, yerel gıda sisteminizin bel kemiğidir. Açık Gıda Ağı'ndaki mağazanız aracılığıyla kendi ürünlerinizi ve çevrenizdeki diğer üreticilerin ürünlerini beraber satabilirsiniz. @@ -808,7 +809,7 @@ tr: profile_description_text: İnsanlar Açık Gıda Ağı üzerinden sizi bulabilir ve sizinle iletişim kurabilir. İşletmeniz haritada ve listelerde görünür olacak. hub_shop: Türetici Pazarı hub_shop_text: Başkalarının ürünlerini satın - hub_shop_description_text: İşletmeniz yerel gıda sisteminizin belkemiğidir. Diğer işletmelerin ürünlerini bir araya getirebilir, Açık Gıda Ağı'na kayıtlı mağazanız üzerinden alıcılara ulaştırabilirsiniz. + hub_shop_description_text: İşletmeniz yerel gıda sisteminizin belkemiğidir. Diğer işletmelerin ürünlerini bir araya getirebilir, Açık Gıda Ağı'na kayıtlı dükkanınız üzerinden alıcılara ulaştırabilirsiniz. choose_option: Lütfen yukarıdaki seçeneklerden birini seçin. change_now: Değiştir enterprise_user_index: @@ -1045,9 +1046,9 @@ tr: query_placeholder: "E-posta ile ara ..." setup_explanation: just_a_few_more_steps: 'Başlamadan önce birkaç adım kaldı:' - enable_subscriptions: "Mağazalarınızdan en az biri için üyelikleri etkinleştirin" - enable_subscriptions_step_1_html: 1. %{enterprises_link} sayfasına gidin, tezgahınızı bulun ve ‘Yönet’i tıklayın - enable_subscriptions_step_2: 2. 'Mağaza Tercihleri' altındaki Üyelikler seçeneğini etkinleştirin + enable_subscriptions: "Dükkanınızdan en az biri için üyelikleri etkinleştirin" + enable_subscriptions_step_1_html: 1. %{enterprises_link} sayfasına gidin, dükkanınızı bulun ve ‘Yönet’i tıklayın + enable_subscriptions_step_2: 2. 'Dükkan Tercihleri' altındaki Üyelikler seçeneğini etkinleştirin set_up_shipping_and_payment_methods_html: '%{shipping_link} ve %{payment_link} yöntemlerini ayarlayın' set_up_shipping_and_payment_methods_note_html: Yalnızca Nakit ve Online ödeme yöntemlerinin
'ü üyeliklerle kullanılabilir ensure_at_least_one_customer_html: En az bir %{customer_link} bulunduğundan emin olun @@ -1139,20 +1140,25 @@ tr: failed: "Ödeme başarısız oldu. Siparişinizi işleme koyabilmemiz için lütfen bizimle iletişime geçin." shops: hubs: - show_closed_shops: "Kapalı mağazaları göster" - hide_closed_shops: "Kapalı mağazaları gizle" + show_closed_shops: "Kapalı dükkanları göster" + hide_closed_shops: "Kapalı dükkanları gizle" show_on_map: "Tümünü haritada göster" shared: menu: cart: cart: "Sepet" + cart_sidebar: + checkout: "Ödeme Yap" + edit_cart: "Sepeti düzenle" + items_in_cart_singular: "Sepetnizide %{num} ürün var" + items_in_cart_plural: "Sepetinizde %{num} ürün var" + close: "KAPANIŞ" + cart_empty: "Sepetiniz boş" + take_me_shopping: "Alışveriş yap!" signed_in: profile: "Profil" mobile_menu: cart: "Sepet" - joyride: - checkout: "Alışverişi Tamamla" - already_ordered_products: "Bu sipariş dönemi içinde zaten sipariş verildi" register_call: selling_on_ofn: "Açık Gıda Ağı üzerinden satış yapmak ister misiniz?" register: "Buradan kaydolun" @@ -1163,7 +1169,7 @@ tr: footer_contact_email: "Bize e-posta gönderin" footer_nav_headline: "Gezin" footer_join_headline: "Bize katılın" - footer_join_body: "Açık Gıda Ağı üzerinden ürünlerinizi sergileyin, çevirimiçi mağazanızı oluşturun veya grubunuzu listeleyin." + footer_join_body: "Açık Gıda Ağı üzerinden ürünlerinizi sergileyin, dükkanınızı oluşturun veya topluluğunuzu, grubunuzu listeleyin." footer_join_cta: "Daha fazlasını anlat!" footer_legal_call: "Okuyun" footer_legal_tos: "Şartlar ve koşullar" @@ -1179,7 +1185,7 @@ tr: login: "Oturum Aç / Kaydol" signup: "Kaydol" contact: "İLETİŞİM" - require_customer_login: "Yalnızca onaylı müşteriler buradan alışveriş yapabilir." + require_customer_login: "Yalnızca onaylı müşteriler (üyeler) buradan alışveriş yapabilir." require_login_html: "Zaten onaylanmış bir müşteri iseniz, devam etmek için %{login} veya %{signup}" require_login_2_html: "Buradan alışveriş mi yapmak istiyorsunuz? Lütfen katılmak için sorun: %{contact}%{enterprise} " require_customer_html: "Buradan alışveriş yapmaya başlamak istiyorsanız, katılmak için lütfen sorun: %{contact} %{enterprise} " @@ -1269,7 +1275,7 @@ tr: unconfirmed: doğrulanmamış days: günler authorization_failure: "Yetki Hatası" - label_shop: "Pazar" + label_shop: "Dükkan" label_shops: "PAZAR YERİ" label_map: "HARİTA" label_producer: "ÜRETİCİ" @@ -1354,10 +1360,10 @@ tr: cookies_policy_link_desc: "Daha fazla bilgi edinmek istiyorsanız," cookies_policy_link: "çerezler politikası" cookies_accept_button: "Çerezleri kabul et" - home_shop: ŞİMDİ ALIŞVERİŞ YAPIN + home_shop: 'ŞİMDİ ALIŞVERİŞE BAŞLAYIN ' brandstory_headline: "Bağımsız, adil ve temiz gıda ..." brandstory_intro: "Bazen sistemi düzeltmenin en iyi yolu yeni bir sistem yaratmaktır…" - brandstory_part1: "Açık Gıda Ağı, yerel, bağımsız, adil ve temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." + brandstory_part1: "Açık Gıda Ağı, adil, temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." brandstory_part2: "AGA, üreticilere ve alıcılara aracısız ticaret faydaları sağlar ve toplumsal iletişimi ve güveni cesaretlendirir. Gıda yetiştiriciliği ve satışının kendine özgü ihtiyaçlarını karşılamak için geliştirilmiştir. Temiz gıdaya ulaşım sürecini kolaylaştırır." brandstory_part3: "Platform üzerinden yalnızca yerel ve bağımsız gıda üreticileri ve dağıtımcıları satış yapabilir. Siz de ürünlerinizi AGA üzerinden oluşturduğunuz tezgah ile doğrudan alıcılara ulaştırabilir, dilerseniz bölgenizdeki diğer üreticiler ile bir araya gelerek kendi ortak 'Üretici Pazarı' veya 'Türetici Pazarı' nızı oluşturabilirsiniz. Bu şekilde çeşitliliği ve bereketi artırır, dayanışmanın getirdiği faydalardan da yararlanabilirsiniz." brandstory_part4: "Her yerde çalışıyor. Her şeyi değiştiriyor." @@ -1537,7 +1543,7 @@ tr: hubs_matches: "Bunu mu arıyordunuz?" hubs_intro: Bulunduğunuz bölgeden alışveriş yapın hubs_distance: En yakın - hubs_distance_filter: "Bana %{location} yakınındaki tezgahları göster" + hubs_distance_filter: "Bana %{location} yakınındaki dükkanları göster" shop_changeable_orders_alert_html: one: %{shop} / %{order} ile siparişiniz incelemeye açık. %{oc_close} tarihine kadar değişiklik yapabilirsiniz. other: Şu anda düzenlemeye açık %{shop} ile %{count} siparişiniz var. %{oc_close} tarihine kadar değişiklik yapabilirsiniz. @@ -1568,7 +1574,7 @@ tr: products_no_results_html: "Üzgünüz, sonuç bulunamadı %{query}" products_clear_search: "Aramayı temizle" search_no_results_html: "Üzgünüz, %{query} sonuç bulunamadı. Başka bir arama yapmak ister misiniz?" - components_profiles_popover: "Açık Gıda Ağında bir mağazası olmayan ancak başka bir sitede kendi satış siteleri olan hesaplar" + components_profiles_popover: "Açık Gıda Ağında bir dükkanı olmayan ancak başka bir sitede kendi satış siteleri olan hesaplar" components_profiles_show: "Profilleri göster" components_filters_nofilters: "Filtresiz" components_filters_clearfilters: "Tüm filtreleri temizle" @@ -1645,9 +1651,9 @@ tr: sell_groups_detail: "Bölgenizdeki veya ağınızdaki işletmelerin (üreticilerin, pazarların veya diğer grupların) detaylı rehber listesini oluşturun." sell_user_guide: "Kullanım kılavuzumuzdan daha fazla bilgi edinin." sell_listing_price: "AGA üzerinde görünür olmak ücretsizdir. Platform üzerinden satış yapan işletmeler için işlem başına uygulanan ücretlendirme KDV dahil %5'tir. Kar amacı gütmeyen topluluklar, kooperatifler ve ekoloji/gıda temelli dernekler ile çalışan üreticiler karşılıklı dayanışma ve özel fiyatlandırma için iletişime geçebilirler. Fiyatlandırma hakkında bilgi almak için, üst menüdeki Hakkımızda bağlantısını kullanarak Fiyatlandırma bölümünü ziyaret edin." - sell_embed: "Kendi e-ticaret siteniz olsa bile Açık Gıda Ağı size hikayenizi anlatmanız ve ürünlerinizi satmanız için yeni ve farklı bir seçenek sunuyor. Siz de bu ailenin bir parçası olun, hep beraber büyüyelim!" + sell_embed: "Kendi e-ticaret siteniz veya farklı satış kanallarınız olsa bile Açık Gıda Ağı size hikayenizi anlatmanız ve ürünlerinizi satmanız için yeni ve farklı bir seçenek sunuyor. Siz de bu ailenin bir parçası olun, hep beraber büyüyelim!" sell_ask_services: "Detaylar için bizimle iletişime geçin." - shops_title: Mağazalar + shops_title: Dükkanlar shops_headline: Alışveriş biçim değiştiriyor shops_text: Gıda dönemsel yetiştirilir, dönemsel hasat edilir ve dönemsel sipariş edilir. Aradığınız mağazanın sipariş dönemi kapalı ise kısa süre sonra tekrar kontrol edin. shops_signup_title: Pazar olarak kaydolun @@ -1694,11 +1700,11 @@ tr: products_cart_distributor_choice: "Siparişinizin dağıtımcısı:" products_cart_distributor_change: "Bu ürünü sepetinize eklerseniz, bu sipariş için dağıtımcınız %{name} olarak değiştirilecektir." products_cart_distributor_is: "Bu sipariş için dağıtımcınız %{name}." - products_distributor_error: "Başka bir dağıtımcıdan alışveriş yapmadan önce lütfen siparişinizi %{link} adresinden tamamlayın." + products_distributor_error: "Başka bir dağıtımcıdan alışveriş yapmadan önce lütfen %{link} adresinden siparişinizi tamamlayın." products_oc: "Siparişiniz için sipariş dönemi:" products_oc_change: "Bu ürünü sepetinize eklerseniz, bu sipariş için sipariş döneminiz %{name} olarak değiştirilecektir." products_oc_is: "Bu sipariş için sipariş döneminiz %{name}." - products_oc_error: "Farklı bir sipariş döneminden alışveriş yapmadan önce lütfen siparişinizi %{link} ' tamamlayın." + products_oc_error: "Farklı bir sipariş döneminden alışveriş yapmadan önce lütfen %{link} siparişinizi tamamlayın." products_oc_current: "mevcut sipariş döneminiz" products_max_quantity: Maks miktar products_distributor: Dağıtımcı @@ -1888,7 +1894,7 @@ tr: shop_variant_quantity_max: "maks" follow: "Takip et" shop_for_products_html: "%{enterprise} ürünleri için şuradan alışveriş yapın:" - change_shop: "Mağazayı şuna değiştir:" + change_shop: "Dükkanı şuna değiştir:" shop_at: "Şimdi alışveriş yapın:" price_breakdown: "Fiyat dökümü" admin_fee: "Yönetim Ücreti" @@ -2323,14 +2329,14 @@ tr: unavailable: Kullanım dışı profile: Profil hub: pazar - shop: MAĞAZA + shop: Dükkan choose: Seç resolve_errors: Lütfen aşağıdaki hataları düzeltin more_items: "+ %{count} Daha " default_card_updated: Varsayılan Kart Güncellendi cart: add_to_cart_failed: > - Bu ürünü sepete eklerken bir hata oluştu. Ürün stokları bitmiş veya mağaza + Bu ürünü sepete eklerken bir hata oluştu. Ürün stokları bitmiş veya dükkan kapanıyor olabilir. admin: enterprise_limit_reached: "Hesap başına standart işletme sınırına ulaştınız. Artırmanız gerekiyorsa %{contact_email}'a yazın." @@ -2368,7 +2374,7 @@ tr: hub_profile_text2: > Bir profil sahibi olmak, Açık Gıda Ağı üzerinden bağlantı kurmak her zaman ücretsiz olacaktır. - hub_shop: Pazar Mağazası + hub_shop: Pazar Dükkanı hub_shop_text1: > İşletmeniz yerel gıda sisteminizin bel kemiğidir. Ulaşabilir olduğunuz bölgedeki üreticilerin ürünlerini bir araya getirip Açık Gıda Ağı üzerinden @@ -2392,17 +2398,17 @@ tr: ve yeni işbirlikleri aramak için güzel bir yerdesiniz. profile_only_text2: > Eğer yalnızca çiftçiliğe odaklanmak ve ürünlerin satış kısmını başkalarına - bırakmak istiyorsanız, Açık Gıda Ağı üzerinde bir tezgah sahibi olmanıza + bırakmak istiyorsanız, Açık Gıda Ağı üzerinde bir dükkan sahibi olmanıza gerek yoktur. profile_only_text3: > Ürünlerinizi Açık Gıda Ağı'na ekleyin. Böylece üretici & türetici pazarları gibi diğer hesaplar ürünlerinizi kendi listelerine ekleyip satışa sunabilsinler. - producer_shop: ÜRETİCİ TEZGAHI + producer_shop: ÜRETİCİ DÜKKANI producer_shop_text1: > - Açık Gıda Ağı üzerindeki mağazanız aracılığıyla ürünlerinizi alıcılara + Açık Gıda Ağı üzerindeki dükkanınız aracılığıyla ürünlerinizi alıcılara direk olarak satın. producer_shop_text2: > - Üretici Tezgahı yalnızca kendi ürünlerinizi satmanız içindir. Kendi + Üretici Dükkanı yalnızca kendi ürünlerinizi satmanız içindir. Kendi üretiminiz haricindeki ürünlerden de satmak isterseniz lütfen 'Üretici Pazarı' nı seçin. producer_hub: Üretici Pazarı @@ -2541,7 +2547,7 @@ tr: subscriptions: error_saving: "Üyelik kaydedilirken hata oluştu" new: - please_select_a_shop: "Lütfen bir mağaza seçin" + please_select_a_shop: "Lütfen bir dükkan seçin" insufficient_stock: "Yetersiz stok, sadece %{on_hand} kaldı" out_of_stock: reduced_stock_available: Azaltılmış stok mevcut @@ -2572,12 +2578,12 @@ tr: changing_on_hand_stock: Eldeki stok seviyeleri değiştiriliyor ... stock_reset: Stoklar varsayılana ayarlanır tag_rules: - show_hide_variants: 'MAĞAZAMDA VARYANTLARI GÖSTER VEYA GİZLE' + show_hide_variants: 'DÜKKANIMDA VARYANTLARI GÖSTER VEYA GİZLE' show_hide_shipping: 'Ödeme sırasında teslimat yöntemlerini göster veya gizle' show_hide_payment: 'Ödeme sırasında ödeme yöntemlerini göster veya gizle' - show_hide_order_cycles: 'MAĞAZAMDA SİPARİŞ DÖNEMLERİNİ GÖSTER VEYA GİZLE' + show_hide_order_cycles: 'DÜKKANIMDA SİPARİŞ DÖNEMLERİNİ GÖSTER VEYA GİZLE' visible: GÖRÜNÜR - not_visible: GÖRÜNÜR DEĞİL + not_visible: GİZLİ services: unsaved_changes_message: Kaydedilmemiş değişiklikler var, şimdi kaydet veya yoksay? save: KAYDET @@ -2601,7 +2607,7 @@ tr: producer: "Üretici" non_producer: "Üretici Değil" customers: - select_shop: 'Lütfen önce bir mağaza seçin' + select_shop: 'Lütfen önce bir dükkan seçin' could_not_create: Afedersiniz! Oluşturulamadı subscriptions: closes: kapanır @@ -3255,7 +3261,7 @@ tr: display_as_placeholder: 'örn. 2 kg' display_name_placeholder: 'örn. Domates' autocomplete: - out_of_stock: "Tükendi" + out_of_stock: "Stokta Yok" producer_name: "Üretici" unit: "Birim" shared: @@ -3385,7 +3391,7 @@ tr: transaction_history: İşlem Geçmişi open_orders: order: Sipariş - shop: MAĞAZA + shop: DÜKKAN changes_allowed_until: Değişiklikler Şu Zamana Kadar İzin Verildi items: Ürünler total: Toplam @@ -3395,7 +3401,7 @@ tr: until: Şu zamana kadar past_orders: order: Sipariş - shop: MAĞAZA + shop: DÜKKAN completed_at: Tamamlanma Tarihi items: Ürünler total: Toplam @@ -3409,7 +3415,7 @@ tr: authorised_shops_popover: Sahip olabileceğiniz tüm üyelikler (mesela tekrarlayan siparişleriniz) için varsayılan kredi kartınızdan işlem yapmasına izin verilen işletmelerin listesidir. Kart bilgileriniz güvende tutulacak ve işletme sahipleriyle paylaşılmayacak. Ödeme alındığında her zaman bilgilendirileceksiniz. saved_cards_popover: Bu, daha sonra kullanmak üzere kaydetmeyi seçtiğiniz kartların listesidir. Bir siparişin ödemesi tamamlandığında 'varsayılan'ınız otomatik olarak seçilir ve izin verdiğiniz satıcılar tarafından ücretlendirilebilir (sağa bakın). authorised_shops: - shop_name: "MAĞAZA ADI" + shop_name: "DÜKKAN ADI" allow_charges?: "Ücretlere İzin Verilsin mi?" localized_number: invalid_format: geçersiz bir biçime sahip. Lütfen bir numara giriniz. From a0c7dc2ccbf4ca07e847b9db61f44183aa42cb7e Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 24 Jun 2020 11:47:26 +1000 Subject: [PATCH 057/261] Remove leftover empty spec context --- spec/features/consumer/shopping/shopping_spec.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index b947b23d3d..6d37432902 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -148,17 +148,6 @@ feature "As a consumer I want to shop with a distributor", js: true do end end end - - context "when logged in" do - let!(:prev_order) { create(:completed_order_with_totals, order_cycle: oc1, distributor: distributor, user: order.user) } - - before do - distributor.allow_order_changes = true - distributor.save - quick_login_as order.user - visit shop_path - end - end end end From 70347148a18b31800ea47978f06930cc14433774 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 19 Jun 2020 16:36:44 +1000 Subject: [PATCH 058/261] Stabilise shopping specs and open them for change The way we add items to the cart will change. Encapsulating that code in a common place will make the mobile ux work clearer and avoid merge conflicts. The waiting for background requests has also been improved and made more consistent which should make these specs more reliable. --- .../shopping/embedded_shopfronts_spec.rb | 2 +- .../consumer/shopping/shopping_spec.rb | 89 ++++++------------- .../shopping/variant_overrides_spec.rb | 26 +++--- spec/support/request/checkout_workflow.rb | 2 +- spec/support/request/shop_workflow.rb | 73 ++++++++++++++- spec/support/request/ui_component_helper.rb | 4 - spec/support/request/web_helper.rb | 4 - 7 files changed, 112 insertions(+), 88 deletions(-) diff --git a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb index 20c7bfccb8..445a92186f 100644 --- a/spec/features/consumer/shopping/embedded_shopfronts_spec.rb +++ b/spec/features/consumer/shopping/embedded_shopfronts_spec.rb @@ -45,7 +45,7 @@ feature "Using embedded shopfront functionality", js: true do it "allows shopping and checkout" do on_embedded_page do - fill_in "variants[#{variant.id}]", with: 1 + click_add_to_cart edit_cart diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index 6d37432902..cf825ca475 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -104,9 +104,8 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_content with_currency(1020.99) # -- Cart shows correct price - fill_in "variants[#{variant.id}]", with: 1 - toggle_cart - within(".cart-sidebar") { expect(page).to have_content with_currency(1020.99) } + click_add_to_cart variant + expect(page).to have_in_cart with_currency(1020.99) toggle_cart # -- Changing order cycle @@ -119,10 +118,8 @@ feature "As a consumer I want to shop with a distributor", js: true do # ng-animate means that the old product row is likely to be present, so we ensure # that we are not filling in the quantity on the outgoing row expect(page).not_to have_selector "tr.product-cart" - within('product:not(.ng-leave)') { fill_in "variants[#{variant.id}]", with: 1 } - - wait_for_cart - within(".cart-sidebar") { expect(page).to have_content with_currency(19.99) } + within('product:not(.ng-leave)') { click_add_to_cart variant } + expect(page).to have_in_cart with_currency(19.99) end describe "declining to clear the cart" do @@ -132,15 +129,14 @@ feature "As a consumer I want to shop with a distributor", js: true do visit shop_path select "turtles", from: "order_cycle_id" - fill_in "variants[#{variant.id}]", with: 1 + click_add_to_cart variant end it "leaves the cart untouched when the user declines" do handle_js_confirm(false) do select "frogs", from: "order_cycle_id" - toggle_cart + expect(page).to have_in_cart "1" expect(page).to have_selector "tr.product-cart" - expect(page).to have_selector '.cart-sidebar', text: '1' # The order cycle choice should not have changed expect(page).to have_select 'order_cycle_id', selected: 'turtles' @@ -219,11 +215,8 @@ feature "As a consumer I want to shop with a distributor", js: true do visit shop_path expect(page).to have_content product.name - # Add product to cart - fill_in "variants[#{variant.id}]", with: '1' - wait_for_debounce + click_add_to_cart variant expect(page).to have_in_cart product.name - wait_until { !cart_dirty } # Try to go to cart visit main_app.cart_path @@ -249,17 +242,14 @@ feature "As a consumer I want to shop with a distributor", js: true do it "should save group buy data to the cart and display it on shopfront reload" do # -- Quantity - fill_in "variants[#{variant.id}]", with: 6 - wait_for_debounce + click_add_bulk_to_cart variant, 6 expect(page).to have_in_cart product.name - wait_until { !cart_dirty } + toggle_cart expect(order.reload.line_items.first.quantity).to eq(6) # -- Max quantity - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: 7 - wait_for_debounce - wait_until { !cart_dirty } + click_add_bulk_max_to_cart variant, 7 expect(order.reload.line_items.first.max_quantity).to eq(7) @@ -285,15 +275,15 @@ feature "As a consumer I want to shop with a distributor", js: true do end it "lets us add and remove products from our cart" do - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect(page).to have_in_cart product.name - wait_until { !cart_dirty } li = Spree::Order.order(:created_at).last.line_items.order(:created_at).last expect(li.quantity).to eq(1) - fill_in "variants[#{variant.id}]", with: '0' + toggle_cart + click_remove_from_cart variant + toggle_cart within('.cart-sidebar') { expect(page).not_to have_content product.name } - wait_until { !cart_dirty } expect(Spree::LineItem.where(id: li)).to be_empty end @@ -302,7 +292,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update on_hand: 5, on_demand: true visit shop_path - fill_in "variants[#{variant.id}]", with: '10' + click_add_to_cart variant, 10 expect(page).to have_field "variants[#{variant.id}]", with: '10' end @@ -311,6 +301,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update on_hand: 5 visit shop_path + accept_alert 'Insufficient stock available, only 5 remaining' do fill_in "variants[#{variant.id}]", with: '10' end @@ -325,9 +316,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update! on_hand: 0 # -- Messaging - expect(page).to have_input "variants[#{variant.id}]" - fill_in "variants[#{variant.id}]", with: '1' - wait_until { !cart_dirty } + click_add_to_cart variant within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -342,8 +331,6 @@ feature "As a consumer I want to shop with a distributor", js: true do # Update amount available in product list # If amount falls to zero, variant should be greyed out and input disabled expect(page).to have_selector "#variant-#{variant.id}.out-of-stock" - expect(page).to have_selector "#variants_#{variant.id}[ofn-on-hand='0']" - expect(page).to have_selector "#variants_#{variant.id}[disabled='disabled']" end it 'does not show out of stock modal if product is on_demand' do @@ -351,9 +338,7 @@ feature "As a consumer I want to shop with a distributor", js: true do variant.update! 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 } + click_add_to_cart variant expect(page).to_not have_selector '.out-of-stock-modal' end @@ -363,13 +348,11 @@ feature "As a consumer I want to shop with a distributor", js: true do it "does the same" do # -- Place in cart so we can set max_quantity, then make out of stock - fill_in "variants[#{variant.id}]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant variant.update! on_hand: 0 # -- Messaging - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_max_to_cart variant within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -389,13 +372,11 @@ feature "As a consumer I want to shop with a distributor", js: true do context "when the update is for another product" do it "updates quantity" do - fill_in "variants[#{variant.id}]", with: '2' - wait_until { !cart_dirty } + click_add_to_cart variant, 2 variant.update! on_hand: 1 - fill_in "variants[#{variant2.id}]", with: '1' - wait_until { !cart_dirty } + click_add_to_cart variant2 within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -407,13 +388,12 @@ feature "As a consumer I want to shop with a distributor", js: true do let(:product) { create(:simple_product, group_buy: true) } it "does not update max_quantity" do - fill_in "variants[#{variant.id}]", with: '2' - fill_in "variant_attributes[#{variant.id}][max_quantity]", with: '3' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant, 2 + click_add_bulk_max_to_cart variant, 3 + variant.update! on_hand: 1 - fill_in "variants[#{variant2.id}]", with: '1' - wait_until { !cart_dirty } + click_add_bulk_to_cart variant2 within(".out-of-stock-modal") do expect(page).to have_content "stock levels for one or more of the products in your cart have reduced" @@ -432,7 +412,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "handles it as if the variant has gone out of stock" do variant.delete - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect_out_of_stock_behavior end @@ -447,7 +427,7 @@ feature "As a consumer I want to shop with a distributor", js: true do it "handles it as if the variant has gone out of stock" do variant.delete - fill_in "variants[#{variant.id}]", with: '1' + click_add_to_cart variant expect_out_of_stock_behavior end @@ -567,16 +547,7 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_content product.name end - def wait_for_debounce - # The auto-submit on these specific form elements (add to cart) now has a small built-in - # waiting period before submitting the data... - sleep 0.6 - end - def expect_out_of_stock_behavior - wait_for_debounce - wait_until { !cart_dirty } - # Shows an "out of stock" modal, with helpful user feedback within(".out-of-stock-modal") do expect(page).to have_content I18n.t('js.out_of_stock.out_of_stock_text') @@ -587,9 +558,5 @@ feature "As a consumer I want to shop with a distributor", js: true do expect(page).to have_selector "#variant-#{variant.id}.out-of-stock" expect(page).to have_selector "#variants_#{variant.id}[ofn-on-hand='0']" expect(page).to have_selector "#variants_#{variant.id}[disabled='disabled']" - - # We need to wait again for the cart to finish updating in Angular or the test can fail - # as the session cannot be reset properly (after the test) while it's still loading - wait_until { !cart_dirty } end end diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index 6dfed074a7..eec53d5871 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -66,9 +66,7 @@ feature "shopping with variant overrides defined", js: true do end it "shows the correct prices when products are in the cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" - toggle_cart - wait_until_enabled '.cart-sidebar a.edit-cart' + click_add_to_cart product1_variant1, 2 visit shop_path expect(page).to have_price with_currency(61.11) end @@ -77,14 +75,14 @@ feature "shopping with variant overrides defined", js: true do # https://github.com/openfoodfoundation/openfoodnetwork/issues/312 it "shows the overridden price with fees in the quick cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 toggle_cart expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .quantity", text: '2' expect(page).to have_selector "#cart-variant-#{product1_variant1.id} .total-price", text: with_currency(122.22) end it "shows the correct prices in the shopping cart" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 edit_cart expect(page).to have_selector "tr.line-item.variant-#{product1_variant1.id} .cart-item-price", text: with_currency(61.11) @@ -96,7 +94,7 @@ feature "shopping with variant overrides defined", js: true do end it "shows the correct prices in the checkout" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout expect(page).to have_selector 'form.edit_order .cart-total', text: with_currency(122.22) @@ -107,7 +105,7 @@ feature "shopping with variant overrides defined", js: true do describe "creating orders" do it "creates the order with the correct prices" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout complete_checkout @@ -118,7 +116,7 @@ feature "shopping with variant overrides defined", js: true do end it "subtracts stock from the override" do - fill_in "variants[#{product1_variant3.id}]", with: "2" + click_add_to_cart product1_variant3, 2 click_checkout expect do @@ -129,7 +127,7 @@ feature "shopping with variant overrides defined", js: true do end it "subtracts stock from stock-overridden on_demand variants" do - fill_in "variants[#{product3_variant2.id}]", with: "2" + click_add_to_cart product3_variant2, 2 click_checkout expect do @@ -140,7 +138,7 @@ feature "shopping with variant overrides defined", js: true do end it "does not subtract stock from overrides that do not override count_on_hand" do - fill_in "variants[#{product1_variant1.id}]", with: "2" + click_add_to_cart product1_variant1, 2 click_checkout expect do complete_checkout @@ -149,7 +147,7 @@ feature "shopping with variant overrides defined", js: true do end it "does not subtract stock from variants where the override has on_demand: true" do - fill_in "variants[#{product4_variant1.id}]", with: "2" + click_add_to_cart product4_variant1, 2 click_checkout expect do complete_checkout @@ -159,7 +157,7 @@ feature "shopping with variant overrides defined", js: true do it "does not show out of stock flags on order confirmation page" do product1_variant3.on_hand = 0 - fill_in "variants[#{product1_variant3.id}]", with: "2" + click_add_to_cart product1_variant3, 2 click_checkout complete_checkout @@ -202,7 +200,7 @@ feature "shopping with variant overrides defined", js: true do def click_checkout toggle_cart - wait_until_enabled '.cart-sidebar a.edit-cart' - first(:link, I18n.t('shared.menu.cart_sidebar.checkout')).click + wait_for_cart + click_link I18n.t('shared.menu.cart_sidebar.checkout') end end diff --git a/spec/support/request/checkout_workflow.rb b/spec/support/request/checkout_workflow.rb index 8a4ea7974d..c6863a1bf5 100644 --- a/spec/support/request/checkout_workflow.rb +++ b/spec/support/request/checkout_workflow.rb @@ -4,7 +4,7 @@ module CheckoutWorkflow end def checkout_as_guest - find("button", text: "Checkout as guest").click + click_button "Checkout as guest" end def place_order diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index e5123715e0..c6a469e6c4 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -1,13 +1,28 @@ module ShopWorkflow + # If a spec uses `within` but we want to check something outside of that + # scope, we can search from the body element instead. + def find_body + page.all("body").first || page.find(:xpath, "ancestor::body") + end + def wait_for_cart - first("#cart").click - within '.cart-sidebar' do - expect(page).to_not have_link "Updating cart..." + # Wait for debounce + # + # The auto-submit on these specific form elements (add to cart) now has a small built-in + # waiting period before submitting the data... + sleep 0.6 + + within find_body do + # We ignore visibility in case the cart dropdown is not open. + within '.cart-sidebar', visible: false do + expect(page).to_not have_link "Updating cart...", visible: false + end end end def edit_cart wait_for_cart + toggle_cart within '.cart-sidebar' do expect(page).to have_link I18n.t('shared.menu.cart_sidebar.edit_cart') end @@ -34,6 +49,58 @@ module ShopWorkflow order.update_distribution_charge! end + # Add an item to the cart + # + # At the moment, the user enters the quantity into an input field. + # But with the coming mobile-friendly UX, the user will click a button to + # add an item, hence the naming. + # + # This is temporary code. The duplication will be removed by the mobile + # product listings feature. This has been backported to avoid merge + # conflicts and to make the current build more stable. + def click_add_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_remove_from_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i - quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_add_bulk_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find("input") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def click_add_bulk_max_to_cart(variant = nil, quantity = 1) + within_variant(variant) do + input = page.find(:field, "variant_attributes[#{variant.id}][max_quantity]") + new_quantity = input.value.to_i + quantity + fill_in input[:name], with: new_quantity + end + wait_for_cart + end + + def within_variant(variant = nil) + selector = variant ? "#variant-#{variant.id}" : ".variants" + within(selector) do + yield + end + end + def toggle_accordion(name) find("dd a", text: name).click end diff --git a/spec/support/request/ui_component_helper.rb b/spec/support/request/ui_component_helper.rb index b23002e3d7..dd2f38bd46 100644 --- a/spec/support/request/ui_component_helper.rb +++ b/spec/support/request/ui_component_helper.rb @@ -69,10 +69,6 @@ module UIComponentHelper page.find("#cart").click end - def cart_dirty - page.find("span.cart-span")[:class].include? 'pure-dirty' - end - def wait_for_ajax counter = 0 while page.execute_script("return $.active").to_i > 0 diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb index 732e306a29..25ae07bbc1 100644 --- a/spec/support/request/web_helper.rb +++ b/spec/support/request/web_helper.rb @@ -95,10 +95,6 @@ module WebHelper end end - def wait_until_enabled(selector) - wait_until(10) { first("#{selector}:not([disabled='disabled'])") } - end - def select2_select(value, options) id = options[:from] options[:from] = "#s2id_#{id}" From d7c9bb2e5afb7f39274343e69ad9cc504c9fa296 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Thu, 25 Jun 2020 16:36:39 +1000 Subject: [PATCH 059/261] Navigate more efficiently in spec The spec is not supposed to test the navigation to the shop. Going directly to the shop reduces the test execution time by 7%. --- spec/features/consumer/shopping/variant_overrides_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/features/consumer/shopping/variant_overrides_spec.rb b/spec/features/consumer/shopping/variant_overrides_spec.rb index eec53d5871..9c7ca0a5d1 100644 --- a/spec/features/consumer/shopping/variant_overrides_spec.rb +++ b/spec/features/consumer/shopping/variant_overrides_spec.rb @@ -37,8 +37,7 @@ feature "shopping with variant overrides defined", js: true do outgoing_exchange.variants = [product1_variant1, product1_variant2, product2_variant1, product1_variant3, product3_variant1, product3_variant2, product4_variant1] outgoing_exchange.enterprise_fees << enterprise_fee sm.calculator.preferred_amount = 0 - visit shops_path - click_link hub.name + visit enterprise_shop_path(hub) end describe "viewing products" do From 4b25c2d49a8c6fc8fa1bfafc94fd251da1e0a9c1 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 26 Jun 2020 09:56:49 +1000 Subject: [PATCH 060/261] Correct typo in file naming --- .../{darkwarm_caching_spec.rb => darkswarm_caching_spec.rb} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/features/consumer/caching/{darkwarm_caching_spec.rb => darkswarm_caching_spec.rb} (100%) diff --git a/spec/features/consumer/caching/darkwarm_caching_spec.rb b/spec/features/consumer/caching/darkswarm_caching_spec.rb similarity index 100% rename from spec/features/consumer/caching/darkwarm_caching_spec.rb rename to spec/features/consumer/caching/darkswarm_caching_spec.rb From e567348a69a0a02f474ed56ea809eff36ab3ee0f Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 26 Jun 2020 14:24:01 +1000 Subject: [PATCH 061/261] Ensure that enough time passes for caching spec --- spec/features/consumer/caching/darkswarm_caching_spec.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/features/consumer/caching/darkswarm_caching_spec.rb b/spec/features/consumer/caching/darkswarm_caching_spec.rb index 55f41aeee1..14ccbd2ab9 100644 --- a/spec/features/consumer/caching/darkswarm_caching_spec.rb +++ b/spec/features/consumer/caching/darkswarm_caching_spec.rb @@ -45,6 +45,9 @@ feature "Darkswarm data caching", js: true, caching: true do expect(page).to have_content property.presentation end + # Update rows which should also update the timestamp. + # The timestamp represents seconds, so waiting one second is enough. + sleep 1 taxon.update!(name: "Changed Taxon") property.update!(presentation: "Changed Property") From 1266bcde1b783a8f8cfff0baa04c50d90fcd5b11 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 26 Jun 2020 16:56:19 +1000 Subject: [PATCH 062/261] Updating translations for config/locales/en_FR.yml --- config/locales/en_FR.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/en_FR.yml b/config/locales/en_FR.yml index 7e58bae598..39c246d2d9 100644 --- a/config/locales/en_FR.yml +++ b/config/locales/en_FR.yml @@ -270,6 +270,7 @@ en_FR: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -2071,6 +2072,7 @@ en_FR: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2307,6 +2309,7 @@ en_FR: 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" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2772,6 +2775,7 @@ en_FR: previous: "Previous" last: "Last" spree: + more: "More" 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)" From f47271ba98ad1eb97c6193ae99f5eb8286c2df6f Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 26 Jun 2020 16:59:37 +1000 Subject: [PATCH 063/261] Updating translations for config/locales/fr.yml --- config/locales/fr.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 8935f5a339..435b24fbf6 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -270,6 +270,7 @@ fr: backordered: "(à volonté)" on hand: "En stock" ship: "Expédier" + shipping_category: "Condition de transport" actions: create_and_add_another: "Créer et ajouter nouveau" create: "Créer" @@ -1188,8 +1189,8 @@ fr: signup: "inscrivez-vous" contact: "contacter" require_customer_login: "Seul les acheteurs autorisés peuvent accéder à cette boutique." - require_login_html: "Si vous êtes déjà autorisé à accéder à la boutique, %{login}ou %{signup}pour continuer." - require_login_2_html: "Vous souhaitez réaliser vos courses ici? Merci de %{contact}%{enterprise} afin d'avoir l'autorisation d'accès à la boutique." + require_login_html: "Si vous êtes déjà autorisé à accéder à la boutique, %{login} ou %{signup} pour continuer." + require_login_2_html: "Vous souhaitez réaliser vos courses ici ? Merci de %{contact} %{enterprise} afin d'avoir l'autorisation d'accès à la boutique." require_customer_html: "Si vous voulez demander à y accéder, veuillez %{contact} %{enterprise}." select_oc: select_oc_html: "Merci de sélectionner une option dans la liste déroulante, afin de voir quel produits sont disponibles." @@ -2073,6 +2074,7 @@ fr: hub_sidebar_at_least: "Sélectionnez un/des hubs" hub_sidebar_blue: "bleu" hub_sidebar_red: "rouge" + order_cycles_closed_for_hub: "La boutique sélectionnée a fermé temporairement ses commandes. Veuillez essayez à nouveau ultérieurement." report_customers_distributor: "Distributeur" report_customers_supplier: "Fournisseur" report_customers_cycle: "Cycle de vente" @@ -2311,6 +2313,7 @@ fr: order_cycles_email_to_producers_notice: 'Les emails à destination des producteurs ont été mis en file d''attente.' order_cycles_no_permission_to_coordinate_error: "Aucune de vos entreprises n'a les droits requis pour coordonner un cycle de vente" order_cycles_no_permission_to_create_error: "Vous n'avez pas les droits requis pour créer un cycle de vente coordonné par cette entreprise" + order_cycle_closed: "Le cycle de vente que vous avez sélectionné a fermé. " back_to_orders_list: "Retour à la liste des commandes" no_orders_found: "Aucune commande trouvée pour ces critères" order_information: "Info commande" @@ -2802,6 +2805,7 @@ fr: previous: "Précédent" last: "Fin" spree: + more: "Plus" your_order_is_empty_add_product: "Votre commande est vide, veuillez ajouter des produits" add_product: "Ajouter un produit" name_or_sku: "Nom ou Ref Produit (entrer au moins les 4 premiers caractères du nom du produit)" From a1227d93aed9308bf1b72d9545861626e874ab0f Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 26 Jun 2020 20:27:34 +1000 Subject: [PATCH 064/261] Updating translations for config/locales/en_GB.yml --- config/locales/en_GB.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 9fe8406cd5..794411e0d1 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -270,6 +270,7 @@ en_GB: backordered: "Backordered" on hand: "In Stock" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -2071,6 +2072,7 @@ en_GB: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2307,6 +2309,7 @@ en_GB: 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" + order_cycle_closed: "The order cycle you've selected has just closed." back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2778,6 +2781,7 @@ en_GB: previous: "Previous" last: "Last" spree: + more: "More" 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)" From 0d5ad6fac30acbd6e65ac5572b0c04d27edb5f79 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 26 Jun 2020 21:04:54 +1000 Subject: [PATCH 065/261] Updating translations for config/locales/en_IE.yml --- config/locales/en_IE.yml | 67 ++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 10 deletions(-) diff --git a/config/locales/en_IE.yml b/config/locales/en_IE.yml index e9b243f1e0..2693a59bb6 100644 --- a/config/locales/en_IE.yml +++ b/config/locales/en_IE.yml @@ -270,6 +270,7 @@ en_IE: backordered: "Backordered" on hand: "In Stock" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -370,7 +371,10 @@ en_IE: title: "Matomo Settings" matomo_url: "Matomo URL" matomo_site_id: "Matomo Site ID" + matomo_tag_manager_url: "Matomo Tag Manager URL" + info_html: "Matomo is a Web and Mobile Analytics application. 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." + config_instructions_tag_manager_html: "Setting the Matomo Tag Manager URL enables Matomo Tag Manager. This tool allows you to set up analytics events. The Matomo Tag Manager URL is copied from the Install Code section of Matomo Tag Manager. Ensure you select the right container and environment as these options change the URL." customers: index: new_customer: "New Customer" @@ -476,6 +480,7 @@ en_IE: 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}" + malformed_csv: "Product Import encountered a malformed CSV: %{error_message}" index: notice: "Notice" beta_notice: "This feature is still in beta: you may experience some errors while using it. Please don't hesitate to contact support." @@ -688,6 +693,7 @@ en_IE: ofn_uid_tip: The unique id used to identify the enterprise on Open Food Network. shipping_methods: name: "Name" + applies: "Active?" manage: "Manage Shipping Methods" create_button: "Create New Shipping Method" create_one_button: "Create One Now" @@ -1142,13 +1148,18 @@ en_IE: menu: cart: cart: "Basket" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit cart" + items_in_cart_singular: "%{num} item in your cart" + items_in_cart_plural: "%{num} items in your cart" + close: "Close" + cart_empty: "Your cart is empty" + take_me_shopping: "Take me shopping!" signed_in: profile: "Profile" mobile_menu: cart: "Basket" - joyride: - checkout: "Checkout now" - already_ordered_products: "Already ordered in this order cycle" register_call: selling_on_ofn: "Interested in selling through the Open Food Network?" register: "Register here" @@ -1250,7 +1261,7 @@ en_IE: city: City city_placeholder: eg. Dublin postcode: Eircode - postcode_placeholder: eg. D01 F5P2 + postcode_placeholder: eg. D01 XXXX suburb: Town state: County country: Country @@ -1775,17 +1786,17 @@ en_IE: producer: "Great! 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 Chilli Farm" + producer_name_field_placeholder: "e.g. Charlie's Farm" producer_name_field_error: "Sorry, this name has already been taken. Please try another." address1_field: "Address line 1:" - address1_field_placeholder: "e.g. 123 Apple Drive" + address1_field_placeholder: "e.g. 123 Apple Road" address1_field_error: "Please enter an address" address2_field: "Address line 2:" suburb_field: "Town:" - suburb_field_placeholder: "eg. Taunton" + suburb_field_placeholder: "eg. Kilbride" suburb_field_error: "Please enter a postal town" postcode_field: "Eircode:" - postcode_field_placeholder: "eg. D01 F5P2" + postcode_field_placeholder: "eg. D01 XXXX" postcode_field_error: "Eircode required" state_field: "County:" state_field_error: "County Required" @@ -1933,7 +1944,7 @@ en_IE: admin_enterprise_groups_contact_city: "Suburb" admin_enterprise_groups_contact_city_placeholder: "eg. Dublin" admin_enterprise_groups_contact_zipcode: "Postcode" - admin_enterprise_groups_contact_zipcode_placeholder: "eg. 3070" + admin_enterprise_groups_contact_zipcode_placeholder: "eg. D01 XXXX" admin_enterprise_groups_contact_state_id: "County" admin_enterprise_groups_contact_country_id: "Country" admin_enterprise_groups_web: "Web Resources" @@ -2017,7 +2028,7 @@ en_IE: 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, Dublin, D01 F5P2'" + spree_admin_eg_collect_your_order: "eg. 'Please collect your order from 123 Imaginary St, Dublin, D01 XXXX'" 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." @@ -2061,6 +2072,7 @@ en_IE: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2297,6 +2309,7 @@ en_IE: 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" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2768,6 +2781,7 @@ en_IE: previous: "Previous" last: "Last" spree: + more: "More" 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)" @@ -2816,6 +2830,12 @@ en_IE: void: "Void" login: "Login" password: "Password" + signature: "Signature" + solution: "Solution" + landing_page: "Landing Page" + server: "Server" + test_mode: "Test Mode" + logourl: "Logourl" configurations: "Configurations" general_settings: "General Settings" site_name: "Site Name" @@ -2932,6 +2952,12 @@ en_IE: options: "Options" actions: update: "Update" + shared: + error_messages: + errors_prohibited_this_record_from_being_saved: + one: "1 error prohibited this record from being saved:" + other: "%{count} errors prohibited this record from being saved:" + there_were_problems_with_the_following_fields: "There were problems with the following fields" errors: messages: blank: "can't be blank" @@ -3074,6 +3100,8 @@ en_IE: zone: "Zone" calculator: "Calculator" display: "Display" + both: "Both Checkout and Back office" + back_end: "Back office only" no_shipping_methods_found: "No shipping methods found" new: new_shipping_method: "New Shipping Method" @@ -3085,6 +3113,9 @@ en_IE: form: categories: "Categories" zones: "Zones" + both: "Both Checkout and Back office" + back_end: "Back office only" + deactivation_warning: "De-activating a shipping method can make the shipping method disappear from your list. Alternatively, you can hide a shipping method from the checkout page by setting the option 'Display' to 'back office only'." payment_methods: index: payment_methods: "Payment Methods" @@ -3096,8 +3127,11 @@ en_IE: display: "Display" active: "Active" both: "Both" + front_end: "Checkout only" + back_end: "Back office only" active_yes: "Yes" active_no: "No" + no_payment_methods_found: "No payment methods found" new: new_payment_method: "New Payment Method" back_to_payment_methods_list: "Back To Payment Methods List" @@ -3126,7 +3160,11 @@ en_IE: active: "Active" active_yes: "Yes" active_no: "No" + both: "Both Checkout and Back office" + front_end: "Checkout only" + back_end: "Back office only" tags: "Tags" + deactivation_warning: "De-activating a payment method can make the payment method disappear from your list. Alternatively, you can hide a payment method from the checkout page by setting the option 'Display' to 'back office only'." providers: provider: "Provider" payments: @@ -3269,6 +3307,7 @@ en_IE: format: '%Y-%m-%d' js_format: 'yy-mm-dd' orders: + error_flash_for_unavailable_items: "An item in your cart has become unavailable. Please update the selected quantities." edit: login_to_view_order: "Please log in to view your order." bought: @@ -3296,6 +3335,14 @@ en_IE: invalid: invalid order_mailer: cancel_email: + customer_greeting: "Dear %{name}," + instructions_html: "Your order with %{distributor} has been CANCELED. Please retain this cancellation information for your records." + dont_cancel: "If you have changed your mind or don't wish to cancel this order please contact %{email}" + order_summary_canceled_html: "Order Summary #%{number} [CANCELED]" + details: "Here are the details of what you ordered:" + unpaid_order: "Your order was unpaid so no refund has been made" + paid_order: "Your order was paid so %{distributor} has refunded the full amount" + credit_order: "Your order was paid so your account has been credited" subject: "Cancellation of Order" confirm_email: subject: "Order Confirmation" From 4f2d32b2625f817b9fac1d5cc591634776468669 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sat, 27 Jun 2020 04:22:14 +1000 Subject: [PATCH 066/261] Updating translations for config/locales/tr.yml --- config/locales/tr.yml | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/config/locales/tr.yml b/config/locales/tr.yml index d94a87fd02..653ec29c07 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -6,7 +6,7 @@ tr: fee_type: Ücret TÜRÜ spree/order: payment_state: Ödeme Durumu - shipment_state: ' Teslimat Durumu' + shipment_state: ' TESLİMAT Durumu' completed_at: Oluşturulma TARİHİ number: Numara state: Durum @@ -16,11 +16,11 @@ tr: spree/product: primary_taxon: "ÜRÜN KATEGORİSİ" supplier: "TEDARİKÇİ" - shipping_category_id: "Teslimat KategOrİSİ" + shipping_category_id: "TESLİMAT KATEGORİSİ" variant_unit: "Varyant BİRİMİ" - variant_unit_name: "Varyant Birim Adı" + variant_unit_name: "Varyant Birim ADI" spree/credit_card: - base: "Kredi kartı" + base: "Kredİ kartI" order_cycle: orders_close_at: BİTİŞ TARİHİ variant_override: @@ -128,7 +128,7 @@ tr: email_userguide_html: "Tezgah veya Pazar hesapları ayarları ile ilgili ayrıntılı desteğe sahip Kullanıcı Kılavuzu burada: %{link}" userguide: "Açık Gıda Ağı Kullanıcı Kılavuzu" email_admin_html: "%{link}'dan oturum açarak veya ana sayfanın sağ üst kısmındaki ayarlar simgesini tıkladıktan sonra Yönetim' butonu üzerinden hesabınızı yönetebilirsiniz." - admin_panel: "Yönetici Paneli" + admin_panel: "YönetiİCİ Panelİ" email_community_html: "Ayrıca, AGA yazılımı ve bir işletmeyi yönetmek ile ilgili fikir alışverişlerinde bulunduğumuz bir forumumuz var. Sizleri de paylaşmaya bekliyoruz. Sürekli olarak kendimizi yenillemeye çalışıyoruz ve düşünceleriniz bundan sonra olacakları şekillendirecek. %{link}" join_community: "Topluluğa katılın !" invite_manager: @@ -139,7 +139,7 @@ tr: shipment_mailer: shipped_email: dear_customer: "Değerli müşterimiz," - instructions: "Siparişiniz kargoya teslim edildi" + instructions: "Siparişiniz gönderildi" shipment_summary: "Teslimat Özeti" subject: "TESLİMAT BİLDİRİMİ" thanks: "İş birliğiniz için teşekkür ederim." @@ -270,6 +270,7 @@ tr: backordered: "Bakiye Sipariş" on hand: "Mevcut" ship: "Teslimat" + shipping_category: "Teslimat KategOrİSİ" actions: create_and_add_another: "Oluştur ve Yeni Ekle" create: "Oluştur" @@ -2071,6 +2072,7 @@ tr: hub_sidebar_at_least: "En az bir pazar seçilmelidir" hub_sidebar_blue: "mavi" hub_sidebar_red: "kırmızı" + order_cycles_closed_for_hub: "Seçtiğiniz pazar geçici olarak siparişlere kapalı durumdadır. Lütfen daha sonra tekrar deneyiniz." report_customers_distributor: "Dağıtımcı" report_customers_supplier: "Tedarikçi" report_customers_cycle: "Sipariş Dönemi" @@ -2151,7 +2153,7 @@ tr: report_header_total_available: Toplam mevcut report_header_unallocated: Paylaştırılmamış report_header_max_quantity_excess: Maksimum Miktar Fazlası - report_header_taxons: sınıflar + report_header_taxons: KATEGORİ report_header_supplier: Tedarikçi report_header_producer: Üretici report_header_producer_suburb: Yapımcı İlçesi @@ -2307,6 +2309,7 @@ tr: order_cycles_email_to_producers_notice: 'Üreticilere gönderilecek e-postalar gönderilmek üzere sıraya alınmıştır.' order_cycles_no_permission_to_coordinate_error: "Hiçbir işletmenizin sipariş dönemini koordine etme izni yok" order_cycles_no_permission_to_create_error: "Bu işletme tarafından koordine edilen bir sipariş dönemi oluşturma izniniz yok" + order_cycle_closed: "Seçmiş olduğunuz sipariş dönemi az önce kapandı. Lütfen daha sonra tekrar deneyin :(" back_to_orders_list: "Sipariş listesine geri dön" no_orders_found: "SİPARİŞ BULUNAMADI" order_information: "Sipariş Bilgisi" @@ -2774,6 +2777,7 @@ tr: previous: "Önceki" last: "Son" spree: + more: "Daha Fazla" your_order_is_empty_add_product: "Sepetiniz boş, lütfen bir ürün arayın ve ekleyin" add_product: "ürün ekle" name_or_sku: "Ad veya STOK KODU (ürün adının en az ilk 4 karakterini girin)" @@ -2892,9 +2896,9 @@ tr: abbreviation: "Kısaltma" new_state: "Yeni Şehir" payment_methods: "Ödeme yöntemleri" - taxonomies: "cinsler" - new_taxonomy: "Yeni Cins" - back_to_taxonomies_list: "Cinsler Listesine Geri Dön" + taxonomies: "KATEGORİ" + new_taxonomy: "YENİ KATEGORİ" + back_to_taxonomies_list: "Kategori Listesine Geri Dön" shipping_methods: "Teslimat Yöntemleri" shipping_categories: "Nakliye Kategorileri" new_shipping_category: "Yeni Nakliye Kategorisi" @@ -3434,4 +3438,4 @@ tr: key_cleared: "Anahtar temizlendi" shipment: cannot_ready: "Gönderim hazırlanamıyor." - invalid_taxonomy_id: "Geçersiz sınıflandırma kimliği." + invalid_taxonomy_id: "Geçersiz kategori kimliği." From 032a70fa7e1085aa03ed3d1b272284ae13f3b0dd Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Fri, 26 Jun 2020 19:16:32 +0000 Subject: [PATCH 067/261] Bump ddtrace from 0.36.0 to 0.37.0 Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.36.0 to 0.37.0. - [Release notes](https://github.com/DataDog/dd-trace-rb/releases) - [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md) - [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.36.0...v0.37.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 4524b2f6e3..9b88388c41 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -207,7 +207,7 @@ GEM activerecord (>= 3.2.0, < 5.0) fog (~> 1.0) rails (>= 3.2.0, < 5.0) - ddtrace (0.36.0) + ddtrace (0.37.0) msgpack debugger-linecache (1.2.0) delayed_job (4.1.8) From ff8cb43717aed42a9aa01d430a02bc86bc4fd457 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 26 Jun 2020 20:01:55 +0200 Subject: [PATCH 068/261] Move default versions of Paperclip-managed images to /public Image paths for these files are handled by Paperclip, which (with our current version) does not handle fingerprints on assets. Therefore we need to make these images available under /public --- app/models/content_configuration.rb | 8 ++++---- .../images/home => public/default_images}/home.jpg | Bin .../default_images}/ofn-logo-footer.png | Bin .../default_images}/ofn-logo-mobile.svg | 0 .../images => public/default_images}/ofn-logo.png | Bin 5 files changed, 4 insertions(+), 4 deletions(-) rename {app/assets/images/home => public/default_images}/home.jpg (100%) rename {app/assets/images => public/default_images}/ofn-logo-footer.png (100%) rename {app/assets/images => public/default_images}/ofn-logo-mobile.svg (100%) rename {app/assets/images => public/default_images}/ofn-logo.png (100%) diff --git a/app/models/content_configuration.rb b/app/models/content_configuration.rb index 29ab8f3308..39d4fd9a5c 100644 --- a/app/models/content_configuration.rb +++ b/app/models/content_configuration.rb @@ -7,15 +7,15 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration preference :logo, :file preference :logo_mobile, :file preference :logo_mobile_svg, :file - has_attached_file :logo, default_url: "/assets/ofn-logo.png" + has_attached_file :logo, default_url: "/default_images/ofn-logo.png" has_attached_file :logo_mobile - has_attached_file :logo_mobile_svg, default_url: "/assets/ofn-logo-mobile.svg" + has_attached_file :logo_mobile_svg, default_url: "/default_images/ofn-logo-mobile.svg" # Home page preference :home_page_alert_html, :text preference :home_hero, :file preference :home_show_stats, :boolean, default: true - has_attached_file :home_hero, default_url: "/assets/home/home.jpg" + has_attached_file :home_hero, default_url: "/default_images/home.jpg" # Map preference :open_street_map_enabled, :boolean, default: false @@ -57,7 +57,7 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration # Footer preference :footer_logo, :file - has_attached_file :footer_logo, default_url: "/assets/ofn-logo-footer.png" + has_attached_file :footer_logo, default_url: "/default_images/ofn-logo-footer.png" # Other preference :footer_facebook_url, :string, default: "https://www.facebook.com/OpenFoodNet" diff --git a/app/assets/images/home/home.jpg b/public/default_images/home.jpg similarity index 100% rename from app/assets/images/home/home.jpg rename to public/default_images/home.jpg diff --git a/app/assets/images/ofn-logo-footer.png b/public/default_images/ofn-logo-footer.png similarity index 100% rename from app/assets/images/ofn-logo-footer.png rename to public/default_images/ofn-logo-footer.png diff --git a/app/assets/images/ofn-logo-mobile.svg b/public/default_images/ofn-logo-mobile.svg similarity index 100% rename from app/assets/images/ofn-logo-mobile.svg rename to public/default_images/ofn-logo-mobile.svg diff --git a/app/assets/images/ofn-logo.png b/public/default_images/ofn-logo.png similarity index 100% rename from app/assets/images/ofn-logo.png rename to public/default_images/ofn-logo.png From a5f541b59df7565dd90e5a0cf1f5a7c0967aa989 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 27 Jun 2020 08:53:05 +0200 Subject: [PATCH 069/261] Update admin logo path --- config/initializers/spree.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index cc2ff359ba..5aca0161f8 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -23,7 +23,7 @@ require "#{Rails.root}/app/models/spree/gateway_decorator" Spree.config do |config| config.shipping_instructions = true config.address_requires_state = true - config.admin_interface_logo = 'ofn-logo.png' + config.admin_interface_logo = '/default_images/ofn-logo.png' # -- spree_paypal_express # Auto-capture payments. Without this option, payments must be manually captured in the paypal interface. From b325e489571c88873dc9b30571d31627275cadce Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 27 Jun 2020 10:32:38 +0200 Subject: [PATCH 070/261] Update content config spec to use new default image paths --- spec/models/content_configuration_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/models/content_configuration_spec.rb b/spec/models/content_configuration_spec.rb index 7ac8877b83..d9eaf960d4 100644 --- a/spec/models/content_configuration_spec.rb +++ b/spec/models/content_configuration_spec.rb @@ -10,8 +10,7 @@ describe ContentConfiguration do end def image_exist?(default_url) - image_path = default_url.gsub(%r{/assets/}, '/assets/images/') - File.exist?(File.join(Rails.root, 'app', image_path)) + File.exist?(File.join(Rails.root, 'public', default_url)) end end end From 10b8c2b7899e71a0ddda78b706e7e368bf889b7f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 15:54:58 +0100 Subject: [PATCH 071/261] Relax the assertion and dont check row number so that it passes even if order of elements is not the same --- spec/features/admin/configuration/taxonomies_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/configuration/taxonomies_spec.rb b/spec/features/admin/configuration/taxonomies_spec.rb index 6947a9a0b3..6e871e3529 100644 --- a/spec/features/admin/configuration/taxonomies_spec.rb +++ b/spec/features/admin/configuration/taxonomies_spec.rb @@ -14,8 +14,10 @@ describe "Taxonomies" do create(:taxonomy, name: 'Brand') create(:taxonomy, name: 'Categories') click_link "Taxonomies" - within_row(1) { expect(page).to have_content("Brand") } - within_row(2) { expect(page).to have_content("Categories") } + within("table.index tbody") do + expect(page).to have_content("Brand") + expect(page).to have_content("Categories") + end end end From 651603742088774b8b865693e9fd1f7dfe93ace4 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 20:36:33 +0100 Subject: [PATCH 072/261] Reload knapsack report --- knapsack_rspec_report.json | 729 ++++++++++++++++++++----------------- 1 file changed, 392 insertions(+), 337 deletions(-) diff --git a/knapsack_rspec_report.json b/knapsack_rspec_report.json index 3d054ce4d9..91499ba40e 100644 --- a/knapsack_rspec_report.json +++ b/knapsack_rspec_report.json @@ -1,339 +1,394 @@ { - "spec/features/admin/orders_spec.rb": 209.85864853858948, - "spec/features/admin/variant_overrides_spec.rb": 103.19363331794739, - "spec/features/admin/bulk_order_management_spec.rb": 128.97811818122864, - "spec/features/consumer/shopping/checkout_spec.rb": 89.76498866081238, - "spec/features/admin/product_import_spec.rb": 84.0241048336029, - "spec/features/admin/order_cycles_spec.rb": 148.29575443267822, - "spec/features/consumer/shopping/variant_overrides_spec.rb": 92.9798493385315, - "spec/features/consumer/authentication_spec.rb": 56.12566685676575, - "spec/features/admin/subscriptions_spec.rb": 90.58396697044373, - "spec/features/admin/bulk_product_update_spec.rb": 143.26294326782227, - "spec/features/consumer/shopping/shopping_spec.rb": 67.1083915233612, - "spec/features/admin/enterprises_spec.rb": 39.2133104801178, - "spec/features/admin/payment_method_spec.rb": 50.03155517578125, - "spec/features/admin/tag_rules_spec.rb": 30.245259761810303, - "spec/models/order_cycle_spec.rb": 41.354451417922974, - "spec/features/consumer/shopping/orders_spec.rb": 25.612257957458496, - "spec/features/admin/enterprise_relationships_spec.rb": 44.3502836227417, - "spec/models/product_importer_spec.rb": 39.65096569061279, - "spec/features/admin/shipping_methods_spec.rb": 38.50179934501648, - "spec/models/spree/order_spec.rb": 30.600374937057495, - "spec/features/admin/enterprise_roles_spec.rb": 25.807589530944824, - "spec/features/admin/customers_spec.rb": 31.028107404708862, - "spec/features/consumer/shops_spec.rb": 27.150686264038086, - "spec/controllers/api/orders_controller_spec.rb": 43.287739515304565, - "spec/features/admin/products_spec.rb": 16.402274131774902, - "spec/services/order_syncer_spec.rb": 30.67478346824646, - "spec/helpers/injection_helper_spec.rb": 28.66439199447632, - "spec/features/admin/reports_spec.rb": 21.09156608581543, - "spec/controllers/admin/subscriptions_controller_spec.rb": 28.021868228912354, - "spec/controllers/api/products_controller_spec.rb": 13.549290895462036, - "spec/features/admin/enterprise_fees_spec.rb": 17.234047651290894, - "spec/features/consumer/registration_spec.rb": 14.555023193359375, - "spec/features/consumer/cookies_spec.rb": 31.677974462509155, - "spec/jobs/subscription_confirm_job_spec.rb": 23.378596305847168, - "spec/features/consumer/shopping/cart_spec.rb": 21.239376544952393, - "spec/features/consumer/groups_spec.rb": 13.469002485275269, - "spec/models/spree/line_item_spec.rb": 29.30591082572937, - "spec/controllers/spree/orders_controller_spec.rb": 18.490586280822754, - "spec/lib/open_food_network/order_cycle_permissions_spec.rb": 18.68953037261963, - "spec/controllers/api/shipments_controller_spec.rb": 16.687517642974854, - "spec/features/admin/adjustments_spec.rb": 17.467090368270874, - "spec/controllers/admin/bulk_line_items_controller_spec.rb": 23.035269260406494, - "spec/features/consumer/shopping/embedded_shopfronts_spec.rb": 19.298624753952026, - "spec/features/admin/enterprises/images_spec.rb": 11.094250679016113, - "spec/controllers/spree/admin/reports_controller_spec.rb": 14.215487003326416, - "spec/features/consumer/account_spec.rb": 12.601296663284302, - "spec/models/spree/product_spec.rb": 13.086605787277222, - "spec/mailers/producer_mailer_spec.rb": 15.4656503200531, - "spec/mailers/subscription_mailer_spec.rb": 14.124800682067871, - "spec/features/consumer/shopping/embedded_groups_spec.rb": 12.80406141281128, - "spec/features/consumer/producers_spec.rb": 13.81577444076538, - "spec/models/exchange_spec.rb": 4.696550130844116, - "spec/jobs/subscription_placement_job_spec.rb": 12.984622478485107, - "spec/features/admin/schedules_spec.rb": 10.006147146224976, - "spec/features/consumer/multilingual_spec.rb": 10.963010787963867, - "spec/features/admin/variants_spec.rb": 15.094644784927368, - "spec/controllers/api/variants_controller_spec.rb": 10.557931661605835, - "spec/models/spree/variant_spec.rb": 13.415100574493408, - "spec/features/consumer/shopping/checkout_auth_spec.rb": 12.420539855957031, - "spec/features/admin/reports/enterprise_fee_summaries_spec.rb": 14.304540395736694, - "spec/features/admin/enterprises/index_spec.rb": 8.40625262260437, - "spec/lib/open_food_network/permissions_spec.rb": 6.9782798290252686, - "spec/models/proxy_order_spec.rb": 8.073801279067993, - "spec/lib/open_food_network/enterprise_fee_calculator_spec.rb": 5.851940155029297, - "spec/features/admin/enterprise_groups_spec.rb": 13.105037212371826, - "spec/services/order_factory_spec.rb": 8.655417680740356, - "spec/models/spree/ability_spec.rb": 10.093905210494995, - "spec/controllers/line_items_controller_spec.rb": 9.24480938911438, - "spec/lib/open_food_network/proxy_order_syncer_spec.rb": 6.615863084793091, - "spec/features/admin/authentication_spec.rb": 2.6402037143707275, - "spec/lib/open_food_network/scope_variant_to_hub_spec.rb": 5.528027057647705, - "spec/models/enterprise_spec.rb": 7.465655565261841, - "spec/controllers/admin/proxy_orders_controller_spec.rb": 10.103626012802124, - "spec/features/consumer/shopping/checkout_paypal_spec.rb": 5.646831035614014, - "spec/models/enterprise_relationship_spec.rb": 5.4444804191589355, - "spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb": 8.639384031295776, - "spec/lib/open_food_network/user_balance_calculator_spec.rb": 6.210071563720703, - "spec/lib/open_food_network/order_cycle_form_applicator_spec.rb": 6.225666046142578, - "spec/lib/open_food_network/address_finder_spec.rb": 8.498907804489136, - "spec/requests/checkout/stripe_connect_spec.rb": 7.812800645828247, - "spec/models/spree/adjustment_spec.rb": 7.6640002727508545, - "spec/features/consumer/footer_links_spec.rb": 5.052169561386108, - "spec/models/variant_override_spec.rb": 5.968475580215454, - "spec/controllers/api/logos_controller_spec.rb": 1.4243378639221191, - "spec/controllers/spree/admin/orders_controller_spec.rb": 5.91344141960144, - "spec/mailers/order_mailer_spec.rb": 5.1312196254730225, - "spec/lib/open_food_network/packing_report_spec.rb": 5.236347436904907, - "spec/services/advance_order_service_spec.rb": 4.330220460891724, - "spec/features/consumer/shopping/products_spec.rb": 4.986042261123657, - "spec/models/spree/property_spec.rb": 4.247157335281372, - "spec/controllers/api/product_images_controller_spec.rb": 1.5374972820281982, - "spec/models/spree/stock/availability_validator_spec.rb": 4.662952899932861, - "spec/lib/open_food_network/bulk_coop_report_spec.rb": 6.051215648651123, - "spec/services/subscription_estimator_spec.rb": 4.492072582244873, - "spec/models/enterprise_fee_spec.rb": 1.6908893585205078, - "spec/features/consumer/account/settings_spec.rb": 3.6030097007751465, - "spec/controllers/spree/admin/orders/customer_details_controller_spec.rb": 4.426133871078491, - "spec/controllers/spree/users_controller_spec.rb": 3.8197484016418457, - "spec/features/admin/overview_spec.rb": 4.293005704879761, - "spec/controllers/spree/admin/variants_controller_spec.rb": 3.284226894378662, - "spec/features/admin/users_spec.rb": 7.302890300750732, - "spec/controllers/admin/variant_overrides_controller_spec.rb": 3.715315341949463, - "spec/lib/open_food_network/products_and_inventory_report_spec.rb": 3.820003032684326, - "spec/controllers/admin/enterprises_controller_spec.rb": 3.8785862922668457, - "spec/models/spree/payment_spec.rb": 3.9647903442382812, - "spec/features/admin/reports/packing_report_spec.rb": 2.331310272216797, - "spec/models/concerns/variant_stock_spec.rb": 3.1730740070343018, - "spec/serializers/api/order_serializer_spec.rb": 3.8849294185638428, - "spec/models/spree/image_spec.rb": 0.010381937026977539, - "spec/features/admin/multilingual_spec.rb": 3.5513908863067627, - "spec/jobs/order_cycle_notification_job_spec.rb": 1.3160836696624756, - "spec/controllers/spree/admin/products_controller_spec.rb": 2.776277542114258, - "spec/lib/open_food_network/group_buy_report_spec.rb": 2.9200246334075928, - "spec/controllers/shop_controller_spec.rb": 1.094660997390747, - "spec/features/admin/payments_spec.rb": 2.9398913383483887, - "spec/lib/open_food_network/order_cycle_management_report_spec.rb": 3.1769142150878906, - "spec/models/calculator/weight_spec.rb": 2.7677314281463623, - "spec/services/invoice_renderer_spec.rb": 2.9274940490722656, - "spec/controllers/api/promo_images_controller_spec.rb": 1.8630146980285645, - "spec/features/consumer/account/cards_spec.rb": 3.3731846809387207, - "spec/services/subscription_variants_service_spec.rb": 2.44708251953125, - "spec/controllers/spree/admin/payments_controller_spec.rb": 2.7492406368255615, - "spec/lib/open_food_network/customers_report_spec.rb": 2.010512351989746, - "spec/helpers/enterprises_helper_spec.rb": 2.575876474380493, - "spec/models/spree/calculator_spec.rb": 2.28029465675354, - "spec/controllers/admin/order_cycles_controller_spec.rb": 2.5031261444091797, - "spec/serializers/api/admin/exchange_serializer_spec.rb": 2.1571648120880127, - "spec/models/enterprise_caching_spec.rb": 2.0464723110198975, - "spec/lib/open_food_network/lettuce_share_report_spec.rb": 2.6065244674682617, - "spec/lib/open_food_network/scope_variants_to_search_spec.rb": 2.0106847286224365, - "spec/controllers/admin/schedules_controller_spec.rb": 2.1028177738189697, - "spec/services/bulk_invoice_service_spec.rb": 2.135669708251953, - "spec/lib/open_food_network/subscription_payment_updater_spec.rb": 2.519094228744507, - "spec/controllers/admin/subscription_line_items_controller_spec.rb": 1.8447153568267822, - "spec/requests/checkout/failed_checkout_spec.rb": 1.9410381317138672, - "spec/controllers/admin/inventory_items_controller_spec.rb": 2.0562922954559326, - "spec/serializers/api/admin/enterprise_serializer_spec.rb": 0.5516650676727295, - "spec/models/product_import/inventory_reset_strategy_spec.rb": 1.9712626934051514, - "spec/controllers/enterprises_controller_spec.rb": 2.159472703933716, - "spec/models/product_import/products_reset_strategy_spec.rb": 1.8046910762786865, - "spec/serializers/api/current_order_serializer_spec.rb": 1.6418733596801758, - "spec/models/spree/shipping_method_spec.rb": 1.5293469429016113, - "spec/views/spree/admin/orders/edit.html.haml_spec.rb": 1.4302563667297363, - "spec/services/tax_rate_finder_spec.rb": 1.765697717666626, - "spec/models/producer_property_spec.rb": 1.8772265911102295, - "spec/services/order_cycle_distributed_products_spec.rb": 2.5216150283813477, - "spec/services/variants_stock_levels_spec.rb": 1.4711685180664062, - "spec/serializers/api/enterprise_shopfront_serializer_spec.rb": 1.4934852123260498, - "spec/controllers/cart_controller_spec.rb": 1.4728140830993652, - "spec/models/concerns/order_shipment_spec.rb": 1.9231147766113281, - "spec/services/subscription_form_spec.rb": 1.5087761878967285, - "spec/controllers/checkout_controller_spec.rb": 1.513655424118042, - "spec/requests/checkout/paypal_spec.rb": 1.292949914932251, - "spec/models/spree/product_set_spec.rb": 1.7520904541015625, - "spec/serializers/api/cached_enterprise_serializer_spec.rb": 1.1505959033966064, - "spec/controllers/spree/admin/overview_controller_spec.rb": 0.47139525413513184, - "spec/models/spree/taxon_spec.rb": 0.7411928176879883, - "spec/services/subscription_validator_spec.rb": 1.417020559310913, - "spec/services/cart_service_spec.rb": 0.9984734058380127, - "spec/models/concerns/product_stock_spec.rb": 1.0030314922332764, - "spec/lib/open_food_network/tag_rule_applicator_spec.rb": 1.2484149932861328, - "spec/controllers/spree/admin/shipping_methods_controller_spec.rb": 1.0473082065582275, - "spec/services/exchange_variant_bulk_updater_spec.rb": 1.1361675262451172, - "spec/features/admin/content_spec.rb": 1.1164579391479492, - "spec/models/spree/order/checkout_spec.rb": 0.9971451759338379, - "spec/models/spree/shipment_spec.rb": 0.8724184036254883, - "spec/controllers/admin/customers_controller_spec.rb": 0.8800466060638428, - "spec/controllers/shops_controller_spec.rb": 0.8274595737457275, - "spec/serializers/api/admin/variant_serializer_spec.rb": 0.8609609603881836, - "spec/lib/open_food_network/order_and_distributor_report_spec.rb": 0.6863596439361572, - "spec/serializers/api/admin/for_order_cycle/enterprise_serializer_spec.rb": 0.7560875415802002, - "spec/controllers/api/taxons_controller_spec.rb": 0.5672154426574707, - "spec/controllers/admin/manager_invitations_controller_spec.rb": 0.8336856365203857, - "spec/lib/open_food_network/enterprise_fee_applicator_spec.rb": 0.5529074668884277, - "spec/models/spree/user_spec.rb": 0.8885831832885742, - "spec/models/spree/price_spec.rb": 0.2001354694366455, - "spec/services/restart_checkout_spec.rb": 0.8455610275268555, - "spec/requests/embedded_shopfronts_headers_spec.rb": 0.730147123336792, - "spec/controllers/api/enterprises_controller_spec.rb": 0.7297313213348389, - "spec/services/subscriptions_count_spec.rb": 1.0329487323760986, - "spec/models/subscription_spec.rb": 0.8652608394622803, - "spec/services/order_cycle_form_spec.rb": 0.6517574787139893, - "spec/features/admin/enterprise_user_spec.rb": 0.7582378387451172, - "spec/controllers/spree/admin/search_controller_spec.rb": 0.6782004833221436, - "spec/controllers/spree/admin/payment_methods_controller_spec.rb": 1.032891035079956, - "spec/helpers/admin/subscriptions_helper_spec.rb": 0.6923768520355225, - "spec/models/spree/classification_spec.rb": 0.1685178279876709, - "spec/models/spree/calculator/flat_percent_item_total_spec.rb": 0.4571397304534912, - "spec/models/spree/calculator/price_sack_spec.rb": 0.5336060523986816, - "spec/serializers/api/admin/for_order_cycle/supplied_product_serializer_spec.rb": 0.42862772941589355, - "spec/models/spree/payment_method_spec.rb": 0.4095613956451416, - "spec/models/order_updater_spec.rb": 0.6351447105407715, - "spec/controllers/spree/admin/adjustments_controller_spec.rb": 0.608527421951294, - "spec/models/spree/calculator/flexi_rate_spec.rb": 0.4524409770965576, - "spec/services/search_orders_spec.rb": 0.21066808700561523, - "spec/helpers/admin/orders_helper_spec.rb": 0.452254056930542, - "spec/lib/open_food_network/option_value_namer_spec.rb": 0.09297728538513184, - "spec/controllers/admin/stripe_accounts_controller_spec.rb": 0.48218297958374023, - "spec/features/admin/tax_settings_spec.rb": 0.39211606979370117, - "spec/models/spree/gateway_tagging_spec.rb": 0.4623403549194336, - "spec/serializers/api/admin/product_serializer_spec.rb": 0.16631841659545898, - "spec/controllers/admin/tag_rules_controller_spec.rb": 0.1727132797241211, - "spec/serializers/api/admin/variant_override_serializer_spec.rb": 0.21732354164123535, - "spec/controllers/user_confirmations_controller_spec.rb": 0.3694608211517334, - "spec/helpers/order_cycles_helper_spec.rb": 0.37854909896850586, - "spec/helpers/i18n_helper_spec.rb": 0.3624556064605713, - "spec/models/stripe_account_spec.rb": 0.19968080520629883, - "spec/models/tag_rule/filter_payment_methods_spec.rb": 0.20981264114379883, - "spec/controllers/spree/admin/reports/enterprise_fee_summaries_controller_spec.rb": 0.3504636287689209, - "spec/controllers/api/customers_controller_spec.rb": 0.29506921768188477, - "spec/models/customer_spec.rb": 0.2992515563964844, - "spec/models/enterprise_group_spec.rb": 0.2686808109283447, - "spec/models/adjustment_metadata_spec.rb": 0.15410161018371582, - "spec/mailers/enterprise_mailer_spec.rb": 0.2028944492340088, - "spec/features/consumer/confirm_invitation_spec.rb": 0.1965491771697998, - "spec/models/column_preference_spec.rb": 0.18862366676330566, - "spec/controllers/admin/stripe_connect_settings_controller_spec.rb": 0.21590971946716309, - "spec/controllers/spree/checkout_controller_spec.rb": 0.25676560401916504, - "spec/models/model_set_spec.rb": 0.19089746475219727, - "spec/lib/open_food_network/users_and_enterprises_report_spec.rb": 0.37776756286621094, - "spec/serializers/api/shipping_method_serializer_spec.rb": 0.26949477195739746, - "spec/models/tag_rule/filter_order_cycles_spec.rb": 0.14159250259399414, - "spec/lib/stripe/account_connector_spec.rb": 0.27176880836486816, - "spec/models/spree/calculator/per_item_spec.rb": 0.22195911407470703, - "spec/controllers/admin/column_preferences_controller_spec.rb": 0.14211821556091309, - "spec/controllers/spree/admin/base_controller_spec.rb": 0.25708532333374023, - "spec/controllers/spree/credit_cards_controller_spec.rb": 0.32630300521850586, - "spec/lib/open_food_network/subscription_summary_spec.rb": 0.1385807991027832, - "spec/lib/open_food_network/property_merge_spec.rb": 0.24811196327209473, - "spec/models/spree/tax_rate_spec.rb": 0.25828003883361816, - "spec/mailers/user_mailer_spec.rb": 0.2304532527923584, - "spec/controllers/spree/paypal_controller_spec.rb": 0.24924159049987793, - "spec/serializers/api/variant_serializer_spec.rb": 0.18966460227966309, - "spec/models/tag_rule/filter_shipping_methods_spec.rb": 0.26709508895874023, - "spec/features/admin/image_settings_spec.rb": 0.2686142921447754, - "spec/models/stock/package_spec.rb": 0.2378373146057129, - "spec/features/admin/external_services_spec.rb": 0.25201988220214844, - "spec/models/tag_rule/filter_products_spec.rb": 0.16270112991333008, - "spec/controllers/stripe/callbacks_controller_spec.rb": 0.32970166206359863, - "spec/controllers/spree/admin/users_controller_spec.rb": 0.18564677238464355, - "spec/models/spree/credit_card_spec.rb": 0.1279582977294922, - "spec/serializers/api/admin/index_enterprise_serializer_spec.rb": 0.12614202499389648, - "spec/serializers/api/admin/customer_serializer_spec.rb": 0.13819241523742676, - "spec/models/product_import/settings_spec.rb": 0.0827949047088623, - "spec/controllers/user_passwords_controller_spec.rb": 0.12400317192077637, - "spec/controllers/user_registrations_controller_spec.rb": 0.13727235794067383, - "spec/helpers/checkout_helper_spec.rb": 0.08210468292236328, - "spec/views/spree/admin/orders/index.html.haml_spec.rb": 0.13492274284362793, - "spec/serializers/api/group_list_serializer_spec.rb": 0.14428400993347168, - "spec/serializers/api/enterprise_serializer_spec.rb": 0.12647700309753418, - "spec/controllers/stripe/webhooks_controller_spec.rb": 0.1504201889038086, - "spec/controllers/groups_controller_spec.rb": 0.0957021713256836, - "spec/lib/open_food_network/xero_invoices_report_spec.rb": 0.11310100555419922, - "spec/models/tag_rule/discount_order_spec.rb": 0.10718297958374023, - "spec/helpers/spree/orders_helper_spec.rb": 0.11443710327148438, - "spec/lib/spree/product_filters_spec.rb": 0.09136056900024414, - "spec/models/spree/addresses_spec.rb": 0.08072257041931152, - "spec/controllers/api/enterprise_fees_controller_spec.rb": 0.1456611156463623, - "spec/serializers/api/enterprise_shopfront_list_serializer_spec.rb": 0.13787007331848145, - "spec/features/consumer/sitemap_spec.rb": 0.1070859432220459, - "spec/lib/open_food_network/sales_tax_report_spec.rb": 0.11518430709838867, - "spec/lib/open_food_network/i18n_config_spec.rb": 0.10601115226745605, - "spec/services/default_stock_location_spec.rb": 0.1458897590637207, - "spec/controllers/registration_controller_spec.rb": 0.11335277557373047, - "spec/serializers/api/order_cycle_serializer_spec.rb": 0.09752154350280762, - "spec/helpers/shared_helper_spec.rb": 0.06739163398742676, - "spec/controllers/api/taxonomies_controller_spec.rb": 0.05540919303894043, - "spec/serializers/api/admin/subscription_customer_serializer_spec.rb": 0.049886465072631836, - "spec/helpers/navigation_helper_spec.rb": 0.045441389083862305, - "spec/models/spree/gateway/stripe_connect_spec.rb": 0.049462080001831055, - "spec/helpers/spree/admin/orders_helper_spec.rb": 0.050534963607788086, - "spec/helpers/shop_helper_spec.rb": 0.044415950775146484, - "spec/validators/date_time_string_validator_spec.rb": 0.030704498291015625, - "spec/lib/open_food_network/subscription_summarizer_spec.rb": 0.03782463073730469, - "spec/lib/stripe/webhook_handler_spec.rb": 0.0348663330078125, - "spec/jobs/welcome_enterprise_job_spec.rb": 0.04198408126831055, - "spec/validators/integer_array_validator_spec.rb": 0.033490896224975586, - "spec/models/tag_rule_spec.rb": 0.04035758972167969, - "spec/controllers/spree/user_sessions_controller_spec.rb": 0.056906700134277344, - "spec/helpers/html_helper_spec.rb": 0.04384016990661621, - "spec/lib/spree/localized_number_spec.rb": 0.03789019584655762, - "spec/lib/open_food_network/order_grouper_spec.rb": 0.03744339942932129, - "spec/models/spree/preferences/file_configuration_spec.rb": 0.03453230857849121, - "spec/jobs/confirm_order_job_spec.rb": 0.03809309005737305, - "spec/lib/open_food_network/reports/report_spec.rb": 0.02672100067138672, - "spec/lib/open_food_network/enterprise_issue_validator_spec.rb": 0.03448891639709473, - "spec/services/embedded_page_service_spec.rb": 0.03394007682800293, - "spec/controllers/api/statuses_controller_spec.rb": 0.02658700942993164, - "spec/models/product_import/reset_absent_spec.rb": 0.029580354690551758, - "spec/models/product_import/entry_processor_spec.rb": 0.030652284622192383, - "spec/controllers/spree/store_controller_spec.rb": 0.05485796928405762, - "spec/models/subscription_line_item_spec.rb": 0.029042720794677734, - "spec/controllers/base_controller_spec.rb": 0.03686809539794922, - "spec/services/reset_order_service_spec.rb": 0.021564006805419922, - "spec/services/order_cycle_distributed_variants_spec.rb": 0.0191500186920166, - "spec/models/calculator/flat_percent_per_item_spec.rb": 0.02089238166809082, - "spec/lib/open_food_network/reports/rule_spec.rb": 0.01708674430847168, - "spec/requests/large_request_spec.rb": 0.01527857780456543, - "spec/jobs/confirm_signup_job_spec.rb": 0.01926112174987793, - "spec/lib/open_food_network/referer_parser_spec.rb": 0.019036531448364258, - "spec/lib/open_food_network/feature_toggle_spec.rb": 0.01768207550048828, - "spec/helpers/groups_helper_spec.rb": 0.010357141494750977, - "spec/serializers/api/credit_card_serializer_spec.rb": 0.013578414916992188, - "spec/helpers/products_helper_spec.rb": 0.01333308219909668, - "spec/jobs/heartbeat_job_spec.rb": 0.013099193572998047, - "spec/models/spree/calculator/flat_rate_spec.rb": 0.01121664047241211, - "spec/services/mail_configuration_spec.rb": 0.010842561721801758, - "spec/helpers/serializer_helper_spec.rb": 0.013910770416259766, - "spec/helpers/spree/admin/base_helper_spec.rb": 0.006238222122192383, - "spec/models/content_configuration_spec.rb": 0.005331277847290039, - "spec/services/upload_sanitizer_spec.rb": 0.005086660385131836, - "spec/lib/open_food_network/error_logger_spec.rb": 0.005143880844116211, - "spec/config/application_spec.rb": 0.004831075668334961, - "spec/lib/open_food_network/reports/row_spec.rb": 0.004848003387451172, - "spec/controllers/api/base_controller_spec.rb": 0.2383410930633545, - "spec/controllers/api/order_cycles_controller_spec.rb": 8.10491132736206, - "spec/controllers/spree/admin/image_settings_controller_spec.rb": 0.20762252807617188, - "spec/controllers/spree/admin/mail_methods_controller_spec.rb": 0.2593998908996582, - "spec/features/admin/configuration/general_settings_spec.rb": 0.512702465057373, - "spec/features/admin/configuration/image_settings_spec.rb": 1.0649611949920654, - "spec/features/admin/configuration/mail_methods_spec.rb": 0.5447854995727539, - "spec/features/admin/configuration/states_spec.rb": 8.655013084411621, - "spec/features/admin/configuration/tax_categories_spec.rb": 1.3367998600006104, - "spec/features/admin/configuration/tax_rates_spec.rb": 0.6975750923156738, - "spec/features/admin/configuration/taxonomies_spec.rb": 1.427445650100708, - "spec/features/admin/configuration/zones_spec.rb": 0.8336474895477295, - "spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb": 0.9327311515808105, - "spec/lib/open_food_network/orders_and_fulfillments_report/distributor_totals_by_supplier_report_spec.rb": 0.8202314376831055, - "spec/lib/open_food_network/orders_and_fulfillments_report/supplier_totals_by_distributor_report_spec.rb": 0.8403346538543701, - "spec/lib/open_food_network/orders_and_fulfillments_report/supplier_totals_report_spec.rb": 0.9129531383514404, - "spec/lib/tasks/enterprises_rake_spec.rb": 0.0565638542175293, - "spec/lib/tasks/users_rake_spec.rb": 0.2098069190979004, - "spec/serializers/api/admin/subscription_line_item_serializer_spec.rb": 0.6548449993133545, - "spec/serializers/api/product_serializer_spec.rb": 7.2200376987457275, - "spec/services/default_shipping_category_spec.rb": 0.03317761421203613, - "spec/services/product_tag_rules_filterer_spec.rb": 0.9287967681884766, - "spec/services/products_renderer_spec.rb": 4.769314765930176 + "spec/features/admin/variant_overrides_spec.rb": 99.30756449699402, + "spec/features/admin/product_import_spec.rb": 73.07663607597351, + "spec/features/admin/enterprise_relationships_spec.rb": 41.326045751571655, + "spec/features/admin/enterprises_spec.rb": 32.637606143951416, + "spec/models/spree/order_spec.rb": 27.992523431777954, + "spec/controllers/admin/subscriptions_controller_spec.rb": 27.568928956985474, + "spec/jobs/subscription_confirm_job_spec.rb": 21.490560293197632, + "spec/features/consumer/shopping/embedded_shopfronts_spec.rb": 38.76921033859253, + "spec/features/admin/enterprise_fees_spec.rb": 10.35721755027771, + "spec/features/admin/variants_spec.rb": 8.782998323440552, + "spec/features/consumer/producers_spec.rb": 10.305850982666016, + "spec/features/admin/enterprise_groups_spec.rb": 9.281317949295044, + "spec/features/consumer/account_spec.rb": 12.364761114120483, + "spec/controllers/api/variants_controller_spec.rb": 9.698291301727295, + "spec/controllers/admin/proxy_orders_controller_spec.rb": 9.294223308563232, + "spec/controllers/line_items_controller_spec.rb": 9.073998928070068, + "spec/lib/open_food_network/address_finder_spec.rb": 8.379472494125366, + "spec/features/admin/enterprises/index_spec.rb": 4.946447134017944, + "spec/requests/checkout/stripe_connect_spec.rb": 7.5777587890625, + "spec/models/spree/adjustment_spec.rb": 7.560959815979004, + "spec/serializers/api/product_serializer_spec.rb": 8.135705709457397, + "spec/lib/open_food_network/permissions_spec.rb": 3.799001455307007, + "spec/lib/open_food_network/bulk_coop_report_spec.rb": 5.437628269195557, + "spec/models/variant_override_spec.rb": 7.263522624969482, + "spec/features/consumer/shopping/checkout_paypal_spec.rb": 4.054832696914673, + "spec/lib/open_food_network/scope_variant_to_hub_spec.rb": 6.51300835609436, + "spec/mailers/order_mailer_spec.rb": 5.846204519271851, + "spec/features/consumer/footer_links_spec.rb": 2.7448785305023193, + "spec/models/exchange_spec.rb": 5.689413547515869, + "spec/features/admin/overview_spec.rb": 3.0301671028137207, + "spec/models/spree/payment_spec.rb": 4.219077110290527, + "spec/lib/open_food_network/products_and_inventory_report_spec.rb": 4.522545576095581, + "spec/features/admin/multilingual_spec.rb": 1.779911756515503, + "spec/features/consumer/account/cards_spec.rb": 3.4125499725341797, + "spec/models/concerns/variant_stock_spec.rb": 4.260012865066528, + "spec/controllers/spree/admin/products_controller_spec.rb": 2.9444453716278076, + "spec/models/calculator/weight_spec.rb": 4.537610769271851, + "spec/lib/open_food_network/lettuce_share_report_spec.rb": 2.5369696617126465, + "spec/features/admin/reports/packing_report_spec.rb": 2.4766170978546143, + "spec/models/spree/calculator_spec.rb": 2.4739301204681396, + "spec/services/bulk_invoice_service_spec.rb": 2.6490700244903564, + "spec/lib/open_food_network/scope_variants_to_search_spec.rb": 2.6042325496673584, + "spec/lib/open_food_network/customers_report_spec.rb": 2.2221970558166504, + "spec/models/concerns/order_shipment_spec.rb": 1.4907066822052002, + "spec/models/spree/product_set_spec.rb": 1.9434475898742676, + "spec/models/enterprise_fee_spec.rb": 1.8590900897979736, + "spec/models/spree/shipping_method_spec.rb": 1.939526081085205, + "spec/services/variants_stock_levels_spec.rb": 2.701181411743164, + "spec/views/spree/admin/orders/edit.html.haml_spec.rb": 1.4470489025115967, + "spec/features/admin/configuration/tax_categories_spec.rb": 1.29876708984375, + "spec/serializers/api/cached_enterprise_serializer_spec.rb": 1.4465532302856445, + "spec/features/admin/configuration/image_settings_spec.rb": 1.2370245456695557, + "spec/controllers/spree/admin/shipping_methods_controller_spec.rb": 1.7793538570404053, + "spec/services/cart_service_spec.rb": 3.899951696395874, + "spec/lib/open_food_network/orders_and_fulfillments_report/supplier_totals_report_spec.rb": 1.0069975852966309, + "spec/models/spree/user_spec.rb": 0.8939847946166992, + "spec/models/subscription_spec.rb": 0.7737770080566406, + "spec/features/admin/configuration/zones_spec.rb": 2.0647647380828857, + "spec/controllers/shops_controller_spec.rb": 1.1841659545898438, + "spec/models/spree/taxon_spec.rb": 1.4563179016113281, + "spec/helpers/admin/subscriptions_helper_spec.rb": 0.7952499389648438, + "spec/lib/open_food_network/order_and_distributor_report_spec.rb": 1.7040517330169678, + "spec/services/order_cycle_form_spec.rb": 0.8009114265441895, + "spec/lib/open_food_network/enterprise_fee_applicator_spec.rb": 0.640235185623169, + "spec/serializers/api/admin/enterprise_serializer_spec.rb": 0.6820120811462402, + "spec/features/admin/configuration/general_settings_spec.rb": 0.5539102554321289, + "spec/models/spree/calculator/flat_percent_item_total_spec.rb": 0.5510048866271973, + "spec/models/spree/calculator/flexi_rate_spec.rb": 0.5088491439819336, + "spec/models/spree/payment_method_spec.rb": 0.47752952575683594, + "spec/controllers/user_confirmations_controller_spec.rb": 0.8516778945922852, + "spec/helpers/i18n_helper_spec.rb": 0.14914989471435547, + "spec/models/customer_spec.rb": 0.3615994453430176, + "spec/models/enterprise_group_spec.rb": 0.2747635841369629, + "spec/models/spree/tax_rate_spec.rb": 0.2905604839324951, + "spec/controllers/spree/admin/base_controller_spec.rb": 0.1441051959991455, + "spec/lib/open_food_network/property_merge_spec.rb": 0.2783482074737549, + "spec/controllers/api/base_controller_spec.rb": 0.1090250015258789, + "spec/models/spree/calculator/per_item_spec.rb": 0.26129627227783203, + "spec/models/tag_rule/filter_payment_methods_spec.rb": 0.2537047863006592, + "spec/models/spree/price_spec.rb": 0.238206148147583, + "spec/models/stripe_account_spec.rb": 0.2526712417602539, + "spec/serializers/api/variant_serializer_spec.rb": 0.26934289932250977, + "spec/controllers/spree/admin/users_controller_spec.rb": 0.1959519386291504, + "spec/models/spree/classification_spec.rb": 0.19763445854187012, + "spec/models/tag_rule/filter_products_spec.rb": 0.1828017234802246, + "spec/controllers/stripe/webhooks_controller_spec.rb": 0.13119006156921387, + "spec/services/default_stock_location_spec.rb": 0.07834315299987793, + "spec/controllers/admin/column_preferences_controller_spec.rb": 0.1527540683746338, + "spec/models/tag_rule/filter_order_cycles_spec.rb": 0.19031882286071777, + "spec/controllers/user_registrations_controller_spec.rb": 0.14432930946350098, + "spec/models/spree/credit_card_spec.rb": 0.1434488296508789, + "spec/serializers/api/admin/index_enterprise_serializer_spec.rb": 0.15880084037780762, + "spec/controllers/user_passwords_controller_spec.rb": 0.11744856834411621, + "spec/controllers/registration_controller_spec.rb": 0.08824491500854492, + "spec/models/tag_rule/discount_order_spec.rb": 0.1451718807220459, + "spec/lib/open_food_network/i18n_config_spec.rb": 0.06594657897949219, + "spec/serializers/api/order_cycle_serializer_spec.rb": 0.09044694900512695, + "spec/lib/spree/product_filters_spec.rb": 0.11472368240356445, + "spec/models/product_import/settings_spec.rb": 0.08627009391784668, + "spec/helpers/shared_helper_spec.rb": 0.019224166870117188, + "spec/controllers/spree/store_controller_spec.rb": 0.02562713623046875, + "spec/serializers/api/admin/subscription_customer_serializer_spec.rb": 0.058799028396606445, + "spec/helpers/navigation_helper_spec.rb": 0.042215585708618164, + "spec/helpers/html_helper_spec.rb": 0.04345393180847168, + "spec/models/tag_rule_spec.rb": 0.04623818397521973, + "spec/lib/spree/localized_number_spec.rb": 0.03824877738952637, + "spec/controllers/base_controller_spec.rb": 0.022301673889160156, + "spec/models/spree/preferences/file_configuration_spec.rb": 0.0330810546875, + "spec/services/embedded_page_service_spec.rb": 0.032323360443115234, + "spec/services/default_shipping_category_spec.rb": 0.03125119209289551, + "spec/models/product_import/entry_processor_spec.rb": 0.030833005905151367, + "spec/models/subscription_line_item_spec.rb": 0.021193265914916992, + "spec/controllers/api/statuses_controller_spec.rb": 0.02451467514038086, + "spec/lib/open_food_network/referer_parser_spec.rb": 0.015799283981323242, + "spec/lib/open_food_network/reports/rule_spec.rb": 0.01628732681274414, + "spec/helpers/serializer_helper_spec.rb": 0.004682064056396484, + "spec/jobs/heartbeat_job_spec.rb": 0.013271570205688477, + "spec/services/mail_configuration_spec.rb": 0.01050567626953125, + "spec/models/content_configuration_spec.rb": 0.004523277282714844, + "spec/lib/open_food_network/error_logger_spec.rb": 0.004483938217163086, + "spec/services/upload_sanitizer_spec.rb": 0.00407862663269043, + "spec/config/application_spec.rb": 0.004088878631591797, + "engines/order_management/spec/features/order_management/reports/enterprise_fee_summaries_spec.rb": 14.05416202545166, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/permissions_spec.rb": 6.665990352630615, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_service_spec.rb": 43.40459585189819, + "engines/order_management/spec/services/order_management/subscriptions/payment_setup_spec.rb": 0.6526827812194824, + "engines/order_management/spec/services/order_management/subscriptions/summarizer_spec.rb": 0.041594743728637695, + "engines/web/spec/features/consumer/cookies_spec.rb": 24.080432891845703, + "spec/controllers/checkout_controller_concurrency_spec.rb": 2.275583505630493, + "spec/controllers/spree/admin/shipping_categories_controller_spec.rb": 0.07861185073852539, + "spec/features/admin/order_cycles/complex_editing_spec.rb": 5.987002611160278, + "spec/features/admin/order_cycles_complex_nav_check_spec.rb": 2.227072238922119, + "spec/features/consumer/caching/darkwarm_caching_spec.rb": 2.8325679302215576, + "spec/lib/stripe/payment_intent_validator_spec.rb": 0.022137880325317383, + "spec/models/spree/stock/quantifier_spec.rb": 0.23374128341674805, + "spec/requests/checkout/stripe_sca_spec.rb": 7.938737869262695, + "spec/services/checkout/form_data_adapter_spec.rb": 0.17598271369934082, + "spec/services/exchange_products_renderer_spec.rb": 3.1031360626220703, + "spec/services/order_cycle_warning_spec.rb": 0.19490528106689453, + "spec/services/permitted_attributes/order_cycle_spec.rb": 0.015558242797851562, + "spec/views/spree/admin/orders/invoice.html.haml_spec.rb": 6.268559455871582, + "spec/features/admin/bulk_order_management_spec.rb": 140.8281648159027, + "spec/features/consumer/shopping/checkout_spec.rb": 99.63996767997742, + "spec/features/admin/payment_method_spec.rb": 47.7765429019928, + "spec/models/product_importer_spec.rb": 58.75986576080322, + "spec/services/order_syncer_spec.rb": 31.290876388549805, + "spec/helpers/injection_helper_spec.rb": 32.275402784347534, + "spec/features/consumer/shopping/orders_spec.rb": 22.38155460357666, + "spec/features/admin/reports_spec.rb": 19.470484495162964, + "spec/features/admin/adjustments_spec.rb": 11.78750228881836, + "spec/mailers/producer_mailer_spec.rb": 29.681770086288452, + "spec/mailers/subscription_mailer_spec.rb": 26.084392070770264, + "spec/models/spree/variant_spec.rb": 14.30089783668518, + "spec/features/consumer/shopping/embedded_groups_spec.rb": 4.744326591491699, + "spec/features/consumer/multilingual_spec.rb": 7.861083507537842, + "spec/features/admin/schedules_spec.rb": 5.3575074672698975, + "spec/lib/open_food_network/orders_and_fulfillments_report_spec.rb": 9.90589451789856, + "spec/models/proxy_order_spec.rb": 7.81204891204834, + "spec/features/admin/users_spec.rb": 4.110132217407227, + "spec/lib/open_food_network/user_balance_calculator_spec.rb": 17.331896781921387, + "spec/lib/open_food_network/enterprise_fee_calculator_spec.rb": 10.376912832260132, + "spec/lib/open_food_network/packing_report_spec.rb": 7.372665643692017, + "spec/services/products_renderer_spec.rb": 6.482128858566284, + "spec/models/spree/stock/availability_validator_spec.rb": 9.495196104049683, + "spec/services/advance_order_service_spec.rb": 7.021219968795776, + "spec/controllers/admin/enterprises_controller_spec.rb": 4.748497247695923, + "spec/controllers/spree/users_controller_spec.rb": 5.6285271644592285, + "spec/features/consumer/account/settings_spec.rb": 3.27730393409729, + "spec/lib/open_food_network/order_cycle_management_report_spec.rb": 4.047335863113403, + "spec/features/admin/payments_spec.rb": 7.85437798500061, + "spec/lib/open_food_network/group_buy_report_spec.rb": 3.6540842056274414, + "spec/features/admin/authentication_spec.rb": 3.2194108963012695, + "spec/helpers/enterprises_helper_spec.rb": 3.27225923538208, + "spec/controllers/admin/order_cycles_controller_spec.rb": 3.0946338176727295, + "spec/serializers/api/admin/exchange_serializer_spec.rb": 3.0946173667907715, + "spec/controllers/admin/schedules_controller_spec.rb": 3.847097158432007, + "spec/models/enterprise_caching_spec.rb": 3.255535364151001, + "spec/requests/checkout/failed_checkout_spec.rb": 2.4441702365875244, + "spec/controllers/api/promo_images_controller_spec.rb": 3.4382574558258057, + "spec/services/tax_rate_finder_spec.rb": 2.9899346828460693, + "spec/controllers/api/product_images_controller_spec.rb": 3.9871389865875244, + "spec/controllers/checkout_controller_spec.rb": 4.339718341827393, + "spec/controllers/cart_controller_spec.rb": 2.3228118419647217, + "spec/controllers/api/logos_controller_spec.rb": 3.2836084365844727, + "spec/lib/open_food_network/tag_rule_applicator_spec.rb": 2.221569299697876, + "spec/services/exchange_variant_bulk_updater_spec.rb": 2.6784279346466064, + "spec/controllers/shop_controller_spec.rb": 3.5295212268829346, + "spec/models/concerns/product_stock_spec.rb": 2.5454351902008057, + "spec/models/spree/order/checkout_spec.rb": 1.958070993423462, + "spec/services/product_tag_rules_filterer_spec.rb": 2.044708013534546, + "spec/models/spree/shipment_spec.rb": 1.6677730083465576, + "spec/serializers/api/admin/variant_serializer_spec.rb": 1.2669260501861572, + "spec/controllers/admin/manager_invitations_controller_spec.rb": 1.1235411167144775, + "spec/features/admin/enterprise_user_spec.rb": 1.4083926677703857, + "spec/requests/embedded_shopfronts_headers_spec.rb": 1.80560302734375, + "spec/features/admin/configuration/tax_rates_spec.rb": 1.076134204864502, + "spec/serializers/api/admin/subscription_line_item_serializer_spec.rb": 1.103409767150879, + "spec/models/order_updater_spec.rb": 0.893103837966919, + "spec/controllers/api/taxons_controller_spec.rb": 1.4529874324798584, + "spec/models/spree/calculator/price_sack_spec.rb": 2.4207956790924072, + "spec/controllers/admin/stripe_accounts_controller_spec.rb": 0.7403256893157959, + "spec/models/spree/gateway_tagging_spec.rb": 0.5006825923919678, + "spec/serializers/api/admin/for_order_cycle/supplied_product_serializer_spec.rb": 0.6309933662414551, + "spec/features/admin/tax_settings_spec.rb": 0.4539029598236084, + "spec/lib/open_food_network/users_and_enterprises_report_spec.rb": 0.45987796783447266, + "spec/controllers/spree/credit_cards_controller_spec.rb": 0.3677220344543457, + "spec/controllers/api/customers_controller_spec.rb": 0.5009043216705322, + "spec/serializers/api/shipping_method_serializer_spec.rb": 0.418184757232666, + "spec/features/admin/image_settings_spec.rb": 0.3251943588256836, + "spec/controllers/spree/admin/mail_methods_controller_spec.rb": 0.1681194305419922, + "spec/controllers/spree/paypal_controller_spec.rb": 0.3564426898956299, + "spec/mailers/user_mailer_spec.rb": 0.25026392936706543, + "spec/serializers/api/admin/variant_override_serializer_spec.rb": 0.3578934669494629, + "spec/services/search_orders_spec.rb": 0.3271763324737549, + "spec/lib/tasks/users_rake_spec.rb": 0.18160343170166016, + "spec/mailers/enterprise_mailer_spec.rb": 0.22394657135009766, + "spec/models/model_set_spec.rb": 0.29787373542785645, + "spec/models/column_preference_spec.rb": 0.2551867961883545, + "spec/controllers/admin/tag_rules_controller_spec.rb": 0.26432085037231445, + "spec/serializers/api/admin/product_serializer_spec.rb": 0.28866004943847656, + "spec/models/adjustment_metadata_spec.rb": 0.2655766010284424, + "spec/controllers/api/enterprise_fees_controller_spec.rb": 0.11628031730651855, + "spec/serializers/api/group_list_serializer_spec.rb": 0.2681000232696533, + "spec/serializers/api/admin/customer_serializer_spec.rb": 0.34451889991760254, + "spec/serializers/api/enterprise_shopfront_list_serializer_spec.rb": 0.20429253578186035, + "spec/views/spree/admin/orders/index.html.haml_spec.rb": 0.26395225524902344, + "spec/serializers/api/enterprise_serializer_spec.rb": 0.23106741905212402, + "spec/lib/open_food_network/sales_tax_report_spec.rb": 0.12182736396789551, + "spec/helpers/spree/orders_helper_spec.rb": 0.03900146484375, + "spec/lib/open_food_network/xero_invoices_report_spec.rb": 0.18147039413452148, + "spec/features/consumer/sitemap_spec.rb": 0.12035298347473145, + "spec/controllers/groups_controller_spec.rb": 0.16557097434997559, + "spec/lib/open_food_network/option_value_namer_spec.rb": 0.13304948806762695, + "spec/models/spree/addresses_spec.rb": 0.11377644538879395, + "spec/lib/tasks/enterprises_rake_spec.rb": 0.0833287239074707, + "spec/controllers/api/taxonomies_controller_spec.rb": 0.08802604675292969, + "spec/helpers/spree/admin/orders_helper_spec.rb": 0.0646059513092041, + "spec/models/spree/gateway/stripe_connect_spec.rb": 0.05724668502807617, + "spec/helpers/shop_helper_spec.rb": 0.3690376281738281, + "spec/jobs/welcome_enterprise_job_spec.rb": 0.08383440971374512, + "spec/jobs/confirm_order_job_spec.rb": 0.06512808799743652, + "spec/lib/open_food_network/order_grouper_spec.rb": 0.05493974685668945, + "spec/lib/stripe/webhook_handler_spec.rb": 0.05923867225646973, + "spec/lib/open_food_network/enterprise_issue_validator_spec.rb": 0.058492183685302734, + "spec/validators/integer_array_validator_spec.rb": 0.04994392395019531, + "spec/validators/date_time_string_validator_spec.rb": 0.05316734313964844, + "spec/models/product_import/reset_absent_spec.rb": 0.04071307182312012, + "spec/lib/open_food_network/reports/report_spec.rb": 0.04329681396484375, + "spec/jobs/confirm_signup_job_spec.rb": 0.03060293197631836, + "spec/services/order_cycle_distributed_variants_spec.rb": 0.02808237075805664, + "spec/lib/open_food_network/feature_toggle_spec.rb": 0.0240786075592041, + "spec/requests/large_request_spec.rb": 0.029397964477539062, + "spec/serializers/api/credit_card_serializer_spec.rb": 0.018352746963500977, + "spec/models/spree/calculator/flat_rate_spec.rb": 0.014808177947998047, + "spec/models/spree/image_spec.rb": 0.014715909957885742, + "spec/helpers/spree/admin/base_helper_spec.rb": 0.008042573928833008, + "spec/lib/open_food_network/reports/row_spec.rb": 0.005358695983886719, + "engines/order_management/spec/controllers/order_management/reports/enterprise_fee_summaries_controller_spec.rb": 0.7100100517272949, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/parameters_spec.rb": 4.190261602401733, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/report_data/enterprise_fee_type_total_spec.rb": 0.006247282028198242, + "engines/order_management/spec/services/order_management/subscriptions/form_spec.rb": 2.317678928375244, + "engines/order_management/spec/services/order_management/subscriptions/stripe_sca_payment_authorize_spec.rb": 0.7113745212554932, + "engines/order_management/spec/services/order_management/subscriptions/variants_list_spec.rb": 5.509528398513794, + "spec/controllers/api/shops_controller_spec.rb": 1.5322284698486328, + "spec/controllers/spree/admin/return_authorizations_controller_spec.rb": 1.8667445182800293, + "spec/features/admin/order_cycles/complex_editing_multiple_product_pages_spec.rb": 8.482699632644653, + "spec/features/admin/order_cycles/simple_spec.rb": 54.873196601867676, + "spec/features/admin/properties_spec.rb": 0.4787609577178955, + "spec/jobs/job_logger_spec.rb": 0.017215251922607422, + "spec/lib/stripe/credit_card_cloner_spec.rb": 0.04944920539855957, + "spec/lib/tasks/data/truncate_data_spec.rb": 6.85896372795105, + "spec/services/cache_service_spec.rb": 0.0431828498840332, + "spec/services/checkout/stripe_redirect_spec.rb": 0.3430206775665283, + "spec/services/order_completion_reset_spec.rb": 0.019972562789916992, + "spec/services/permissions/order_spec.rb": 11.389648914337158, + "spec/services/variant_overrides_indexed_spec.rb": 1.599395990371704, + "spec/features/admin/bulk_product_update_spec.rb": 85.68869709968567, + "spec/features/admin/subscriptions_spec.rb": 66.11615419387817, + "spec/features/consumer/authentication_spec.rb": 52.20323586463928, + "spec/models/order_cycle_spec.rb": 49.266600131988525, + "spec/features/admin/customers_spec.rb": 24.988075256347656, + "spec/models/spree/line_item_spec.rb": 43.67242765426636, + "spec/features/admin/enterprise_roles_spec.rb": 20.88746976852417, + "spec/features/consumer/shopping/cart_spec.rb": 31.941763639450073, + "spec/controllers/spree/orders_controller_spec.rb": 33.53650450706482, + "spec/features/admin/products_spec.rb": 18.70025324821472, + "spec/controllers/spree/admin/reports_controller_spec.rb": 24.616009950637817, + "spec/features/consumer/groups_spec.rb": 8.961438655853271, + "spec/jobs/subscription_placement_job_spec.rb": 19.798776626586914, + "spec/features/admin/enterprises/images_spec.rb": 8.75648546218872, + "spec/models/spree/ability_spec.rb": 18.13743495941162, + "spec/features/admin/configuration/states_spec.rb": 3.9561424255371094, + "spec/controllers/api/order_cycles_controller_spec.rb": 15.353764295578003, + "spec/models/enterprise_spec.rb": 15.155356407165527, + "spec/lib/open_food_network/order_cycle_form_applicator_spec.rb": 9.664437294006348, + "spec/controllers/spree/admin/orders_controller_spec.rb": 11.2395179271698, + "spec/models/enterprise_relationship_spec.rb": 10.401739358901978, + "spec/features/consumer/shopping/products_spec.rb": 4.121779441833496, + "spec/controllers/spree/admin/orders/customer_details_controller_spec.rb": 6.558723211288452, + "spec/serializers/api/order_serializer_spec.rb": 6.36934494972229, + "spec/controllers/admin/variant_overrides_controller_spec.rb": 6.027082681655884, + "spec/controllers/spree/admin/variants_controller_spec.rb": 4.790205717086792, + "spec/services/invoice_renderer_spec.rb": 3.852773666381836, + "spec/controllers/spree/admin/payments_controller_spec.rb": 12.54552435874939, + "spec/services/order_cycle_distributed_products_spec.rb": 4.698481321334839, + "spec/controllers/enterprises_controller_spec.rb": 7.326315879821777, + "spec/controllers/admin/inventory_items_controller_spec.rb": 3.6743903160095215, + "spec/models/product_import/inventory_reset_strategy_spec.rb": 3.342827796936035, + "spec/controllers/admin/subscription_line_items_controller_spec.rb": 3.391206741333008, + "spec/serializers/api/current_order_serializer_spec.rb": 2.8222057819366455, + "spec/serializers/api/enterprise_shopfront_serializer_spec.rb": 2.453338384628296, + "spec/features/admin/configuration/taxonomies_spec.rb": 2.2291758060455322, + "spec/requests/checkout/paypal_spec.rb": 1.9109196662902832, + "spec/features/admin/content_spec.rb": 1.6747770309448242, + "spec/controllers/spree/admin/payment_methods_controller_spec.rb": 1.7733421325683594, + "spec/lib/open_food_network/orders_and_fulfillments_report/customer_totals_report_spec.rb": 5.486632347106934, + "spec/controllers/admin/customers_controller_spec.rb": 1.6756572723388672, + "spec/lib/open_food_network/orders_and_fulfillments_report/supplier_totals_by_distributor_report_spec.rb": 1.494542121887207, + "spec/lib/open_food_network/orders_and_fulfillments_report/distributor_totals_by_supplier_report_spec.rb": 1.536348581314087, + "spec/controllers/api/enterprises_controller_spec.rb": 0.5235552787780762, + "spec/controllers/spree/admin/search_controller_spec.rb": 1.0657844543457031, + "spec/controllers/spree/admin/adjustments_controller_spec.rb": 0.9423079490661621, + "spec/features/admin/configuration/mail_methods_spec.rb": 0.43262410163879395, + "spec/controllers/spree/admin/overview_controller_spec.rb": 0.8039264678955078, + "spec/helpers/admin/orders_helper_spec.rb": 0.7706241607666016, + "spec/helpers/order_cycles_helper_spec.rb": 0.6262946128845215, + "spec/controllers/stripe/callbacks_controller_spec.rb": 0.41001367568969727, + "spec/lib/stripe/account_connector_spec.rb": 0.4642143249511719, + "spec/models/tag_rule/filter_shipping_methods_spec.rb": 0.47301149368286133, + "spec/features/admin/external_services_spec.rb": 0.3893253803253174, + "spec/models/stock/package_spec.rb": 0.43047094345092773, + "spec/controllers/admin/stripe_connect_settings_controller_spec.rb": 0.27138352394104004, + "spec/controllers/spree/admin/image_settings_controller_spec.rb": 0.2584362030029297, + "spec/features/consumer/confirm_invitation_spec.rb": 0.3224337100982666, + "spec/helpers/checkout_helper_spec.rb": 0.13036370277404785, + "spec/helpers/groups_helper_spec.rb": 0.012569427490234375, + "engines/dfc_provider/spec/controllers/dfc_provider/api/products_controller_spec.rb": 2.489386558532715, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/authorizer_spec.rb": 0.3381996154785156, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/renderers/html_renderer_spec.rb": 0.03400373458862305, + "engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb": 7.829980373382568, + "engines/order_management/spec/services/order_management/subscriptions/stripe_payment_setup_spec.rb": 1.1807715892791748, + "engines/order_management/spec/services/order_management/subscriptions/validator_spec.rb": 2.3976430892944336, + "spec/controllers/api/exchange_products_controller_spec.rb": 11.865624189376831, + "spec/features/admin/order_cycles/complex_editing_exchange_same_enterprise_spec.rb": 2.529176950454712, + "spec/features/admin/order_cycles/list_spec.rb": 11.831752300262451, + "spec/features/admin/order_spec.rb": 171.90774178504944, + "spec/helpers/spree/admin/reports_helper_spec.rb": 5.590947389602661, + "spec/lib/stripe/authorize_response_patcher_spec.rb": 0.015482425689697266, + "spec/lib/tasks/data/truncate_data_rake_spec.rb": 4.825200080871582, + "spec/serializers/api/admin/order_serializer_spec.rb": 3.7998077869415283, + "spec/services/checkout/post_checkout_actions_spec.rb": 0.5116136074066162, + "spec/services/order_checkout_restart_spec.rb": 1.1087470054626465, + "spec/services/order_tax_adjustments_fetcher_spec.rb": 7.905844449996948, + "spec/services/user_default_address_setter_spec.rb": 0.32790184020996094, + "spec/views/spree/shared/_order_details.html.haml_spec.rb": 6.581799507141113, +"spec/features/admin/orders_spec.rb": 37.106088638305664, + "spec/features/consumer/shopping/variant_overrides_spec.rb": 141.61448574066162, + "spec/features/consumer/shopping/shopping_spec.rb": 108.44787383079529, + "spec/controllers/api/orders_controller_spec.rb": 105.54521131515503, + "spec/features/admin/shipping_methods_spec.rb": 43.61902475357056, + "spec/features/admin/tag_rules_spec.rb": 31.836936473846436, + "spec/features/consumer/shops_spec.rb": 32.17615461349487, + "spec/controllers/admin/bulk_line_items_controller_spec.rb": 56.091858863830566, + "spec/lib/open_food_network/order_cycle_permissions_spec.rb": 49.695056438446045, + "spec/controllers/api/shipments_controller_spec.rb": 38.7325336933136, + "spec/features/consumer/registration_spec.rb": 15.266984462738037, + "spec/controllers/api/products_controller_spec.rb": 34.40333008766174, + "spec/models/spree/product_spec.rb": 41.200894832611084, + "spec/features/consumer/shopping/checkout_auth_spec.rb": 15.087469100952148, + "spec/services/order_factory_spec.rb": 21.278146266937256, + "spec/jobs/order_cycle_notification_job_spec.rb": 2.3313727378845215, + "spec/controllers/spree/user_sessions_controller_spec.rb": 0.06848526000976562, + "spec/models/calculator/flat_percent_per_item_spec.rb": 0.03157782554626465, + "engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb": 4.549654483795166, + "engines/order_management/spec/services/order_management/reports/enterprise_fee_summary/renderers/csv_renderer_spec.rb": 0.06129932403564453, + "engines/order_management/spec/services/order_management/subscriptions/count_spec.rb": 1.851973533630371, + "engines/order_management/spec/services/order_management/subscriptions/proxy_order_syncer_spec.rb": 13.164706230163574, + "engines/order_management/spec/services/order_management/subscriptions/summary_spec.rb": 0.3277547359466553, + "engines/web/spec/helpers/cookies_policy_helper_spec.rb": 0.054679155349731445, + "spec/controllers/spree/admin/countries_controller_spec.rb": 0.07967424392700195, + "spec/features/admin/order_cycles/complex_creating_specific_time_spec.rb": 13.867288827896118, + "spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb": 20.47591543197632, + "spec/features/admin/order_print_ticket_spec.rb": 6.32416033744812, + "spec/features/consumer/caching/shops_caching_spec.rb": 10.797699213027954, + "spec/lib/open_food_network/i18n_inflections_spec.rb": 0.04519987106323242, + "spec/lib/stripe/profile_storer_spec.rb": 0.6562683582305908, + "spec/serializers/api/admin/order_cycle_serializer_spec.rb": 10.537176847457886, + "spec/services/checkout/paypal_redirect_spec.rb": 0.1902143955230713, + "spec/services/order_cart_reset_spec.rb": 2.440279245376587, + "spec/services/order_payment_finder_spec.rb": 1.5698633193969727, + "spec/services/permitted_attributes/user_spec.rb": 0.021186351776123047, + "spec/views/spree/admin/payment_methods/index.html.haml_spec.rb": 0.16062402725219727 } From bb80c81097052b17968dcab9051fef1e4196d747 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Mon, 29 Jun 2020 05:22:13 +1000 Subject: [PATCH 073/261] Updating translations for config/locales/en_US.yml --- config/locales/en_US.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/en_US.yml b/config/locales/en_US.yml index 7917bbc6e6..5cdc1914cf 100644 --- a/config/locales/en_US.yml +++ b/config/locales/en_US.yml @@ -270,6 +270,7 @@ en_US: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -2071,6 +2072,7 @@ en_US: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2307,6 +2309,7 @@ en_US: 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" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again with a different order cycle!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2772,6 +2775,7 @@ en_US: previous: "Previous" last: "Last" spree: + more: "More" your_order_is_empty_add_product: "Your cart 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)" From c892f9c69b17fa94898951956c9d2d84b3fd643c Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Mon, 29 Jun 2020 12:01:59 +0200 Subject: [PATCH 074/261] Make button border radius consistent --- app/views/spree/orders/form/_update_buttons.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/orders/form/_update_buttons.html.haml b/app/views/spree/orders/form/_update_buttons.html.haml index 5757d1742f..476e7d23d6 100644 --- a/app/views/spree/orders/form/_update_buttons.html.haml +++ b/app/views/spree/orders/form/_update_buttons.html.haml @@ -16,7 +16,7 @@ %i.ofn-i_009-close = t(:cancel_order) .columns.small-12.medium-3 - = button_tag :class => 'button primary radius expand', :id => 'update-button', "ng-disabled" => 'update_order_form.$pristine' do + = button_tag :class => 'button primary expand', :id => 'update-button', "ng-disabled" => 'update_order_form.$pristine' do %i.ofn-i_051-check-big %span{ ng: { show: 'update_order_form.$dirty' } }= t(:save_changes) %span{ ng: { hide: 'update_order_form.$dirty' } }= t(:order_saved) From 5bec887f93129fca23579396a3f9f193a86095cb Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 29 Jun 2020 19:57:36 +0200 Subject: [PATCH 075/261] Move /assets/images/noimage/* to /public/noimage/* --- {app/assets/images => public}/noimage/group.png | Bin {app/assets/images => public}/noimage/large.png | Bin {app/assets/images => public}/noimage/mini.png | Bin {app/assets/images => public}/noimage/product.png | Bin {app/assets/images => public}/noimage/small.png | Bin 5 files changed, 0 insertions(+), 0 deletions(-) rename {app/assets/images => public}/noimage/group.png (100%) rename {app/assets/images => public}/noimage/large.png (100%) rename {app/assets/images => public}/noimage/mini.png (100%) rename {app/assets/images => public}/noimage/product.png (100%) rename {app/assets/images => public}/noimage/small.png (100%) diff --git a/app/assets/images/noimage/group.png b/public/noimage/group.png similarity index 100% rename from app/assets/images/noimage/group.png rename to public/noimage/group.png diff --git a/app/assets/images/noimage/large.png b/public/noimage/large.png similarity index 100% rename from app/assets/images/noimage/large.png rename to public/noimage/large.png diff --git a/app/assets/images/noimage/mini.png b/public/noimage/mini.png similarity index 100% rename from app/assets/images/noimage/mini.png rename to public/noimage/mini.png diff --git a/app/assets/images/noimage/product.png b/public/noimage/product.png similarity index 100% rename from app/assets/images/noimage/product.png rename to public/noimage/product.png diff --git a/app/assets/images/noimage/small.png b/public/noimage/small.png similarity index 100% rename from app/assets/images/noimage/small.png rename to public/noimage/small.png From b441ac2644296341c5e849c90b578ab2e0773fff Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 29 Jun 2020 20:07:08 +0200 Subject: [PATCH 076/261] Update paths to "noimage" images --- app/assets/javascripts/darkswarm/services/products.js.coffee | 2 +- app/assets/javascripts/templates/product_modal.html.haml | 2 +- app/serializers/api/admin/product_serializer.rb | 4 ++-- app/serializers/api/variant_serializer.rb | 2 +- app/views/groups/show.html.haml | 2 +- app/views/spree/admin/products/new.html.haml | 2 +- app/views/spree/admin/variants/_autocomplete.js.erb | 2 +- spec/features/admin/bulk_product_update_spec.rb | 2 +- .../unit/darkswarm/services/products_spec.js.coffee | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/assets/javascripts/darkswarm/services/products.js.coffee b/app/assets/javascripts/darkswarm/services/products.js.coffee index 59bd19efb4..83b19251bb 100644 --- a/app/assets/javascripts/darkswarm/services/products.js.coffee +++ b/app/assets/javascripts/darkswarm/services/products.js.coffee @@ -34,7 +34,7 @@ Darkswarm.factory 'Products', (OrderCycleResource, OrderCycle, Shopfront, curren product.price = Math.min.apply(null, prices) product.hasVariants = product.variants?.length > 0 product.primaryImage = product.images[0]?.small_url if product.images - product.primaryImageOrMissing = product.primaryImage || "/assets/noimage/small.png" + product.primaryImageOrMissing = product.primaryImage || "/noimage/small.png" product.largeImage = product.images[0]?.large_url if product.images dereference: -> diff --git a/app/assets/javascripts/templates/product_modal.html.haml b/app/assets/javascripts/templates/product_modal.html.haml index 9c65bbbad7..95c74c5f72 100644 --- a/app/assets/javascripts/templates/product_modal.html.haml +++ b/app/assets/javascripts/templates/product_modal.html.haml @@ -15,6 +15,6 @@ .columns.small-12.medium-6.large-6.product-img %img{"ng-src" => "{{::product.largeImage}}", "ng-if" => "::product.largeImage"} - %img.placeholder{ src: "/assets/noimage/large.png", "ng-if" => "::!product.largeImage"} + %img.placeholder{ src: "/noimage/large.png", "ng-if" => "::!product.largeImage"} %ng-include{src: "'partials/close.html'"} diff --git a/app/serializers/api/admin/product_serializer.rb b/app/serializers/api/admin/product_serializer.rb index c4b9f15a34..2be4995305 100644 --- a/app/serializers/api/admin/product_serializer.rb +++ b/app/serializers/api/admin/product_serializer.rb @@ -12,7 +12,7 @@ class Api::Admin::ProductSerializer < ActiveModel::Serializer if object.images.present? object.images.first.attachment.url(:product) else - "/assets/noimage/product.png" + "/noimage/product.png" end end @@ -20,7 +20,7 @@ class Api::Admin::ProductSerializer < ActiveModel::Serializer if object.images.present? object.images.first.attachment.url(:mini) else - "/assets/noimage/mini.png" + "/noimage/mini.png" end end diff --git a/app/serializers/api/variant_serializer.rb b/app/serializers/api/variant_serializer.rb index 38cc649910..0306c95f95 100644 --- a/app/serializers/api/variant_serializer.rb +++ b/app/serializers/api/variant_serializer.rb @@ -35,7 +35,7 @@ class Api::VariantSerializer < ActiveModel::Serializer if object.product.images.present? object.product.images.first.attachment.url(:mini) else - "/assets/noimage/mini.png" + "/noimage/mini.png" end end end diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 4701791daa..b5622063a2 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -22,7 +22,7 @@ - if @group.logo.present? %img.group-logo{"src" => @group.logo} - else - %img.group-logo{"src" => image_path('noimage/group.png') } + %img.group-logo{"src" => '/noimage/group.png' } %h2.group-name= @group.name %p= @group.description diff --git a/app/views/spree/admin/products/new.html.haml b/app/views/spree/admin/products/new.html.haml index 34665fbdcb..908f30b5b9 100644 --- a/app/views/spree/admin/products/new.html.haml +++ b/app/views/spree/admin/products/new.html.haml @@ -83,7 +83,7 @@ %fieldset.no-border-bottom{ id: "image" } %legend{align: "center"}= t(".image") .row - = image_tag "noimage/product.png", class: "four columns alpha" + = image_tag "/noimage/product.png", class: "four columns alpha" .row = f.fields_for 'images_attributes[]', f.object.images.build do |image_fields| = image_fields.file_field :attachment diff --git a/app/views/spree/admin/variants/_autocomplete.js.erb b/app/views/spree/admin/variants/_autocomplete.js.erb index 9e4c29a50a..c4d1f8d96a 100644 --- a/app/views/spree/admin/variants/_autocomplete.js.erb +++ b/app/views/spree/admin/variants/_autocomplete.js.erb @@ -4,7 +4,7 @@ {{#if variant.image }} {{ else }} - + {{/if}} diff --git a/spec/features/admin/bulk_product_update_spec.rb b/spec/features/admin/bulk_product_update_spec.rb index 09bdf68fca..c0b55ed224 100644 --- a/spec/features/admin/bulk_product_update_spec.rb +++ b/spec/features/admin/bulk_product_update_spec.rb @@ -770,7 +770,7 @@ feature ' expect(page).to have_selector "td.image" # Shows default image when no image set - expect(page).to have_css "img[src='/assets/noimage/mini.png']" + expect(page).to have_css "img[src='/noimage/mini.png']" @old_thumb_src = page.find("a.image-modal img")['src'] # Click image diff --git a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee index 88ff585f00..db9ed1e628 100644 --- a/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee +++ b/spec/javascripts/unit/darkswarm/services/products_spec.js.coffee @@ -107,7 +107,7 @@ describe 'Products service', -> $httpBackend.expectGET(endpoint).respond([product]) $httpBackend.flush() expect(Products.products[0].primaryImage).toBeUndefined() - expect(Products.products[0].primaryImageOrMissing).toEqual "/assets/noimage/small.png" + expect(Products.products[0].primaryImageOrMissing).toEqual "/noimage/small.png" it "sets largeImage", -> $httpBackend.expectGET(endpoint).respond([productWithImage]) From 23178763b00b0ede0c72062ccec709183dd45b06 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 5 Jun 2020 17:04:59 +0200 Subject: [PATCH 077/261] Do not print the bill addr. name when there's none The error ``` ActionView::Template::Error: undefined method `full_name' for nil:NilClass ``` happens a few times a day and raises exceptions we don't pay attention to. They add unnecessary noise that hides other more relevant issues. This, however, is a symptom of a deeper data integrity problem that needs solving at some point. This is just a countermeasure. --- app/views/spree/admin/orders/invoice.html.haml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/spree/admin/orders/invoice.html.haml b/app/views/spree/admin/orders/invoice.html.haml index bc2b4dc556..ff4a930e5a 100644 --- a/app/views/spree/admin/orders/invoice.html.haml +++ b/app/views/spree/admin/orders/invoice.html.haml @@ -33,16 +33,19 @@ %td{ align: "left" } %strong= "#{t('.to')}:" %br - = @order.bill_address.full_name + - if @order.bill_address + = @order.bill_address.full_name - if @order.andand.customer.andand.code.present? %br = "#{t('.code')}: #{@order.customer.code}" %br - = @order.bill_address.full_address + - if @order.bill_address + = @order.bill_address.full_address %br - if @order.andand.customer.andand.email.present? = "#{@order.customer.email}," - = "#{@order.bill_address.phone}" + - if @order.bill_address + = "#{@order.bill_address.phone}" %td   %td{ align: "left", style: "border-left: .1em solid black; padding-left: 1em" } From 0c93de8298523c7b25f6db834e8eeb6d9a3cda4b Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Fri, 19 Jun 2020 14:06:57 +0200 Subject: [PATCH 078/261] Manage OFN's font through the asset pipeline --- {public => app/assets/fonts}/OFN-v2.eot | Bin {public => app/assets/fonts}/OFN-v2.svg | 0 {public => app/assets/fonts}/OFN-v2.ttf | Bin {public => app/assets/fonts}/OFN-v2.woff | Bin app/assets/stylesheets/darkswarm/style.scss | 10 +++++----- app/views/layouts/darkswarm.html.haml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename {public => app/assets/fonts}/OFN-v2.eot (100%) rename {public => app/assets/fonts}/OFN-v2.svg (100%) rename {public => app/assets/fonts}/OFN-v2.ttf (100%) rename {public => app/assets/fonts}/OFN-v2.woff (100%) diff --git a/public/OFN-v2.eot b/app/assets/fonts/OFN-v2.eot similarity index 100% rename from public/OFN-v2.eot rename to app/assets/fonts/OFN-v2.eot diff --git a/public/OFN-v2.svg b/app/assets/fonts/OFN-v2.svg similarity index 100% rename from public/OFN-v2.svg rename to app/assets/fonts/OFN-v2.svg diff --git a/public/OFN-v2.ttf b/app/assets/fonts/OFN-v2.ttf similarity index 100% rename from public/OFN-v2.ttf rename to app/assets/fonts/OFN-v2.ttf diff --git a/public/OFN-v2.woff b/app/assets/fonts/OFN-v2.woff similarity index 100% rename from public/OFN-v2.woff rename to app/assets/fonts/OFN-v2.woff diff --git a/app/assets/stylesheets/darkswarm/style.scss b/app/assets/stylesheets/darkswarm/style.scss index e9f018445b..9228b0bbe9 100644 --- a/app/assets/stylesheets/darkswarm/style.scss +++ b/app/assets/stylesheets/darkswarm/style.scss @@ -1,10 +1,10 @@ @font-face { font-family: 'OFN'; - src:url('/OFN-v2.eot?eslsji'); - src:url('/OFN-v2.eot?#iefixeslsji') format('embedded-opentype'), - url('/OFN-v2.woff?eslsji') format('woff'), - url('/OFN-v2.ttf?eslsji') format('truetype'), - url('/OFN-v2.svg?eslsji#OFN') format('svg'); + src: font-url('OFN-v2.eot'); + src: font-url('OFN-v2.eot') format('embedded-opentype'), + font-url('OFN-v2.woff') format('woff'), + font-url('OFN-v2.ttf') format('truetype'), + font-url('OFN-v2.svg') format('svg'); font-weight: normal; font-style: normal; } diff --git a/app/views/layouts/darkswarm.html.haml b/app/views/layouts/darkswarm.html.haml index f45b157a51..7fd21a35d3 100644 --- a/app/views/layouts/darkswarm.html.haml +++ b/app/views/layouts/darkswarm.html.haml @@ -13,7 +13,7 @@ - else = favicon_link_tag "/favicon-staging.ico" %link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"} - %link{href: "/OFN-v2.woff?eslsji", rel: "preload", as: "font", crossorigin: "anonymous"} + %link{href: font_path("OFN-v2.woff"), rel: "preload", as: "font", crossorigin: "anonymous"} = stylesheet_link_tag "darkswarm/all" = csrf_meta_tags From 57ba2481c480313dde5247fed4a7ee5a2e200b8a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 09:08:43 +0200 Subject: [PATCH 079/261] Require timestamps --- .../20200630070422_require_timestamps.rb | 251 ++++++++++++++++++ db/schema.rb | 246 ++++++++--------- 2 files changed, 374 insertions(+), 123 deletions(-) create mode 100644 db/migrate/20200630070422_require_timestamps.rb diff --git a/db/migrate/20200630070422_require_timestamps.rb b/db/migrate/20200630070422_require_timestamps.rb new file mode 100644 index 0000000000..d69c9f0832 --- /dev/null +++ b/db/migrate/20200630070422_require_timestamps.rb @@ -0,0 +1,251 @@ +class RequireTimestamps < ActiveRecord::Migration + def up + change_column_null :customers, :created_at, false + change_column_null :customers, :updated_at, false + change_column_null :delayed_jobs, :created_at, false + change_column_null :delayed_jobs, :updated_at, false + change_column_null :distributors_shipping_methods, :created_at, false + change_column_null :distributors_shipping_methods, :updated_at, false + change_column_null :enterprise_fees, :created_at, false + change_column_null :enterprise_fees, :updated_at, false + change_column_null :enterprises, :created_at, false + change_column_null :enterprises, :updated_at, false + change_column_null :exchange_fees, :created_at, false + change_column_null :exchange_fees, :updated_at, false + change_column_null :exchange_variants, :created_at, false + change_column_null :exchange_variants, :updated_at, false + change_column_null :exchanges, :created_at, false + change_column_null :exchanges, :updated_at, false + change_column_null :inventory_items, :created_at, false + change_column_null :inventory_items, :updated_at, false + change_column_null :order_cycle_schedules, :created_at, false + change_column_null :order_cycle_schedules, :updated_at, false + change_column_null :order_cycles, :created_at, false + change_column_null :order_cycles, :updated_at, false + change_column_null :producer_properties, :created_at, false + change_column_null :producer_properties, :updated_at, false + change_column_null :proxy_orders, :created_at, false + change_column_null :proxy_orders, :updated_at, false + change_column_null :schedules, :created_at, false + change_column_null :schedules, :updated_at, false + change_column_null :sessions, :created_at, false + change_column_null :sessions, :updated_at, false + change_column_null :spree_activators, :created_at, false + change_column_null :spree_activators, :updated_at, false + change_column_null :spree_addresses, :created_at, false + change_column_null :spree_addresses, :updated_at, false + change_column_null :spree_adjustments, :created_at, false + change_column_null :spree_adjustments, :updated_at, false + change_column_null :spree_calculators, :created_at, false + change_column_null :spree_calculators, :updated_at, false + change_column_null :spree_configurations, :created_at, false + change_column_null :spree_configurations, :updated_at, false + change_column_null :spree_credit_cards, :created_at, false + change_column_null :spree_credit_cards, :updated_at, false + change_column_null :spree_gateways, :created_at, false + change_column_null :spree_gateways, :updated_at, false + change_column_null :spree_inventory_units, :created_at, false + change_column_null :spree_inventory_units, :updated_at, false + change_column_null :spree_line_items, :created_at, false + change_column_null :spree_line_items, :updated_at, false + change_column_null :spree_log_entries, :created_at, false + change_column_null :spree_log_entries, :updated_at, false + change_column_null :spree_option_types, :created_at, false + change_column_null :spree_option_types, :updated_at, false + change_column_null :spree_option_values, :created_at, false + change_column_null :spree_option_values, :updated_at, false + change_column_null :spree_orders, :created_at, false + change_column_null :spree_orders, :updated_at, false + change_column_null :spree_payment_methods, :created_at, false + change_column_null :spree_payment_methods, :updated_at, false + change_column_null :spree_payments, :created_at, false + change_column_null :spree_payments, :updated_at, false + change_column_null :spree_preferences, :created_at, false + change_column_null :spree_preferences, :updated_at, false + change_column_null :spree_product_option_types, :created_at, false + change_column_null :spree_product_option_types, :updated_at, false + change_column_null :spree_product_properties, :created_at, false + change_column_null :spree_product_properties, :updated_at, false + change_column_null :spree_products, :created_at, false + change_column_null :spree_products, :updated_at, false + change_column_null :spree_promotion_rules, :created_at, false + change_column_null :spree_promotion_rules, :updated_at, false + change_column_null :spree_properties, :created_at, false + change_column_null :spree_properties, :updated_at, false + change_column_null :spree_return_authorizations, :created_at, false + change_column_null :spree_return_authorizations, :updated_at, false + change_column_null :spree_shipments, :created_at, false + change_column_null :spree_shipments, :updated_at, false + change_column_null :spree_shipping_categories, :created_at, false + change_column_null :spree_shipping_categories, :updated_at, false + change_column_null :spree_shipping_method_categories, :created_at, false + change_column_null :spree_shipping_method_categories, :updated_at, false + change_column_null :spree_shipping_methods, :created_at, false + change_column_null :spree_shipping_methods, :updated_at, false + change_column_null :spree_shipping_rates, :created_at, false + change_column_null :spree_shipping_rates, :updated_at, false + change_column_null :spree_skrill_transactions, :created_at, false + change_column_null :spree_skrill_transactions, :updated_at, false + change_column_null :spree_state_changes, :created_at, false + change_column_null :spree_state_changes, :updated_at, false + change_column_null :spree_stock_items, :created_at, false + change_column_null :spree_stock_items, :updated_at, false + change_column_null :spree_stock_locations, :created_at, false + change_column_null :spree_stock_locations, :updated_at, false + change_column_null :spree_stock_movements, :created_at, false + change_column_null :spree_stock_movements, :updated_at, false + change_column_null :spree_stock_transfers, :created_at, false + change_column_null :spree_stock_transfers, :updated_at, false + change_column_null :spree_tax_categories, :created_at, false + change_column_null :spree_tax_categories, :updated_at, false + change_column_null :spree_tax_rates, :created_at, false + change_column_null :spree_tax_rates, :updated_at, false + change_column_null :spree_taxonomies, :created_at, false + change_column_null :spree_taxonomies, :updated_at, false + change_column_null :spree_taxons, :created_at, false + change_column_null :spree_taxons, :updated_at, false + change_column_null :spree_tokenized_permissions, :created_at, false + change_column_null :spree_tokenized_permissions, :updated_at, false + change_column_null :spree_users, :created_at, false + change_column_null :spree_users, :updated_at, false + change_column_null :spree_zone_members, :created_at, false + change_column_null :spree_zone_members, :updated_at, false + change_column_null :spree_zones, :created_at, false + change_column_null :spree_zones, :updated_at, false + change_column_null :stripe_accounts, :created_at, false + change_column_null :stripe_accounts, :updated_at, false + change_column_null :subscription_line_items, :created_at, false + change_column_null :subscription_line_items, :updated_at, false + change_column_null :subscriptions, :created_at, false + change_column_null :subscriptions, :updated_at, false + change_column_null :tag_rules, :created_at, false + change_column_null :tag_rules, :updated_at, false + change_column_null :column_preferences, :created_at, false + change_column_null :column_preferences, :updated_at, false + end + + def down + change_column_null :customers, :created_at, true + change_column_null :customers, :updated_at, true + change_column_null :delayed_jobs, :created_at, true + change_column_null :delayed_jobs, :updated_at, true + change_column_null :distributors_shipping_methods, :created_at, true + change_column_null :distributors_shipping_methods, :updated_at, true + change_column_null :enterprise_fees, :created_at, true + change_column_null :enterprise_fees, :updated_at, true + change_column_null :enterprises, :created_at, true + change_column_null :enterprises, :updated_at, true + change_column_null :exchange_fees, :created_at, true + change_column_null :exchange_fees, :updated_at, true + change_column_null :exchange_variants, :created_at, true + change_column_null :exchange_variants, :updated_at, true + change_column_null :exchanges, :created_at, true + change_column_null :exchanges, :updated_at, true + change_column_null :inventory_items, :created_at, true + change_column_null :inventory_items, :updated_at, true + change_column_null :order_cycle_schedules, :created_at, true + change_column_null :order_cycle_schedules, :updated_at, true + change_column_null :order_cycles, :created_at, true + change_column_null :order_cycles, :updated_at, true + change_column_null :producer_properties, :created_at, true + change_column_null :producer_properties, :updated_at, true + change_column_null :proxy_orders, :created_at, true + change_column_null :proxy_orders, :updated_at, true + change_column_null :schedules, :created_at, true + change_column_null :schedules, :updated_at, true + change_column_null :sessions, :created_at, true + change_column_null :sessions, :updated_at, true + change_column_null :spree_activators, :created_at, true + change_column_null :spree_activators, :updated_at, true + change_column_null :spree_addresses, :created_at, true + change_column_null :spree_addresses, :updated_at, true + change_column_null :spree_adjustments, :created_at, true + change_column_null :spree_adjustments, :updated_at, true + change_column_null :spree_calculators, :created_at, true + change_column_null :spree_calculators, :updated_at, true + change_column_null :spree_configurations, :created_at, true + change_column_null :spree_configurations, :updated_at, true + change_column_null :spree_credit_cards, :created_at, true + change_column_null :spree_credit_cards, :updated_at, true + change_column_null :spree_gateways, :created_at, true + change_column_null :spree_gateways, :updated_at, true + change_column_null :spree_inventory_units, :created_at, true + change_column_null :spree_inventory_units, :updated_at, true + change_column_null :spree_line_items, :created_at, true + change_column_null :spree_line_items, :updated_at, true + change_column_null :spree_log_entries, :created_at, true + change_column_null :spree_log_entries, :updated_at, true + change_column_null :spree_option_types, :created_at, true + change_column_null :spree_option_types, :updated_at, true + change_column_null :spree_option_values, :created_at, true + change_column_null :spree_option_values, :updated_at, true + change_column_null :spree_orders, :created_at, true + change_column_null :spree_orders, :updated_at, true + change_column_null :spree_payment_methods, :created_at, true + change_column_null :spree_payment_methods, :updated_at, true + change_column_null :spree_payments, :created_at, true + change_column_null :spree_payments, :updated_at, true + change_column_null :spree_preferences, :created_at, true + change_column_null :spree_preferences, :updated_at, true + change_column_null :spree_product_option_types, :created_at, true + change_column_null :spree_product_option_types, :updated_at, true + change_column_null :spree_product_properties, :created_at, true + change_column_null :spree_product_properties, :updated_at, true + change_column_null :spree_products, :created_at, true + change_column_null :spree_products, :updated_at, true + change_column_null :spree_promotion_rules, :created_at, true + change_column_null :spree_promotion_rules, :updated_at, true + change_column_null :spree_properties, :created_at, true + change_column_null :spree_properties, :updated_at, true + change_column_null :spree_return_authorizations, :created_at, true + change_column_null :spree_return_authorizations, :updated_at, true + change_column_null :spree_shipments, :created_at, true + change_column_null :spree_shipments, :updated_at, true + change_column_null :spree_shipping_categories, :created_at, true + change_column_null :spree_shipping_categories, :updated_at, true + change_column_null :spree_shipping_method_categories, :created_at, true + change_column_null :spree_shipping_method_categories, :updated_at, true + change_column_null :spree_shipping_methods, :created_at, true + change_column_null :spree_shipping_methods, :updated_at, true + change_column_null :spree_shipping_rates, :created_at, true + change_column_null :spree_shipping_rates, :updated_at, true + change_column_null :spree_skrill_transactions, :created_at, true + change_column_null :spree_skrill_transactions, :updated_at, true + change_column_null :spree_state_changes, :created_at, true + change_column_null :spree_state_changes, :updated_at, true + change_column_null :spree_stock_items, :created_at, true + change_column_null :spree_stock_items, :updated_at, true + change_column_null :spree_stock_locations, :created_at, true + change_column_null :spree_stock_locations, :updated_at, true + change_column_null :spree_stock_movements, :created_at, true + change_column_null :spree_stock_movements, :updated_at, true + change_column_null :spree_stock_transfers, :created_at, true + change_column_null :spree_stock_transfers, :updated_at, true + change_column_null :spree_tax_categories, :created_at, true + change_column_null :spree_tax_categories, :updated_at, true + change_column_null :spree_tax_rates, :created_at, true + change_column_null :spree_tax_rates, :updated_at, true + change_column_null :spree_taxonomies, :created_at, true + change_column_null :spree_taxonomies, :updated_at, true + change_column_null :spree_taxons, :created_at, true + change_column_null :spree_taxons, :updated_at, true + change_column_null :spree_tokenized_permissions, :created_at, true + change_column_null :spree_tokenized_permissions, :updated_at, true + change_column_null :spree_users, :created_at, true + change_column_null :spree_users, :updated_at, true + change_column_null :spree_zone_members, :created_at, true + change_column_null :spree_zone_members, :updated_at, true + change_column_null :spree_zones, :created_at, true + change_column_null :spree_zones, :updated_at, true + change_column_null :stripe_accounts, :created_at, true + change_column_null :stripe_accounts, :updated_at, true + change_column_null :subscription_line_items, :created_at, true + change_column_null :subscription_line_items, :updated_at, true + change_column_null :subscriptions, :created_at, true + change_column_null :subscriptions, :updated_at, true + change_column_null :tag_rules, :created_at, true + change_column_null :tag_rules, :updated_at, true + change_column_null :column_preferences, :created_at, true + change_column_null :column_preferences, :updated_at, true + end +end diff --git a/db/schema.rb b/db/schema.rb index 930e3e955d..6867489e98 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200624091611) do +ActiveRecord::Schema.define(version: 20200630070422) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -32,8 +32,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "action_name", null: false t.string "column_name", null: false t.boolean "visible", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "column_preferences", ["user_id", "action_name", "column_name"], name: "index_column_prefs_on_user_id_and_action_name_and_column_name", unique: true, using: :btree @@ -51,8 +51,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "enterprise_id", null: false t.string "code" t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "bill_address_id" t.integer "ship_address_id" t.string "name" @@ -75,8 +75,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.datetime "failed_at" t.string "locked_by" t.string "queue" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree @@ -92,8 +92,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "distributors_shipping_methods", force: true do |t| t.integer "distributor_id" t.integer "shipping_method_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "distributors_shipping_methods", ["distributor_id"], name: "index_distributors_shipping_methods_on_distributor_id", using: :btree @@ -103,8 +103,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "enterprise_id" t.string "fee_type" t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "tax_category_id" t.boolean "inherits_tax_category", default: false, null: false end @@ -190,8 +190,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "address_id" t.text "pickup_times" t.string "next_collection_at" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.text "distributor_info" t.string "logo_file_name" t.string "logo_content_type" @@ -229,8 +229,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "exchange_fees", force: true do |t| t.integer "exchange_id" t.integer "enterprise_fee_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "exchange_fees", ["enterprise_fee_id"], name: "index_exchange_fees_on_enterprise_fee_id", using: :btree @@ -239,8 +239,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "exchange_variants", force: true do |t| t.integer "exchange_id" t.integer "variant_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "exchange_variants", ["exchange_id"], name: "index_exchange_variants_on_exchange_id", using: :btree @@ -252,8 +252,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "receiver_id" t.text "pickup_time" t.text "pickup_instructions" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "incoming", default: false, null: false t.text "receival_instructions" end @@ -266,8 +266,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "enterprise_id", null: false t.integer "variant_id", null: false t.boolean "visible", default: true, null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "inventory_items", ["enterprise_id", "variant_id"], name: "index_inventory_items_on_enterprise_id_and_variant_id", unique: true, using: :btree @@ -275,8 +275,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "order_cycle_schedules", force: true do |t| t.integer "order_cycle_id", null: false t.integer "schedule_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "order_cycle_schedules", ["order_cycle_id"], name: "index_order_cycle_schedules_on_order_cycle_id", using: :btree @@ -287,8 +287,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.datetime "orders_open_at" t.datetime "orders_close_at" t.integer "coordinator_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "producer_properties", force: true do |t| @@ -296,8 +296,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "producer_id" t.integer "property_id" t.integer "position", default: 0, null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "producer_properties", ["position"], name: "index_producer_properties_on_position", using: :btree @@ -308,8 +308,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "subscription_id", null: false t.integer "order_id" t.datetime "canceled_at" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "order_cycle_id", null: false t.datetime "placed_at" t.datetime "confirmed_at" @@ -321,15 +321,15 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "schedules", force: true do |t| t.string "name", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "sessions", force: true do |t| t.string "session_id", null: false t.text "data" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree @@ -338,8 +338,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_activators", force: true do |t| t.string "description" t.datetime "expires_at" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.datetime "starts_at" t.string "name" t.string "event_name" @@ -363,8 +363,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "alternative_phone" t.integer "state_id" t.integer "country_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "company" t.float "latitude" t.float "longitude" @@ -379,8 +379,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "label" t.string "source_type" t.integer "adjustable_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "mandatory" t.integer "originator_id" t.string "originator_type" @@ -413,15 +413,15 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "type" t.integer "calculable_id", null: false t.string "calculable_type", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_configurations", force: true do |t| t.string "name" t.string "type", limit: 50 - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "spree_configurations", ["name", "type"], name: "index_configurations_on_name_and_type", using: :btree @@ -446,8 +446,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "start_year" t.string "issue_number" t.integer "address_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "gateway_customer_profile_id" t.string "gateway_payment_profile_id" t.integer "user_id" @@ -466,16 +466,16 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "environment", default: "development" t.string "server", default: "test" t.boolean "test_mode", default: true - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_inventory_units", force: true do |t| t.string "state" t.integer "variant_id" t.integer "order_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "shipment_id" t.integer "return_authorization_id" t.boolean "pending", default: true @@ -490,8 +490,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "variant_id" t.integer "quantity", null: false t.decimal "price", precision: 8, scale: 2, null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "max_quantity" t.string "currency" t.decimal "distribution_fee", precision: 10, scale: 2 @@ -507,15 +507,15 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "source_id" t.string "source_type" t.text "details" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_option_types", force: true do |t| t.string "name", limit: 100 t.string "presentation", limit: 100 - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "position", default: 0, null: false end @@ -524,8 +524,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "name" t.string "presentation" t.integer "option_type_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_option_values_line_items", id: false, force: true do |t| @@ -550,8 +550,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "state" t.decimal "adjustment_total", precision: 10, scale: 2, default: 0.0, null: false t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.datetime "completed_at" t.integer "bill_address_id" t.integer "ship_address_id" @@ -581,8 +581,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.text "description" t.boolean "active", default: true t.string "environment", default: "development" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.datetime "deleted_at" t.string "display_on" end @@ -590,8 +590,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_payments", force: true do |t| t.decimal "amount", precision: 10, scale: 2, default: 0.0, null: false t.integer "order_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "source_id" t.string "source_type" t.integer "payment_method_id" @@ -635,8 +635,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_preferences", force: true do |t| t.text "value" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "key" t.string "value_type" end @@ -670,16 +670,16 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "position" t.integer "product_id" t.integer "option_type_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_product_properties", force: true do |t| t.string "value" t.integer "product_id" t.integer "property_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "position", default: 0 end @@ -704,8 +704,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "meta_keywords" t.integer "tax_category_id" t.integer "shipping_category_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "supplier_id" t.boolean "group_buy" t.float "group_buy_unit_size" @@ -758,8 +758,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "user_id" t.integer "product_group_id" t.string "type" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "spree_promotion_rules", ["product_group_id"], name: "index_promotion_rules_on_product_group_id", using: :btree @@ -776,8 +776,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_properties", force: true do |t| t.string "name" t.string "presentation", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_return_authorizations", force: true do |t| @@ -786,8 +786,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.decimal "amount", precision: 10, scale: 2, default: 0.0, null: false t.integer "order_id" t.text "reason" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "stock_location_id" end @@ -810,8 +810,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.datetime "shipped_at" t.integer "order_id" t.integer "address_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "state" t.integer "stock_location_id" end @@ -821,16 +821,16 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_shipping_categories", force: true do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "temperature_controlled", default: false, null: false end create_table "spree_shipping_method_categories", force: true do |t| t.integer "shipping_method_id", null: false t.integer "shipping_category_id", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "spree_shipping_method_categories", ["shipping_category_id"], name: "index_spree_shipping_method_categories_on_shipping_category_id", using: :btree @@ -838,8 +838,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_shipping_methods", force: true do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "display_on" t.datetime "deleted_at" t.boolean "require_ship_address", default: true @@ -857,8 +857,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "shipping_method_id" t.boolean "selected", default: false t.decimal "cost", precision: 8, scale: 2, default: 0.0 - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "spree_shipping_rates", ["shipment_id", "shipping_method_id"], name: "spree_shipping_rates_join_index", unique: true, using: :btree @@ -870,8 +870,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "transaction_id" t.integer "customer_id" t.string "payment_type" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_state_changes", force: true do |t| @@ -879,8 +879,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "previous_state" t.integer "stateful_id" t.integer "user_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "stateful_type" t.string "next_state" end @@ -895,8 +895,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "stock_location_id" t.integer "variant_id" t.integer "count_on_hand", default: 0, null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "backorderable", default: false t.datetime "deleted_at" end @@ -907,8 +907,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_stock_locations", force: true do |t| t.string "name" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "address1" t.string "address2" t.string "city" @@ -926,8 +926,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "stock_item_id" t.integer "quantity", default: 0 t.string "action" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "originator_id" t.string "originator_type" end @@ -939,8 +939,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "reference" t.integer "source_location_id" t.integer "destination_location_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "number" end @@ -951,8 +951,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_tax_categories", force: true do |t| t.string "name" t.string "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "is_default", default: false t.datetime "deleted_at" end @@ -961,8 +961,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.decimal "amount", precision: 8, scale: 5 t.integer "zone_id" t.integer "tax_category_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "included_in_price", default: false t.string "name" t.boolean "show_rate_in_label", default: true @@ -971,8 +971,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "spree_taxonomies", force: true do |t| t.string "name", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "position", default: 0 end @@ -982,8 +982,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "name", null: false t.string "permalink" t.integer "taxonomy_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "lft" t.integer "rgt" t.string "icon_file_name" @@ -1004,8 +1004,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "permissable_id" t.string "permissable_type" t.string "token" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end add_index "spree_tokenized_permissions", ["permissable_id", "permissable_type"], name: "index_tokenized_name_and_type", using: :btree @@ -1028,8 +1028,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.string "login" t.integer "ship_address_id" t.integer "bill_address_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.string "authentication_token" t.string "unlock_token" t.datetime "locked_at" @@ -1075,15 +1075,15 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "zoneable_id" t.string "zoneable_type" t.integer "zone_id" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "spree_zones", force: true do |t| t.string "name" t.string "description" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "default_tax", default: false t.integer "zone_members_count", default: 0 end @@ -1091,8 +1091,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "stripe_accounts", force: true do |t| t.string "stripe_user_id" t.string "stripe_publishable_key" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "enterprise_id" end @@ -1102,8 +1102,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "subscription_id", null: false t.integer "variant_id", null: false t.integer "quantity", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.decimal "price_estimate", precision: 8, scale: 2 end @@ -1118,8 +1118,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do t.integer "shipping_method_id", null: false t.datetime "begins_at" t.datetime "ends_at" - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.integer "bill_address_id", null: false t.integer "ship_address_id", null: false t.datetime "canceled_at" @@ -1147,8 +1147,8 @@ ActiveRecord::Schema.define(version: 20200624091611) do create_table "tag_rules", force: true do |t| t.integer "enterprise_id", null: false t.string "type", null: false - t.datetime "created_at" - t.datetime "updated_at" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "is_default", default: false, null: false t.integer "priority", default: 99, null: false end From abe96c6f32553107ea1119089ad65dec5fc8bfde Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 11:21:29 +0200 Subject: [PATCH 080/261] Add specs for updating existing default addresses during checkout These specs fail with the "NULL values for created_at / updated_at" errors we've been seeing. --- .../consumer/shopping/checkout_spec.rb | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index a6135bf88c..4f24532212 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -74,7 +74,7 @@ feature "As a consumer I want to check out my cart", js: true do fill_out_form end - it "allows user to save default billing address and shipping address" do + it "creates a new default billing address and shipping address" do expect(user.bill_address).to be_nil expect(user.ship_address).to be_nil @@ -94,6 +94,32 @@ feature "As a consumer I want to check out my cart", js: true do expect(user.reload.ship_address.address1).to eq '123 Your Head' end + context "when the user and customer have existing default addresses" do + let(:existing_address) { create(:address) } + + before do + user.bill_address = existing_address + user.ship_address = existing_address + end + + xit "updates billing address and shipping address" do + expect(order.bill_address).to be_nil + expect(order.ship_address).to be_nil + + place_order + expect(page).to have_content "Your order has been processed successfully" + + expect(order.reload.bill_address.address1).to eq '123 Your Head' + expect(order.reload.ship_address.address1).to eq '123 Your Head' + + expect(order.customer.bill_address.address1).to eq '123 Your Head' + expect(order.customer.ship_address.address1).to eq '123 Your Head' + + expect(user.reload.bill_address.address1).to eq '123 Your Head' + expect(user.reload.ship_address.address1).to eq '123 Your Head' + end + end + it "it doesn't tell about previous orders" do expect(page).to have_no_content("You have an order for this order cycle already.") end From ce8908f53b713ba915dcc272d9cbf4db9769938c Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Mon, 29 Jun 2020 19:54:28 +0200 Subject: [PATCH 081/261] Use #dup when copying attributes hash In Rails 4, #clone behaves differently. The attributes hash of the cloned object is shared with the original, it's not a separate object! https://github.com/rails/rails/blob/4-0-stable/activerecord/lib/active_record/core.rb#L217-L220 --- app/services/user_default_address_setter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/user_default_address_setter.rb b/app/services/user_default_address_setter.rb index 7a83078290..0746bae8cf 100644 --- a/app/services/user_default_address_setter.rb +++ b/app/services/user_default_address_setter.rb @@ -9,7 +9,7 @@ class UserDefaultAddressSetter # Sets the order bill address as the user default bill address def set_default_bill_address - new_bill_address = @order.bill_address.clone.attributes + new_bill_address = @order.bill_address.dup.attributes set_bill_address_attributes(@current_user, new_bill_address) set_bill_address_attributes(@order.customer, new_bill_address) @@ -17,7 +17,7 @@ class UserDefaultAddressSetter # Sets the order ship address as the user default ship address def set_default_ship_address - new_ship_address = @order.ship_address.clone.attributes + new_ship_address = @order.ship_address.dup.attributes set_ship_address_attributes(@current_user, new_ship_address) set_ship_address_attributes(@order.customer, new_ship_address) From 87cd936c9413d9ec84bf1137038f5a9124487376 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 09:12:49 +0200 Subject: [PATCH 082/261] Blacklist timestamp attributes when assigning for update Doing #clone or #dup of an object's attributes then passing it to an #update/#update_attributes call means we are manually passing values for created_at and updated_at, which can cause problems, especially if the object being duped hasn't been persisted yet: in this case we would be manually attempting to save timestamps with nil values, which is not a good idea. Here they are blacklisted from the attributes hash. --- app/services/user_default_address_setter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/user_default_address_setter.rb b/app/services/user_default_address_setter.rb index 0746bae8cf..20a80afc3d 100644 --- a/app/services/user_default_address_setter.rb +++ b/app/services/user_default_address_setter.rb @@ -9,7 +9,7 @@ class UserDefaultAddressSetter # Sets the order bill address as the user default bill address def set_default_bill_address - new_bill_address = @order.bill_address.dup.attributes + new_bill_address = @order.bill_address.dup.attributes.except!('created_at', 'updated_at') set_bill_address_attributes(@current_user, new_bill_address) set_bill_address_attributes(@order.customer, new_bill_address) @@ -17,7 +17,7 @@ class UserDefaultAddressSetter # Sets the order ship address as the user default ship address def set_default_ship_address - new_ship_address = @order.ship_address.dup.attributes + new_ship_address = @order.ship_address.dup.attributes.except!('created_at', 'updated_at') set_ship_address_attributes(@current_user, new_ship_address) set_ship_address_attributes(@order.customer, new_ship_address) From 3e7f5a4ea99f6dd876715ffb7d8a25a889582f6c Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 10:38:08 +0200 Subject: [PATCH 083/261] Update user address tests I considered deleting these tests, as they're not very good and are testing Rails functionality. I decided to leave them in case something explodes in a future upgrade. For reference: there are issues in Rails 4 when using `object.clone.attributes`, and with assigning a hash containing `created_at` and `updated_at` values with `object.update(attributes_hash)`. --- spec/models/spree/user_spec.rb | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/spec/models/spree/user_spec.rb b/spec/models/spree/user_spec.rb index 0e48621452..ba5b4cd488 100644 --- a/spec/models/spree/user_spec.rb +++ b/spec/models/spree/user_spec.rb @@ -9,23 +9,25 @@ describe Spree.user_class do describe "addresses" do let(:user) { create(:user, bill_address: create(:address)) } - it 'updates billing address with new address' do - old_bill_address = user.bill_address - new_bill_address = create(:address, firstname: 'abc') + context "updating addresses via nested attributes" do + it 'updates billing address with new address' do + old_bill_address = user.bill_address + new_bill_address = create(:address, firstname: 'abc') - user.update(bill_address_attributes: new_bill_address.clone.attributes.merge('id' => old_bill_address.id)) + user.update(bill_address_attributes: new_bill_address.dup.attributes.merge('id' => old_bill_address.id).except!('created_at', 'updated_at')) - expect(user.bill_address.id).to eq old_bill_address.id - expect(user.bill_address.firstname).to eq new_bill_address.firstname - end + expect(user.bill_address.id).to eq old_bill_address.id + expect(user.bill_address.firstname).to eq new_bill_address.firstname + end - it 'creates new shipping address' do - new_ship_address = create(:address, firstname: 'abc') + it 'creates new shipping address' do + new_ship_address = create(:address, firstname: 'abc') - user.update(ship_address_attributes: new_ship_address.clone.attributes) + user.update(ship_address_attributes: new_ship_address.dup.attributes.except!('created_at', 'updated_at')) - expect(user.ship_address.id).not_to eq new_ship_address.id - expect(user.ship_address.firstname).to eq new_ship_address.firstname + expect(user.ship_address.id).not_to eq new_ship_address.id + expect(user.ship_address.firstname).to eq new_ship_address.firstname + end end end From 11da38562482a5616c1cb3cf164f3290af1b9169 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 11:23:04 +0200 Subject: [PATCH 084/261] Enable pending checkout spec --- spec/features/consumer/shopping/checkout_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index 4f24532212..76983d030b 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -102,7 +102,7 @@ feature "As a consumer I want to check out my cart", js: true do user.ship_address = existing_address end - xit "updates billing address and shipping address" do + it "updates billing address and shipping address" do expect(order.bill_address).to be_nil expect(order.ship_address).to be_nil From 2dce10bec280ef7d1ef70937741e1902a24bd86c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 30 Jun 2020 10:49:45 +0100 Subject: [PATCH 085/261] Fix admin enterprises controller spec, for some reason the correct controller is not being picked up in the test --- .../admin/enterprises_controller_spec.rb | 958 +++++++++--------- 1 file changed, 478 insertions(+), 480 deletions(-) diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb index a95334d292..054b37e2de 100644 --- a/spec/controllers/admin/enterprises_controller_spec.rb +++ b/spec/controllers/admin/enterprises_controller_spec.rb @@ -1,561 +1,559 @@ require 'spec_helper' require 'open_food_network/order_cycle_permissions' -module Admin - describe EnterprisesController, type: :controller do - include AuthenticationWorkflow +describe Admin::EnterprisesController, type: :controller do + include AuthenticationWorkflow - let(:user) { create(:user) } - let(:admin_user) { create(:admin_user) } - let(:distributor_manager) { create(:user, enterprise_limit: 10, enterprises: [distributor]) } - let(:supplier_manager) { create(:user, enterprise_limit: 10, enterprises: [supplier]) } - let(:distributor_owner) { create(:user, enterprise_limit: 10) } - let(:supplier_owner) { create(:user) } + let(:user) { create(:user) } + let(:admin_user) { create(:admin_user) } + let(:distributor_manager) { create(:user, enterprise_limit: 10, enterprises: [distributor]) } + let(:supplier_manager) { create(:user, enterprise_limit: 10, enterprises: [supplier]) } + let(:distributor_owner) { create(:user, enterprise_limit: 10) } + let(:supplier_owner) { create(:user) } - let(:distributor) { create(:distributor_enterprise, owner: distributor_owner ) } - let(:supplier) { create(:supplier_enterprise, owner: supplier_owner) } + let(:distributor) { create(:distributor_enterprise, owner: distributor_owner ) } + let(:supplier) { create(:supplier_enterprise, owner: supplier_owner) } - before { @request.env['HTTP_REFERER'] = 'http://test.com/' } + before { @request.env['HTTP_REFERER'] = 'http://test.com/' } - describe "creating an enterprise" do - let(:country) { Spree::Country.find_by name: 'Australia' } - let(:state) { Spree::State.find_by name: 'Victoria' } - let(:enterprise_params) { { enterprise: { name: 'zzz', permalink: 'zzz', is_primary_producer: '0', address_attributes: { address1: 'a', city: 'a', zipcode: 'a', country_id: country.id, state_id: state.id } } } } + describe "creating an enterprise" do + let(:country) { Spree::Country.find_by name: 'Australia' } + let(:state) { Spree::State.find_by name: 'Victoria' } + let(:enterprise_params) { { enterprise: { name: 'zzz', permalink: 'zzz', is_primary_producer: '0', address_attributes: { address1: 'a', city: 'a', zipcode: 'a', country_id: country.id, state_id: state.id } } } } - it "grants management permission if the current user is an enterprise user" do - allow(controller).to receive_messages spree_current_user: distributor_manager - enterprise_params[:enterprise][:owner_id] = distributor_manager + it "grants management permission if the current user is an enterprise user" do + allow(controller).to receive_messages spree_current_user: distributor_manager + enterprise_params[:enterprise][:owner_id] = distributor_manager + + spree_put :create, enterprise_params + enterprise = Enterprise.find_by name: 'zzz' + expect(response).to redirect_to edit_admin_enterprise_path enterprise + expect(distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first).to be + end + + it "overrides the owner_id submitted by the user (when not super admin)" do + allow(controller).to receive_messages spree_current_user: distributor_manager + enterprise_params[:enterprise][:owner_id] = user + + spree_put :create, enterprise_params + enterprise = Enterprise.find_by name: 'zzz' + expect(response).to redirect_to edit_admin_enterprise_path enterprise + expect(distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first).to be + end + + context "when I already own a hub" do + before { distributor } + + it "creates new non-producers as hubs" do + allow(controller).to receive_messages spree_current_user: distributor_owner + enterprise_params[:enterprise][:owner_id] = distributor_owner spree_put :create, enterprise_params enterprise = Enterprise.find_by name: 'zzz' expect(response).to redirect_to edit_admin_enterprise_path enterprise - expect(distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first).to be + expect(enterprise.sells).to eq('any') end - it "overrides the owner_id submitted by the user (when not super admin)" do - allow(controller).to receive_messages spree_current_user: distributor_manager - enterprise_params[:enterprise][:owner_id] = user + it "creates new producers as sells none" do + allow(controller).to receive_messages spree_current_user: distributor_owner + enterprise_params[:enterprise][:owner_id] = distributor_owner + enterprise_params[:enterprise][:is_primary_producer] = '1' spree_put :create, enterprise_params enterprise = Enterprise.find_by name: 'zzz' expect(response).to redirect_to edit_admin_enterprise_path enterprise - expect(distributor_manager.enterprise_roles.where(enterprise_id: enterprise).first).to be + expect(enterprise.sells).to eq('none') end - context "when I already own a hub" do - before { distributor } + it "doesn't affect the hub status for super admins" do + admin_user.enterprises << create(:distributor_enterprise) - it "creates new non-producers as hubs" do - allow(controller).to receive_messages spree_current_user: distributor_owner - enterprise_params[:enterprise][:owner_id] = distributor_owner + allow(controller).to receive_messages spree_current_user: admin_user + enterprise_params[:enterprise][:owner_id] = admin_user + enterprise_params[:enterprise][:sells] = 'none' - spree_put :create, enterprise_params - enterprise = Enterprise.find_by name: 'zzz' - expect(response).to redirect_to edit_admin_enterprise_path enterprise - expect(enterprise.sells).to eq('any') - end - - it "creates new producers as sells none" do - allow(controller).to receive_messages spree_current_user: distributor_owner - enterprise_params[:enterprise][:owner_id] = distributor_owner - enterprise_params[:enterprise][:is_primary_producer] = '1' - - spree_put :create, enterprise_params - enterprise = Enterprise.find_by name: 'zzz' - expect(response).to redirect_to edit_admin_enterprise_path enterprise - expect(enterprise.sells).to eq('none') - end - - it "doesn't affect the hub status for super admins" do - admin_user.enterprises << create(:distributor_enterprise) - - allow(controller).to receive_messages spree_current_user: admin_user - enterprise_params[:enterprise][:owner_id] = admin_user - enterprise_params[:enterprise][:sells] = 'none' - - spree_put :create, enterprise_params - enterprise = Enterprise.find_by name: 'zzz' - expect(response).to redirect_to edit_admin_enterprise_path enterprise - expect(enterprise.sells).to eq('none') - end - end - - context "when I do not have a hub" do - it "does not create the new enterprise as a hub" do - allow(controller).to receive_messages spree_current_user: supplier_manager - enterprise_params[:enterprise][:owner_id] = supplier_manager - - spree_put :create, enterprise_params - enterprise = Enterprise.find_by name: 'zzz' - expect(enterprise.sells).to eq('none') - end - - it "doesn't affect the hub status for super admins" do - allow(controller).to receive_messages spree_current_user: admin_user - enterprise_params[:enterprise][:owner_id] = admin_user - enterprise_params[:enterprise][:sells] = 'any' - - spree_put :create, enterprise_params - enterprise = Enterprise.find_by name: 'zzz' - expect(enterprise.sells).to eq('any') - end + spree_put :create, enterprise_params + enterprise = Enterprise.find_by name: 'zzz' + expect(response).to redirect_to edit_admin_enterprise_path enterprise + expect(enterprise.sells).to eq('none') end end - describe "updating an enterprise" do - let(:profile_enterprise) { create(:enterprise, sells: 'none') } + context "when I do not have a hub" do + it "does not create the new enterprise as a hub" do + allow(controller).to receive_messages spree_current_user: supplier_manager + enterprise_params[:enterprise][:owner_id] = supplier_manager - context "as manager" do - it "does not allow 'sells' to be changed" do - profile_enterprise.enterprise_roles.build(user: distributor_manager).save - allow(controller).to receive_messages spree_current_user: distributor_manager - enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } - - spree_put :update, enterprise_params - profile_enterprise.reload - expect(profile_enterprise.sells).to eq 'none' - end - - it "does not allow owner to be changed" do - allow(controller).to receive_messages spree_current_user: distributor_manager - update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } - spree_post :update, update_params - - distributor.reload - expect(distributor.owner).to eq distributor_owner - end - - it "does not allow managers to be changed" do - allow(controller).to receive_messages spree_current_user: distributor_manager - update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } - spree_post :update, update_params - - distributor.reload - expect(distributor.users).to_not include user - end - - describe "enterprise properties" do - let(:producer) { create(:enterprise) } - let!(:property) { create(:property, name: "A nice name") } - - before do - login_as_enterprise_user [producer] - end - - context "when a submitted property does not already exist" do - it "does not create a new property, or product property" do - spree_put :update, - id: producer, - enterprise: { - producer_properties_attributes: { - '0' => { property_name: 'a different name', value: 'something' } - } - } - expect(Spree::Property.count).to be 1 - expect(ProducerProperty.count).to be 0 - property_names = producer.reload.properties.map(&:name) - expect(property_names).to_not include 'a different name' - end - end - - context "when a submitted property exists" do - it "adds a product property" do - spree_put :update, - id: producer, - enterprise: { - producer_properties_attributes: { - '0' => { property_name: 'A nice name', value: 'something' } - } - } - expect(Spree::Property.count).to be 1 - expect(ProducerProperty.count).to be 1 - property_names = producer.reload.properties.map(&:name) - expect(property_names).to include 'A nice name' - end - end - end - - describe "tag rules" do - let(:enterprise) { create(:distributor_enterprise) } - let!(:tag_rule) { create(:tag_rule, enterprise: enterprise) } - - before do - login_as_enterprise_user [enterprise] - end - - context "discount order rules" do - it "updates the existing rule with new attributes" do - spree_put :update, - id: enterprise, - enterprise: { - tag_rules_attributes: { - '0' => { - id: tag_rule, - type: "TagRule::DiscountOrder", - preferred_customer_tags: "some,new,tags", - calculator_type: "Spree::Calculator::FlatPercentItemTotal", - calculator_attributes: { id: tag_rule.calculator.id, preferred_flat_percent: "15" } - } - } - } - tag_rule.reload - expect(tag_rule.preferred_customer_tags).to eq "some,new,tags" - expect(tag_rule.calculator.preferred_flat_percent).to eq 15 - end - - it "creates new rules with new attributes" do - spree_put :update, - id: enterprise, - enterprise: { - tag_rules_attributes: { - '0' => { - id: "", - type: "TagRule::DiscountOrder", - preferred_customer_tags: "tags,are,awesome", - calculator_type: "Spree::Calculator::FlatPercentItemTotal", - calculator_attributes: { id: "", preferred_flat_percent: "24" } - } - } - } - expect(tag_rule.reload).to be - new_tag_rule = TagRule::DiscountOrder.last - expect(new_tag_rule.preferred_customer_tags).to eq "tags,are,awesome" - expect(new_tag_rule.calculator.preferred_flat_percent).to eq 24 - end - end - end + spree_put :create, enterprise_params + enterprise = Enterprise.find_by name: 'zzz' + expect(enterprise.sells).to eq('none') end - context "as owner" do - it "allows 'sells' to be changed" do - allow(controller).to receive_messages spree_current_user: profile_enterprise.owner - enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } + it "doesn't affect the hub status for super admins" do + allow(controller).to receive_messages spree_current_user: admin_user + enterprise_params[:enterprise][:owner_id] = admin_user + enterprise_params[:enterprise][:sells] = 'any' - spree_put :update, enterprise_params - profile_enterprise.reload - expect(profile_enterprise.sells).to eq 'any' - end - - it "allows owner to be changed" do - allow(controller).to receive_messages spree_current_user: distributor_owner - update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } - spree_post :update, update_params - - distributor.reload - expect(distributor.owner).to eq distributor_manager - end - - it "allows managers to be changed" do - allow(controller).to receive_messages spree_current_user: distributor_owner - update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } - spree_post :update, update_params - - distributor.reload - expect(distributor.users).to include user - end - end - - context "as super admin" do - it "allows 'sells' to be changed" do - allow(controller).to receive_messages spree_current_user: admin_user - enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } - - spree_put :update, enterprise_params - profile_enterprise.reload - expect(profile_enterprise.sells).to eq 'any' - end - - it "allows owner to be changed" do - allow(controller).to receive_messages spree_current_user: admin_user - update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } - spree_post :update, update_params - - distributor.reload - expect(distributor.owner).to eq distributor_manager - end - - it "allows managers to be changed" do - allow(controller).to receive_messages spree_current_user: admin_user - update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } - spree_post :update, update_params - - distributor.reload - expect(distributor.users).to include user - end + spree_put :create, enterprise_params + enterprise = Enterprise.find_by name: 'zzz' + expect(enterprise.sells).to eq('any') end end + end - describe "register" do - let(:enterprise) { create(:enterprise, sells: 'none') } + describe "updating an enterprise" do + let(:profile_enterprise) { create(:enterprise, sells: 'none') } + + context "as manager" do + it "does not allow 'sells' to be changed" do + profile_enterprise.enterprise_roles.build(user: distributor_manager).save + allow(controller).to receive_messages spree_current_user: distributor_manager + enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } + + spree_put :update, enterprise_params + profile_enterprise.reload + expect(profile_enterprise.sells).to eq 'none' + end + + it "does not allow owner to be changed" do + allow(controller).to receive_messages spree_current_user: distributor_manager + update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } + spree_post :update, update_params + + distributor.reload + expect(distributor.owner).to eq distributor_owner + end + + it "does not allow managers to be changed" do + allow(controller).to receive_messages spree_current_user: distributor_manager + update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } + spree_post :update, update_params + + distributor.reload + expect(distributor.users).to_not include user + end + + describe "enterprise properties" do + let(:producer) { create(:enterprise) } + let!(:property) { create(:property, name: "A nice name") } - context "as a normal user" do before do - allow(controller).to receive_messages spree_current_user: distributor_manager + login_as_enterprise_user [producer] end - it "does not allow access" do - spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path + context "when a submitted property does not already exist" do + it "does not create a new property, or product property" do + spree_put :update, + id: producer, + enterprise: { + producer_properties_attributes: { + '0' => { property_name: 'a different name', value: 'something' } + } + } + expect(Spree::Property.count).to be 1 + expect(ProducerProperty.count).to be 0 + property_names = producer.reload.properties.map(&:name) + expect(property_names).to_not include 'a different name' + end + end + + context "when a submitted property exists" do + it "adds a product property" do + spree_put :update, + id: producer, + enterprise: { + producer_properties_attributes: { + '0' => { property_name: 'A nice name', value: 'something' } + } + } + expect(Spree::Property.count).to be 1 + expect(ProducerProperty.count).to be 1 + property_names = producer.reload.properties.map(&:name) + expect(property_names).to include 'A nice name' + end end end - context "as a manager" do + describe "tag rules" do + let(:enterprise) { create(:distributor_enterprise) } + let!(:tag_rule) { create(:tag_rule, enterprise: enterprise) } + before do - allow(controller).to receive_messages spree_current_user: distributor_manager - enterprise.enterprise_roles.build(user: distributor_manager).save + login_as_enterprise_user [enterprise] end - it "does not allow access" do - spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path - end - end - - context "as an owner" do - before do - allow(controller).to receive_messages spree_current_user: enterprise.owner - end - - context "setting 'sells' to 'none'" do - it "is allowed" do - spree_post :register, id: enterprise, sells: 'none' - expect(response).to redirect_to spree.admin_dashboard_path - expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!" - expect(enterprise.reload.sells).to eq 'none' - end - end - - context "setting producer_profile_only" do - it "is ignored" do - spree_post :register, id: enterprise, sells: 'none', producer_profile_only: true - expect(response).to redirect_to spree.admin_dashboard_path - expect(enterprise.reload.producer_profile_only).to be false - end - end - - context "setting 'sells' to 'own'" do - before do - enterprise.sells = 'none' - enterprise.save! + context "discount order rules" do + it "updates the existing rule with new attributes" do + spree_put :update, + id: enterprise, + enterprise: { + tag_rules_attributes: { + '0' => { + id: tag_rule, + type: "TagRule::DiscountOrder", + preferred_customer_tags: "some,new,tags", + calculator_type: "Spree::Calculator::FlatPercentItemTotal", + calculator_attributes: { id: tag_rule.calculator.id, preferred_flat_percent: "15" } + } + } + } + tag_rule.reload + expect(tag_rule.preferred_customer_tags).to eq "some,new,tags" + expect(tag_rule.calculator.preferred_flat_percent).to eq 15 end - it "is allowed" do - spree_post :register, id: enterprise, sells: 'own' - expect(response).to redirect_to spree.admin_dashboard_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 - it "is allowed" do - spree_post :register, id: enterprise, sells: 'any' - expect(response).to redirect_to spree.admin_dashboard_path - expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!" - expect(enterprise.reload.sells).to eq 'any' - end - end - - context "settiing 'sells' to 'unspecified'" do - it "is not allowed" do - spree_post :register, id: enterprise, sells: 'unspecified' - expect(response).to render_template :welcome - expect(flash[:error]).to eq "Please select a package" + it "creates new rules with new attributes" do + spree_put :update, + id: enterprise, + enterprise: { + tag_rules_attributes: { + '0' => { + id: "", + type: "TagRule::DiscountOrder", + preferred_customer_tags: "tags,are,awesome", + calculator_type: "Spree::Calculator::FlatPercentItemTotal", + calculator_attributes: { id: "", preferred_flat_percent: "24" } + } + } + } + expect(tag_rule.reload).to be + new_tag_rule = TagRule::DiscountOrder.last + expect(new_tag_rule.preferred_customer_tags).to eq "tags,are,awesome" + expect(new_tag_rule.calculator.preferred_flat_percent).to eq 24 end end end end - describe "bulk updating enterprises" do - let!(:original_owner) do - user = create_enterprise_user - user.enterprise_limit = 2 - user.save! - user - end - let!(:new_owner) do - user = create_enterprise_user - user.enterprise_limit = 2 - user.save! - user - end - let!(:profile_enterprise1) { create(:enterprise, sells: 'none', owner: original_owner ) } - let!(:profile_enterprise2) { create(:enterprise, sells: 'none', owner: original_owner ) } + context "as owner" do + it "allows 'sells' to be changed" do + allow(controller).to receive_messages spree_current_user: profile_enterprise.owner + enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } - context "as manager" do - it "does not allow 'sells' or 'owner' to be changed" do - profile_enterprise1.enterprise_roles.build(user: new_owner).save - profile_enterprise2.enterprise_roles.build(user: new_owner).save - allow(controller).to receive_messages spree_current_user: new_owner - bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } - - spree_put :bulk_update, bulk_enterprise_params - profile_enterprise1.reload - profile_enterprise2.reload - expect(profile_enterprise1.sells).to eq 'none' - expect(profile_enterprise2.sells).to eq 'none' - expect(profile_enterprise1.owner).to eq original_owner - expect(profile_enterprise2.owner).to eq original_owner - end - - it "cuts down the list of enterprises displayed when error received on bulk update" do - allow_any_instance_of(EnterpriseSet).to receive(:save) { false } - profile_enterprise1.enterprise_roles.build(user: new_owner).save - allow(controller).to receive_messages spree_current_user: new_owner - bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, visible: 'false' } } } } - spree_put :bulk_update, bulk_enterprise_params - expect(assigns(:enterprise_set).collection).to eq [profile_enterprise1] - end + spree_put :update, enterprise_params + profile_enterprise.reload + expect(profile_enterprise.sells).to eq 'any' end - context "as the owner of an enterprise" do - it "allows 'sells' and 'owner' to be changed" do - allow(controller).to receive_messages spree_current_user: original_owner - bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } + it "allows owner to be changed" do + allow(controller).to receive_messages spree_current_user: distributor_owner + update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } + spree_post :update, update_params - spree_put :bulk_update, bulk_enterprise_params - profile_enterprise1.reload - profile_enterprise2.reload - expect(profile_enterprise1.sells).to eq 'any' - expect(profile_enterprise2.sells).to eq 'any' - expect(profile_enterprise1.owner).to eq original_owner - expect(profile_enterprise2.owner).to eq original_owner - end + distributor.reload + expect(distributor.owner).to eq distributor_manager end - context "as super admin" do - it "allows 'sells' and 'owner' to be changed" do - profile_enterprise1.enterprise_roles.build(user: new_owner).save - profile_enterprise2.enterprise_roles.build(user: new_owner).save - allow(controller).to receive_messages spree_current_user: admin_user - bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } + it "allows managers to be changed" do + allow(controller).to receive_messages spree_current_user: distributor_owner + update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } + spree_post :update, update_params - spree_put :bulk_update, bulk_enterprise_params - profile_enterprise1.reload - profile_enterprise2.reload - expect(profile_enterprise1.sells).to eq 'any' - expect(profile_enterprise2.sells).to eq 'any' - expect(profile_enterprise1.owner).to eq new_owner - expect(profile_enterprise2.owner).to eq new_owner - end + distributor.reload + expect(distributor.users).to include user end end - describe "for_order_cycle" do - let!(:user) { create_enterprise_user } - let!(:enterprise) { create(:enterprise, sells: 'any', owner: user) } - let(:permission_mock) { double(:permission) } + context "as super admin" do + it "allows 'sells' to be changed" do + allow(controller).to receive_messages spree_current_user: admin_user + enterprise_params = { id: profile_enterprise, enterprise: { sells: 'any' } } + + spree_put :update, enterprise_params + profile_enterprise.reload + expect(profile_enterprise.sells).to eq 'any' + end + + it "allows owner to be changed" do + allow(controller).to receive_messages spree_current_user: admin_user + update_params = { id: distributor, enterprise: { owner_id: distributor_manager } } + spree_post :update, update_params + + distributor.reload + expect(distributor.owner).to eq distributor_manager + end + + it "allows managers to be changed" do + allow(controller).to receive_messages spree_current_user: admin_user + update_params = { id: distributor, enterprise: { user_ids: [distributor_owner.id, distributor_manager.id, user.id] } } + spree_post :update, update_params + + distributor.reload + expect(distributor.users).to include user + end + end + end + + describe "register" do + let(:enterprise) { create(:enterprise, sells: 'none') } + + context "as a normal user" do + before do + allow(controller).to receive_messages spree_current_user: distributor_manager + end + + it "does not allow access" do + spree_post :register, id: enterprise.id, sells: 'none' + expect(response).to redirect_to spree.unauthorized_path + end + end + + context "as a manager" do + before do + allow(controller).to receive_messages spree_current_user: distributor_manager + enterprise.enterprise_roles.build(user: distributor_manager).save + end + + it "does not allow access" do + spree_post :register, id: enterprise.id, sells: 'none' + expect(response).to redirect_to spree.unauthorized_path + end + end + + context "as an owner" do + before do + allow(controller).to receive_messages spree_current_user: enterprise.owner + end + + context "setting 'sells' to 'none'" do + it "is allowed" do + spree_post :register, id: enterprise, sells: 'none' + expect(response).to redirect_to spree.admin_dashboard_path + expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!" + expect(enterprise.reload.sells).to eq 'none' + end + end + + context "setting producer_profile_only" do + it "is ignored" do + spree_post :register, id: enterprise, sells: 'none', producer_profile_only: true + expect(response).to redirect_to spree.admin_dashboard_path + expect(enterprise.reload.producer_profile_only).to be false + end + end + + context "setting 'sells' to 'own'" do + before do + enterprise.sells = 'none' + enterprise.save! + end + + it "is allowed" do + spree_post :register, id: enterprise, sells: 'own' + expect(response).to redirect_to spree.admin_dashboard_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 + it "is allowed" do + spree_post :register, id: enterprise, sells: 'any' + expect(response).to redirect_to spree.admin_dashboard_path + expect(flash[:success]).to eq "Congratulations! Registration for #{enterprise.name} is complete!" + expect(enterprise.reload.sells).to eq 'any' + end + end + + context "settiing 'sells' to 'unspecified'" do + it "is not allowed" do + spree_post :register, id: enterprise, sells: 'unspecified' + expect(response).to render_template :welcome + expect(flash[:error]).to eq "Please select a package" + end + end + end + end + + describe "bulk updating enterprises" do + let!(:original_owner) do + user = create_enterprise_user + user.enterprise_limit = 2 + user.save! + user + end + let!(:new_owner) do + user = create_enterprise_user + user.enterprise_limit = 2 + user.save! + user + end + let!(:profile_enterprise1) { create(:enterprise, sells: 'none', owner: original_owner ) } + let!(:profile_enterprise2) { create(:enterprise, sells: 'none', owner: original_owner ) } + + context "as manager" do + it "does not allow 'sells' or 'owner' to be changed" do + profile_enterprise1.enterprise_roles.build(user: new_owner).save + profile_enterprise2.enterprise_roles.build(user: new_owner).save + allow(controller).to receive_messages spree_current_user: new_owner + bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } + + spree_put :bulk_update, bulk_enterprise_params + profile_enterprise1.reload + profile_enterprise2.reload + expect(profile_enterprise1.sells).to eq 'none' + expect(profile_enterprise2.sells).to eq 'none' + expect(profile_enterprise1.owner).to eq original_owner + expect(profile_enterprise2.owner).to eq original_owner + end + + it "cuts down the list of enterprises displayed when error received on bulk update" do + allow_any_instance_of(EnterpriseSet).to receive(:save) { false } + profile_enterprise1.enterprise_roles.build(user: new_owner).save + allow(controller).to receive_messages spree_current_user: new_owner + bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, visible: 'false' } } } } + spree_put :bulk_update, bulk_enterprise_params + expect(assigns(:enterprise_set).collection).to eq [profile_enterprise1] + end + end + + context "as the owner of an enterprise" do + it "allows 'sells' and 'owner' to be changed" do + allow(controller).to receive_messages spree_current_user: original_owner + bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } + + spree_put :bulk_update, bulk_enterprise_params + profile_enterprise1.reload + profile_enterprise2.reload + expect(profile_enterprise1.sells).to eq 'any' + expect(profile_enterprise2.sells).to eq 'any' + expect(profile_enterprise1.owner).to eq original_owner + expect(profile_enterprise2.owner).to eq original_owner + end + end + + context "as super admin" do + it "allows 'sells' and 'owner' to be changed" do + profile_enterprise1.enterprise_roles.build(user: new_owner).save + profile_enterprise2.enterprise_roles.build(user: new_owner).save + allow(controller).to receive_messages spree_current_user: admin_user + bulk_enterprise_params = { enterprise_set: { collection_attributes: { '0' => { id: profile_enterprise1.id, sells: 'any', owner_id: new_owner.id }, '1' => { id: profile_enterprise2.id, sells: 'any', owner_id: new_owner.id } } } } + + spree_put :bulk_update, bulk_enterprise_params + profile_enterprise1.reload + profile_enterprise2.reload + expect(profile_enterprise1.sells).to eq 'any' + expect(profile_enterprise2.sells).to eq 'any' + expect(profile_enterprise1.owner).to eq new_owner + expect(profile_enterprise2.owner).to eq new_owner + end + end + end + + describe "for_order_cycle" do + let!(:user) { create_enterprise_user } + let!(:enterprise) { create(:enterprise, sells: 'any', owner: user) } + let(:permission_mock) { double(:permission) } + + before do + # As a user with permission + allow(controller).to receive_messages spree_current_user: user + allow(OrderCycle).to receive_messages find_by: "existing OrderCycle" + allow(Enterprise).to receive_messages find_by: "existing Enterprise" + allow(OrderCycle).to receive_messages new: "new OrderCycle" + + allow(OpenFoodNetwork::OrderCyclePermissions).to receive(:new) { permission_mock } + allow(permission_mock).to receive(:visible_enterprises) { [] } + allow(ActiveModel::ArraySerializer).to receive(:new) { "" } + end + + context "when no order_cycle or coordinator is provided in params" do + before { spree_get :for_order_cycle, format: :json } + it "initializes permissions with nil" do + expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, nil) + end + end + + context "when an order_cycle_id is provided in params" do + before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1 } + it "initializes permissions with the existing OrderCycle" do + expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") + end + end + + context "when a coordinator is provided in params" do + before { spree_get :for_order_cycle, format: :json, coordinator_id: 1 } + it "initializes permissions with a new OrderCycle" do + expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "new OrderCycle") + end + end + + context "when both an order cycle and a coordinator are provided in params" do + before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1, coordinator_id: 1 } + it "initializes permissions with the existing OrderCycle" do + expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") + end + end + end + + describe "visible" do + let!(:user) { create(:user, enterprise_limit: 10) } + let!(:visible_enterprise) { create(:enterprise, sells: 'any', owner: user) } + let!(:not_visible_enterprise) { create(:enterprise, sells: 'any') } + + before do + # As a user with permission + allow(controller).to receive_messages spree_current_user: user + + # :create_variant_overrides does not affect visiblity (at time of writing) + create(:enterprise_relationship, parent: not_visible_enterprise, child: visible_enterprise, permissions_list: [:create_variant_overrides]) + end + + it "uses permissions to determine which enterprises are visible and should be rendered" do + expect(controller).to receive(:render_as_json).with([visible_enterprise], ams_prefix: 'basic', spree_current_user: user).and_call_original + spree_get :visible, format: :json + end + end + + describe "index" do + context "as super admin" do + let(:super_admin) { create(:admin_user) } + let!(:user) { create_enterprise_user(enterprise_limit: 10) } + let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } + let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } + let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } before do - # As a user with permission - allow(controller).to receive_messages spree_current_user: user - allow(OrderCycle).to receive_messages find_by: "existing OrderCycle" - allow(Enterprise).to receive_messages find_by: "existing Enterprise" - allow(OrderCycle).to receive_messages new: "new OrderCycle" - - allow(OpenFoodNetwork::OrderCyclePermissions).to receive(:new) { permission_mock } - allow(permission_mock).to receive(:visible_enterprises) { [] } - allow(ActiveModel::ArraySerializer).to receive(:new) { "" } + allow(controller).to receive_messages spree_current_user: super_admin end - context "when no order_cycle or coordinator is provided in params" do - before { spree_get :for_order_cycle, format: :json } - it "initializes permissions with nil" do - expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, nil) + context "html" do + it "returns all enterprises" do + spree_get :index, format: :html + expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 end end - context "when an order_cycle_id is provided in params" do - before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1 } - it "initializes permissions with the existing OrderCycle" do - expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") - end - end - - context "when a coordinator is provided in params" do - before { spree_get :for_order_cycle, format: :json, coordinator_id: 1 } - it "initializes permissions with a new OrderCycle" do - expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "new OrderCycle") - end - end - - context "when both an order cycle and a coordinator are provided in params" do - before { spree_get :for_order_cycle, format: :json, order_cycle_id: 1, coordinator_id: 1 } - it "initializes permissions with the existing OrderCycle" do - expect(OpenFoodNetwork::OrderCyclePermissions).to have_received(:new).with(user, "existing OrderCycle") + context "json" do + it "returns all enterprises" do + spree_get :index, format: :json + expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 end end end - describe "visible" do - let!(:user) { create(:user, enterprise_limit: 10) } - let!(:visible_enterprise) { create(:enterprise, sells: 'any', owner: user) } - let!(:not_visible_enterprise) { create(:enterprise, sells: 'any') } + context "as an enterprise user" do + let!(:user) { create_enterprise_user(enterprise_limit: 10) } + let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } + let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } + let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } before do - # As a user with permission allow(controller).to receive_messages spree_current_user: user - - # :create_variant_overrides does not affect visiblity (at time of writing) - create(:enterprise_relationship, parent: not_visible_enterprise, child: visible_enterprise, permissions_list: [:create_variant_overrides]) end - it "uses permissions to determine which enterprises are visible and should be rendered" do - expect(controller).to receive(:render_as_json).with([visible_enterprise], ams_prefix: 'basic', spree_current_user: user).and_call_original - spree_get :visible, format: :json - end - end - - describe "index" do - context "as super admin" do - let(:super_admin) { create(:admin_user) } - let!(:user) { create_enterprise_user(enterprise_limit: 10) } - let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } - let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } - let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } - - before do - allow(controller).to receive_messages spree_current_user: super_admin - end - - context "html" do - it "returns all enterprises" do - spree_get :index, format: :html - expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 - end - end - - context "json" do - it "returns all enterprises" do - spree_get :index, format: :json - expect(assigns(:collection)).to include enterprise1, enterprise2, enterprise3 - end + context "html" do + it "returns an empty @collection" do + spree_get :index, format: :html + expect(assigns(:collection)).to eq [] end end - context "as an enterprise user" do - let!(:user) { create_enterprise_user(enterprise_limit: 10) } - let!(:enterprise1) { create(:enterprise, sells: 'any', owner: user) } - let!(:enterprise2) { create(:enterprise, sells: 'own', owner: user) } - let!(:enterprise3) { create(:enterprise, sells: 'any', owner: create_enterprise_user ) } - - before do - allow(controller).to receive_messages spree_current_user: user - end - - context "html" do - it "returns an empty @collection" do - spree_get :index, format: :html - expect(assigns(:collection)).to eq [] - end - end - - context "json" do - it "scopes @collection to enterprises editable by the user" do - spree_get :index, format: :json - expect(assigns(:collection)).to include enterprise1, enterprise2 - expect(assigns(:collection)).to_not include enterprise3 - end + context "json" do + it "scopes @collection to enterprises editable by the user" do + spree_get :index, format: :json + expect(assigns(:collection)).to include enterprise1, enterprise2 + expect(assigns(:collection)).to_not include enterprise3 end end end From 49fb01a3bb37c08d29b6b6cebfb7416d7a88a855 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 30 Jun 2020 17:55:08 +0200 Subject: [PATCH 086/261] Add assign default value of current time whilst altering NOT NULL constraint This argument in #change_column_null assigns this value where any NULL values are found, but it doesn't alter the table's `:default` value --- .../20200630070422_require_timestamps.rb | 246 +++++++++--------- 1 file changed, 124 insertions(+), 122 deletions(-) diff --git a/db/migrate/20200630070422_require_timestamps.rb b/db/migrate/20200630070422_require_timestamps.rb index d69c9f0832..2075876bca 100644 --- a/db/migrate/20200630070422_require_timestamps.rb +++ b/db/migrate/20200630070422_require_timestamps.rb @@ -1,127 +1,129 @@ class RequireTimestamps < ActiveRecord::Migration def up - change_column_null :customers, :created_at, false - change_column_null :customers, :updated_at, false - change_column_null :delayed_jobs, :created_at, false - change_column_null :delayed_jobs, :updated_at, false - change_column_null :distributors_shipping_methods, :created_at, false - change_column_null :distributors_shipping_methods, :updated_at, false - change_column_null :enterprise_fees, :created_at, false - change_column_null :enterprise_fees, :updated_at, false - change_column_null :enterprises, :created_at, false - change_column_null :enterprises, :updated_at, false - change_column_null :exchange_fees, :created_at, false - change_column_null :exchange_fees, :updated_at, false - change_column_null :exchange_variants, :created_at, false - change_column_null :exchange_variants, :updated_at, false - change_column_null :exchanges, :created_at, false - change_column_null :exchanges, :updated_at, false - change_column_null :inventory_items, :created_at, false - change_column_null :inventory_items, :updated_at, false - change_column_null :order_cycle_schedules, :created_at, false - change_column_null :order_cycle_schedules, :updated_at, false - change_column_null :order_cycles, :created_at, false - change_column_null :order_cycles, :updated_at, false - change_column_null :producer_properties, :created_at, false - change_column_null :producer_properties, :updated_at, false - change_column_null :proxy_orders, :created_at, false - change_column_null :proxy_orders, :updated_at, false - change_column_null :schedules, :created_at, false - change_column_null :schedules, :updated_at, false - change_column_null :sessions, :created_at, false - change_column_null :sessions, :updated_at, false - change_column_null :spree_activators, :created_at, false - change_column_null :spree_activators, :updated_at, false - change_column_null :spree_addresses, :created_at, false - change_column_null :spree_addresses, :updated_at, false - change_column_null :spree_adjustments, :created_at, false - change_column_null :spree_adjustments, :updated_at, false - change_column_null :spree_calculators, :created_at, false - change_column_null :spree_calculators, :updated_at, false - change_column_null :spree_configurations, :created_at, false - change_column_null :spree_configurations, :updated_at, false - change_column_null :spree_credit_cards, :created_at, false - change_column_null :spree_credit_cards, :updated_at, false - change_column_null :spree_gateways, :created_at, false - change_column_null :spree_gateways, :updated_at, false - change_column_null :spree_inventory_units, :created_at, false - change_column_null :spree_inventory_units, :updated_at, false - change_column_null :spree_line_items, :created_at, false - change_column_null :spree_line_items, :updated_at, false - change_column_null :spree_log_entries, :created_at, false - change_column_null :spree_log_entries, :updated_at, false - change_column_null :spree_option_types, :created_at, false - change_column_null :spree_option_types, :updated_at, false - change_column_null :spree_option_values, :created_at, false - change_column_null :spree_option_values, :updated_at, false - change_column_null :spree_orders, :created_at, false - change_column_null :spree_orders, :updated_at, false - change_column_null :spree_payment_methods, :created_at, false - change_column_null :spree_payment_methods, :updated_at, false - change_column_null :spree_payments, :created_at, false - change_column_null :spree_payments, :updated_at, false - change_column_null :spree_preferences, :created_at, false - change_column_null :spree_preferences, :updated_at, false - change_column_null :spree_product_option_types, :created_at, false - change_column_null :spree_product_option_types, :updated_at, false - change_column_null :spree_product_properties, :created_at, false - change_column_null :spree_product_properties, :updated_at, false - change_column_null :spree_products, :created_at, false - change_column_null :spree_products, :updated_at, false - change_column_null :spree_promotion_rules, :created_at, false - change_column_null :spree_promotion_rules, :updated_at, false - change_column_null :spree_properties, :created_at, false - change_column_null :spree_properties, :updated_at, false - change_column_null :spree_return_authorizations, :created_at, false - change_column_null :spree_return_authorizations, :updated_at, false - change_column_null :spree_shipments, :created_at, false - change_column_null :spree_shipments, :updated_at, false - change_column_null :spree_shipping_categories, :created_at, false - change_column_null :spree_shipping_categories, :updated_at, false - change_column_null :spree_shipping_method_categories, :created_at, false - change_column_null :spree_shipping_method_categories, :updated_at, false - change_column_null :spree_shipping_methods, :created_at, false - change_column_null :spree_shipping_methods, :updated_at, false - change_column_null :spree_shipping_rates, :created_at, false - change_column_null :spree_shipping_rates, :updated_at, false - change_column_null :spree_skrill_transactions, :created_at, false - change_column_null :spree_skrill_transactions, :updated_at, false - change_column_null :spree_state_changes, :created_at, false - change_column_null :spree_state_changes, :updated_at, false - change_column_null :spree_stock_items, :created_at, false - change_column_null :spree_stock_items, :updated_at, false - change_column_null :spree_stock_locations, :created_at, false - change_column_null :spree_stock_locations, :updated_at, false - change_column_null :spree_stock_movements, :created_at, false - change_column_null :spree_stock_movements, :updated_at, false - change_column_null :spree_stock_transfers, :created_at, false - change_column_null :spree_stock_transfers, :updated_at, false - change_column_null :spree_tax_categories, :created_at, false - change_column_null :spree_tax_categories, :updated_at, false - change_column_null :spree_tax_rates, :created_at, false - change_column_null :spree_tax_rates, :updated_at, false - change_column_null :spree_taxonomies, :created_at, false - change_column_null :spree_taxonomies, :updated_at, false - change_column_null :spree_taxons, :created_at, false - change_column_null :spree_taxons, :updated_at, false - change_column_null :spree_tokenized_permissions, :created_at, false - change_column_null :spree_tokenized_permissions, :updated_at, false - change_column_null :spree_users, :created_at, false - change_column_null :spree_users, :updated_at, false - change_column_null :spree_zone_members, :created_at, false - change_column_null :spree_zone_members, :updated_at, false - change_column_null :spree_zones, :created_at, false - change_column_null :spree_zones, :updated_at, false - change_column_null :stripe_accounts, :created_at, false - change_column_null :stripe_accounts, :updated_at, false - change_column_null :subscription_line_items, :created_at, false - change_column_null :subscription_line_items, :updated_at, false - change_column_null :subscriptions, :created_at, false - change_column_null :subscriptions, :updated_at, false - change_column_null :tag_rules, :created_at, false - change_column_null :tag_rules, :updated_at, false - change_column_null :column_preferences, :created_at, false - change_column_null :column_preferences, :updated_at, false + current_time = Time.zone.now + + change_column_null :customers, :created_at, false, current_time + change_column_null :customers, :updated_at, false, current_time + change_column_null :delayed_jobs, :created_at, false, current_time + change_column_null :delayed_jobs, :updated_at, false, current_time + change_column_null :distributors_shipping_methods, :created_at, false, current_time + change_column_null :distributors_shipping_methods, :updated_at, false, current_time + change_column_null :enterprise_fees, :created_at, false, current_time + change_column_null :enterprise_fees, :updated_at, false, current_time + change_column_null :enterprises, :created_at, false, current_time + change_column_null :enterprises, :updated_at, false, current_time + change_column_null :exchange_fees, :created_at, false, current_time + change_column_null :exchange_fees, :updated_at, false, current_time + change_column_null :exchange_variants, :created_at, false, current_time + change_column_null :exchange_variants, :updated_at, false, current_time + change_column_null :exchanges, :created_at, false, current_time + change_column_null :exchanges, :updated_at, false, current_time + change_column_null :inventory_items, :created_at, false, current_time + change_column_null :inventory_items, :updated_at, false, current_time + change_column_null :order_cycle_schedules, :created_at, false, current_time + change_column_null :order_cycle_schedules, :updated_at, false, current_time + change_column_null :order_cycles, :created_at, false, current_time + change_column_null :order_cycles, :updated_at, false, current_time + change_column_null :producer_properties, :created_at, false, current_time + change_column_null :producer_properties, :updated_at, false, current_time + change_column_null :proxy_orders, :created_at, false, current_time + change_column_null :proxy_orders, :updated_at, false, current_time + change_column_null :schedules, :created_at, false, current_time + change_column_null :schedules, :updated_at, false, current_time + change_column_null :sessions, :created_at, false, current_time + change_column_null :sessions, :updated_at, false, current_time + change_column_null :spree_activators, :created_at, false, current_time + change_column_null :spree_activators, :updated_at, false, current_time + change_column_null :spree_addresses, :created_at, false, current_time + change_column_null :spree_addresses, :updated_at, false, current_time + change_column_null :spree_adjustments, :created_at, false, current_time + change_column_null :spree_adjustments, :updated_at, false, current_time + change_column_null :spree_calculators, :created_at, false, current_time + change_column_null :spree_calculators, :updated_at, false, current_time + change_column_null :spree_configurations, :created_at, false, current_time + change_column_null :spree_configurations, :updated_at, false, current_time + change_column_null :spree_credit_cards, :created_at, false, current_time + change_column_null :spree_credit_cards, :updated_at, false, current_time + change_column_null :spree_gateways, :created_at, false, current_time + change_column_null :spree_gateways, :updated_at, false, current_time + change_column_null :spree_inventory_units, :created_at, false, current_time + change_column_null :spree_inventory_units, :updated_at, false, current_time + change_column_null :spree_line_items, :created_at, false, current_time + change_column_null :spree_line_items, :updated_at, false, current_time + change_column_null :spree_log_entries, :created_at, false, current_time + change_column_null :spree_log_entries, :updated_at, false, current_time + change_column_null :spree_option_types, :created_at, false, current_time + change_column_null :spree_option_types, :updated_at, false, current_time + change_column_null :spree_option_values, :created_at, false, current_time + change_column_null :spree_option_values, :updated_at, false, current_time + change_column_null :spree_orders, :created_at, false, current_time + change_column_null :spree_orders, :updated_at, false, current_time + change_column_null :spree_payment_methods, :created_at, false, current_time + change_column_null :spree_payment_methods, :updated_at, false, current_time + change_column_null :spree_payments, :created_at, false, current_time + change_column_null :spree_payments, :updated_at, false, current_time + change_column_null :spree_preferences, :created_at, false, current_time + change_column_null :spree_preferences, :updated_at, false, current_time + change_column_null :spree_product_option_types, :created_at, false, current_time + change_column_null :spree_product_option_types, :updated_at, false, current_time + change_column_null :spree_product_properties, :created_at, false, current_time + change_column_null :spree_product_properties, :updated_at, false, current_time + change_column_null :spree_products, :created_at, false, current_time + change_column_null :spree_products, :updated_at, false, current_time + change_column_null :spree_promotion_rules, :created_at, false, current_time + change_column_null :spree_promotion_rules, :updated_at, false, current_time + change_column_null :spree_properties, :created_at, false, current_time + change_column_null :spree_properties, :updated_at, false, current_time + change_column_null :spree_return_authorizations, :created_at, false, current_time + change_column_null :spree_return_authorizations, :updated_at, false, current_time + change_column_null :spree_shipments, :created_at, false, current_time + change_column_null :spree_shipments, :updated_at, false, current_time + change_column_null :spree_shipping_categories, :created_at, false, current_time + change_column_null :spree_shipping_categories, :updated_at, false, current_time + change_column_null :spree_shipping_method_categories, :created_at, false, current_time + change_column_null :spree_shipping_method_categories, :updated_at, false, current_time + change_column_null :spree_shipping_methods, :created_at, false, current_time + change_column_null :spree_shipping_methods, :updated_at, false, current_time + change_column_null :spree_shipping_rates, :created_at, false, current_time + change_column_null :spree_shipping_rates, :updated_at, false, current_time + change_column_null :spree_skrill_transactions, :created_at, false, current_time + change_column_null :spree_skrill_transactions, :updated_at, false, current_time + change_column_null :spree_state_changes, :created_at, false, current_time + change_column_null :spree_state_changes, :updated_at, false, current_time + change_column_null :spree_stock_items, :created_at, false, current_time + change_column_null :spree_stock_items, :updated_at, false, current_time + change_column_null :spree_stock_locations, :created_at, false, current_time + change_column_null :spree_stock_locations, :updated_at, false, current_time + change_column_null :spree_stock_movements, :created_at, false, current_time + change_column_null :spree_stock_movements, :updated_at, false, current_time + change_column_null :spree_stock_transfers, :created_at, false, current_time + change_column_null :spree_stock_transfers, :updated_at, false, current_time + change_column_null :spree_tax_categories, :created_at, false, current_time + change_column_null :spree_tax_categories, :updated_at, false, current_time + change_column_null :spree_tax_rates, :created_at, false, current_time + change_column_null :spree_tax_rates, :updated_at, false, current_time + change_column_null :spree_taxonomies, :created_at, false, current_time + change_column_null :spree_taxonomies, :updated_at, false, current_time + change_column_null :spree_taxons, :created_at, false, current_time + change_column_null :spree_taxons, :updated_at, false, current_time + change_column_null :spree_tokenized_permissions, :created_at, false, current_time + change_column_null :spree_tokenized_permissions, :updated_at, false, current_time + change_column_null :spree_users, :created_at, false, current_time + change_column_null :spree_users, :updated_at, false, current_time + change_column_null :spree_zone_members, :created_at, false, current_time + change_column_null :spree_zone_members, :updated_at, false, current_time + change_column_null :spree_zones, :created_at, false, current_time + change_column_null :spree_zones, :updated_at, false, current_time + change_column_null :stripe_accounts, :created_at, false, current_time + change_column_null :stripe_accounts, :updated_at, false, current_time + change_column_null :subscription_line_items, :created_at, false, current_time + change_column_null :subscription_line_items, :updated_at, false, current_time + change_column_null :subscriptions, :created_at, false, current_time + change_column_null :subscriptions, :updated_at, false, current_time + change_column_null :tag_rules, :created_at, false, current_time + change_column_null :tag_rules, :updated_at, false, current_time + change_column_null :column_preferences, :created_at, false, current_time + change_column_null :column_preferences, :updated_at, false, current_time end def down From 8c371fd0d1a0c45e35c45a17b332e52f93ee9a7a Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Wed, 1 Jul 2020 11:27:57 +0200 Subject: [PATCH 087/261] Do not print bill addr. in invoice2 either --- app/views/spree/admin/orders/invoice2.html.haml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/views/spree/admin/orders/invoice2.html.haml b/app/views/spree/admin/orders/invoice2.html.haml index 7964f80e56..b9715c2770 100644 --- a/app/views/spree/admin/orders/invoice2.html.haml +++ b/app/views/spree/admin/orders/invoice2.html.haml @@ -44,14 +44,17 @@ %td{ :align => "right" } = t :invoice_billing_address %br - %strong= @order.bill_address.full_name + - if @order.bill_address + %strong= @order.bill_address.full_name - if @order.andand.customer.andand.code.present? %br = "Code: #{@order.customer.code}" %br - = @order.bill_address.address_part1 + - if @order.bill_address + = @order.bill_address.address_part1 %br - = @order.bill_address.address_part2 + - if @order.bill_address + = @order.bill_address.address_part2 = render 'spree/admin/orders/invoice_table2' From 63934b7863d09ff5fd1af1d43d23eab31fa2ccdc Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 30 Jun 2020 15:28:59 +0100 Subject: [PATCH 088/261] Add space after translation so that translators dont have to guess a space is needed after the translation --- app/assets/javascripts/darkswarm/filters/dates.js.coffee | 2 +- app/mailers/spree/user_mailer.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/darkswarm/filters/dates.js.coffee b/app/assets/javascripts/darkswarm/filters/dates.js.coffee index 8793ddefd8..cef73413a7 100644 --- a/app/assets/javascripts/darkswarm/filters/dates.js.coffee +++ b/app/assets/javascripts/darkswarm/filters/dates.js.coffee @@ -12,4 +12,4 @@ Darkswarm.filter "sensible_timeframe", (date_in_wordsFilter)-> if moment().add(2, 'days') < moment(date, dateFormat) t 'orders_open' else - t('closing') + date_in_wordsFilter(date) + t('closing') + ' ' + date_in_wordsFilter(date) diff --git a/app/mailers/spree/user_mailer.rb b/app/mailers/spree/user_mailer.rb index 68d37c4b99..ba25809b5d 100644 --- a/app/mailers/spree/user_mailer.rb +++ b/app/mailers/spree/user_mailer.rb @@ -20,7 +20,7 @@ module Spree @user = user I18n.with_locale valid_locale(@user) do mail(to: user.email, from: from_address, - subject: t(:welcome_to) + Spree::Config[:site_name]) + subject: t(:welcome_to) + ' ' + Spree::Config[:site_name]) end end From 2179cc7fafd686d02a55a63b995878ee66bd6a04 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sun, 17 May 2020 11:35:22 +0100 Subject: [PATCH 089/261] Make StripeSCA void action make a refund instead StripeSCA does not support voiding confirmed payment intents so we need to make a refund instead --- app/models/spree/gateway/stripe_sca.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/spree/gateway/stripe_sca.rb b/app/models/spree/gateway/stripe_sca.rb index 21fa698c3b..02681ae210 100644 --- a/app/models/spree/gateway/stripe_sca.rb +++ b/app/models/spree/gateway/stripe_sca.rb @@ -57,8 +57,11 @@ module Spree # NOTE: the name of this method is determined by Spree::Payment::Processing def void(response_code, _creditcard, gateway_options) + payment_intent_id = response_code + payment_intent_response = Stripe::PaymentIntent.retrieve(payment_intent_id, + stripe_account: stripe_account_id) gateway_options[:stripe_account] = stripe_account_id - provider.void(response_code, gateway_options) + provider.refund(payment_intent_response.amount_received, response_code, gateway_options) end # NOTE: the name of this method is determined by Spree::Payment::Processing From 9e4a793b24cc4c003b6603efc703ae61c12d77c6 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 10 Jun 2020 15:36:02 +0100 Subject: [PATCH 090/261] Fix rubocop issues --- spec/requests/checkout/stripe_sca_spec.rb | 33 ++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index e590b3f601..5018ad321c 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -64,12 +64,20 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques } end let(:payment_intent_response_mock) do - { status: 200, body: JSON.generate(object: "payment_intent", amount: 2000, charges: { data: [{ id: "ch_1234", amount: 2000 }] }) } + { + status: 200, body: JSON.generate(object: "payment_intent", + amount: 2000, + charges: { data: [{ id: "ch_1234", amount: 2000 }] }) + } end let(:payment_intent_authorize_response_mock) do - { status: 200, body: JSON.generate(id: payment_intent_id, object: "payment_intent", amount: 2000, + { + status: 200, body: JSON.generate(id: payment_intent_id, + object: "payment_intent", + amount: 2000, status: "requires_capture", last_payment_error: nil, - charges: { data: [{ id: "ch_1234", amount: 2000 }] }) } + charges: { data: [{ id: "ch_1234", amount: 2000 }] }) + } end before do @@ -166,13 +174,15 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques headers: { 'Stripe-Account' => 'abc123' }) .to_return(hubs_payment_method_response_mock) - # Creates a customer (this stubs the customers call to the main stripe account and also the call to the connected account) + # Creates a customer + # This stubs the customers call to both the main stripe account and the connected account stub_request(:post, "https://api.stripe.com/v1/customers") .with(body: { email: order.email }) .to_return(customer_response_mock) # Attaches the payment method to the customer in the hub's stripe account - stub_request(:post, "https://api.stripe.com/v1/payment_methods/#{hubs_stripe_payment_method}/attach") + stub_request(:post, + "https://api.stripe.com/v1/payment_methods/#{hubs_stripe_payment_method}/attach") .with(body: { customer: customer_id }, headers: { 'Stripe-Account' => 'abc123' }) .to_return(hubs_payment_method_response_mock) @@ -191,7 +201,8 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques source_attributes[:save_requested_by_customer] = '1' # Attaches the payment method to the customer - stub_request(:post, "https://api.stripe.com/v1/payment_methods/#{stripe_payment_method}/attach") + stub_request(:post, + "https://api.stripe.com/v1/payment_methods/#{stripe_payment_method}/attach") .with(body: { customer: customer_id }) .to_return(payment_method_attach_response_mock) end @@ -316,9 +327,13 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques context "when the stripe API sends a url for the authorization of the transaction" do let(:payment_intent_authorize_response_mock) do - { status: 200, body: JSON.generate(id: payment_intent_id, object: "payment_intent", - next_source_action: { type: "authorize_with_url", authorize_with_url: { url: stripe_redirect_url } }, - status: "requires_source_action" ) } + { status: 200, body: JSON.generate(id: payment_intent_id, + object: "payment_intent", + next_source_action: { + type: "authorize_with_url", + authorize_with_url: { url: stripe_redirect_url } + }, + status: "requires_source_action") } end it "redirects the user to the authorization stripe url" do From ecb1920fa97db1e93e90e4b923cfc0d9a863c072 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 10 Jun 2020 15:44:03 +0100 Subject: [PATCH 091/261] Move payment_controller_spec to specific folder so we can break it in more specific parts --- .../spree/admin/{ => orders/payments}/payments_controller_spec.rb | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename spec/controllers/spree/admin/{ => orders/payments}/payments_controller_spec.rb (100%) diff --git a/spec/controllers/spree/admin/payments_controller_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb similarity index 100% rename from spec/controllers/spree/admin/payments_controller_spec.rb rename to spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb From ce493866f95e6eae4735bc9f972991bf3d6884f7 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 10 Jun 2020 15:47:05 +0100 Subject: [PATCH 092/261] Extract refunds specs from payments controller spec --- .../payments_controller_refunds_spec.rb | 136 ++++++++++++++++++ .../payments/payments_controller_spec.rb | 124 ---------------- 2 files changed, 136 insertions(+), 124 deletions(-) create mode 100644 spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb new file mode 100644 index 0000000000..cb43a2e4f6 --- /dev/null +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb @@ -0,0 +1,136 @@ +require 'spec_helper' + +describe Spree::Admin::PaymentsController, type: :controller do + let!(:shop) { create(:enterprise) } + let!(:user) { shop.owner } + let!(:order) { create(:order, distributor: shop, state: 'complete') } + let!(:line_item) { create(:line_item, order: order, price: 5.0) } + + before do + allow(controller).to receive(:spree_current_user) { user } + end + + context "as an enterprise user" do + before do + order.reload.update_totals + end + + context "requesting a refund on a payment" do + let(:params) { { id: payment.id, order_id: order.number, e: :void } } + + # Required for the respond override in the controller decorator to work + before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } + + context "that was processed by stripe" do + let!(:payment_method) { create(:stripe_payment_method, distributors: [shop]) } + let!(:payment) do + create(:payment, order: order, state: 'completed', payment_method: payment_method, + response_code: 'ch_1a2b3c', amount: order.total) + end + + before do + allow(Stripe).to receive(:api_key) { "sk_test_12345" } + end + + context "where the request succeeds" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, + body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "voids the payment" do + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + spree_put :fire, params + expect(payment.reload.state).to eq 'void' + order.reload + expect(order.payment_total).to eq 0 + expect(order.outstanding_balance).to_not eq 0 + end + end + + context "where the request fails" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) + end + + it "does not void the payment" do + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + expect(flash[:error]).to eq "Bup-bow!" + end + end + end + end + + context "requesting a partial credit on a payment" do + let(:params) { { id: payment.id, order_id: order.number, e: :credit } } + + # Required for the respond override in the controller decorator to work + before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } + + context "that was processed by stripe" do + let!(:payment_method) { create(:stripe_payment_method, distributors: [shop]) } + let!(:payment) do + create(:payment, order: order, state: 'completed', payment_method: payment_method, + response_code: 'ch_1a2b3c', amount: order.total + 5) + end + + before do + allow(Stripe).to receive(:api_key) { "sk_test_12345" } + end + + context "where the request succeeds" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, + body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "partially refunds the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + expect(order.outstanding_balance).to eq 0 + end + end + + context "where the request fails" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) + end + + it "does not void the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + expect(flash[:error]).to eq "Bup-bow!" + end + end + end + end + end +end diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb index 6c7c2eeb50..6932efa236 100644 --- a/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb @@ -138,128 +138,4 @@ describe Spree::Admin::PaymentsController, type: :controller do end end end - - context "as an enterprise user" do - before do - order.reload.update_totals - end - - context "requesting a refund on a payment" do - let(:params) { { id: payment.id, order_id: order.number, e: :void } } - - # Required for the respond override in the controller decorator to work - before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } - - context "that was processed by stripe" do - let!(:payment_method) { create(:stripe_payment_method, distributors: [shop]) } - let!(:payment) do - create(:payment, order: order, state: 'completed', payment_method: payment_method, - response_code: 'ch_1a2b3c', amount: order.total) - end - - before do - allow(Stripe).to receive(:api_key) { "sk_test_12345" } - end - - context "where the request succeeds" do - before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). - with(basic_auth: ["sk_test_12345", ""]). - to_return(status: 200, - body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) - end - - it "voids the payment" do - order.reload - expect(order.payment_total).to_not eq 0 - expect(order.outstanding_balance).to eq 0 - spree_put :fire, params - expect(payment.reload.state).to eq 'void' - order.reload - expect(order.payment_total).to eq 0 - expect(order.outstanding_balance).to_not eq 0 - end - end - - context "where the request fails" do - before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). - with(basic_auth: ["sk_test_12345", ""]). - to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) - end - - it "does not void the payment" do - order.reload - expect(order.payment_total).to_not eq 0 - expect(order.outstanding_balance).to eq 0 - spree_put :fire, params - expect(payment.reload.state).to eq 'completed' - order.reload - expect(order.payment_total).to_not eq 0 - expect(order.outstanding_balance).to eq 0 - expect(flash[:error]).to eq "Bup-bow!" - end - end - end - end - - context "requesting a partial credit on a payment" do - let(:params) { { id: payment.id, order_id: order.number, e: :credit } } - - # Required for the respond override in the controller decorator to work - before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } - - context "that was processed by stripe" do - let!(:payment_method) { create(:stripe_payment_method, distributors: [shop]) } - let!(:payment) do - create(:payment, order: order, state: 'completed', payment_method: payment_method, - response_code: 'ch_1a2b3c', amount: order.total + 5) - end - - before do - allow(Stripe).to receive(:api_key) { "sk_test_12345" } - end - - context "where the request succeeds" do - before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). - with(basic_auth: ["sk_test_12345", ""]). - to_return(status: 200, - body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) - end - - it "partially refunds the payment" do - order.reload - expect(order.payment_total).to eq order.total + 5 - expect(order.outstanding_balance).to eq(-5) - spree_put :fire, params - expect(payment.reload.state).to eq 'completed' - order.reload - expect(order.payment_total).to eq order.total - expect(order.outstanding_balance).to eq 0 - end - end - - context "where the request fails" do - before do - stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). - with(basic_auth: ["sk_test_12345", ""]). - to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) - end - - it "does not void the payment" do - order.reload - expect(order.payment_total).to eq order.total + 5 - expect(order.outstanding_balance).to eq(-5) - spree_put :fire, params - expect(payment.reload.state).to eq 'completed' - order.reload - expect(order.payment_total).to eq order.total + 5 - expect(order.outstanding_balance).to eq(-5) - expect(flash[:error]).to eq "Bup-bow!" - end - end - end - end - end end From 2d4326ded3c7544cef4154cc323894090db68d3f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 30 Jun 2020 19:40:35 +0100 Subject: [PATCH 093/261] Replace empty? with blank? which is equivalent but a bit more resilient, returns false for nil Present is not blank, so unless blank? becomes if present? --- app/controllers/admin/enterprises_controller.rb | 2 +- app/controllers/checkout_controller.rb | 2 +- app/controllers/spree/admin/image_settings_controller.rb | 4 ++-- app/controllers/spree/admin/products_controller.rb | 2 +- app/controllers/user_registrations_controller.rb | 2 +- app/serializers/api/admin/enterprise_serializer.rb | 2 +- app/serializers/api/admin/units_variant_serializer.rb | 2 +- app/services/permitted_attributes/enterprise.rb | 2 +- app/services/permitted_attributes/order_cycle.rb | 2 +- app/services/permitted_attributes/subscription.rb | 2 +- .../producer_properties/_producer_property_fields.html.haml | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/controllers/admin/enterprises_controller.rb b/app/controllers/admin/enterprises_controller.rb index 333926a728..4277dc2ff4 100644 --- a/app/controllers/admin/enterprises_controller.rb +++ b/app/controllers/admin/enterprises_controller.rb @@ -146,7 +146,7 @@ module Admin enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, @order_cycle) .visible_enterprises - unless enterprises.empty? + if enterprises.present? enterprises.includes( supplied_products: [:supplier, master: [:images], variants: { option_values: :option_type }] diff --git a/app/controllers/checkout_controller.rb b/app/controllers/checkout_controller.rb index 8616f4f6ad..c83b5e361d 100644 --- a/app/controllers/checkout_controller.rb +++ b/app/controllers/checkout_controller.rb @@ -241,7 +241,7 @@ class CheckoutController < Spree::StoreController def update_failed(error = RuntimeError.new(order_error)) Bugsnag.notify(error) - flash[:error] = order_error if flash.empty? + flash[:error] = order_error if flash.blank? checkout_failed update_failed_response end diff --git a/app/controllers/spree/admin/image_settings_controller.rb b/app/controllers/spree/admin/image_settings_controller.rb index 32aae5c783..476dd401a8 100644 --- a/app/controllers/spree/admin/image_settings_controller.rb +++ b/app/controllers/spree/admin/image_settings_controller.rb @@ -26,7 +26,7 @@ module Spree def update_styles(params) if params[:new_attachment_styles].present? params[:new_attachment_styles].each do |_index, style| - params[:attachment_styles][style[:name]] = style[:value] unless style[:value].empty? + params[:attachment_styles][style[:name]] = style[:value] if style[:value].present? end end @@ -38,7 +38,7 @@ module Spree def update_headers(params) if params[:new_s3_headers].present? params[:new_s3_headers].each do |_index, header| - params[:s3_headers][header[:name]] = header[:value] unless header[:value].empty? + params[:s3_headers][header[:name]] = header[:value] if header[:value].present? end end diff --git a/app/controllers/spree/admin/products_controller.rb b/app/controllers/spree/admin/products_controller.rb index 707a65b3f1..76f0066d86 100644 --- a/app/controllers/spree/admin/products_controller.rb +++ b/app/controllers/spree/admin/products_controller.rb @@ -171,7 +171,7 @@ module Spree end def permitted_resource_params - return params[:product] if params[:product].empty? + return params[:product] if params[:product].blank? params.require(:product).permit(::PermittedAttributes::Product.attributes) end diff --git a/app/controllers/user_registrations_controller.rb b/app/controllers/user_registrations_controller.rb index 873d7d4036..d6fdf5ac76 100644 --- a/app/controllers/user_registrations_controller.rb +++ b/app/controllers/user_registrations_controller.rb @@ -33,7 +33,7 @@ class UserRegistrationsController < Spree::UserRegistrationsController private def spree_user_params - return params[:spree_user] if params[:spree_user].empty? + return params[:spree_user] if params[:spree_user].blank? PermittedAttributes::User.new(params, :spree_user).call([:remember_me]) end diff --git a/app/serializers/api/admin/enterprise_serializer.rb b/app/serializers/api/admin/enterprise_serializer.rb index bcb2fe39d7..e3024fdc46 100644 --- a/app/serializers/api/admin/enterprise_serializer.rb +++ b/app/serializers/api/admin/enterprise_serializer.rb @@ -25,7 +25,7 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags. split(","). map{ |t| { text: t } }) - if tag_group[:rules].empty? + if tag_group[:rules].blank? tag_groups << tag_group tag_group[:position] = tag_groups.count end diff --git a/app/serializers/api/admin/units_variant_serializer.rb b/app/serializers/api/admin/units_variant_serializer.rb index dc27e3adc3..f70959b925 100644 --- a/app/serializers/api/admin/units_variant_serializer.rb +++ b/app/serializers/api/admin/units_variant_serializer.rb @@ -3,6 +3,6 @@ class Api::Admin::UnitsVariantSerializer < ActiveModel::Serializer def full_name full_name = object.full_name - object.product.name + (full_name.empty? ? "" : ": #{full_name}") + object.product.name + (full_name.blank? ? "" : ": #{full_name}") end end diff --git a/app/services/permitted_attributes/enterprise.rb b/app/services/permitted_attributes/enterprise.rb index f02863b2a5..db7f31f10c 100644 --- a/app/services/permitted_attributes/enterprise.rb +++ b/app/services/permitted_attributes/enterprise.rb @@ -7,7 +7,7 @@ module PermittedAttributes end def call - return @params[:enterprise] if @params[:enterprise].empty? + return @params[:enterprise] if @params[:enterprise].blank? @params.require(:enterprise).permit( basic_permitted_attributes + [ diff --git a/app/services/permitted_attributes/order_cycle.rb b/app/services/permitted_attributes/order_cycle.rb index 6da6175a51..41fd82bead 100644 --- a/app/services/permitted_attributes/order_cycle.rb +++ b/app/services/permitted_attributes/order_cycle.rb @@ -7,7 +7,7 @@ module PermittedAttributes end def call - return @params[:order_cycle] if @params[:order_cycle].empty? + return @params[:order_cycle] if @params[:order_cycle].blank? @params.require(:order_cycle).permit( :name, :orders_open_at, :orders_close_at, :coordinator_id, diff --git a/app/services/permitted_attributes/subscription.rb b/app/services/permitted_attributes/subscription.rb index 2ab3956fca..21e523e4fe 100644 --- a/app/services/permitted_attributes/subscription.rb +++ b/app/services/permitted_attributes/subscription.rb @@ -7,7 +7,7 @@ module PermittedAttributes end def call - return @params[:subscription] if @params[:subscription].empty? + return @params[:subscription] if @params[:subscription].blank? @params.require(:subscription).permit(basic_permitted_attributes + other_permitted_attributes) end diff --git a/app/views/admin/producer_properties/_producer_property_fields.html.haml b/app/views/admin/producer_properties/_producer_property_fields.html.haml index 6fe0b1d7ad..841a0cfb73 100644 --- a/app/views/admin/producer_properties/_producer_property_fields.html.haml +++ b/app/views/admin/producer_properties/_producer_property_fields.html.haml @@ -11,5 +11,5 @@ %td.value = f.text_field :value, :class => 'autocomplete' %td.actions - - unless @enterprise.producer_properties.empty? + - if @enterprise.producer_properties.present? = link_to_remove_fields t(:remove), f, no_text: true, url: (f.object.persisted? && main_app.admin_enterprise_producer_property_path(@enterprise, f.object)), html: {"onclick" => "if(typeof(enterprise_form) != 'undefined') { angular.element(enterprise_form).scope().setFormDirty() }".html_safe} From 6555f8bfba32c027136e0b39a5b3911498544e38 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 10 Jun 2020 16:42:08 +0100 Subject: [PATCH 094/261] Add specs to cover stripeSCA refunds Duplication between stripe connect and stripeSCA is done on purpose so we can easily delete stripeConnect code when the migration is done --- .../payments_controller_refunds_spec.rb | 147 +++++++++++++++++- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb index cb43a2e4f6..08e923b5c3 100644 --- a/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb +++ b/spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Spree::Admin::PaymentsController, type: :controller do @@ -8,13 +10,10 @@ describe Spree::Admin::PaymentsController, type: :controller do before do allow(controller).to receive(:spree_current_user) { user } + order.reload.update_totals end - context "as an enterprise user" do - before do - order.reload.update_totals - end - + context "Stripe Connect" do context "requesting a refund on a payment" do let(:params) { { id: payment.id, order_id: order.number, e: :void } } @@ -133,4 +132,142 @@ describe Spree::Admin::PaymentsController, type: :controller do end end end + + context "StripeSCA" do + context "requesting a refund on a payment" do + let(:params) { { id: payment.id, order_id: order.number, e: :void } } + + # Required for the respond override in the controller decorator to work + before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } + + context "that was processed by stripe" do + let!(:payment_method) { create(:stripe_sca_payment_method, distributors: [shop]) } + let!(:payment) do + create(:payment, order: order, state: 'completed', payment_method: payment_method, + response_code: 'pi_123', amount: order.total) + end + let(:stripe_account) { create(:stripe_account, enterprise: shop) } + + before do + allow(Stripe).to receive(:api_key) { "sk_test_12345" } + allow(StripeAccount).to receive(:find_by) { stripe_account } + + # Retrieves payment intent info + stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") + .with(headers: { 'Stripe-Account' => 'abc123' }) + .to_return({ status: 200, body: JSON.generate( + amount_received: 2000, + charges: { data: [{ id: "ch_1a2b3c" }] } + ) }) + end + + context "where the request succeeds" do + before do + # Issues the refund + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, + body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "voids the payment" do + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + spree_put :fire, params + expect(payment.reload.state).to eq 'void' + order.reload + expect(order.payment_total).to eq 0 + expect(order.outstanding_balance).to_not eq 0 + end + end + + context "where the request fails" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) + end + + it "does not void the payment" do + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to_not eq 0 + expect(order.outstanding_balance).to eq 0 + expect(flash[:error]).to eq "Bup-bow!" + end + end + end + end + + context "requesting a partial credit on a payment" do + let(:params) { { id: payment.id, order_id: order.number, e: :credit } } + + # Required for the respond override in the controller decorator to work + before { @request.env['HTTP_REFERER'] = spree.admin_order_payments_url(payment) } + + context "that was processed by stripe" do + let!(:payment_method) { create(:stripe_sca_payment_method, distributors: [shop]) } + let!(:payment) do + create(:payment, order: order, state: 'completed', payment_method: payment_method, + response_code: 'pi_123', amount: order.total + 5) + end + + before do + allow(Stripe).to receive(:api_key) { "sk_test_12345" } + + # Retrieves payment intent info + stub_request(:get, "https://api.stripe.com/v1/payment_intents/pi_123") + .to_return({ status: 200, body: JSON.generate( + amount_received: 2000, + charges: { data: [{ id: "ch_1a2b3c" }] } + ) }) + end + + context "where the request succeeds" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, + body: JSON.generate(id: 're_123', object: 'refund', status: 'succeeded') ) + end + + it "partially refunds the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + expect(order.outstanding_balance).to eq 0 + end + end + + context "where the request fails" do + before do + stub_request(:post, "https://api.stripe.com/v1/charges/ch_1a2b3c/refunds"). + with(basic_auth: ["sk_test_12345", ""]). + to_return(status: 200, body: JSON.generate(error: { message: "Bup-bow!" }) ) + end + + it "does not void the payment" do + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + spree_put :fire, params + expect(payment.reload.state).to eq 'completed' + order.reload + expect(order.payment_total).to eq order.total + 5 + expect(order.outstanding_balance).to eq(-5) + expect(flash[:error]).to eq "Bup-bow!" + end + end + end + end + end end From e8417b8be606ff048fbb423eaa1d901603c24e53 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 12 Jun 2020 10:56:51 +0100 Subject: [PATCH 095/261] Remove specs testing filtering of master variants Master variants are not used in the report --- .../products_and_inventory_report_base.rb | 1 - .../products_and_inventory_report_spec.rb | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/lib/open_food_network/products_and_inventory_report_base.rb b/lib/open_food_network/products_and_inventory_report_base.rb index d0f4a50de8..c669dc4d6a 100644 --- a/lib/open_food_network/products_and_inventory_report_base.rb +++ b/lib/open_food_network/products_and_inventory_report_base.rb @@ -36,7 +36,6 @@ module OpenFoodNetwork end # Using the `in_stock?` method allows overrides by distributors. - # It also allows the upgrade to Spree 2.0. def filter_on_hand(variants) if params[:report_type] == 'inventory' variants.select(&:in_stock?) diff --git a/spec/lib/open_food_network/products_and_inventory_report_spec.rb b/spec/lib/open_food_network/products_and_inventory_report_spec.rb index e4d4d27142..f0844dfffb 100644 --- a/spec/lib/open_food_network/products_and_inventory_report_spec.rb +++ b/spec/lib/open_food_network/products_and_inventory_report_spec.rb @@ -97,18 +97,7 @@ module OpenFoodNetwork describe "Filtering variants" do let(:variants) { Spree::Variant.where(nil).joins(:product).where(is_master: false) } - it "should return unfiltered variants sans-params" do - product1 = create(:simple_product, supplier: supplier) - product2 = create(:simple_product, supplier: supplier) - expect(subject.filter(Spree::Variant.where(nil))).to match_array [product1.master, product1.variants.first, product2.master, product2.variants.first] - end - it "should filter deleted products" do - product1 = create(:simple_product, supplier: supplier) - product2 = create(:simple_product, supplier: supplier) - product2.destroy - expect(subject.filter(Spree::Variant.where(nil))).to match_array [product1.master, product1.variants.first] - end describe "based on report type" do it "returns only variants on hand" do product1 = create(:simple_product, supplier: supplier, on_hand: 99) From eff9d6edd0a154c43e13eca24009ad91a3c6b5ab Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2020 00:06:17 +0000 Subject: [PATCH 096/261] Bump database_cleaner from 1.7.0 to 1.8.5 Bumps [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) from 1.7.0 to 1.8.5. - [Release notes](https://github.com/DatabaseCleaner/database_cleaner/releases) - [Changelog](https://github.com/DatabaseCleaner/database_cleaner/blob/master/History.rdoc) - [Commits](https://github.com/DatabaseCleaner/database_cleaner/compare/v1.7.0...v1.8.5) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 550d32ab24..cb914eaa4b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -201,7 +201,7 @@ GEM addressable daemons (1.3.1) dalli (2.7.10) - database_cleaner (1.7.0) + database_cleaner (1.8.5) db2fog (0.9.0) activerecord (>= 3.2.0, < 5.0) fog (~> 1.0) From 1b8669bb0bcbcfdb671054bc21013ceda0ecf8ff Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Thu, 2 Jul 2020 18:28:33 +1000 Subject: [PATCH 097/261] Updating translations for config/locales/en_NZ.yml --- config/locales/en_NZ.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/config/locales/en_NZ.yml b/config/locales/en_NZ.yml index c3ed978054..cfff4ec299 100644 --- a/config/locales/en_NZ.yml +++ b/config/locales/en_NZ.yml @@ -270,6 +270,7 @@ en_NZ: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -479,6 +480,7 @@ en_NZ: 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}" + malformed_csv: "Product Import encountered a malformed CSV: %{error_message}" index: notice: "Notice" beta_notice: "This feature is still in beta: you may experience some errors while using it. Please don't hesitate to contact support." @@ -1146,13 +1148,18 @@ en_NZ: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit cart" + items_in_cart_singular: "%{num} item in your cart" + items_in_cart_plural: "%{num} items in your cart" + close: "Close" + cart_empty: "Your cart is empty" + take_me_shopping: "Take me shopping!" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" @@ -2065,6 +2072,7 @@ en_NZ: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2301,6 +2309,7 @@ en_NZ: 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" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" @@ -2766,6 +2775,7 @@ en_NZ: previous: "Previous" last: "Last" spree: + more: "More" 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)" From cc34f126ecebd82220382e55ed30618c8ce3997f Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2020 11:22:57 +0000 Subject: [PATCH 098/261] Bump mini_racer from 0.2.14 to 0.2.15 Bumps [mini_racer](https://github.com/discourse/mini_racer) from 0.2.14 to 0.2.15. - [Release notes](https://github.com/discourse/mini_racer/releases) - [Changelog](https://github.com/rubyjs/mini_racer/blob/master/CHANGELOG) - [Commits](https://github.com/discourse/mini_racer/compare/v0.2.14...v0.2.15) Signed-off-by: dependabot-preview[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index a389ced8fb..4eccf3fcf8 100644 --- a/Gemfile +++ b/Gemfile @@ -109,7 +109,7 @@ gem 'test-unit', '~> 3.3' gem 'coffee-rails', '~> 4.2.2' gem 'compass-rails' -gem 'mini_racer', '0.2.14' +gem 'mini_racer', '0.2.15' gem 'uglifier', '>= 1.0.3' diff --git a/Gemfile.lock b/Gemfile.lock index 550d32ab24..718deb9482 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -456,7 +456,7 @@ GEM mime-types-data (3.2020.0512) mini_mime (1.0.2) mini_portile2 (2.4.0) - mini_racer (0.2.14) + mini_racer (0.2.15) libv8 (> 7.3) minitest (4.7.5) momentjs-rails (2.20.1) @@ -749,7 +749,7 @@ DEPENDENCIES kaminari (~> 0.14.1) knapsack letter_opener (>= 1.4.1) - mini_racer (= 0.2.14) + mini_racer (= 0.2.15) momentjs-rails money (= 5.1.1) newrelic_rpm (~> 3.0) From 3326366c6e41721b34051cf4011451480b97a481 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 14:10:56 +0200 Subject: [PATCH 099/261] Add specs for applying stored locales during login --- spec/features/consumer/authentication_spec.rb | 35 +++++++++++++++++++ .../request/authentication_workflow.rb | 5 +++ 2 files changed, 40 insertions(+) diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index 201cd45621..cd4921190a 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' feature "Authentication", js: true do + include AuthenticationWorkflow include UIComponentHelper include OpenFoodNetwork::EmailHelper @@ -135,5 +136,39 @@ feature "Authentication", js: true do uri = URI.parse(current_url) expect(uri.path + "#" + uri.fragment).to eq('/#/login') end + + describe "with user locales" do + before do + visit root_path + open_login_modal + end + + context "when the user has a valid locale saved" do + before do + user.update!(locale: "es") + end + + it "logs in successfully, applying the saved locale" do + fill_in_and_submit_login_form(user) + expect_logged_in + + expect(page).to have_content I18n.t(:home_shop, locale: :es).upcase + end + end + + context "when the user has an unavailable locale saved" do + before do + user.update!(locale: "xx") + end + + xit "logs in successfully and resets the user's locale to the default" do + fill_in_and_submit_login_form(user) + expect_logged_in + + expect(page).to have_content I18n.t(:home_shop, locale: :en).upcase + expect(user.reload.locale).to eq "en" + end + end + end end end diff --git a/spec/support/request/authentication_workflow.rb b/spec/support/request/authentication_workflow.rb index e07327d3e7..a654cf9934 100644 --- a/spec/support/request/authentication_workflow.rb +++ b/spec/support/request/authentication_workflow.rb @@ -68,6 +68,11 @@ module AuthenticationWorkflow fill_in "password", with: user.password click_button "Login" end + + def expect_logged_in + # Ensure page has been reloaded after submitting login form + expect(page).to_not have_selector ".menu #login-link" + end end RSpec.configure do |config| From 8dfaea629ba2f04be40e46c76c52a6633dc45249 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 12:54:11 +0200 Subject: [PATCH 100/261] Refactor current_user_locale to a new method --- app/helpers/i18n_helper.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index a04405ac97..c37d036f62 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -1,17 +1,17 @@ module I18nHelper def set_locale - # Save a given locale + # Save a given locale from params if params[:locale] && available_locale?(params[:locale]) spree_current_user&.update!(locale: params[:locale]) cookies[:locale] = params[:locale] end # After logging in, check if the user chose a locale before - if spree_current_user && spree_current_user.locale.nil? && cookies[:locale] - spree_current_user.update!(locale: params[:locale]) + if current_user_locale.nil? && cookies[:locale] + spree_current_user&.update!(locale: params[:locale]) end - I18n.locale = spree_current_user.andand.locale || cookies[:locale] || I18n.default_locale + I18n.locale = current_user_locale || cookies[:locale] || I18n.default_locale end def valid_locale(user) @@ -29,4 +29,8 @@ module I18nHelper def available_locale?(locale) Rails.application.config.i18n.available_locales.include?(locale) end + + def current_user_locale + spree_current_user.andand.locale + end end From aa6f4d4fb98585b5bb68df767eb3591692be90e6 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 12:56:20 +0200 Subject: [PATCH 101/261] Don't set unavailable locales on the current user --- app/helpers/i18n_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index c37d036f62..5ce1539f05 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -7,7 +7,7 @@ module I18nHelper end # After logging in, check if the user chose a locale before - if current_user_locale.nil? && cookies[:locale] + if current_user_locale.nil? && cookies[:locale] && available_locale?(params[:locale]) spree_current_user&.update!(locale: params[:locale]) end From d70d61439ace50712bd8e48abb053f3ba11aa4b8 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 12:58:29 +0200 Subject: [PATCH 102/261] Always return an available locale --- app/helpers/i18n_helper.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index 5ce1539f05..6d4c3845c1 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -11,7 +11,7 @@ module I18nHelper spree_current_user&.update!(locale: params[:locale]) end - I18n.locale = current_user_locale || cookies[:locale] || I18n.default_locale + I18n.locale = valid_current_locale end def valid_locale(user) @@ -33,4 +33,14 @@ module I18nHelper def current_user_locale spree_current_user.andand.locale end + + def valid_current_locale + if available_locale?(current_user_locale) + current_user_locale + elsif available_locale?(cookies[:locale]) + cookies[:locale] + else + I18n.default_locale + end + end end From 91880cdbecc285e87f77aaf1aca0fef8fd7563ef Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 14:33:41 +0200 Subject: [PATCH 103/261] Make I18nHelper `#available_locale?` method public --- app/helpers/i18n_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index 6d4c3845c1..b755e85a54 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -24,12 +24,12 @@ module I18nHelper end end - private - def available_locale?(locale) Rails.application.config.i18n.available_locales.include?(locale) end + private + def current_user_locale spree_current_user.andand.locale end From 4e08d2049faa8fc738b3baef8031c5b4fa7fc950 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 14:35:02 +0200 Subject: [PATCH 104/261] Ensure a valid locale is persisted during login This action has to be performed here and not in I18nHelper, as spree_current_user is not initialized yet during the other checks / setting the selected locale value in the app --- app/controllers/spree/user_sessions_controller.rb | 8 ++++++++ spec/features/consumer/authentication_spec.rb | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index 82ca577fc3..44fb56a312 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -6,11 +6,13 @@ module Spree include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::SSL + include I18nHelper ssl_required :new, :create, :destroy, :update ssl_allowed :login_bar before_action :set_checkout_redirect, only: :create + after_action :ensure_valid_locale, only: :create def create authenticate_spree_user! @@ -48,5 +50,11 @@ module Spree redirect_to(session["spree_user_return_to"] || default) session["spree_user_return_to"] = nil end + + def ensure_valid_locale + return unless spree_current_user && !available_locale?(spree_current_user.locale) + + spree_current_user.update!(locale: I18n.default_locale) + end end end diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index cd4921190a..3e676b4c1e 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -161,7 +161,7 @@ feature "Authentication", js: true do user.update!(locale: "xx") end - xit "logs in successfully and resets the user's locale to the default" do + it "logs in successfully and resets the user's locale to the default" do fill_in_and_submit_login_form(user) expect_logged_in From dee61e8b82eed59ac52968a73c2579067385a387 Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Thu, 2 Jul 2020 15:14:02 +0200 Subject: [PATCH 105/261] Index spree_state_changes.stateful_id column This speeds up a great deal one of the most awful queries our DB servers execute. It's not rare to see traces above 20s in Datadog :scream:. In staging, with no traffic, we go from ``` EXPLAIN ANALYZE SELECT COUNT ( * ) FROM spree_state_changes WHERE spree_state_changes . stateful_id = 2024 AND spree_state_changes . stateful_type = 'Spree::Order'; Planning time: 0.142 ms Execution time: 9.073 ms ``` to ``` EXPLAIN ANALYZE SELECT COUNT ( * ) FROM spree_state_changes WHERE spree_state_changes . stateful_id = 2024 AND spree_state_changes . stateful_type = 'Spree::Order'; Planning time: 0.284 ms Execution time: 0.202 ms ``` --- .../20200702112157_add_stateful_id_index_to_state_changes.rb | 5 +++++ db/schema.rb | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 db/migrate/20200702112157_add_stateful_id_index_to_state_changes.rb diff --git a/db/migrate/20200702112157_add_stateful_id_index_to_state_changes.rb b/db/migrate/20200702112157_add_stateful_id_index_to_state_changes.rb new file mode 100644 index 0000000000..8a52643cff --- /dev/null +++ b/db/migrate/20200702112157_add_stateful_id_index_to_state_changes.rb @@ -0,0 +1,5 @@ +class AddStatefulIdIndexToStateChanges < ActiveRecord::Migration + def change + add_index :spree_state_changes, :stateful_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 6867489e98..97ddcb63d2 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20200630070422) do +ActiveRecord::Schema.define(version: 20200702112157) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -885,6 +885,8 @@ ActiveRecord::Schema.define(version: 20200630070422) do t.string "next_state" end + add_index "spree_state_changes", ["stateful_id"], name: "index_spree_state_changes_on_stateful_id", using: :btree + create_table "spree_states", force: true do |t| t.string "name" t.string "abbr" From b10fd99a5326dd8261f6a09055b3f07c8b8f5b0a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 16:46:53 +0200 Subject: [PATCH 106/261] Update all locales with the latest Transifex translations --- config/locales/ar.yml | 8 +- config/locales/ca.yml | 16 ++-- config/locales/de_DE.yml | 8 +- config/locales/en_AU.yml | 21 ++--- config/locales/en_BE.yml | 8 +- config/locales/en_CA.yml | 2 + config/locales/en_DE.yml | 8 +- config/locales/en_PH.yml | 8 +- config/locales/en_ZA.yml | 14 +-- config/locales/es.yml | 8 +- config/locales/es_CR.yml | 10 +- config/locales/fil_PH.yml | 53 +++++------ config/locales/fr.yml | 2 +- config/locales/fr_BE.yml | 8 +- config/locales/fr_CA.yml | 8 +- config/locales/it.yml | 8 +- config/locales/nb.yml | 2 + config/locales/nl_BE.yml | 8 +- config/locales/pt.yml | 7 +- config/locales/pt_BR.yml | 8 +- config/locales/sv.yml | 6 +- config/locales/tr.yml | 188 +++++++++++++++++++------------------- 22 files changed, 221 insertions(+), 188 deletions(-) diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 9af7be11b0..01ada3d77c 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -266,6 +266,7 @@ ar: backordered: "طلبات متأخرة" on hand: "متوفر" ship: "الشحن" + shipping_category: "نوع الشحن" actions: create_and_add_another: "إنشاء وإضافة آخر" create: "انشاء" @@ -1134,13 +1135,13 @@ ar: menu: cart: cart: "سلة" + cart_sidebar: + checkout: "تابع للخروج" + close: "إغلاق" signed_in: profile: "الملف الشخصي" mobile_menu: cart: "سلة" - joyride: - checkout: "الخروج الآن" - already_ordered_products: "تم الطلب بالفعل في دورة الطلب هذه" register_call: selling_on_ofn: "هل أنت مهتم بالحصول على شبكة الغذاء المفتوح؟" register: "سجل هنا" @@ -2709,6 +2710,7 @@ ar: previous: "السابق" last: "الاخير" spree: + more: "أكثر" your_order_is_empty_add_product: "طلبك فارغ ، يرجى البحث عن المنتج أعلاه وإضافته" add_product: "أضف منتج" name_or_sku: "الاسم أو SKU (أدخل أول 4 أحرف على الأقل من اسم المنتج)" diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 91d5b762cf..7c4ac98c2e 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -270,6 +270,7 @@ ca: backordered: "Reabastit" on hand: "Disponibles" ship: "Enviament" + shipping_category: "Categoria d'enviament" actions: create_and_add_another: "Crea i afegeix-ne una altra" create: "Crear" @@ -898,7 +899,7 @@ ca: incoming: "2. Productes entrants" outgoing: "3. Productes sortints" exchange_form: - pickup_time_tip: Quan les comandes d'aquest cicle de comandes estiguin preparades per a les consumidores + pickup_time_tip: Quan les comandes d'aquest cicle de comandes estiguin llestes per a les consumidores pickup_instructions_placeholder: "Instruccions de recollida" pickup_instructions_tip: Aquestes instruccions es mostraran a les consumidores després d'haver completat una comanda pickup_time_placeholder: "Preparat per (és a dir, data / hora)" @@ -948,7 +949,7 @@ ca: distributors: distribuïdores variants: variants simple_form: - ready_for: Preparat per + ready_for: Llest per ready_for_placeholder: Data / hora customer_instructions: Instruccions de la consumidora customer_instructions_placeholder: Notes de recollida o de lliurament @@ -1109,7 +1110,7 @@ ca: pause_failure_msg: "Ho sentim, la pausa ha fallat!" confirm_unpause_msg: "Si teniu un cicle de comanda obert a la programació d'aquesta subscripció, es crearà una comanda per a aquesta consumidora. Esteu segur que voleu anul·lar aquesta subscripció?" unpause_failure_msg: "Ho sentim, la represa ha fallat!" - confirm_cancel_open_orders_msg: "Actualment hi ha algunes comandes obertes per a aquesta subscripció. Ja s'ha notificat a les consumidores que les comandes serà atesa. Voleu cancel·lar aquestes comandes o conservar-les?" + confirm_cancel_open_orders_msg: "Actualment hi ha algunes comandes obertes per a aquesta subscripció. Ja s'ha notificat a les consumidores que la comanda seran ateses. Voleu cancel·lar aquestes comandes o conservar-les?" resume_canceled_orders_msg: "Algunes comandes d'aquesta subscripció es poden reprendre ara mateix. Podeu reprendre-les des del menú desplegable de comandes." yes_cancel_them: Cancel·lar-les no_keep_them: Conservar-les @@ -1392,7 +1393,7 @@ ca: stats_orders: "comandes de menjar" checkout_title: Realitza la comanda checkout_now: Validar ara - checkout_order_ready: Comanda preparada per + checkout_order_ready: Comanda llesta per checkout_hide: Amaga checkout_expand: Expandeix checkout_headline: "Estàs preparada per validar la compra?" @@ -1404,7 +1405,7 @@ ca: checkout_default_ship_address: "Desa per defecte com a adreça d'enviament " checkout_method_free: Gratuït checkout_address_same: L'adreça d'enviament és igual que l'adreça de facturació? - checkout_ready_for: "Preparat per:" + checkout_ready_for: "Llest per:" checkout_instructions: "Alguns comentaris o instruccions especials?" checkout_payment: Pagament checkout_send: Realitza una comanda ara @@ -1527,7 +1528,7 @@ ca: shopping_groups_part_of: "forma part de:" shopping_producers_of_hub: "Productores de%{hub}:" enterprises_next_closing: "Tancament de la comanda següent" - enterprises_ready_for: "Preparat per" + enterprises_ready_for: "Llest per" enterprises_choose: "Escull quan vols la teva comanda:" maps_open: "Obert" maps_closed: "Tancat" @@ -1672,7 +1673,7 @@ ca: orders_fees: Comissions... orders_edit_title: Cistella de la compra orders_edit_headline: El teu cistell de la compra - orders_edit_time: Comanda preparada per + orders_edit_time: Comanda llesta per orders_edit_continue: Continuar comprant orders_edit_checkout: Realitza la compra orders_form_empty_cart: "Cistella buida" @@ -2778,6 +2779,7 @@ ca: previous: "Anterior" last: "Últim" spree: + more: "Més" your_order_is_empty_add_product: "La comanda està buida, si us plau cerca i afegeix un producte a dalt" add_product: "Afegeix un producte" name_or_sku: "Nom o codi (introduïu com a mínim els primers 4 caràcters del nom del producte)" diff --git a/config/locales/de_DE.yml b/config/locales/de_DE.yml index 94dd643337..df3d7e29c1 100644 --- a/config/locales/de_DE.yml +++ b/config/locales/de_DE.yml @@ -270,6 +270,7 @@ de_DE: backordered: "Nachbestellt" on hand: "Verfügbar" ship: "Liefern" + shipping_category: "Versandkategorie" actions: create_and_add_another: "Erstellen und weitere hinzufügen" create: "Neu" @@ -1142,13 +1143,13 @@ de_DE: menu: cart: cart: "Wagen" + cart_sidebar: + checkout: "Kasse" + close: "Abschließen" signed_in: profile: "Profil" mobile_menu: cart: "Wagen" - joyride: - checkout: "Zur Kasse" - already_ordered_products: "Bereits in diesem Bestellzyklus bestellt" register_call: selling_on_ofn: "Sie möchten selbst im Open Food Network verkaufen?" register: "Hier anmelden" @@ -2741,6 +2742,7 @@ de_DE: previous: "Bisherige" last: "Zuletzt" spree: + more: "Mehr" your_order_is_empty_add_product: "Ihre Bestellung ist leer. Suchen Sie oben ein Produkt und fügen Sie es hinzu" add_product: "Produkt hinzufügen" name_or_sku: "Name oder SKU (geben Sie mindestens die ersten 4 Zeichen des Produktnamens ein)" diff --git a/config/locales/en_AU.yml b/config/locales/en_AU.yml index c940313002..111c9a7522 100644 --- a/config/locales/en_AU.yml +++ b/config/locales/en_AU.yml @@ -262,6 +262,7 @@ en_AU: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -704,14 +705,11 @@ en_AU: shopfront_message: "\"Home\" message" shopfront_message_placeholder: > Create your home page content to welcome customers and explain how people - can shop with you. - - Include details about your delivery and pick up options, how often you - open the shop for orders, and all the details your customers will need - to understand the process of buying from you. - - You can also include links to your newsletter sign up, so that people - can connect with you to hear when your next order cycle opens. + can shop with you. Include details about your delivery and pick up options, + how often you open the shop for orders, and all the details your customers + will need to understand the process of buying from you. You can also + include links to your newsletter sign up, so that people can connect + with you to hear when your next order cycle opens. shopfront_message_link_tooltip: "Insert / edit link" shopfront_message_link_prompt: "Please enter a URL to insert" shopfront_closed_message: "Shopfront Closed Message" @@ -1141,13 +1139,13 @@ en_AU: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + close: "Close" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" @@ -2660,6 +2658,7 @@ en_AU: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/en_BE.yml b/config/locales/en_BE.yml index 4b4d63ac8f..73e6f2c1b8 100644 --- a/config/locales/en_BE.yml +++ b/config/locales/en_BE.yml @@ -257,6 +257,7 @@ en_BE: back_to_payments_list: "Back to Payments List" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1099,13 +1100,13 @@ en_BE: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + close: "Close" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" @@ -2616,6 +2617,7 @@ en_BE: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index 70e0cacc68..cd9e2ba69c 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -270,6 +270,7 @@ en_CA: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -2771,6 +2772,7 @@ en_CA: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/en_DE.yml b/config/locales/en_DE.yml index 3f65f77b11..d8d0b20675 100644 --- a/config/locales/en_DE.yml +++ b/config/locales/en_DE.yml @@ -262,6 +262,7 @@ en_DE: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1109,13 +1110,13 @@ en_DE: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + close: "Close" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" @@ -2627,6 +2628,7 @@ en_DE: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/en_PH.yml b/config/locales/en_PH.yml index 2ca3436aa6..77dad9a54e 100644 --- a/config/locales/en_PH.yml +++ b/config/locales/en_PH.yml @@ -270,6 +270,7 @@ en_PH: backordered: "Backordered" on hand: "On Hand" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1140,13 +1141,13 @@ en_PH: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "Checkout" + close: "Close" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - 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" @@ -2744,6 +2745,7 @@ en_PH: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/en_ZA.yml b/config/locales/en_ZA.yml index b105c0fc11..191b96311d 100644 --- a/config/locales/en_ZA.yml +++ b/config/locales/en_ZA.yml @@ -270,6 +270,7 @@ en_ZA: backordered: "Backordered" on hand: "In Stock" ship: "Ship" + shipping_category: "Shipping Category" actions: create_and_add_another: "Create and Add Another" create: "Create" @@ -1142,13 +1143,13 @@ en_ZA: menu: cart: cart: "Basket" + cart_sidebar: + checkout: "Checkout" + close: "Close" signed_in: profile: "Profile" mobile_menu: cart: "Basket" - joyride: - checkout: "Checkout now" - already_ordered_products: "Already ordered in this order cycle" register_call: selling_on_ofn: "Interested in selling through the Open Food Network?" register: "Register here" @@ -1217,11 +1218,11 @@ en_ZA: menu_4_title: "Groups" menu_4_url: "/groups" menu_5_title: "About" - menu_5_url: "https://www.openfoodnetwork.co.za" + menu_5_url: "https://www.openfoodnetwork.co.za/" menu_6_title: "Blog" - menu_6_url: "https://www.openfoodnetwork.co.za/blog" + menu_6_url: "https://www.openfoodnetwork.co.za/blog/" menu_7_title: "Support" - menu_7_url: "https://www.openfoodnetwork.co.za/support" + menu_7_url: "https://www.openfoodnetwork.co.za/support/" logo: "Logo (640x130)" logo_mobile: "Mobile logo (75x26)" logo_mobile_svg: "Mobile logo (SVG)" @@ -2690,6 +2691,7 @@ en_ZA: previous: "Previous" last: "Last" spree: + more: "More" 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)" diff --git a/config/locales/es.yml b/config/locales/es.yml index aef7d7c62b..ad2e732f52 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -270,6 +270,7 @@ es: backordered: "Reabastecido" on hand: "Disponibles" ship: "Envío" + shipping_category: "Categoría de envío" actions: create_and_add_another: "Crear y agregar otro" create: "Crear" @@ -1149,13 +1150,13 @@ es: menu: cart: cart: "Carrito" + cart_sidebar: + checkout: "Validar" + close: "Cerrar" signed_in: profile: "Perfil" mobile_menu: cart: "Carrito" - joyride: - checkout: "Validar el carrito ahora" - already_ordered_products: "Pedido en este ciclo de pedido" register_call: selling_on_ofn: "¿Estás interesada en entrar en Open Food Network?" register: "Regístrate aquí" @@ -2773,6 +2774,7 @@ es: previous: "Anterior" last: "Último" spree: + more: "Más" your_order_is_empty_add_product: "Su pedido está vacío, busque y añada un producto arriba" add_product: "Añadir Producto" name_or_sku: "Nombre o código SKU (ingrese al menos los primeros 4 caracteres del nombre del producto)" diff --git a/config/locales/es_CR.yml b/config/locales/es_CR.yml index 891c34c21b..17883da027 100644 --- a/config/locales/es_CR.yml +++ b/config/locales/es_CR.yml @@ -270,6 +270,7 @@ es_CR: backordered: "Pedido pendiente" on hand: "Disponibles" ship: "Envío" + shipping_category: "Categoría de envío" actions: create_and_add_another: "Crear y agregar otro" create: "Crear" @@ -1143,15 +1144,15 @@ es_CR: menu: cart: cart: "Carrito" + cart_sidebar: + checkout: "Validar el carrito" + close: "Cerrar" signed_in: profile: "Perfil" mobile_menu: cart: "Carrito" - joyride: - checkout: "Validar el carrito ahora" - already_ordered_products: "Pedido en este ciclo de pedido" register_call: - selling_on_ofn: "¿Quiere ser parte de Open Food Network (LaFeriaCR)?" + selling_on_ofn: "¿Tiene interés en vender a través de Open Food Network (LaFeriaCR)?" register: "Regístrarse aquí" footer: footer_secure: "Seguro y de confianza." @@ -2752,6 +2753,7 @@ es_CR: previous: "Anterior" last: "Último" spree: + more: "Más" your_order_is_empty_add_product: "Su pedido está vacío, busque y añada un producto arriba" add_product: "Añadir Producto" name_or_sku: "Nombre o código SKU (ingrese al menos los primeros 4 caracteres del nombre del producto)" diff --git a/config/locales/fil_PH.yml b/config/locales/fil_PH.yml index 6bf53bd65f..af89a9a22f 100644 --- a/config/locales/fil_PH.yml +++ b/config/locales/fil_PH.yml @@ -270,6 +270,7 @@ fil_PH: backordered: "na-backorder" on hand: "on hand" ship: "ship" + shipping_category: "Kategorya ng Pagpapadala" actions: create_and_add_another: "Gumawa at magdagdag ng isa pa" create: "gumawa" @@ -718,7 +719,7 @@ fil_PH: ito ay makikita sa home tab kapag ang customer ay nasa loob na ng inyong shopfront. shopfront_message_link_tooltip: "ilagay/ i-edit ang link" - shopfront_message_link_prompt: "ilagay ang URL na ipapasok" + shopfront_message_link_prompt: "ipasok ang URL na ilalagay" shopfront_closed_message: "pagsasarang mensahe ng Shopfront" shopfront_closed_message_placeholder: > isang mensahe na nagbibigay ng mas detalyadong paliwanag kung bakit @@ -1035,7 +1036,7 @@ fil_PH: edit: i-edit ang subscription table: edit_subscription: i-edit ang subscription - pause_subscription: ihinto ang subscription + pause_subscription: panandaliang ihinto ang subscription unpause_subscription: ituloy ang subscription cancel_subscription: kanselahin ang nauulit na order filters: @@ -1074,8 +1075,8 @@ fil_PH: allowed_payment_method_types_tip: Cash at pamamaraang Stripe lamang ang maaaring gamitin sa kasalukuyan. credit_card: Credit Card charges_not_allowed: ang paniningil ay hindi pinapayagan ng customer na ito - no_default_card: ang customer ay walang mga card na maaaring singilin - card_ok: ang customer ay may card na maaaring singilin + no_default_card: ang customer ay walang mga card na maaaring i-charge + card_ok: ang customer ay may card na maaaring i-charge begins_at_placeholder: "pumili ng petsa" ends_at_placeholder: "opsyonal" loading_flash: @@ -1095,7 +1096,7 @@ fil_PH: out_of_stock: "Walang stock" orders: number: bilang - confirm_edit: sigurado ka bang nais mo ayusin ang order na ito? maaaring magdulot ito ng mas mahirap na awtomatikong pagsasaayos ng mga subscription sa hinaharap. + confirm_edit: sigurado ka bang nais mo i-edit ang order na ito? maaaring magdulot ito ng mas mahirap na awtomatikong pagsasaayos ng mga subscription sa hinaharap. confirm_cancel_msg: "sigurado ka bang nais mong kanselahin ang nauulit na order na ito? hindi na ito maaaring ibalik kapag nagawa na." cancel_failure_msg: "paumanhin ngunit hindi naging matagumpay ang pagkansela!" confirm_pause_msg: "sigurado ka bang nais mong pansamantalang itigil ang subscription na ito?" @@ -1143,13 +1144,13 @@ fil_PH: menu: cart: cart: "Cart" + cart_sidebar: + checkout: "checkout" + close: "isara" signed_in: profile: "Profile" mobile_menu: cart: "Cart" - joyride: - checkout: "Mag-checkout na" - already_ordered_products: "Naka-order na sa order cycle na ito" register_call: selling_on_ofn: "Interesado ka ba maging parte ng Open Food Network?" register: "Magrehistro dito" @@ -1175,7 +1176,7 @@ fil_PH: customer_required: login: "mag-log-in" signup: "mag-sign-up" - contact: "makipag-ugnay" + contact: "makipag-ugnayan" require_customer_login: "ang mga inaprubahang customer lamang ang maaaring gumamit ng shop na ito." require_customer_html: "kung nais mong magsimulang mamili rito, maaaring%{contact}%{enterprise} at magtanong kung paano sumali." card_could_not_be_updated: hindi ma-update ang card @@ -1252,7 +1253,7 @@ fil_PH: state: province country: Bansa unauthorized: hindi awtorisado - terms_of_service: "mga palatuntunan ng serbisyo" + terms_of_service: "mga tuntunin ng serbisyo" on_demand: on demand none: wala not_allowed: hindi pinapayagan @@ -1266,7 +1267,7 @@ fil_PH: label_shops: "mga shop" label_map: "mapa" label_producer: "Producer" - label_producers: "Producers" + label_producers: "Mga Producer" label_groups: "mga grupo" label_about: "tungkol sa" label_connect: "kumonekta" @@ -1288,7 +1289,7 @@ fil_PH: total: "kabuuan" cart_updating: "ina-update ang cart" cart_empty: "walang laman ang cart" - cart_edit: "ayusin ang cart" + cart_edit: "i-edit ang cart" card_number: numero ng card card_securitycode: "Security code" card_expiry_date: petsa ng pag-expire @@ -1297,15 +1298,15 @@ fil_PH: new_credit_card: "bagong credit card" my_credit_cards: ang aking mga credit card add_new_credit_card: magdagdag ng bagong credit card - saved_cards: i-save ang mga card + saved_cards: naka-save na mga card add_a_card: magdagdag ng card add_card: idagdag ang card you_have_no_saved_cards: wala ka pang nai-save na card. saving_credit_card: sine-save ang credit card... - card_has_been_removed: "ang iyong card ay tinanggal na (numero:%{number})" - card_could_not_be_removed: paumanhin, hindi maalis ang card + card_has_been_removed: "ang iyong card ay natanggal na (numero:%{number})" + card_could_not_be_removed: paumanhin, hindi matanggal ang card invalid_credit_card: "hindi valid ang credit card" - ie_warning_headline: "ang iyong browser ay luma na :-(" + ie_warning_headline: "ang iyong browser ay out of date :-(" ie_warning_text: "para sa pinakamagandang karanasan sa Open Food Network, mariin naming nirerekomenda ang pag-upgrade ng inyong browser:" ie_warning_chrome: i-download ang Chrome ie_warning_firefox: i-download ang Firefox @@ -2381,7 +2382,7 @@ fil_PH: din ito upang maisalaysay ang inyong kwento. profile_only_text2: > kung mas nais mong magpokus sa paggawa ng pagkain at ipaubaya sa iba - ang pagbebenta nito, hindi kailangan ang shop sa Open Food Network. + ang pagbebenta nito, hindi na kailangan ang shop sa Open Food Network. profile_only_text3: > idagdag ang inyong produkto sa Open Food Network, upang mabigyan ng permiso ang mga hub na ilagay ang inyong produkto sa kanilang mga tindahan. @@ -2390,9 +2391,9 @@ fil_PH: Direktang ibenta ang inyong produkto sa mga customer sa pamamagitan ng iyong sariling Open Food Network shopfront. producer_shop_text2: > - ang shop ng Producer ay para lamang sa iyong mga produkto, kung nais - mong magtinda ng mga produkto na itinanim/ginawa sa labas ng site, piliin - ang 'Hub ng producer'. + ang Producer Shop ay para lamang sa iyong mga produkto, kung nais mong + magtinda ng mga produkto na itinanim/ginawa sa labas ng site, piliin + ang 'Producer Hub'. producer_hub: Producer Hub producer_hub_text1: > ang iyong enterprise ang saligan ng iyong lokal na sistema ng pagkain. @@ -2400,9 +2401,8 @@ fil_PH: pinagsama sama mula sa ibang enterprise sa pamamagitan ng iyong shopfront sa Open Food Network. producer_hub_text2: > - ang mga hub ng producer ay maaring may iba't ibang anyo tulad ng CSA, - isang programang veggie-box o isang co-op ng pagkain na may hardin sa - rooftop. + ang mga producer hub ay maaring may iba't ibang anyo tulad ng CSA, isang + programang veggie-box o isang co-op ng pagkain na may hardin sa rooftop. producer_hub_text3: > ang layunin ng Open Food Network ay sumuporta sa mga modelo ng hub gaano man ito karami, kaya ano man ang inyong sitwasyon, nais naming ibigay @@ -2549,14 +2549,14 @@ fil_PH: 'yes': "oo" 'no': "hindi" inventory_products: "mga produktong naka-imbentaryo" - hidden_products: "mga nakatagong pprodukto" - new_products: "bagong produkto" + hidden_products: "nakatagong mga produkto" + new_products: "bagong mga produkto" reset_stock_levels: i-reset ang lebel ng stock sa default changes_to: mga pagbabago sa one_override: isang override overrides: mga override remain_unsaved: nananatiling hindi naka-save. - no_changes_to_save: walang pagbabago na ise-save + no_changes_to_save: walang mga pagbabago na ise-save no_authorisation: "hindi ko makuha ang awtorisasyon para i-save ang mga pagbabago kaya mananatili ang mga ito na hindi naka-save." some_trouble: "nagkaroon ako ng problema sa pagse-save: %{errors}" changing_on_hand_stock: pagbabago sa lebel ng hand stock @@ -2758,6 +2758,7 @@ fil_PH: previous: "nauna" last: "huli" spree: + more: "Karagdagang Impormasyon" your_order_is_empty_add_product: "ang iyong order ay walang laman, humanap at magdagdag ng produkto sa itaas." add_product: "magdagdag ng produkto" name_or_sku: "Pangalan o SKU (ipasok ang 4 na letra sa pangalan ng produkto)" diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 435b24fbf6..e7805cfee8 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -1653,7 +1653,7 @@ fr: sell_hubs_detail: "Créer un profil pour votre entreprise de distribution ou organisation sur OFFrance. A tout moment vous pourrez créer une boutique multi-fournisseurs." sell_groups_detail: "Créer un répertoire sur mesure (regroupant différents producteurs et hubs de distribution) pour votre région ou votre organisation." sell_user_guide: "En savoir plus en explorant le guide utilisateur." - sell_listing_price: "L'inscription sur OFFrance est gratuite. Ouvrir et gérer une boutique sur OFFrance ou créer un groupe sur OFFrance pour votre organisation ou réseau régional, n'est pas gratuit, mais le prix est libre: soit 2% du chiffre d'affaire (ou autre forme de contribution libre designée par votre hub), soit une contribution \"en compétences\" à Open Food France (développement de fonctionnalités, recherche de financement, support utilisateur, etc.), soit un mix des deux." + sell_listing_price: "L'inscription sur OFFrance est gratuite. Ouvrir et gérer une boutique sur OFFrance ou créer un groupe sur OFFrance pour votre organisation ou réseau régional, n'est pas gratuit. Il existe deux formules : soit la formule \"petit débrouillard\" où vous pouvez opter pour un montant libre à nous reverser (mais vous ne pouvez pas disposer de support personnalisé), soit vous nous reversez 1% du volume de vente réalisé sur la plateforme pour bénéfier de notre accompagnement. Ce pourcentage peut être dégressif à partir d'un certain montant. Veuillez nous contacter pour en savoir plus !" sell_embed: "Nous pouvons aussi intégrer votre boutique OFFrance dans votre propre site web ou construire un site web d'alimentation locale sur mesure pour votre région." sell_ask_services: "Nous consulter sur les services des partenaires OFFrance." shops_title: Boutiques diff --git a/config/locales/fr_BE.yml b/config/locales/fr_BE.yml index 5b2e89defd..2fa3fccab6 100644 --- a/config/locales/fr_BE.yml +++ b/config/locales/fr_BE.yml @@ -270,6 +270,7 @@ fr_BE: backordered: "En rupture de stock" on hand: "En stock" ship: "Expédier" + shipping_category: "Catégorie de livraison" actions: create_and_add_another: "Créer et ajouter un nouveau" create: "Créer" @@ -1142,13 +1143,13 @@ fr_BE: menu: cart: cart: "Panier" + cart_sidebar: + checkout: "Etape suivante (coordonnées)" + close: "Ferme" signed_in: profile: "Profil" mobile_menu: cart: "Panier" - joyride: - checkout: "Passer la commande" - already_ordered_products: "Déjà commandé dans ce cycle de vente" register_call: selling_on_ofn: "Intéressé·e à vendre sur Open Food Network?" register: "Démarrez ici" @@ -2695,6 +2696,7 @@ fr_BE: previous: "Précédent" last: "Fin" spree: + more: "Plus" your_order_is_empty_add_product: "Votre commande est vide, merci de chercher et d'ajouter un des produits ci-dessus" add_product: "Ajoutez un produit" name_or_sku: "Nom ou N° d'article (entrer au moins 4 lettres du nom du produit) " diff --git a/config/locales/fr_CA.yml b/config/locales/fr_CA.yml index 78d26c0da0..47e23fb486 100644 --- a/config/locales/fr_CA.yml +++ b/config/locales/fr_CA.yml @@ -271,6 +271,7 @@ fr_CA: backordered: "à volonté" on hand: "En stock" ship: "Expédier" + shipping_category: "Condition de transport" actions: create_and_add_another: "Créer et ajouter nouveau" create: "Créer" @@ -1148,13 +1149,13 @@ fr_CA: menu: cart: cart: "Panier" + cart_sidebar: + checkout: "Finalisation commande" + close: "Ferme" signed_in: profile: "Profil" mobile_menu: cart: "Panier" - joyride: - checkout: "Passer la commande" - already_ordered_products: "Déjà commandé dans ce cycle de vente" register_call: selling_on_ofn: "Vous souhaitez proposer vos produits sur Open Food Network?" register: "Démarrez ici" @@ -2779,6 +2780,7 @@ fr_CA: previous: "Précédent" last: "Fin" spree: + more: "Plus" your_order_is_empty_add_product: "Votre commande est vide, veuillez ajouter des produits" add_product: "Ajouter un produit" name_or_sku: "Nom ou Ref Produit (entrer au moins les 4 premiers caractères du nom du produit)" diff --git a/config/locales/it.yml b/config/locales/it.yml index 7d0ef72e69..35c1d111d1 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -270,6 +270,7 @@ it: backordered: "Ordini arretrati" on hand: "Disponibile" ship: "Spedizione" + shipping_category: "Categoria Spedizioni" actions: create_and_add_another: "Crea e Aggiungi un Altro" create: "Crea" @@ -1148,13 +1149,13 @@ it: menu: cart: cart: "Carrello" + cart_sidebar: + checkout: "Paga" + close: "Chiuso" signed_in: profile: "Profilo" mobile_menu: cart: "Carrello" - joyride: - checkout: "Checkout adesso" - already_ordered_products: "Già richiesto in questo ciclo di richieste" register_call: selling_on_ofn: "Interessato ad entrare in Open Food Network?" register: "Registrati qui" @@ -2771,6 +2772,7 @@ it: previous: "Precedente" last: "Ultimo" spree: + more: "Di più" your_order_is_empty_add_product: "Il tuo ordine è vuoto, cerca e aggiungi un prodotto qui sopra" add_product: "Aggiungi prodotto" name_or_sku: "Nome o SKU (inserisci almeno i primi 4 caratteri del nome del prodotto)" diff --git a/config/locales/nb.yml b/config/locales/nb.yml index cfa66bd401..52289b57dd 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -270,6 +270,7 @@ nb: backordered: "Restbestilte" on hand: "Tilgjengelig" ship: "Levere" + shipping_category: "Leveringskategori" actions: create_and_add_another: "Opprett og legg til en annen" create: "Opprett" @@ -2771,6 +2772,7 @@ nb: previous: "Tidligere" last: "Siste" spree: + more: "Mer" your_order_is_empty_add_product: "Bestillingen din er tom, vennligst søk etter og legg til et produkt over" add_product: "Legg til produkt" name_or_sku: "Navn eller SKU (skriv inn minst 4 tegn av produktnavn)" diff --git a/config/locales/nl_BE.yml b/config/locales/nl_BE.yml index 2a80116410..2b9af3b10d 100644 --- a/config/locales/nl_BE.yml +++ b/config/locales/nl_BE.yml @@ -257,6 +257,7 @@ nl_BE: back_to_payments_list: "Terug naar Betalingslijst" on hand: "Bij de Hand" ship: "Verzenden" + shipping_category: "Verzendcategorie" actions: create_and_add_another: "Een ander maken en toevoegen" create: "Maak" @@ -1102,13 +1103,13 @@ nl_BE: menu: cart: cart: "kar" + cart_sidebar: + checkout: "Kassa" + close: "Sluit" signed_in: profile: "Profiel" mobile_menu: cart: "kar" - joyride: - checkout: "Naar de kassa" - already_ordered_products: "Reeds besteld in de huidige bestelcyclus" register_call: selling_on_ofn: "Geïnteresseerd om deel uit te maken van het Open Food Network?" register: "Registreer hier" @@ -2625,6 +2626,7 @@ nl_BE: previous: "Voorgaande" last: "Laatst" spree: + more: "Meer" your_order_is_empty_add_product: "Je bestelling is leeg, gelieve hierboven een product te zoeken en toe te voegen " add_product: "Voeg een product toe" name_or_sku: "Beschrijving of artikelnummer ( tenminste 4 letters van de productnaam invoeren )" diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 2e4d9c06de..2337322325 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -1082,11 +1082,11 @@ pt: show_on_map: "Mostrar todas as lojas no mapa" shared: menu: + cart_sidebar: + checkout: "Finalizar compra" + close: "Fechar" signed_in: profile: "Perfil" - joyride: - checkout: "Finalizar compra agora" - already_ordered_products: "Já encomendado neste ciclo de encomendas" register_call: selling_on_ofn: "Tem interesse em participar na Open Food Network?" register: "Registe-se aqui" @@ -2582,6 +2582,7 @@ pt: previous: "Anterior" last: "Último" spree: + more: "Mais" your_order_is_empty_add_product: "A sua encomenda está vazia, por favor procure e adicione um produto em cima" add_product: "Adicionar Produto" name_or_sku: "Nome ou Código (insira pelo menos 4 caracteres)" diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml index e2cae6de9f..8d58c3b56f 100644 --- a/config/locales/pt_BR.yml +++ b/config/locales/pt_BR.yml @@ -270,6 +270,7 @@ pt_BR: backordered: "Pedidos em atraso" on hand: "Disponível" ship: "Envio" + shipping_category: "Tipos de Frete" actions: create_and_add_another: "Criar e adicionar outro" create: "Criar" @@ -1141,13 +1142,13 @@ pt_BR: menu: cart: cart: "Carrinho" + cart_sidebar: + checkout: "Fechar pedido" + close: "Fechado" signed_in: profile: "Perfil" mobile_menu: cart: "Carrinho" - joyride: - checkout: "Fechar pedido agora" - already_ordered_products: "Já pediu neste ciclo de pedidos" register_call: selling_on_ofn: "Interessado em registrar a sua iniciativa na Open Food Brasil?" register: "Registre-se aqui" @@ -2766,6 +2767,7 @@ pt_BR: previous: "Anterior" last: "Último" spree: + more: "Mais" your_order_is_empty_add_product: "Seu pedido está vazio, pesquise e adicione um produto acima" add_product: "Adicionar produto" name_or_sku: "Nome ou SKU (digite pelo menos os 4 primeiros caracteres do nome do produto)" diff --git a/config/locales/sv.yml b/config/locales/sv.yml index addd879f88..9877738000 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -633,11 +633,11 @@ sv: show_on_map: "Visa allt på kartan" shared: menu: + cart_sidebar: + checkout: "Utcheckning" + close: "Stängd" signed_in: profile: "Profil" - joyride: - checkout: "Slutför beställning" - already_ordered_products: "Redan beställd i denna beställningsomgång" register_call: selling_on_ofn: "Intresserad av att gå med i Open Food Network?" register: "Registrera dig här" diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 653ec29c07..856613867e 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -3,7 +3,7 @@ tr: activerecord: attributes: enterprise_fee: - fee_type: Ücret TÜRÜ + fee_type: Ücret Türü spree/order: payment_state: Ödeme Durumu shipment_state: ' TESLİMAT Durumu' @@ -18,9 +18,9 @@ tr: supplier: "TEDARİKÇİ" shipping_category_id: "TESLİMAT KATEGORİSİ" variant_unit: "Varyant BİRİMİ" - variant_unit_name: "Varyant Birim ADI" + variant_unit_name: "Varyant Birim Adı" spree/credit_card: - base: "Kredİ kartI" + base: "Kredİ kartı" order_cycle: orders_close_at: BİTİŞ TARİHİ variant_override: @@ -223,7 +223,7 @@ tr: distributors: Dağıtımcılar bulk_order_management: Toplu Sipariş Yönetimi enterprises: İşletmeler - enterprise_groups: Gruplar + enterprise_groups: AĞLAR reports: Raporlar variant_overrides: Stok import: Aktar @@ -287,13 +287,13 @@ tr: email: E-posta ends_at: Bitiş ends_on: Bitiş vakti - name: İsİM + name: Ad on_hand: Mevcut on_demand: Talep Üzerine on_demand?: Talep Üzerine? order_cycle: Sipariş Dönemi payment: Ödeme - payment_method: Ödeme Şekli + payment_method: ÖDEME YÖNTEMİ phone: Telefon price: Fiyat producer: ÜRETİCİ @@ -302,18 +302,18 @@ tr: quantity: Miktar schedule: Takvim shipping: Teslimat - shipping_method: Teslimat Yöntemi + shipping_method: TESLİMAT YÖNTEMİ shop: Dükkan sku: Stok Kodu status_state: Durum - tags: Etiketler + tags: ETİKETLER variant: Varyant weight: Ağırlık volume: Hacim items: Ölçüler select_all: Hepsini seç quick_search: Hızlı Arama - clear_all: Hepsini Temizle + clear_all: HEPSİNİ TEMİZLE start_date: "Başlangıç Tarihi" end_date: "Bitiş Tarihi" form_invalid: "Formda eksik veya geçersiz alanlar var" @@ -515,7 +515,7 @@ tr: options_and_defaults: İçe aktarma seçenekleri ve varsayılanlar no_permission: bu işletmeyi yönetme izniniz yok not_found: işletme veritabanında bulunamadı - no_name: İsİMSİZ + no_name: İSİMSİZ blank_enterprise: bazı ürünler için tanımlanmış bir işletme yok reset_absent?: Mevcut olmayan ürünleri sıfırla reset_absent_tip: Dosyada bulunmayan tüm mevcut ürünler için stoğu sıfıra ayarlayın @@ -639,9 +639,9 @@ tr: website: İnternet sitesi website_placeholder: 'Örn: www.yesilciftlik.com' enterprise_fees: - name: ad + name: Ad fee_type: Ücret Türü - manage_fees: İşletme Ücretlerini Yönet + manage_fees: İŞLETME ÜCRETLERİNİ YÖNET no_fees_yet: Henüz herhangi bir işletme ücretiniz yok. create_button: Şimdi Oluştur images: @@ -663,16 +663,16 @@ tr: payment_methods: name: Ad applies: Uygulanma? - manage: Ödeme Yöntemlerini Yönet + manage: ÖDEME YÖNTEMLERİNİ YÖNET no_method_yet: Henüz herhangi bir ödeme yönteminiz yok. - create_button: Yeni Ödeme Yöntemi Oluştur + create_button: YENİ ÖDEME YÖNTEMİ OLUŞTUR create_one_button: Şimdi Oluştur primary_details: name: Ad name_placeholder: Örn. Ahmet Amca'nın Ekolojik Meyveleri - groups: Gruplar - groups_tip: Üyesi olduğunuz grupları veya bölgeleri seçin. Bu, müşterilerin işletmenizi bulmasına yardımcı olur. - groups_placeholder: Mevcut grupları aramak için yazmaya başlayın ... + groups: AĞLAR + groups_tip: Dahil olduğunuz ağları veya bölgeleri seçin. Bu, müşterilerin işletmenizi bulmasına yardımcı olur. + groups_placeholder: Mevcut ağları aramak için yazmaya başlayın ... primary_producer: Birincil üretici misiniz? primary_producer_tip: Siz de birincil üreticisiyseniz 'Üretici' yi seçin. producer: ÜRETİCİ @@ -693,9 +693,9 @@ tr: ofn_uid_tip: Açık Gıda Ağı'na kayıtlı işletmenize özel tanımlanan kimlik numarası shipping_methods: name: "Ad" - applies: "Aktif?" + applies: "AKTİF?" manage: "Teslimat Yöntemlerini Yönet" - create_button: "Yeni Teslimat Yöntemi Oluştur" + create_button: "Yenİ Teslİmat Yöntemİ Oluştur" create_one_button: "Şimdi Oluştur" no_method_yet: "Henüz herhangi bir teslimat yönteminiz yok." shop_preferences: @@ -779,10 +779,10 @@ tr: email_not_confirmed: "E-posta onaylanmadı" actions: edit_profile: Ayarlar - properties: Özellikler - payment_methods: Ödeme Yöntemleri + properties: ÖZELLİKLER + payment_methods: ÖDEME YÖNTEMLERİ payment_methods_tip: Bu işletmenin henüz ödeme yöntemi yok - shipping_methods: Teslimat Yöntemleri + shipping_methods: TESLİMAT YÖNTEMLERİ shipping_methods_tip: Bu işletme teslimat yöntemlerine sahip enterprise_fees: İşletme Ücretleri enterprise_fees_tip: Bu işletmeye kayıtlı bir ücret yok @@ -883,7 +883,7 @@ tr: outgoing: "Giden" distributor: "Dağıtımcı" products: "Ürünler" - tags: "Etiketler" + tags: "ETİKETLER" delivery_details: "Teslimat Detayları" fees: "Ücretler" previous: "Önceki" @@ -894,7 +894,7 @@ tr: wizard_progress: edit: "1. Genel Ayarlar" incoming: "2. Gelen Ürünler" - outgoing: "3. Giden Ürünler" + outgoing: "3. GİDEN ÜRÜNLER" exchange_form: pickup_time_tip: Bu sipariş dönemine ait siparişlerin müşteriler için hazır olma tarihi pickup_instructions_placeholder: "Teslimat Talimatları" @@ -929,17 +929,17 @@ tr: outgoing: Giden distributor: Dağıtımcı products: Ürünler - tags: Etiketler + tags: ETİKETLER add_a_tag: Etiket ekle delivery_details: Teslimat/Gönderim Bilgileri index: schedule: Takvim - schedules: Takvimler + schedules: TAKVİM new_schedule: Yeni Takvim name_and_timing_form: name: Ad orders_open: 'SİPARİŞ AÇILIŞ:' - coordinator: Koordinatör + coordinator: KOORDİNATÖR orders_close: SİPARİŞ KAPANIŞ row: suppliers: tedarikçileri @@ -1015,7 +1015,7 @@ tr: orders_and_fulfillment: name: Siparişler ve Gerçekleşme Raporları customers: - name: Müşteriler + name: MÜŞTERİLER products_and_inventory: name: Ürünler ve Stok users_and_enterprises: @@ -1225,7 +1225,7 @@ tr: menu_2_url: "/map" menu_3_title: "ÜRETİCİLER" menu_3_url: "/producers" - menu_4_title: "GRUPLAR" + menu_4_title: "AĞLAR" menu_4_url: "/groups" menu_5_title: "HAKKIMIZDA" menu_5_url: "https://hakkimizda.acikgida.com" @@ -1249,7 +1249,7 @@ tr: footer_links_md: "Bağlantılar" footer_about_url: "HAKKIMIZDA URL" user_guide_link: "Kullanıcı Kılavuzu Linki" - name: İSİM + name: Ad first_name: Ad last_name: Soyadı email: E-posta @@ -1281,7 +1281,7 @@ tr: label_map: "HARİTA" label_producer: "ÜRETİCİ" label_producers: "ÜRETİCİLER" - label_groups: "Gruplar" + label_groups: "AĞLAR" label_about: "HAKKIMIZDA" label_connect: "Bağlan" label_learn: "Öğren" @@ -1366,7 +1366,7 @@ tr: brandstory_intro: "Bazen sistemi düzeltmenin en iyi yolu yeni bir sistem yaratmaktır…" brandstory_part1: "Açık Gıda Ağı, adil, temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." brandstory_part2: "AGA, üreticilere ve alıcılara aracısız ticaret faydaları sağlar ve toplumsal iletişimi ve güveni cesaretlendirir. Gıda yetiştiriciliği ve satışının kendine özgü ihtiyaçlarını karşılamak için geliştirilmiştir. Temiz gıdaya ulaşım sürecini kolaylaştırır." - brandstory_part3: "Platform üzerinden yalnızca yerel ve bağımsız gıda üreticileri ve dağıtımcıları satış yapabilir. Siz de ürünlerinizi AGA üzerinden oluşturduğunuz tezgah ile doğrudan alıcılara ulaştırabilir, dilerseniz bölgenizdeki diğer üreticiler ile bir araya gelerek kendi ortak 'Üretici Pazarı' veya 'Türetici Pazarı' nızı oluşturabilirsiniz. Bu şekilde çeşitliliği ve bereketi artırır, dayanışmanın getirdiği faydalardan da yararlanabilirsiniz." + brandstory_part3: "Platform üzerinden yalnızca yerel ve bağımsız gıda üreticileri ve dağıtımcıları satış yapabilir. Siz de ürünlerinizi AGA üzerinden oluşturduğunuz dükan ile doğrudan alıcılara ulaştırabilir, dilerseniz bölgenizdeki diğer üreticiler ile bir araya gelerek kendi ortak 'Üretici Pazarı' veya 'Türetici Pazarı' nızı oluşturabilirsiniz. Bu şekilde çeşitliliği ve bereketi artırır, dayanışmanın getirdiği faydalardan da yararlanabilirsiniz." brandstory_part4: "Her yerde çalışıyor. Her şeyi değiştiriyor." brandstory_part5_strong: "Biz buna Açık Gıda Ağı diyoruz." brandstory_part6: "Hepimiz gıdamızı seviyoruz. Artık gıda sistemimizi de sevmeye başlayabiliriz." @@ -1423,9 +1423,9 @@ tr: order_special_instructions: "Notların:" order_pickup_time: Teslimat için hazır order_pickup_instructions: Teslim Alma Talimatları - order_produce: Üretim + order_produce: Ürün order_total_price: Toplam - order_includes_tax: (vergi dahil) + order_includes_tax: (vergi) order_payment_paypal_successful: PayPal ile ödemeniz başarıyla işlendi. order_hub_info: Pazar Bilgisi order_back_to_store: Siteye Geri Dön @@ -1463,7 +1463,7 @@ tr: email_order_summary_price: "Fiyat" email_order_summary_subtotal: "Ara toplam:" email_order_summary_total: "Toplam:" - email_order_summary_includes_tax: "(vergi dahil):" + email_order_summary_includes_tax: "(vergi):" email_payment_paid: ÖDENDİ email_payment_not_paid: ÖDENMEDİ email_payment_summary: Ödeme özeti @@ -1578,12 +1578,12 @@ tr: components_profiles_popover: "Açık Gıda Ağında bir dükkanı olmayan ancak başka bir sitede kendi satış siteleri olan hesaplar" components_profiles_show: "Profilleri göster" components_filters_nofilters: "Filtresiz" - components_filters_clearfilters: "Tüm filtreleri temizle" + components_filters_clearfilters: "TÜM FİLTRELERİ TEMİZLE" groups_title: Gruplar groups_headline: Gruplar groups_text: "Her üretici özeldir ve her işletmenin ortaya koyabileceği farklı bir değer vardır. Üyelerimiz, ürünlerini, emeklerini ve gıdanın ortak değerleri paylaşan üretici, türetici ve dağıtımcı kolektifleridir. Bu bileşenler, adil ve temiz gıdaya ulaşım yollarını kolaylaştırır ve bozulmuş gıda sistemini hep beraber düzeltmemize yardımcı olur." groups_search: "İsim veya anahtar kelime ile ara" - groups_no_groups: "Grup bulunamadı" + groups_no_groups: "Ağ bulunamadı" groups_about: "Hakkımızda" groups_producers: "ÜRETİCİLERİMİZ" groups_hubs: "Pazarlarımız" @@ -1594,7 +1594,7 @@ tr: groups_contact_website: İnternet sitemizi ziyaret edin groups_contact_facebook: Bizi Facebook'tan takip edin groups_signup_title: Grup olarak kaydolun - groups_signup_headline: Gruplara kaydolma + groups_signup_headline: Ağ kayıt groups_signup_intro: "İşbirliği ve dayanışma temelli satış-pazarlama yöntemleri için harika bir platformuz. Yeni müşterilere ulaşmak ve doğru bir gıda sistemi oluşturmak için.. Basit, şeffaf, dürüst bir sosyal girişim." groups_signup_email: Bize e-posta gönderin groups_signup_motivation1: Gıda sistemlerini adil bir şekilde dönüştürüyoruz. @@ -1646,7 +1646,7 @@ tr: sell_motivation: "Temiz gıdanızı sergileyin." sell_producers: "Üreticiler" sell_hubs: "Pazarlar" - sell_groups: "Gruplar" + sell_groups: "AĞLAR" sell_producers_detail: "AGA üzerinden işletmeniz adına bir profil oluşturun. Dilediğiniz zaman profilinizi bir tezgaha yükseltebilir ve ürünlerinizi müşterilerinize doğrudan satabilirsiniz." sell_hubs_detail: "AGA üzerinden gıda işletmeniz veya topluluğunuz için bir profil oluşturun. İstediğiniz zaman profilinizi çok üreticili bir pazara yükseltebilirsiniz." sell_groups_detail: "Bölgenizdeki veya ağınızdaki işletmelerin (üreticilerin, pazarların veya diğer grupların) detaylı rehber listesini oluşturun." @@ -1819,7 +1819,7 @@ tr: producer_field_error: "Lütfen birini seçin. Üretici misiniz?" yes_producer_help: "Siz de birşeyler yetiştiriyor, büyütüyor, sağıyor, hasat ediyor, pişiriyor kurutuyor veya hazırlıyorsanız, üreticisiniz demektir." no_producer_help: "Üretici değilseniz muhtemelen gıdaya ulaşım sağlayan, dağıtım veya satış yapan bir grup ya da işletmesiniz. Bir dükkan, kooperatif, gıda topluluğu, restaurant veya toptancı bile olabilirsiniz. " - create_profile: "Profil oluştur" + create_profile: "Profil Oluştur" about: title: "HAKKIMIZDA" headline: "Güzel!" @@ -1959,7 +1959,7 @@ tr: product_name: "Ürün Adı" product_description: "Ürün Açıklaması" units: "Ölçü Birimi" - coordinator: "Koordinatör" + coordinator: "KOORDİNATÖR" distributor: "Dağıtımcı" enterprise_fees: "İşletme Ücretleri" process_my_order: "Siparişimi İşle" @@ -1975,8 +1975,8 @@ tr: flat_rate_per_order: "Sabit Ücret (sipariş başına) " flexible_rate: "Esnek Ücret" price_sack: "Değişken Ücret" - new_order_cycles: "Yeni Sipariş Dönemleri" - new_order_cycle: "Yeni Sipariş Dönemi" + new_order_cycles: "YENİ SİPARİŞ DÖNEMİ" + new_order_cycle: "YENİ SİPARİŞ DÖNEMİ" select_a_coordinator_for_your_order_cycle: "Sipariş döneminiz için bir koordinatör seçin" notify_producers: 'Üreticilere bildir' edit_order_cycle: "Sipariş Dönemini Düzenle" @@ -1988,7 +1988,7 @@ tr: started_at: "Başlama tarihi" queued: "sıraya eklendi" scheduled_for: "Planlanan tarih" - customers: "Müşteriler" + customers: "MÜŞTERİLER" please_select_hub: "Lütfen bir pazar seçin" loading_customers: "Müşteriler Yükleniyor" no_customers_found: "Müşteri bulunamadı" @@ -2006,7 +2006,7 @@ tr: spree_admin_overview_enterprises_footer: "İŞLETMELERİMİ YÖNET" spree_admin_enterprises_hubs_name: "ad" spree_admin_enterprises_create_new: "YENİ OLUŞTUR" - spree_admin_enterprises_shipping_methods: "Teslimat Yöntemleri" + spree_admin_enterprises_shipping_methods: "TESLİMAT YÖNTEMLERİ" spree_admin_enterprises_fees: "İşletme Ücretleri" spree_admin_enterprises_none_create_a_new_enterprise: "YENİ BİR İŞLETME OLUŞTUR" spree_admin_enterprises_none_text: "Henüz hiç işletmeniz yok" @@ -2081,7 +2081,7 @@ tr: report_producers: "ÜRECİTİLER:" report_type: "Rapor türü:" report_hubs: "Pazarlar:" - report_payment: "Ödeme yöntemleri:" + report_payment: "ÖDEME YÖNTEMLERİ:" report_distributor: "Dağıtımcı:" report_payment_by: 'Türüne Göre Ödemeler' report_itemised_payment: 'Ayrıntılı Ödeme Toplamları' @@ -2112,7 +2112,7 @@ tr: report_header_paid: Ödeme? report_header_delivery: Teslimat? report_header_shipping: Teslimat - report_header_shipping_method: Teslimat Yöntemi + report_header_shipping_method: TESLİMAT YÖNTEMİ report_header_shipping_instructions: Teslimat bilgileri report_header_ship_street: Teslimat Adresi report_header_ship_street_2: Teslimat Adresi 2 @@ -2131,7 +2131,7 @@ tr: report_header_order_number: Sipariş numarası report_header_date: tarih report_header_confirmation_date: Onay tarihi - report_header_tags: Etiketler + report_header_tags: ETİKETLER report_header_items: Kalemler report_header_items_total: "Toplam ürün %{currency_symbol}" report_header_taxable_items_total: "Vergiye tabi kalemler toplamı (%{currency_symbol})" @@ -2163,7 +2163,7 @@ tr: report_header_shipping_cost: Teslimat Maliyeti report_header_curr_cost_per_unit: Birim Maliyet report_header_total_shipping_cost: Toplam Teslimat Maliyeti - report_header_payment_method: Ödeme Yöntemi + report_header_payment_method: ÖDEME YÖNTEMİ report_header_sells: NE SATIYOR report_header_visible: Görünür report_header_price: Fiyat @@ -2231,7 +2231,7 @@ tr: due_date: "Vade tarihi:" account_code: "Hesap kodu:" equals: "Eşittir" - contains: "içerik" + contains: "İÇERİYOR" discount: "İndirim" filter_products: "Ürünleri Filtrele" delete_product_variant: "Son varyant silinemez!" @@ -2250,21 +2250,21 @@ tr: about: "HAKKIMIZDA" images: "Görseller" web: "Web" - primary_details: "Temel Bilgiler" + primary_details: "TEMEL BİLGİLER" adrdress: "Adres" contact: "İLETİŞİM" social: "Sosyal" business_details: "İşletme Detayları" - properties: "Özellikler" + properties: "ÖZELLİKLER" shipping: "Teslimat" - shipping_methods: "Teslimat Yöntemleri" - payment_methods: "Ödeme yöntemleri" + shipping_methods: "TESLİMAT YÖNTEMLERİ" + payment_methods: "ÖDEME YÖNTEMLERİ" payment_method_fee: "İşlem ücreti" payment_processing_failed: "Ödeme işlenemedi, lütfen girdiğiniz bilgileri kontrol edin" payment_method_not_supported: "Bu ödeme yöntemi desteklenmiyor. Lütfen başka birini seçiniz." payment_updated: "Ödeme Güncellendi" inventory_settings: "Stok Ayarları" - tag_rules: "Etiket Kuralları" + tag_rules: "ETİKET KURALLARI" shop_preferences: "Mağaza Tercihleri" enterprise_fee_whole_order: Tüm sipariş enterprise_fee_by: "%{role}%{enterprise_name} tarafından%{type} ücreti" @@ -2345,11 +2345,11 @@ tr: enterprise_limit_reached: "Hesap başına standart işletme sınırına ulaştınız. Artırmanız gerekiyorsa %{contact_email}'a yazın." modals: got_it: Anladım - close: "KAPANIŞ" + close: "Kapat" invite: "Davet et" invite_title: "Kayıtlı olmayan bir kullanıcıyı davet et" tag_rule_help: - title: Etiket Kuralları + title: ETİKET KURALLARI overview: genel bakış overview_text: > Etiket kuralları müşterileri özelinde hangi seçeneklerin görünür veya @@ -2360,7 +2360,7 @@ tr: Varsayılan kurallar istediğiniz ürünleri gizlemenizi ve varsayılanda görünür olmamalarını sağlar. Bu tercihlerinizi, müşteri bazlı etiketler için kurallar belirleyerek değiştirebilirsiniz. - customer_tagged_rules: "'Müşteriler Etiketleri' Kuralları" + customer_tagged_rules: "'Müşteri Etiketleri' Kuralları" customer_tagged_rules_text: > Spesifik bir müşteri etiketi için kural oluşturarak, varsayılan görünürlük kuralını da güncellemiş olursunuz. (yalnızca ilgili müşteriler için) @@ -2469,7 +2469,7 @@ tr: tag_rules: shipping_method_tagged_top: "Teslimat Yöntemi etiketi" shipping_method_tagged_bottom: "ise durumu:" - payment_method_tagged_top: "Ödeme Yönteml etiketi" + payment_method_tagged_top: "Ödeme Yöntemi etiketi" payment_method_tagged_bottom: "ise durumu:" order_cycle_tagged_top: "Sipariş Dönemi etiketi" order_cycle_tagged_bottom: "ise durumu:" @@ -2581,10 +2581,10 @@ tr: changing_on_hand_stock: Eldeki stok seviyeleri değiştiriliyor ... stock_reset: Stoklar varsayılana ayarlanır tag_rules: - show_hide_variants: 'DÜKKANIMDA VARYANTLARI GÖSTER VEYA GİZLE' + show_hide_variants: 'Dükkanımda varyantları göster veya gizle' show_hide_shipping: 'Ödeme sırasında teslimat yöntemlerini göster veya gizle' show_hide_payment: 'Ödeme sırasında ödeme yöntemlerini göster veya gizle' - show_hide_order_cycles: 'DÜKKANIMDA SİPARİŞ DÖNEMLERİNİ GÖSTER VEYA GİZLE' + show_hide_order_cycles: 'Dükkanımda sipariş dönemlerini göster veya gizle' visible: GÖRÜNÜR not_visible: GİZLİ services: @@ -2722,7 +2722,7 @@ tr: fee_placements: supplier: "Gelen" distributor: "Giden" - coordinator: "Koordinatör" + coordinator: "KOORDİNATÖR" tax_category_name: shipping_instance_rate: "Platform Hızı" formats: @@ -2740,7 +2740,7 @@ tr: header: fee_type: "Ücret Türü" enterprise_name: "İşletme Sahibi" - fee_name: "ÜCRET ADI" + fee_name: "Ücret Adı" customer_name: "Müşteri" fee_placement: "Ücret Yerleşimi" fee_calculated_on_transfer_through_name: "Aktarma Ücreti Hesaplama" @@ -2755,7 +2755,7 @@ tr: payments: "Ödemeler" return_authorizations: "İade Yetkileri" payment: "Ödeme" - payment_method: "Ödeme yöntemi" + payment_method: "ÖDEME YÖNTEMİ" shipment: "Teslimat" shipment_inc_vat: "KDV dahil teslimat" shipping_tax_rate: "Kargo Vergi Oranı" @@ -2769,7 +2769,7 @@ tr: logout: "Çıkış Yap" date_range: "Tarih aralığı" status: "durum" - new: "Yeni" + new: "YENİ" start: "Başlangıç" end: "Son" stop: "Bitiş" @@ -2807,7 +2807,7 @@ tr: account: "Hesap" billing_address: "Fatura Adresi" shipping_address: "Teslimat Adresi" - first_name: "İsim" + first_name: "Ad" last_name: "Soyadı" street_address: "Açık adres" street_address_2: "Açık Adres (devam)" @@ -2895,11 +2895,11 @@ tr: states: "Şehİrler" abbreviation: "Kısaltma" new_state: "Yeni Şehir" - payment_methods: "Ödeme yöntemleri" + payment_methods: "ÖDEME YÖNTEMLERİ" taxonomies: "KATEGORİ" new_taxonomy: "YENİ KATEGORİ" back_to_taxonomies_list: "Kategori Listesine Geri Dön" - shipping_methods: "Teslimat Yöntemleri" + shipping_methods: "TESLİMAT YÖNTEMLERİ" shipping_categories: "Nakliye Kategorileri" new_shipping_category: "Yeni Nakliye Kategorisi" back_to_shipping_categories: "Teslimat Kategorilerine Geri Dön" @@ -2911,7 +2911,7 @@ tr: zone: "bölge" display: "GÖSTER" environment: "çevre" - active: "Aktif" + active: "AKTİF" nore: "Daha fazla" no_results: "Sonuç yok" create: "Oluştur" @@ -2970,7 +2970,7 @@ tr: subscriptions: "Üyelikler" products: "Ürünler" option_types: "Seçenek Türleri" - properties: "Özellikler" + properties: "ÖZELLİKLER" variant_overrides: "Stok" reports: "Raporlar" configuration: "KURULUM" @@ -2979,8 +2979,8 @@ tr: order_cycles: "SİPARİŞ DÖNEMLERİ" enterprises: "İşletmeler" enterprise_relationships: "İZİNLER" - customers: "Müşteriler" - groups: "Gruplar" + customers: "MÜŞTERİLER" + groups: "AĞLAR" product_properties: index: inherits_properties_checkbox_hint: "Özellikler %{supplier}'den devralınsın mı? (yukarıda geçersiz kılınmadıkça)" @@ -2988,9 +2988,9 @@ tr: select_from_prototype: "Prototipten Seç" properties: index: - properties: "Özellikler" + properties: "ÖZELLİKLER" new_property: "Yeni Özellik" - name: "ad" + name: "Ad" presentation: "Sunum" new: new_property: "Yeni Özellik" @@ -2998,7 +2998,7 @@ tr: editing_property: "Özellikleri Düzenle" back_to_properties_list: "Özellikler Listesine Geri Dön" form: - name: "ad" + name: "Ad" presentation: "Sunum" return_authorizations: index: @@ -3089,9 +3089,9 @@ tr: manage_order_cycles: "SİPARİŞ DÖNEMLERİNİ YÖNET" shipping_methods: index: - shipping_methods: "Teslimat Yöntemleri" - new_shipping_method: "Yeni Teslimat Yöntemi" - name: "ad" + shipping_methods: "TESLİMAT YÖNTEMLERİ" + new_shipping_method: "YENİ TESLİMAT YÖNTEMİ" + name: "Ad" products_distributor: "Dağıtımcı" zone: "bölge" calculator: "Hesaplama" @@ -3100,12 +3100,12 @@ tr: back_end: "Sadece panel" no_shipping_methods_found: "Hiçbir teslimat yöntemi bulunamadı" new: - new_shipping_method: "Yeni Teslimat Yöntemi" - back_to_shipping_methods_list: "Teslimat Yöntemlerine Geri Dön" + new_shipping_method: "YENİ TESLİMAT YÖNTEMİ" + back_to_shipping_methods_list: "Teslİmat Yöntemlerİne Gerİ Dön" edit: - editing_shipping_method: "Teslimat Yöntemini Düzenle" - new: "Yeni" - back_to_shipping_methods_list: "Teslimat Yöntemlerine Geri Dön" + editing_shipping_method: "Teslİmat YöntemİNİ Düzenle" + new: "YENİ" + back_to_shipping_methods_list: "Teslİmat Yöntemlerİne Gerİ Dön" form: categories: "Kategoriler" zones: "bölgeler" @@ -3115,13 +3115,13 @@ tr: payment_methods: index: payment_methods: "ÖDEME YÖNTEMLERİ" - new_payment_method: "Yeni Ödeme Yöntemi" - name: "İSİM" + new_payment_method: "YENİ ÖDEME YÖNTEMİ" + name: "Ad" products_distributor: "Dağıtımcı" provider: "Sağlayıcı" environment: "Çevre" display: "GÖSTER" - active: "Aktif" + active: "AKTİF" both: "Her ikisi de" front_end: "Sadece Ödeme" back_end: "Sadece panel" @@ -3129,10 +3129,10 @@ tr: active_no: "Hayır" no_payment_methods_found: "Ödeme yöntemi bulunamadı" new: - new_payment_method: "Yeni Ödeme Yöntemi" + new_payment_method: "YENİ ÖDEME YÖNTEMİ" back_to_payment_methods_list: "Ödeme Yöntemleri Listesine Geri Dön" edit: - new: "Yeni" + new: "YENİ" editing_payment_method: "Ödeme Yöntemi Düzenleniyor" back_to_payment_methods_list: "Ödeme Yöntemleri Listesine Geri Dön" stripe_connect: @@ -3146,20 +3146,20 @@ tr: status: durum connected: bağlı account_id: Hesap Kimliği - business_name: işletme adı + business_name: İşletme Adı charges_enabled: Masraflar Etkin form: - name: "İSİM" + name: "Ad" description: "Açıklama" environment: "Çevre" display: "GÖSTER" - active: "Aktif" + active: "AKTİF" active_yes: "Evet" active_no: "Hayır" both: "Ödeme Sayfası ve Panel" front_end: "Sadece Ödeme" back_end: "Sadece panel" - tags: "Etiketler" + tags: "ETİKETLER" deactivation_warning: "Bir ödeme yöntemini kaldırmak listenizden silinmesine sebep olabilir. Alternatif olarak, ödeme yöntemi ayarını 'Göster' yerine 'Sadece Panel' olarak değiştirebilirsiniz. " providers: provider: "Sağlayıcı" @@ -3193,7 +3193,7 @@ tr: no_products: "Henüz ürün yok. Neden biraz eklemiyorsun?" no_results: "Üzgünüz, sonuç bulunamadı" products_head: - name: ad + name: Ad unit: birim display_as: Gösterme Şekli category: Kategori @@ -3361,7 +3361,7 @@ tr: returned: iade edildi skrill: skrill subscription_state: - active: aktif + active: AKTİF pending: bekliyor ended: bitti paused: durduruldu From eeb6c57f9945dbdaec69a16f6d5f48ac70c24461 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 17:55:35 +0200 Subject: [PATCH 107/261] Update missing image paths in other order views --- app/views/spree/orders/_bought.html.haml | 6 +++--- app/views/spree/orders/_line_item.html.haml | 6 +++--- app/views/spree/orders/_summary.html.haml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/views/spree/orders/_bought.html.haml b/app/views/spree/orders/_bought.html.haml index e739caeff2..eb9e9edd48 100644 --- a/app/views/spree/orders/_bought.html.haml +++ b/app/views/spree/orders/_bought.html.haml @@ -16,10 +16,10 @@ %td.cart-item-description %div.item-thumb-image - - if variant.images.length == 0 - = mini_image(variant.product) + - if variant.product.images.length == 0 + = image_tag("/noimage/mini.png") - else - = image_tag(variant.images.first.attachment.url(:mini)) + = image_tag(variant.product.images.first.attachment.url(:mini)) = render 'spree/shared/line_item_name', line_item: line_item %span.already-confirmed= t(:orders_bought_already_confirmed) diff --git a/app/views/spree/orders/_line_item.html.haml b/app/views/spree/orders/_line_item.html.haml index 918a520fdf..97fce45415 100644 --- a/app/views/spree/orders/_line_item.html.haml +++ b/app/views/spree/orders/_line_item.html.haml @@ -2,10 +2,10 @@ %td.cart-item-description{'data-hook' => "cart_item_description"} %div.item-thumb-image{"data-hook" => "cart_item_image"} - - if variant.images.length == 0 - = mini_image(variant.product) + - if variant.product.images.length == 0 + = image_tag("/noimage/mini.png") - else - = image_tag(variant.images.first.attachment.url(:mini)) + = image_tag(variant.product.images.first.attachment.url(:mini)) = render 'spree/shared/line_item_name', line_item: line_item diff --git a/app/views/spree/orders/_summary.html.haml b/app/views/spree/orders/_summary.html.haml index 670a9b6ec7..1227dd24ff 100644 --- a/app/views/spree/orders/_summary.html.haml +++ b/app/views/spree/orders/_summary.html.haml @@ -16,10 +16,10 @@ %td(data-hook = "order_item_description") %div.item-thumb-image{"data-hook" => "order_item_image"} - - if item.variant.images.length == 0 - = mini_image(item.variant.product) + - if item.variant.product.images.length == 0 + = image_tag("/noimage/mini.png") - else - = image_tag(item.variant.images.first.attachment.url(:mini)) + = image_tag(item.variant.product.images.first.attachment.url(:mini)) = render 'spree/shared/line_item_name', line_item: item From 8fc407a9d54623a691c310825b3f6155f33eda4f Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 2 Jul 2020 17:58:51 +0200 Subject: [PATCH 108/261] Extract repeated variant thumbnail code to a shared partial --- app/views/spree/orders/_bought.html.haml | 5 +---- app/views/spree/orders/_line_item.html.haml | 5 +---- app/views/spree/orders/_summary.html.haml | 6 +----- app/views/spree/shared/_variant_thumbnail.html.haml | 4 ++++ 4 files changed, 7 insertions(+), 13 deletions(-) create mode 100644 app/views/spree/shared/_variant_thumbnail.html.haml diff --git a/app/views/spree/orders/_bought.html.haml b/app/views/spree/orders/_bought.html.haml index eb9e9edd48..f7030b31a8 100644 --- a/app/views/spree/orders/_bought.html.haml +++ b/app/views/spree/orders/_bought.html.haml @@ -16,10 +16,7 @@ %td.cart-item-description %div.item-thumb-image - - if variant.product.images.length == 0 - = image_tag("/noimage/mini.png") - - else - = image_tag(variant.product.images.first.attachment.url(:mini)) + = render 'spree/shared/variant_thumbnail', variant: variant = render 'spree/shared/line_item_name', line_item: line_item %span.already-confirmed= t(:orders_bought_already_confirmed) diff --git a/app/views/spree/orders/_line_item.html.haml b/app/views/spree/orders/_line_item.html.haml index 97fce45415..19292cb219 100644 --- a/app/views/spree/orders/_line_item.html.haml +++ b/app/views/spree/orders/_line_item.html.haml @@ -2,10 +2,7 @@ %td.cart-item-description{'data-hook' => "cart_item_description"} %div.item-thumb-image{"data-hook" => "cart_item_image"} - - if variant.product.images.length == 0 - = image_tag("/noimage/mini.png") - - else - = image_tag(variant.product.images.first.attachment.url(:mini)) + = render 'spree/shared/variant_thumbnail', variant: variant = render 'spree/shared/line_item_name', line_item: line_item diff --git a/app/views/spree/orders/_summary.html.haml b/app/views/spree/orders/_summary.html.haml index 1227dd24ff..f1c25fea61 100644 --- a/app/views/spree/orders/_summary.html.haml +++ b/app/views/spree/orders/_summary.html.haml @@ -16,11 +16,7 @@ %td(data-hook = "order_item_description") %div.item-thumb-image{"data-hook" => "order_item_image"} - - if item.variant.product.images.length == 0 - = image_tag("/noimage/mini.png") - - else - = image_tag(item.variant.product.images.first.attachment.url(:mini)) - + = render 'spree/shared/variant_thumbnail', variant: item.variant = render 'spree/shared/line_item_name', line_item: item diff --git a/app/views/spree/shared/_variant_thumbnail.html.haml b/app/views/spree/shared/_variant_thumbnail.html.haml new file mode 100644 index 0000000000..719725c927 --- /dev/null +++ b/app/views/spree/shared/_variant_thumbnail.html.haml @@ -0,0 +1,4 @@ +- if variant.product.images.length == 0 + = image_tag("/noimage/mini.png") +- else + = image_tag(variant.product.images.first.attachment.url(:mini)) From 4fce50620153e0bf70b3b9d1f2ee38c78ee6f43a Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 15:48:19 +0100 Subject: [PATCH 109/261] Bring splitter/base from spree --- app/models/spree/stock/splitter/base.rb | 29 +++++++++++++++ spec/models/spree/stock/splitter/base_spec.rb | 37 +++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 app/models/spree/stock/splitter/base.rb create mode 100644 spec/models/spree/stock/splitter/base_spec.rb diff --git a/app/models/spree/stock/splitter/base.rb b/app/models/spree/stock/splitter/base.rb new file mode 100644 index 0000000000..46ee1499bb --- /dev/null +++ b/app/models/spree/stock/splitter/base.rb @@ -0,0 +1,29 @@ +module Spree + module Stock + module Splitter + class Base + attr_reader :packer, :next_splitter + + def initialize(packer, next_splitter=nil) + @packer = packer + @next_splitter = next_splitter + end + delegate :stock_location, :order, to: :packer + + def split(packages) + return_next(packages) + end + + private + + def return_next(packages) + next_splitter ? next_splitter.split(packages) : packages + end + + def build_package(contents=[]) + @packer.package_factory.new(stock_location, order, contents) + end + end + end + end +end diff --git a/spec/models/spree/stock/splitter/base_spec.rb b/spec/models/spree/stock/splitter/base_spec.rb new file mode 100644 index 0000000000..a8b58e0e7b --- /dev/null +++ b/spec/models/spree/stock/splitter/base_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +module Spree + module Stock + module Splitter + describe Base do + let(:packer) { build(:stock_packer) } + + it 'continues to splitter chain' do + splitter1 = Base.new(packer) + splitter2 = Base.new(packer, splitter1) + packages = [] + + splitter1.should_receive(:split).with(packages) + splitter2.split(packages) + end + + it 'builds package using package factory' do + # Basic extension of Base splitter used to test build_package method + class ::BasicSplitter < Base + def split(packages) + build_package + end + end + + # Custom package used to test setting package factory + class ::CustomPackage + def initialize(stock_location, order, splitters); end + end + allow(Spree::Config).to receive(:package_factory) { CustomPackage } + + expect(::BasicSplitter.new(packer).split(nil).class).to eq CustomPackage + end + end + end + end +end From 735ee1e7ed733d57f1e6f8abe469519b28606517 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 15:50:31 +0100 Subject: [PATCH 110/261] Fix simple rubocop issues --- app/models/spree/stock/splitter/base.rb | 6 ++++-- spec/models/spree/stock/splitter/base_spec.rb | 4 +++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/spree/stock/splitter/base.rb b/app/models/spree/stock/splitter/base.rb index 46ee1499bb..ba2f8b9de9 100644 --- a/app/models/spree/stock/splitter/base.rb +++ b/app/models/spree/stock/splitter/base.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + module Spree module Stock module Splitter class Base attr_reader :packer, :next_splitter - def initialize(packer, next_splitter=nil) + def initialize(packer, next_splitter = nil) @packer = packer @next_splitter = next_splitter end @@ -20,7 +22,7 @@ module Spree next_splitter ? next_splitter.split(packages) : packages end - def build_package(contents=[]) + def build_package(contents = []) @packer.package_factory.new(stock_location, order, contents) end end diff --git a/spec/models/spree/stock/splitter/base_spec.rb b/spec/models/spree/stock/splitter/base_spec.rb index a8b58e0e7b..d1b368494f 100644 --- a/spec/models/spree/stock/splitter/base_spec.rb +++ b/spec/models/spree/stock/splitter/base_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree @@ -18,7 +20,7 @@ module Spree it 'builds package using package factory' do # Basic extension of Base splitter used to test build_package method class ::BasicSplitter < Base - def split(packages) + def split(_packages) build_package end end From d18fec71255fb55efdf6b40c0ad70a5c3eef1ce9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:00:05 +0100 Subject: [PATCH 111/261] Move Base splitter from main app models to order management engine services --- app/models/spree/stock/splitter/base.rb | 31 --------------- config/application.rb | 2 +- .../order_management/stock/basic_splitter.rb | 29 ++++++++++++++ .../stock/basic_splitter_spec.rb | 37 ++++++++++++++++++ spec/config/application_spec.rb | 4 +- spec/models/spree/stock/splitter/base_spec.rb | 39 ------------------- 6 files changed, 69 insertions(+), 73 deletions(-) delete mode 100644 app/models/spree/stock/splitter/base.rb create mode 100644 engines/order_management/app/services/order_management/stock/basic_splitter.rb create mode 100644 engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb delete mode 100644 spec/models/spree/stock/splitter/base_spec.rb diff --git a/app/models/spree/stock/splitter/base.rb b/app/models/spree/stock/splitter/base.rb deleted file mode 100644 index ba2f8b9de9..0000000000 --- a/app/models/spree/stock/splitter/base.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: true - -module Spree - module Stock - module Splitter - class Base - attr_reader :packer, :next_splitter - - def initialize(packer, next_splitter = nil) - @packer = packer - @next_splitter = next_splitter - end - delegate :stock_location, :order, to: :packer - - def split(packages) - return_next(packages) - end - - private - - def return_next(packages) - next_splitter ? next_splitter.split(packages) : packages - end - - def build_package(contents = []) - @packer.package_factory.new(stock_location, order, contents) - end - end - end - end -end diff --git a/config/application.rb b/config/application.rb index d48b5d2b8b..419638b236 100644 --- a/config/application.rb +++ b/config/application.rb @@ -83,7 +83,7 @@ module Openfoodnetwork # we must use this splitter and no other initializer "spree.register.stock_splitters" do |app| app.config.spree.stock_splitters = [ - Spree::Stock::Splitter::Base + OrderManagement::Stock::BasicSplitter ] end diff --git a/engines/order_management/app/services/order_management/stock/basic_splitter.rb b/engines/order_management/app/services/order_management/stock/basic_splitter.rb new file mode 100644 index 0000000000..eacbf05704 --- /dev/null +++ b/engines/order_management/app/services/order_management/stock/basic_splitter.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +module OrderManagement + module Stock + class BasicSplitter + attr_reader :packer, :next_splitter + + def initialize(packer, next_splitter = nil) + @packer = packer + @next_splitter = next_splitter + end + delegate :stock_location, :order, to: :packer + + def split(packages) + return_next(packages) + end + + private + + def return_next(packages) + next_splitter ? next_splitter.split(packages) : packages + end + + def build_package(contents = []) + @packer.package_factory.new(stock_location, order, contents) + end + end + end +end diff --git a/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb b/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb new file mode 100644 index 0000000000..9cd68834b8 --- /dev/null +++ b/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module OrderManagement + module Stock + describe BasicSplitter do + let(:packer) { build(:stock_packer) } + + it 'continues to splitter chain' do + splitter1 = BasicSplitter.new(packer) + splitter2 = BasicSplitter.new(packer, splitter1) + packages = [] + + splitter1.should_receive(:split).with(packages) + splitter2.split(packages) + end + + it 'builds package using package factory' do + # Basic extension of Base splitter used to test build_package method + class ::RealSplitter < BasicSplitter + def split(_packages) + build_package + end + end + + # Custom package used to test setting package factory + class ::CustomPackage + def initialize(stock_location, order, splitters); end + end + allow(Spree::Config).to receive(:package_factory) { CustomPackage } + + expect(::RealSplitter.new(packer).split(nil).class).to eq CustomPackage + end + end + end +end diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb index 126325a4f1..40c8d1c302 100644 --- a/spec/config/application_spec.rb +++ b/spec/config/application_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Openfoodnetwork::Application, 'configuration' do let(:config) { described_class.config } - it "sets Spree::Stock::Splitter::Base as the only stock splitter" do - expect(config.spree.stock_splitters).to eq [Spree::Stock::Splitter::Base] + it "sets OrderManagement::Stock::BasicSplitter as the only stock splitter" do + expect(config.spree.stock_splitters).to eq [OrderManagement::Stock::BasicSplitter] end end diff --git a/spec/models/spree/stock/splitter/base_spec.rb b/spec/models/spree/stock/splitter/base_spec.rb deleted file mode 100644 index d1b368494f..0000000000 --- a/spec/models/spree/stock/splitter/base_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -module Spree - module Stock - module Splitter - describe Base do - let(:packer) { build(:stock_packer) } - - it 'continues to splitter chain' do - splitter1 = Base.new(packer) - splitter2 = Base.new(packer, splitter1) - packages = [] - - splitter1.should_receive(:split).with(packages) - splitter2.split(packages) - end - - it 'builds package using package factory' do - # Basic extension of Base splitter used to test build_package method - class ::BasicSplitter < Base - def split(_packages) - build_package - end - end - - # Custom package used to test setting package factory - class ::CustomPackage - def initialize(stock_location, order, splitters); end - end - allow(Spree::Config).to receive(:package_factory) { CustomPackage } - - expect(::BasicSplitter.new(packer).split(nil).class).to eq CustomPackage - end - end - end - end -end From 3ae2877d4ec21066f007e366d0671b0b186f439b Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:03:46 +0100 Subject: [PATCH 112/261] Bring adjuster and prioritizer from spree_core --- app/models/spree/stock/adjuster.rb | 28 +++++ app/models/spree/stock/prioritizer.rb | 47 +++++++++ spec/models/spree/stock/prioritizer_spec.rb | 111 ++++++++++++++++++++ 3 files changed, 186 insertions(+) create mode 100644 app/models/spree/stock/adjuster.rb create mode 100644 app/models/spree/stock/prioritizer.rb create mode 100644 spec/models/spree/stock/prioritizer_spec.rb diff --git a/app/models/spree/stock/adjuster.rb b/app/models/spree/stock/adjuster.rb new file mode 100644 index 0000000000..91e38ed345 --- /dev/null +++ b/app/models/spree/stock/adjuster.rb @@ -0,0 +1,28 @@ +# Used by Prioritizer to adjust item quantities +# see prioritizer_spec for use cases +module Spree + module Stock + class Adjuster + attr_accessor :variant, :need, :status + + def initialize(variant, quantity, status) + @variant = variant + @need = quantity + @status = status + end + + def adjust(item) + if item.quantity >= need + item.quantity = need + @need = 0 + elsif item.quantity < need + @need -= item.quantity + end + end + + def fulfilled? + @need == 0 + end + end + end +end diff --git a/app/models/spree/stock/prioritizer.rb b/app/models/spree/stock/prioritizer.rb new file mode 100644 index 0000000000..cdef38e043 --- /dev/null +++ b/app/models/spree/stock/prioritizer.rb @@ -0,0 +1,47 @@ +module Spree + module Stock + class Prioritizer + attr_reader :packages, :order + + def initialize(order, packages, adjuster_class=Adjuster) + @order = order + @packages = packages + @adjuster_class = adjuster_class + end + + def prioritized_packages + sort_packages + adjust_packages + prune_packages + packages + end + + private + def adjust_packages + order.line_items.each do |line_item| + adjuster = @adjuster_class.new(line_item.variant, line_item.quantity, :on_hand) + + visit_packages(adjuster) + + adjuster.status = :backordered + visit_packages(adjuster) + end + end + + def visit_packages(adjuster) + packages.each do |package| + item = package.find_item adjuster.variant, adjuster.status + adjuster.adjust(item) if item + end + end + + def sort_packages + # order packages by preferred stock_locations + end + + def prune_packages + packages.reject! { |pkg| pkg.empty? } + end + end + end +end diff --git a/spec/models/spree/stock/prioritizer_spec.rb b/spec/models/spree/stock/prioritizer_spec.rb new file mode 100644 index 0000000000..52ce3ae97e --- /dev/null +++ b/spec/models/spree/stock/prioritizer_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +module Spree + module Stock + describe Prioritizer do + let(:order) { create(:order_with_line_items, line_items_count: 2) } + let(:stock_location) { build(:stock_location) } + let(:variant1) { order.line_items[0].variant } + let(:variant2) { order.line_items[1].variant } + + def pack + package = Package.new(order, stock_location) + yield(package) if block_given? + package + end + + it 'keeps a single package' do + package1 = pack do |package| + package.add variant1, 1, :on_hand + package.add variant2, 1, :on_hand + end + + packages = [package1] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + packages.size.should eq 1 + end + + it 'removes duplicate packages' do + package1 = pack do |package| + package.add variant1, 1, :on_hand + package.add variant2, 1, :on_hand + end + package2 = pack do |package| + package.add variant1, 1, :on_hand + package.add variant2, 1, :on_hand + end + + packages = [package1, package2] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + packages.size.should eq 1 + end + + it 'split over 2 packages' do + package1 = pack do |package| + package.add variant1, 1, :on_hand + end + package2 = pack do |package| + package.add variant2, 1, :on_hand + end + + packages = [package1, package2] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + packages.size.should eq 2 + end + + it '1st has some, 2nd has remaining' do + order.line_items[0].stub(:quantity => 5) + package1 = pack do |package| + package.add variant1, 2, :on_hand + end + package2 = pack do |package| + package.add variant1, 5, :on_hand + end + + packages = [package1, package2] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + packages.count.should eq 2 + packages[0].quantity.should eq 2 + packages[1].quantity.should eq 3 + end + + it '1st has backorder, 2nd has some' do + order.line_items[0].stub(:quantity => 5) + package1 = pack do |package| + package.add variant1, 5, :backordered + end + package2 = pack do |package| + package.add variant1, 2, :on_hand + end + + packages = [package1, package2] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + + packages[0].quantity(:backordered).should eq 3 + packages[1].quantity(:on_hand).should eq 2 + end + + it '1st has backorder, 2nd has all' do + order.line_items[0].stub(:quantity => 5) + package1 = pack do |package| + package.add variant1, 3, :backordered + package.add variant2, 1, :on_hand + end + package2 = pack do |package| + package.add variant1, 5, :on_hand + end + + packages = [package1, package2] + prioritizer = Prioritizer.new(order, packages) + packages = prioritizer.prioritized_packages + packages[0].quantity(:backordered).should eq 0 + packages[1].quantity(:on_hand).should eq 5 + end + end + end +end From eb13595fd3c8ef45f21221e9bbc4ec60d0cee3a9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:08:05 +0100 Subject: [PATCH 113/261] Fix simple rubocop issues --- app/models/spree/stock/adjuster.rb | 4 +++- app/models/spree/stock/prioritizer.rb | 7 +++++-- spec/models/spree/stock/prioritizer_spec.rb | 8 +++++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/app/models/spree/stock/adjuster.rb b/app/models/spree/stock/adjuster.rb index 91e38ed345..4926e8a7e6 100644 --- a/app/models/spree/stock/adjuster.rb +++ b/app/models/spree/stock/adjuster.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Used by Prioritizer to adjust item quantities # see prioritizer_spec for use cases module Spree @@ -21,7 +23,7 @@ module Spree end def fulfilled? - @need == 0 + @need.zero? end end end diff --git a/app/models/spree/stock/prioritizer.rb b/app/models/spree/stock/prioritizer.rb index cdef38e043..41ef339702 100644 --- a/app/models/spree/stock/prioritizer.rb +++ b/app/models/spree/stock/prioritizer.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module Spree module Stock class Prioritizer attr_reader :packages, :order - def initialize(order, packages, adjuster_class=Adjuster) + def initialize(order, packages, adjuster_class = Adjuster) @order = order @packages = packages @adjuster_class = adjuster_class @@ -17,6 +19,7 @@ module Spree end private + def adjust_packages order.line_items.each do |line_item| adjuster = @adjuster_class.new(line_item.variant, line_item.quantity, :on_hand) @@ -40,7 +43,7 @@ module Spree end def prune_packages - packages.reject! { |pkg| pkg.empty? } + packages.reject!(&:empty?) end end end diff --git a/spec/models/spree/stock/prioritizer_spec.rb b/spec/models/spree/stock/prioritizer_spec.rb index 52ce3ae97e..c038a6dfeb 100644 --- a/spec/models/spree/stock/prioritizer_spec.rb +++ b/spec/models/spree/stock/prioritizer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree @@ -57,7 +59,7 @@ module Spree end it '1st has some, 2nd has remaining' do - order.line_items[0].stub(:quantity => 5) + order.line_items[0].stub(quantity: 5) package1 = pack do |package| package.add variant1, 2, :on_hand end @@ -74,7 +76,7 @@ module Spree end it '1st has backorder, 2nd has some' do - order.line_items[0].stub(:quantity => 5) + order.line_items[0].stub(quantity: 5) package1 = pack do |package| package.add variant1, 5, :backordered end @@ -91,7 +93,7 @@ module Spree end it '1st has backorder, 2nd has all' do - order.line_items[0].stub(:quantity => 5) + order.line_items[0].stub(quantity: 5) package1 = pack do |package| package.add variant1, 3, :backordered package.add variant2, 1, :on_hand From a6d7acb6f1c6f5b811168d78a1f35756ba0c9d46 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:12:16 +0100 Subject: [PATCH 114/261] Convert spec to modern rspec syntax --- .../stock/basic_splitter_spec.rb | 2 +- spec/models/spree/stock/prioritizer_spec.rb | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb b/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb index 9cd68834b8..a8265a1d01 100644 --- a/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb @@ -12,7 +12,7 @@ module OrderManagement splitter2 = BasicSplitter.new(packer, splitter1) packages = [] - splitter1.should_receive(:split).with(packages) + expect(splitter1).to receive(:split).with(packages) splitter2.split(packages) end diff --git a/spec/models/spree/stock/prioritizer_spec.rb b/spec/models/spree/stock/prioritizer_spec.rb index c038a6dfeb..aee367e7b7 100644 --- a/spec/models/spree/stock/prioritizer_spec.rb +++ b/spec/models/spree/stock/prioritizer_spec.rb @@ -25,7 +25,7 @@ module Spree packages = [package1] prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages.size.should eq 1 + expect(packages.size).to eq 1 end it 'removes duplicate packages' do @@ -41,7 +41,7 @@ module Spree packages = [package1, package2] prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages.size.should eq 1 + expect(packages.size).to eq 1 end it 'split over 2 packages' do @@ -55,7 +55,7 @@ module Spree packages = [package1, package2] prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages.size.should eq 2 + expect(packages.size).to eq 2 end it '1st has some, 2nd has remaining' do @@ -70,9 +70,9 @@ module Spree packages = [package1, package2] prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages.count.should eq 2 - packages[0].quantity.should eq 2 - packages[1].quantity.should eq 3 + expect(packages.count).to eq 2 + expect(packages[0].quantity).to eq 2 + expect(packages[1].quantity).to eq 3 end it '1st has backorder, 2nd has some' do @@ -88,8 +88,8 @@ module Spree prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages[0].quantity(:backordered).should eq 3 - packages[1].quantity(:on_hand).should eq 2 + expect(packages[0].quantity(:backordered)).to eq 3 + expect(packages[1].quantity(:on_hand)).to eq 2 end it '1st has backorder, 2nd has all' do @@ -105,8 +105,8 @@ module Spree packages = [package1, package2] prioritizer = Prioritizer.new(order, packages) packages = prioritizer.prioritized_packages - packages[0].quantity(:backordered).should eq 0 - packages[1].quantity(:on_hand).should eq 5 + expect(packages[0].quantity(:backordered)).to eq 0 + expect(packages[1].quantity(:on_hand)).to eq 5 end end end From c2ec34ab9f063f41cf46f4c07120646159771958 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:14:02 +0100 Subject: [PATCH 115/261] Bring coordinator from spree_core --- app/models/spree/stock/coordinator.rb | 59 +++++++++++++++++++++ spec/models/spree/stock/coordinator_spec.rb | 34 ++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 app/models/spree/stock/coordinator.rb create mode 100644 spec/models/spree/stock/coordinator_spec.rb diff --git a/app/models/spree/stock/coordinator.rb b/app/models/spree/stock/coordinator.rb new file mode 100644 index 0000000000..605b9dc343 --- /dev/null +++ b/app/models/spree/stock/coordinator.rb @@ -0,0 +1,59 @@ +module Spree + module Stock + class Coordinator + attr_reader :order + + def initialize(order) + @order = order + end + + def packages + packages = build_packages + packages = prioritize_packages(packages) + packages = estimate_packages(packages) + end + + # Build packages as per stock location + # + # It needs to check whether each stock location holds at least one stock + # item for the order. In case none is found it wouldn't make any sense + # to build a package because it would be empty. Plus we avoid errors down + # the stack because it would assume the stock location has stock items + # for the given order + # + # Returns an array of Package instances + def build_packages(packages = Array.new) + StockLocation.active.each do |stock_location| + next unless stock_location.stock_items.where(:variant_id => order.line_items.pluck(:variant_id)).exists? + + packer = build_packer(stock_location, order) + packages += packer.packages + end + packages + end + + private + def prioritize_packages(packages) + prioritizer = Prioritizer.new(order, packages) + prioritizer.prioritized_packages + end + + def estimate_packages(packages) + estimator = Estimator.new(order) + packages.each do |package| + package.shipping_rates = estimator.shipping_rates(package) + end + packages + end + + def build_packer(stock_location, order) + Packer.new(stock_location, order, splitters(stock_location)) + end + + def splitters(stock_location) + # extension point to return custom splitters for a location + Rails.application.config.spree.stock_splitters + end + end + end +end diff --git a/spec/models/spree/stock/coordinator_spec.rb b/spec/models/spree/stock/coordinator_spec.rb new file mode 100644 index 0000000000..006fd27b8b --- /dev/null +++ b/spec/models/spree/stock/coordinator_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +module Spree + module Stock + describe Coordinator do + let!(:order) { create(:order_with_line_items) } + + subject { Coordinator.new(order) } + + context "packages" do + it "builds, prioritizes and estimates" do + subject.should_receive(:build_packages).ordered + subject.should_receive(:prioritize_packages).ordered + subject.should_receive(:estimate_packages).ordered + subject.packages + end + end + + context "build packages" do + it "builds a package for every stock location" do + subject.packages.count == StockLocation.count + end + + context "missing stock items in stock location" do + let!(:another_location) { create(:stock_location, propagate_all_variants: false) } + + it "builds packages only for valid stock locations" do + subject.build_packages.count.should == (StockLocation.count - 1) + end + end + end + end + end +end From ec50a788a6f1d9e61ce38aefb0a80cc0eafd6137 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:15:53 +0100 Subject: [PATCH 116/261] Fix easy rubocop issues --- app/models/spree/stock/coordinator.rb | 14 +++++++++----- spec/models/spree/stock/coordinator_spec.rb | 2 ++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/models/spree/stock/coordinator.rb b/app/models/spree/stock/coordinator.rb index 605b9dc343..4b42060bd0 100644 --- a/app/models/spree/stock/coordinator.rb +++ b/app/models/spree/stock/coordinator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Stock class Coordinator @@ -10,7 +12,7 @@ module Spree def packages packages = build_packages packages = prioritize_packages(packages) - packages = estimate_packages(packages) + estimate_packages(packages) end # Build packages as per stock location @@ -20,11 +22,12 @@ module Spree # to build a package because it would be empty. Plus we avoid errors down # the stack because it would assume the stock location has stock items # for the given order - # + # # Returns an array of Package instances - def build_packages(packages = Array.new) + def build_packages(packages = []) StockLocation.active.each do |stock_location| - next unless stock_location.stock_items.where(:variant_id => order.line_items.pluck(:variant_id)).exists? + next unless stock_location.stock_items. + where(variant_id: order.line_items.pluck(:variant_id)).exists? packer = build_packer(stock_location, order) packages += packer.packages @@ -33,6 +36,7 @@ module Spree end private + def prioritize_packages(packages) prioritizer = Prioritizer.new(order, packages) prioritizer.prioritized_packages @@ -50,7 +54,7 @@ module Spree Packer.new(stock_location, order, splitters(stock_location)) end - def splitters(stock_location) + def splitters(_stock_location) # extension point to return custom splitters for a location Rails.application.config.spree.stock_splitters end diff --git a/spec/models/spree/stock/coordinator_spec.rb b/spec/models/spree/stock/coordinator_spec.rb index 006fd27b8b..0349664094 100644 --- a/spec/models/spree/stock/coordinator_spec.rb +++ b/spec/models/spree/stock/coordinator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree From e0f9894b7a13bb9fd1cd584a278e2dc2df207d44 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:18:02 +0100 Subject: [PATCH 117/261] Bring packer from spree_core --- app/models/spree/stock/packer.rb | 48 ++++++++++++ spec/models/spree/stock/packer_spec.rb | 102 +++++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 app/models/spree/stock/packer.rb create mode 100644 spec/models/spree/stock/packer_spec.rb diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb new file mode 100644 index 0000000000..2dc5a67b9c --- /dev/null +++ b/app/models/spree/stock/packer.rb @@ -0,0 +1,48 @@ +module Spree + module Stock + class Packer + attr_reader :stock_location, :order, :splitters, :package_factory + + def initialize(stock_location, order, splitters=[Splitter::Base]) + @stock_location = stock_location + @order = order + @splitters = splitters + @package_factory = Spree::Config.package_factory + end + + def packages + if splitters.empty? + [default_package] + else + build_splitter.split [default_package] + end + end + + def default_package + package = package_factory.new(stock_location, order) + order.line_items.each do |line_item| + if Config.track_inventory_levels + next unless stock_location.stock_item(line_item.variant) + + on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) + package.add line_item.variant, on_hand, :on_hand if on_hand > 0 + package.add line_item.variant, backordered, :backordered if backordered > 0 + else + package.add line_item.variant, line_item.quantity, :on_hand + end + end + package + end + + private + + def build_splitter + splitter = nil + splitters.reverse.each do |klass| + splitter = klass.new(self, splitter) + end + splitter + end + end + end +end diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb new file mode 100644 index 0000000000..34259e1c43 --- /dev/null +++ b/spec/models/spree/stock/packer_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper' + +module Spree + module Stock + describe Packer do + let(:order) { create(:order_with_line_items, line_items_count: 5) } + let(:stock_location) { create(:stock_location) } + + subject { Packer.new(stock_location, order) } + + before do + Spree::Config.stub(:package_factory) { Package } + end + + context 'packages' do + it 'builds an array of packages' do + packages = subject.packages + packages.size.should eq 1 + packages.first.contents.size.should eq 5 + end + + it 'allows users to set splitters to an empty array' do + packages = Packer.new(stock_location, order, []).packages + packages.size.should eq 1 + end + end + + context 'default_package' do + it 'contains all the items' do + package = subject.default_package + package.contents.size.should eq 5 + package.weight.should > 0 + end + + it 'variants are added as backordered without enough on_hand' do + stock_location.should_receive(:fill_status).exactly(5).times.and_return([2,3]) + + package = subject.default_package + package.on_hand.size.should eq 5 + package.backordered.size.should eq 5 + end + + context 'when a packer factory is not specified' do + let(:package) { double(:package, add: true) } + + it 'calls Spree::Stock::Package' do + Package + .should_receive(:new) + .with(stock_location, order) + .and_return(package) + + subject.default_package + end + end + + context 'when a packer factory is specified' do + before do + Spree::Config.stub(:package_factory) { TestPackageFactory } + end + + class TestPackageFactory; end + + let(:package) { double(:package, add: true) } + + it 'calls the specified factory' do + TestPackageFactory + .should_receive(:new) + .with(stock_location, order) + .and_return(package) + + subject.default_package + end + end + + context "location doesn't have order items in stock" do + let(:stock_location) { create(:stock_location, propagate_all_variants: false) } + let(:packer) { Packer.new(stock_location, order) } + + it "builds an empty package" do + packer.default_package.contents.should be_empty + end + end + + context "doesn't track inventory levels" do + let(:order) { Order.create } + let!(:line_item) { order.contents.add(create(:variant), 30) } + + before { Config.track_inventory_levels = false } + + it "doesn't bother stock items status in stock location" do + expect(subject.stock_location).not_to receive(:fill_status) + subject.default_package + end + + it "still creates package with proper quantity" do + expect(subject.default_package.quantity).to eql 30 + end + end + end + end + end +end From ccf928df124c90322e3707c00940a153e29c516c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:18:59 +0100 Subject: [PATCH 118/261] Fix simple rubocop issues --- app/models/spree/stock/packer.rb | 8 +++++--- spec/models/spree/stock/packer_spec.rb | 4 +++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb index 2dc5a67b9c..9dab72909c 100644 --- a/app/models/spree/stock/packer.rb +++ b/app/models/spree/stock/packer.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + module Spree module Stock class Packer attr_reader :stock_location, :order, :splitters, :package_factory - def initialize(stock_location, order, splitters=[Splitter::Base]) + def initialize(stock_location, order, splitters = [Splitter::Base]) @stock_location = stock_location @order = order @splitters = splitters @@ -25,8 +27,8 @@ module Spree next unless stock_location.stock_item(line_item.variant) on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) - package.add line_item.variant, on_hand, :on_hand if on_hand > 0 - package.add line_item.variant, backordered, :backordered if backordered > 0 + package.add line_item.variant, on_hand, :on_hand if on_hand.positive? + package.add line_item.variant, backordered, :backordered if backordered.positive? else package.add line_item.variant, line_item.quantity, :on_hand end diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index 34259e1c43..e29c7b92f6 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree @@ -33,7 +35,7 @@ module Spree end it 'variants are added as backordered without enough on_hand' do - stock_location.should_receive(:fill_status).exactly(5).times.and_return([2,3]) + stock_location.should_receive(:fill_status).exactly(5).times.and_return([2, 3]) package = subject.default_package package.on_hand.size.should eq 5 From fdc085f701a5a0948cb5d731628db9d3705ae81c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:28:52 +0100 Subject: [PATCH 119/261] Convert to modern rspec and remove specs not applicable to ofn --- spec/models/spree/stock/packer_spec.rb | 43 ++++++-------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index e29c7b92f6..c392b9788e 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -17,29 +17,31 @@ module Spree context 'packages' do it 'builds an array of packages' do packages = subject.packages - packages.size.should eq 1 - packages.first.contents.size.should eq 5 + expect(packages.size).to eq 1 + expect(packages.first.contents.size).to eq 5 end it 'allows users to set splitters to an empty array' do packages = Packer.new(stock_location, order, []).packages - packages.size.should eq 1 + expect(packages.size).to eq 1 end end context 'default_package' do + before { order.line_items.first.variant.update(weight: 1) } + it 'contains all the items' do package = subject.default_package - package.contents.size.should eq 5 - package.weight.should > 0 + expect(package.contents.size).to eq 5 + expect(package.weight).to be_positive end it 'variants are added as backordered without enough on_hand' do - stock_location.should_receive(:fill_status).exactly(5).times.and_return([2, 3]) + expect(stock_location).to receive(:fill_status).exactly(5).times.and_return([2, 3]) package = subject.default_package - package.on_hand.size.should eq 5 - package.backordered.size.should eq 5 + expect(package.on_hand.size).to eq 5 + expect(package.backordered.size).to eq 5 end context 'when a packer factory is not specified' do @@ -73,31 +75,6 @@ module Spree subject.default_package end end - - context "location doesn't have order items in stock" do - let(:stock_location) { create(:stock_location, propagate_all_variants: false) } - let(:packer) { Packer.new(stock_location, order) } - - it "builds an empty package" do - packer.default_package.contents.should be_empty - end - end - - context "doesn't track inventory levels" do - let(:order) { Order.create } - let!(:line_item) { order.contents.add(create(:variant), 30) } - - before { Config.track_inventory_levels = false } - - it "doesn't bother stock items status in stock location" do - expect(subject.stock_location).not_to receive(:fill_status) - subject.default_package - end - - it "still creates package with proper quantity" do - expect(subject.default_package.quantity).to eql 30 - end - end end end end From 69b9cfbad2ac5182e07b6adb20279cf2af649bb8 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:30:18 +0100 Subject: [PATCH 120/261] Make packer use BasicSplitter by default --- app/models/spree/stock/packer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb index 9dab72909c..242f46536e 100644 --- a/app/models/spree/stock/packer.rb +++ b/app/models/spree/stock/packer.rb @@ -5,7 +5,7 @@ module Spree class Packer attr_reader :stock_location, :order, :splitters, :package_factory - def initialize(stock_location, order, splitters = [Splitter::Base]) + def initialize(stock_location, order, splitters = [OrderManagement::Stock::BasicSplitter]) @stock_location = stock_location @order = order @splitters = splitters From 4711a7469ac3a1930cbe8a357318c04443aa94cc Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:37:23 +0100 Subject: [PATCH 121/261] Adapt coordinator spec to ofn and remove spec that is not applicable (multi stock locations) --- spec/models/spree/stock/coordinator_spec.rb | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/spec/models/spree/stock/coordinator_spec.rb b/spec/models/spree/stock/coordinator_spec.rb index 0349664094..adeec6e7cd 100644 --- a/spec/models/spree/stock/coordinator_spec.rb +++ b/spec/models/spree/stock/coordinator_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' module Spree module Stock describe Coordinator do - let!(:order) { create(:order_with_line_items) } + let!(:order) { create(:order_with_line_items, distributor: create(:distributor_enterprise)) } subject { Coordinator.new(order) } @@ -17,20 +17,6 @@ module Spree subject.packages end end - - context "build packages" do - it "builds a package for every stock location" do - subject.packages.count == StockLocation.count - end - - context "missing stock items in stock location" do - let!(:another_location) { create(:stock_location, propagate_all_variants: false) } - - it "builds packages only for valid stock locations" do - subject.build_packages.count.should == (StockLocation.count - 1) - end - end - end end end end From 8c3b8c4db5b7c0145fc2e037efa30e503f08593b Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:38:50 +0100 Subject: [PATCH 122/261] Bring estimator from spree_core --- app/models/spree/stock/estimator.rb | 50 +++++++++++ spec/models/spree/stock/estimator_spec.rb | 100 ++++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 app/models/spree/stock/estimator.rb create mode 100644 spec/models/spree/stock/estimator_spec.rb diff --git a/app/models/spree/stock/estimator.rb b/app/models/spree/stock/estimator.rb new file mode 100644 index 0000000000..b9647f6255 --- /dev/null +++ b/app/models/spree/stock/estimator.rb @@ -0,0 +1,50 @@ +module Spree + module Stock + class Estimator + attr_reader :order, :currency + + def initialize(order) + @order = order + @currency = order.currency + end + + def shipping_rates(package, frontend_only = true) + shipping_rates = Array.new + shipping_methods = shipping_methods(package) + return [] unless shipping_methods + + shipping_methods.each do |shipping_method| + cost = calculate_cost(shipping_method, package) + shipping_rates << shipping_method.shipping_rates.new(:cost => cost) unless cost.nil? + end + + shipping_rates.sort_by! { |r| r.cost || 0 } + + unless shipping_rates.empty? + if frontend_only + shipping_rates.each do |rate| + rate.selected = true and break if rate.shipping_method.frontend? + end + else + shipping_rates.first.selected = true + end + end + + shipping_rates + end + + private + def shipping_methods(package) + shipping_methods = package.shipping_methods + shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package) } + shipping_methods.delete_if { |ship_method| !ship_method.include?(order.ship_address) } + shipping_methods.delete_if { |ship_method| !(ship_method.calculator.preferences[:currency].nil? || ship_method.calculator.preferences[:currency] == currency) } + shipping_methods + end + + def calculate_cost(shipping_method, package) + shipping_method.calculator.compute(package) + end + end + end +end diff --git a/spec/models/spree/stock/estimator_spec.rb b/spec/models/spree/stock/estimator_spec.rb new file mode 100644 index 0000000000..e5819827a8 --- /dev/null +++ b/spec/models/spree/stock/estimator_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +module Spree + module Stock + describe Estimator do + let!(:shipping_method) { create(:shipping_method) } + let(:package) { build(:stock_package_fulfilled) } + let(:order) { package.order } + subject { Estimator.new(order) } + + context "#shipping rates" do + before(:each) do + shipping_method.zones.first.members.create(:zoneable => order.ship_address.country) + ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(true) + ShippingMethod.any_instance.stub_chain(:calculator, :compute).and_return(4.00) + ShippingMethod.any_instance.stub_chain(:calculator, :preferences).and_return({:currency => "USD"}) + ShippingMethod.any_instance.stub_chain(:calculator, :marked_for_destruction?) + + package.stub(:shipping_methods => [shipping_method]) + end + + it "returns shipping rates from a shipping method if the order's ship address is in the same zone" do + shipping_rates = subject.shipping_rates(package) + shipping_rates.first.cost.should eq 4.00 + end + + it "does not return shipping rates from a shipping method if the order's ship address is in a different zone" do + shipping_method.zones.each{|z| z.members.delete_all} + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end + + it "does not return shipping rates from a shipping method if the calculator is not available for that order" do + ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false) + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end + + it "returns shipping rates from a shipping method if the currency matches the order's currency" do + shipping_rates = subject.shipping_rates(package) + shipping_rates.first.cost.should eq 4.00 + end + + it "does not return shipping rates from a shipping method if the currency is different than the order's currency" do + order.currency = "GBP" + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end + + it "sorts shipping rates by cost" do + shipping_methods = 3.times.map { create(:shipping_method) } + shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00) + shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00) + shipping_methods[2].stub_chain(:calculator, :compute).and_return(4.00) + + subject.stub(:shipping_methods).and_return(shipping_methods) + + expect(subject.shipping_rates(package).map(&:cost)).to eq %w[3.00 4.00 5.00].map(&BigDecimal.method(:new)) + end + + context "general shipping methods" do + let(:shipping_methods) { 2.times.map { create(:shipping_method) } } + + it "selects the most affordable shipping rate" do + shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00) + shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00) + + subject.stub(:shipping_methods).and_return(shipping_methods) + + expect(subject.shipping_rates(package).sort_by(&:cost).map(&:selected)).to eq [true, false] + end + + it "selects the most affordable shipping rate and doesn't raise exception over nil cost" do + shipping_methods[0].stub_chain(:calculator, :compute).and_return(1.00) + shipping_methods[1].stub_chain(:calculator, :compute).and_return(nil) + + subject.stub(:shipping_methods).and_return(shipping_methods) + + subject.shipping_rates(package) + end + end + + context "involves backend only shipping methods" do + let(:backend_method) { create(:shipping_method, display_on: "back_end") } + let(:generic_method) { create(:shipping_method) } + + # regression for #3287 + it "doesn't select backend rates even if they're more affordable" do + backend_method.stub_chain(:calculator, :compute).and_return(0.00) + generic_method.stub_chain(:calculator, :compute).and_return(5.00) + + subject.stub(:shipping_methods).and_return([backend_method, generic_method]) + + expect(subject.shipping_rates(package).map(&:selected)).to eq [false, true] + end + end + end + end + end +end From b16db2f40e425b58b7729b15ba1816444c651fc8 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 16:45:38 +0100 Subject: [PATCH 123/261] Fix easy rubocop issues --- app/models/spree/stock/estimator.rb | 14 +++-- spec/models/spree/stock/estimator_spec.rb | 63 ++++++++++++++--------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/app/models/spree/stock/estimator.rb b/app/models/spree/stock/estimator.rb index b9647f6255..7daf7d9d67 100644 --- a/app/models/spree/stock/estimator.rb +++ b/app/models/spree/stock/estimator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Stock class Estimator @@ -9,13 +11,13 @@ module Spree end def shipping_rates(package, frontend_only = true) - shipping_rates = Array.new + shipping_rates = [] shipping_methods = shipping_methods(package) return [] unless shipping_methods shipping_methods.each do |shipping_method| cost = calculate_cost(shipping_method, package) - shipping_rates << shipping_method.shipping_rates.new(:cost => cost) unless cost.nil? + shipping_rates << shipping_method.shipping_rates.new(cost: cost) unless cost.nil? end shipping_rates.sort_by! { |r| r.cost || 0 } @@ -23,7 +25,7 @@ module Spree unless shipping_rates.empty? if frontend_only shipping_rates.each do |rate| - rate.selected = true and break if rate.shipping_method.frontend? + rate.selected = true && break if rate.shipping_method.frontend? end else shipping_rates.first.selected = true @@ -34,11 +36,15 @@ module Spree end private + def shipping_methods(package) shipping_methods = package.shipping_methods shipping_methods.delete_if { |ship_method| !ship_method.calculator.available?(package) } shipping_methods.delete_if { |ship_method| !ship_method.include?(order.ship_address) } - shipping_methods.delete_if { |ship_method| !(ship_method.calculator.preferences[:currency].nil? || ship_method.calculator.preferences[:currency] == currency) } + shipping_methods.delete_if { |ship_method| + !(ship_method.calculator.preferences[:currency].nil? || + ship_method.calculator.preferences[:currency] == currency) + } shipping_methods end diff --git a/spec/models/spree/stock/estimator_spec.rb b/spec/models/spree/stock/estimator_spec.rb index e5819827a8..e439e85585 100644 --- a/spec/models/spree/stock/estimator_spec.rb +++ b/spec/models/spree/stock/estimator_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree @@ -10,41 +12,52 @@ module Spree context "#shipping rates" do before(:each) do - shipping_method.zones.first.members.create(:zoneable => order.ship_address.country) + shipping_method.zones.first.members.create(zoneable: order.ship_address.country) ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(true) ShippingMethod.any_instance.stub_chain(:calculator, :compute).and_return(4.00) - ShippingMethod.any_instance.stub_chain(:calculator, :preferences).and_return({:currency => "USD"}) + ShippingMethod.any_instance. + stub_chain(:calculator, :preferences).and_return({ currency: "USD" }) ShippingMethod.any_instance.stub_chain(:calculator, :marked_for_destruction?) - package.stub(:shipping_methods => [shipping_method]) + package.stub(shipping_methods: [shipping_method]) end - it "returns shipping rates from a shipping method if the order's ship address is in the same zone" do - shipping_rates = subject.shipping_rates(package) - shipping_rates.first.cost.should eq 4.00 + context "the order's ship address is in the same zone" do + it "returns shipping rates from a shipping method" do + shipping_rates = subject.shipping_rates(package) + shipping_rates.first.cost.should eq 4.00 + end end - it "does not return shipping rates from a shipping method if the order's ship address is in a different zone" do - shipping_method.zones.each{|z| z.members.delete_all} - shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + context "the order's ship address is in a different zone" do + it "does not return shipping rates from a shipping method" do + shipping_method.zones.each{ |z| z.members.delete_all } + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end end - it "does not return shipping rates from a shipping method if the calculator is not available for that order" do - ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false) - shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + context "the calculator is not available for that order" do + it "does not return shipping rates from a shipping method" do + ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false) + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end end - it "returns shipping rates from a shipping method if the currency matches the order's currency" do - shipping_rates = subject.shipping_rates(package) - shipping_rates.first.cost.should eq 4.00 + context "the currency matches the order's currency" do + it "returns shipping rates from a shipping method" do + shipping_rates = subject.shipping_rates(package) + shipping_rates.first.cost.should eq 4.00 + end end - it "does not return shipping rates from a shipping method if the currency is different than the order's currency" do - order.currency = "GBP" - shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + context "the currency is different than the order's currency" do + it "does not return shipping rates from a shipping method" do + order.currency = "GBP" + shipping_rates = subject.shipping_rates(package) + shipping_rates.should == [] + end end it "sorts shipping rates by cost" do @@ -55,7 +68,8 @@ module Spree subject.stub(:shipping_methods).and_return(shipping_methods) - expect(subject.shipping_rates(package).map(&:cost)).to eq %w[3.00 4.00 5.00].map(&BigDecimal.method(:new)) + expected_costs = %w[3.00 4.00 5.00].map(&BigDecimal.method(:new)) + expect(subject.shipping_rates(package).map(&:cost)).to eq expected_costs end context "general shipping methods" do @@ -67,10 +81,11 @@ module Spree subject.stub(:shipping_methods).and_return(shipping_methods) - expect(subject.shipping_rates(package).sort_by(&:cost).map(&:selected)).to eq [true, false] + shipping_rates = subject.shipping_rates(package) + expect(shipping_rates.sort_by(&:cost).map(&:selected)).to eq [true, false] end - it "selects the most affordable shipping rate and doesn't raise exception over nil cost" do + it "selects the cheapest shipping rate and doesn't raise exception over nil cost" do shipping_methods[0].stub_chain(:calculator, :compute).and_return(1.00) shipping_methods[1].stub_chain(:calculator, :compute).and_return(nil) From feadbb086f5a58bb14b1cb47712378b52868116e Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:00:54 +0100 Subject: [PATCH 124/261] Adapt spec to OFN context --- app/models/spree/stock/estimator.rb | 5 ++++- spec/models/spree/stock/estimator_spec.rb | 18 +++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/models/spree/stock/estimator.rb b/app/models/spree/stock/estimator.rb index 7daf7d9d67..9f14033590 100644 --- a/app/models/spree/stock/estimator.rb +++ b/app/models/spree/stock/estimator.rb @@ -25,7 +25,10 @@ module Spree unless shipping_rates.empty? if frontend_only shipping_rates.each do |rate| - rate.selected = true && break if rate.shipping_method.frontend? + if rate.shipping_method.frontend? + rate.selected = true + break + end end else shipping_rates.first.selected = true diff --git a/spec/models/spree/stock/estimator_spec.rb b/spec/models/spree/stock/estimator_spec.rb index e439e85585..a56172777a 100644 --- a/spec/models/spree/stock/estimator_spec.rb +++ b/spec/models/spree/stock/estimator_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' module Spree module Stock describe Estimator do - let!(:shipping_method) { create(:shipping_method) } + let!(:shipping_method) { create(:shipping_method, zones: [Spree::Zone.global] ) } let(:package) { build(:stock_package_fulfilled) } let(:order) { package.order } subject { Estimator.new(order) } @@ -16,7 +16,7 @@ module Spree ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(true) ShippingMethod.any_instance.stub_chain(:calculator, :compute).and_return(4.00) ShippingMethod.any_instance. - stub_chain(:calculator, :preferences).and_return({ currency: "USD" }) + stub_chain(:calculator, :preferences).and_return({ currency: order.currency }) ShippingMethod.any_instance.stub_chain(:calculator, :marked_for_destruction?) package.stub(shipping_methods: [shipping_method]) @@ -25,15 +25,15 @@ module Spree context "the order's ship address is in the same zone" do it "returns shipping rates from a shipping method" do shipping_rates = subject.shipping_rates(package) - shipping_rates.first.cost.should eq 4.00 + expect(shipping_rates.first.cost).to eq 4.00 end end context "the order's ship address is in a different zone" do - it "does not return shipping rates from a shipping method" do + it "still returns shipping rates from a shipping method" do shipping_method.zones.each{ |z| z.members.delete_all } shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + expect(shipping_rates.first.cost).to eq 4.00 end end @@ -41,22 +41,22 @@ module Spree it "does not return shipping rates from a shipping method" do ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false) shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + expect(shipping_rates).to eq [] end end context "the currency matches the order's currency" do it "returns shipping rates from a shipping method" do shipping_rates = subject.shipping_rates(package) - shipping_rates.first.cost.should eq 4.00 + expect(shipping_rates.first.cost).to eq 4.00 end end context "the currency is different than the order's currency" do it "does not return shipping rates from a shipping method" do - order.currency = "GBP" + order.currency = "USD" shipping_rates = subject.shipping_rates(package) - shipping_rates.should == [] + expect(shipping_rates).to eq [] end end From 720ad9de0e85f077aa276b7ab46e70a807f21c57 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:01:54 +0100 Subject: [PATCH 125/261] Convert specs to modern rsspec syntax --- spec/models/spree/stock/coordinator_spec.rb | 6 ++-- spec/models/spree/stock/estimator_spec.rb | 40 ++++++++++----------- spec/models/spree/stock/packer_spec.rb | 12 +++---- spec/models/spree/stock/prioritizer_spec.rb | 6 ++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/spec/models/spree/stock/coordinator_spec.rb b/spec/models/spree/stock/coordinator_spec.rb index adeec6e7cd..63f81e96ce 100644 --- a/spec/models/spree/stock/coordinator_spec.rb +++ b/spec/models/spree/stock/coordinator_spec.rb @@ -11,9 +11,9 @@ module Spree context "packages" do it "builds, prioritizes and estimates" do - subject.should_receive(:build_packages).ordered - subject.should_receive(:prioritize_packages).ordered - subject.should_receive(:estimate_packages).ordered + expect(subject).to receive(:build_packages).ordered + expect(subject).to receive(:prioritize_packages).ordered + expect(subject).to receive(:estimate_packages).ordered subject.packages end end diff --git a/spec/models/spree/stock/estimator_spec.rb b/spec/models/spree/stock/estimator_spec.rb index a56172777a..6cdf8106b2 100644 --- a/spec/models/spree/stock/estimator_spec.rb +++ b/spec/models/spree/stock/estimator_spec.rb @@ -13,13 +13,13 @@ module Spree context "#shipping rates" do before(:each) do shipping_method.zones.first.members.create(zoneable: order.ship_address.country) - ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(true) - ShippingMethod.any_instance.stub_chain(:calculator, :compute).and_return(4.00) - ShippingMethod.any_instance. - stub_chain(:calculator, :preferences).and_return({ currency: order.currency }) - ShippingMethod.any_instance.stub_chain(:calculator, :marked_for_destruction?) + allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(true) + allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :compute).and_return(4.00) + allow_any_instance_of(ShippingMethod). + to receive_message_chain(:calculator, :preferences).and_return({ currency: order.currency }) + allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :marked_for_destruction?) - package.stub(shipping_methods: [shipping_method]) + allow(package).to receive_messages(shipping_methods: [shipping_method]) end context "the order's ship address is in the same zone" do @@ -39,7 +39,7 @@ module Spree context "the calculator is not available for that order" do it "does not return shipping rates from a shipping method" do - ShippingMethod.any_instance.stub_chain(:calculator, :available?).and_return(false) + allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(false) shipping_rates = subject.shipping_rates(package) expect(shipping_rates).to eq [] end @@ -62,11 +62,11 @@ module Spree it "sorts shipping rates by cost" do shipping_methods = 3.times.map { create(:shipping_method) } - shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00) - shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00) - shipping_methods[2].stub_chain(:calculator, :compute).and_return(4.00) + allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00) + allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00) + allow(shipping_methods[2]).to receive_message_chain(:calculator, :compute).and_return(4.00) - subject.stub(:shipping_methods).and_return(shipping_methods) + allow(subject).to receive(:shipping_methods).and_return(shipping_methods) expected_costs = %w[3.00 4.00 5.00].map(&BigDecimal.method(:new)) expect(subject.shipping_rates(package).map(&:cost)).to eq expected_costs @@ -76,20 +76,20 @@ module Spree let(:shipping_methods) { 2.times.map { create(:shipping_method) } } it "selects the most affordable shipping rate" do - shipping_methods[0].stub_chain(:calculator, :compute).and_return(5.00) - shipping_methods[1].stub_chain(:calculator, :compute).and_return(3.00) + allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00) + allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00) - subject.stub(:shipping_methods).and_return(shipping_methods) + allow(subject).to receive(:shipping_methods).and_return(shipping_methods) shipping_rates = subject.shipping_rates(package) expect(shipping_rates.sort_by(&:cost).map(&:selected)).to eq [true, false] end it "selects the cheapest shipping rate and doesn't raise exception over nil cost" do - shipping_methods[0].stub_chain(:calculator, :compute).and_return(1.00) - shipping_methods[1].stub_chain(:calculator, :compute).and_return(nil) + allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(1.00) + allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(nil) - subject.stub(:shipping_methods).and_return(shipping_methods) + allow(subject).to receive(:shipping_methods).and_return(shipping_methods) subject.shipping_rates(package) end @@ -101,10 +101,10 @@ module Spree # regression for #3287 it "doesn't select backend rates even if they're more affordable" do - backend_method.stub_chain(:calculator, :compute).and_return(0.00) - generic_method.stub_chain(:calculator, :compute).and_return(5.00) + allow(backend_method).to receive_message_chain(:calculator, :compute).and_return(0.00) + allow(generic_method).to receive_message_chain(:calculator, :compute).and_return(5.00) - subject.stub(:shipping_methods).and_return([backend_method, generic_method]) + allow(subject).to receive(:shipping_methods).and_return([backend_method, generic_method]) expect(subject.shipping_rates(package).map(&:selected)).to eq [false, true] end diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index c392b9788e..cd694d87e1 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -11,7 +11,7 @@ module Spree subject { Packer.new(stock_location, order) } before do - Spree::Config.stub(:package_factory) { Package } + allow(Spree::Config).to receive(:package_factory) { Package } end context 'packages' do @@ -48,8 +48,8 @@ module Spree let(:package) { double(:package, add: true) } it 'calls Spree::Stock::Package' do - Package - .should_receive(:new) + expect(Package) + .to receive(:new) .with(stock_location, order) .and_return(package) @@ -59,7 +59,7 @@ module Spree context 'when a packer factory is specified' do before do - Spree::Config.stub(:package_factory) { TestPackageFactory } + allow(Spree::Config).to receive(:package_factory) { TestPackageFactory } end class TestPackageFactory; end @@ -67,8 +67,8 @@ module Spree let(:package) { double(:package, add: true) } it 'calls the specified factory' do - TestPackageFactory - .should_receive(:new) + expect(TestPackageFactory) + .to receive(:new) .with(stock_location, order) .and_return(package) diff --git a/spec/models/spree/stock/prioritizer_spec.rb b/spec/models/spree/stock/prioritizer_spec.rb index aee367e7b7..4715da1ab8 100644 --- a/spec/models/spree/stock/prioritizer_spec.rb +++ b/spec/models/spree/stock/prioritizer_spec.rb @@ -59,7 +59,7 @@ module Spree end it '1st has some, 2nd has remaining' do - order.line_items[0].stub(quantity: 5) + allow(order.line_items[0]).to receive_messages(quantity: 5) package1 = pack do |package| package.add variant1, 2, :on_hand end @@ -76,7 +76,7 @@ module Spree end it '1st has backorder, 2nd has some' do - order.line_items[0].stub(quantity: 5) + allow(order.line_items[0]).to receive_messages(quantity: 5) package1 = pack do |package| package.add variant1, 5, :backordered end @@ -93,7 +93,7 @@ module Spree end it '1st has backorder, 2nd has all' do - order.line_items[0].stub(quantity: 5) + allow(order.line_items[0]).to receive_messages(quantity: 5) package1 = pack do |package| package.add variant1, 3, :backordered package.add variant2, 1, :on_hand From d505fc213109988f281c6c414adb5bc2fdcc12c3 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:04:00 +0100 Subject: [PATCH 126/261] Bring availability validator from spree_core --- .../spree/stock/availability_validator.rb | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 app/models/spree/stock/availability_validator.rb diff --git a/app/models/spree/stock/availability_validator.rb b/app/models/spree/stock/availability_validator.rb new file mode 100644 index 0000000000..fe9bc19442 --- /dev/null +++ b/app/models/spree/stock/availability_validator.rb @@ -0,0 +1,25 @@ +module Spree + module Stock + class AvailabilityValidator < ActiveModel::Validator + def validate(line_item) + if shipment = line_item.target_shipment + units = shipment.inventory_units_for(line_item.variant) + return if units.count > line_item.quantity + quantity = line_item.quantity - units.count + else + quantity = line_item.quantity + end + + quantifier = Stock::Quantifier.new(line_item.variant_id) + + unless quantifier.can_supply? quantity + variant = line_item.variant + display_name = %Q{#{variant.name}} + display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank? + + line_item.errors[:quantity] << Spree.t(:out_of_stock, :scope => :order_populator, :item => display_name.inspect) + end + end + end + end +end From 3e14c9777eb997fd54c6bbbaf25fe00d1992a91b Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:05:48 +0100 Subject: [PATCH 127/261] Merge decorator with class brought from spree_core --- .../spree/stock/availability_validator.rb | 56 ++++++++++++++----- .../stock/availability_validator_decorator.rb | 49 ---------------- 2 files changed, 42 insertions(+), 63 deletions(-) delete mode 100644 app/models/spree/stock/availability_validator_decorator.rb diff --git a/app/models/spree/stock/availability_validator.rb b/app/models/spree/stock/availability_validator.rb index fe9bc19442..1ca304e8d0 100644 --- a/app/models/spree/stock/availability_validator.rb +++ b/app/models/spree/stock/availability_validator.rb @@ -2,23 +2,51 @@ module Spree module Stock class AvailabilityValidator < ActiveModel::Validator def validate(line_item) - if shipment = line_item.target_shipment - units = shipment.inventory_units_for(line_item.variant) - return if units.count > line_item.quantity - quantity = line_item.quantity - units.count - else - quantity = line_item.quantity - end + # OFN specific check for in-memory :skip_stock_check attribute + return if line_item.skip_stock_check - quantifier = Stock::Quantifier.new(line_item.variant_id) + quantity_to_validate = line_item.quantity - quantity_in_shipment(line_item) + return if quantity_to_validate < 1 - unless quantifier.can_supply? quantity - variant = line_item.variant - display_name = %Q{#{variant.name}} - display_name += %Q{ (#{variant.options_text})} unless variant.options_text.blank? + validate_quantity(line_item, quantity_to_validate) + end - line_item.errors[:quantity] << Spree.t(:out_of_stock, :scope => :order_populator, :item => display_name.inspect) - end + private + + # This is an adapted version of a fix to the inventory_units not being considered here. + # See #3090 for details. + # This can be removed after upgrading to Spree 2.4. + def quantity_in_shipment(line_item) + shipment = line_item_shipment(line_item) + return 0 unless shipment + + units = shipment.inventory_units_for(line_item.variant) + units.count + end + + def line_item_shipment(line_item) + return line_item.target_shipment if line_item.target_shipment + return line_item.order.shipments.first if line_item.order.andand.shipments.any? + end + + # Overrides Spree v2.0.4 validate method version to: + # - scope variants to hub and thus acivate variant overrides + # - use calculated quantity instead of the line_item.quantity + # - rely on Variant.can_supply? instead of Stock::Quantified.can_supply? + # so that it works correctly for variant overrides + def validate_quantity(line_item, quantity) + line_item.scoper.scope(line_item.variant) + + add_out_of_stock_error(line_item) unless line_item.variant.can_supply? quantity + end + + def add_out_of_stock_error(line_item) + variant = line_item.variant + display_name = variant.name.to_s + display_name += %{(#{variant.options_text})} if variant.options_text.present? + line_item.errors[:quantity] << Spree.t(:out_of_stock, + scope: :order_populator, + item: display_name.inspect) end end end diff --git a/app/models/spree/stock/availability_validator_decorator.rb b/app/models/spree/stock/availability_validator_decorator.rb deleted file mode 100644 index c3ee4c4818..0000000000 --- a/app/models/spree/stock/availability_validator_decorator.rb +++ /dev/null @@ -1,49 +0,0 @@ -Spree::Stock::AvailabilityValidator.class_eval do - def validate(line_item) - # OFN specific check for in-memory :skip_stock_check attribute - return if line_item.skip_stock_check - - quantity_to_validate = line_item.quantity - quantity_in_shipment(line_item) - return if quantity_to_validate < 1 - - validate_quantity(line_item, quantity_to_validate) - end - - private - - # This is an adapted version of a fix to the inventory_units not being considered here. - # See #3090 for details. - # This can be removed after upgrading to Spree 2.4. - def quantity_in_shipment(line_item) - shipment = line_item_shipment(line_item) - return 0 unless shipment - - units = shipment.inventory_units_for(line_item.variant) - units.count - end - - def line_item_shipment(line_item) - return line_item.target_shipment if line_item.target_shipment - return line_item.order.shipments.first if line_item.order.andand.shipments.any? - end - - # Overrides Spree v2.0.4 validate method version to: - # - scope variants to hub and thus acivate variant overrides - # - use calculated quantity instead of the line_item.quantity - # - rely on Variant.can_supply? instead of Stock::Quantified.can_supply? - # so that it works correctly for variant overrides - def validate_quantity(line_item, quantity) - line_item.scoper.scope(line_item.variant) - - add_out_of_stock_error(line_item) unless line_item.variant.can_supply? quantity - end - - def add_out_of_stock_error(line_item) - variant = line_item.variant - display_name = variant.name.to_s - display_name += %{(#{variant.options_text})} if variant.options_text.present? - line_item.errors[:quantity] << Spree.t(:out_of_stock, - scope: :order_populator, - item: display_name.inspect) - end -end From 0ca8b6aab60af99901bc8e2caaecd8d06ebecbe8 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:06:55 +0100 Subject: [PATCH 128/261] Fix easy rubocop issue --- app/models/spree/stock/availability_validator.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/models/spree/stock/availability_validator.rb b/app/models/spree/stock/availability_validator.rb index 1ca304e8d0..6c9516cd08 100644 --- a/app/models/spree/stock/availability_validator.rb +++ b/app/models/spree/stock/availability_validator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Stock class AvailabilityValidator < ActiveModel::Validator From b7255130b6130c4da8bf9126e77542ff7f83be3f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:18:07 +0100 Subject: [PATCH 129/261] Bring Package from spree_core --- app/models/spree/stock/package.rb | 116 ++++++++++++++++++++++++ spec/models/spree/stock/package_spec.rb | 110 ++++++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 app/models/spree/stock/package.rb create mode 100644 spec/models/spree/stock/package_spec.rb diff --git a/app/models/spree/stock/package.rb b/app/models/spree/stock/package.rb new file mode 100644 index 0000000000..68ef8837ab --- /dev/null +++ b/app/models/spree/stock/package.rb @@ -0,0 +1,116 @@ +module Spree + module Stock + class Package + ContentItem = Struct.new(:variant, :quantity, :state) + + attr_reader :stock_location, :order, :contents + attr_accessor :shipping_rates + + def initialize(stock_location, order, contents=[]) + @stock_location = stock_location + @order = order + @contents = contents + @shipping_rates = Array.new + end + + def add(variant, quantity, state=:on_hand) + contents << ContentItem.new(variant, quantity, state) + end + + def weight + contents.sum { |item| item.variant.weight * item.quantity } + end + + def on_hand + contents.select { |item| item.state == :on_hand } + end + + def backordered + contents.select { |item| item.state == :backordered } + end + + def find_item(variant, state=:on_hand) + contents.select do |item| + item.variant == variant && + item.state == state + end.first + end + + def quantity(state=nil) + case state + when :on_hand + on_hand.sum { |item| item.quantity } + when :backordered + backordered.sum { |item| item.quantity } + else + contents.sum { |item| item.quantity } + end + end + + def empty? + quantity == 0 + end + + def flattened + flat = [] + contents.each do |item| + item.quantity.times do + flat << ContentItem.new(item.variant, 1, item.state) + end + end + flat + end + + def flattened=(flattened) + contents.clear + flattened.each do |item| + current_item = find_item(item.variant, item.state) + if current_item + current_item.quantity += 1 + else + add(item.variant, item.quantity, item.state) + end + end + end + + def currency + #TODO calculate from first variant? + end + + def shipping_categories + contents.map { |item| item.variant.shipping_category }.compact.uniq + end + + def shipping_methods + shipping_categories.map { |sc| sc.shipping_methods }.flatten.uniq + end + + def inspect + out = "#{order} - " + out << contents.map do |content_item| + "#{content_item.variant.name} #{content_item.quantity} #{content_item.state}" + end.join('/') + out + end + + def to_shipment + shipment = Spree::Shipment.new + shipment.order = order + shipment.stock_location = stock_location + shipment.shipping_rates = shipping_rates + + contents.each do |item| + item.quantity.times do |n| + unit = shipment.inventory_units.build + unit.pending = true + unit.order = order + unit.variant = item.variant + unit.state = item.state.to_s + end + end + + shipment + end + end + end +end diff --git a/spec/models/spree/stock/package_spec.rb b/spec/models/spree/stock/package_spec.rb new file mode 100644 index 0000000000..532ce23dae --- /dev/null +++ b/spec/models/spree/stock/package_spec.rb @@ -0,0 +1,110 @@ +require 'spec_helper' + +module Spree + module Stock + describe Package do + let(:variant) { build(:variant, weight: 25.0) } + let(:stock_location) { build(:stock_location) } + let(:order) { build(:order) } + + subject { Package.new(stock_location, order) } + + it 'calculates the weight of all the contents' do + subject.add variant, 4 + subject.weight.should == 100.0 + end + + it 'filters by on_hand and backordered' do + subject.add variant, 4, :on_hand + subject.add variant, 3, :backordered + subject.on_hand.count.should eq 1 + subject.backordered.count.should eq 1 + end + + it 'calculates the quantity by state' do + subject.add variant, 4, :on_hand + subject.add variant, 3, :backordered + + subject.quantity.should eq 7 + subject.quantity(:on_hand).should eq 4 + subject.quantity(:backordered).should eq 3 + end + + it 'returns nil for content item not found' do + item = subject.find_item(variant, :on_hand) + item.should be_nil + end + + it 'finds content item for a variant' do + subject.add variant, 4, :on_hand + item = subject.find_item(variant, :on_hand) + item.quantity.should eq 4 + end + + it 'get flattened contents' do + subject.add variant, 4, :on_hand + subject.add variant, 2, :backordered + flattened = subject.flattened + flattened.select { |i| i.state == :on_hand }.size.should eq 4 + flattened.select { |i| i.state == :backordered }.size.should eq 2 + end + + it 'set contents from flattened' do + flattened = [Package::ContentItem.new(variant, 1, :on_hand), + Package::ContentItem.new(variant, 1, :on_hand), + Package::ContentItem.new(variant, 1, :backordered), + Package::ContentItem.new(variant, 1, :backordered)] + + subject.flattened = flattened + subject.on_hand.size.should eq 1 + subject.on_hand.first.quantity.should eq 2 + + subject.backordered.size.should eq 1 + end + + # Contains regression test for #2804 + it 'builds a list of shipping methods from all categories' do + shipping_method1 = create(:shipping_method) + shipping_method2 = create(:shipping_method) + variant1 = mock_model(Variant, shipping_category: shipping_method1.shipping_categories.first) + variant2 = mock_model(Variant, shipping_category: shipping_method2.shipping_categories.first) + variant3 = mock_model(Variant, shipping_category: nil) + contents = [Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant2, 1), + Package::ContentItem.new(variant3, 1)] + + package = Package.new(stock_location, order, contents) + package.shipping_methods.size.should eq 2 + end + + + it "can convert to a shipment" do + flattened = [Package::ContentItem.new(variant, 2, :on_hand), + Package::ContentItem.new(variant, 1, :backordered)] + subject.flattened = flattened + + shipping_method = build(:shipping_method) + subject.shipping_rates = [ Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) ] + + shipment = subject.to_shipment + shipment.order.should == subject.order + shipment.stock_location.should == subject.stock_location + shipment.inventory_units.size.should == 3 + + first_unit = shipment.inventory_units.first + first_unit.variant.should == variant + first_unit.state.should == 'on_hand' + first_unit.order.should == subject.order + first_unit.should be_pending + + last_unit = shipment.inventory_units.last + last_unit.variant.should == variant + last_unit.state.should == 'backordered' + last_unit.order.should == subject.order + + shipment.shipping_method.should eq shipping_method + end + end + end +end From bdb40d68e99ca4c8df7fe65b65cb422facef5bac Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:22:15 +0100 Subject: [PATCH 130/261] Fix easy rubocop issues --- app/models/spree/stock/package.rb | 28 +++++++++--------- spec/models/spree/stock/package_spec.rb | 39 ++++++++++++++----------- 2 files changed, 37 insertions(+), 30 deletions(-) diff --git a/app/models/spree/stock/package.rb b/app/models/spree/stock/package.rb index 68ef8837ab..e724b3efa1 100644 --- a/app/models/spree/stock/package.rb +++ b/app/models/spree/stock/package.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Stock class Package @@ -6,14 +8,14 @@ module Spree attr_reader :stock_location, :order, :contents attr_accessor :shipping_rates - def initialize(stock_location, order, contents=[]) + def initialize(stock_location, order, contents = []) @stock_location = stock_location @order = order @contents = contents - @shipping_rates = Array.new + @shipping_rates = [] end - def add(variant, quantity, state=:on_hand) + def add(variant, quantity, state = :on_hand) contents << ContentItem.new(variant, quantity, state) end @@ -29,26 +31,26 @@ module Spree contents.select { |item| item.state == :backordered } end - def find_item(variant, state=:on_hand) + def find_item(variant, state = :on_hand) contents.select do |item| item.variant == variant && - item.state == state + item.state == state end.first end - def quantity(state=nil) + def quantity(state = nil) case state when :on_hand - on_hand.sum { |item| item.quantity } + on_hand.sum(&:quantity) when :backordered - backordered.sum { |item| item.quantity } + backordered.sum(&:quantity) else - contents.sum { |item| item.quantity } + contents.sum(&:quantity) end end def empty? - quantity == 0 + quantity.zero? end def flattened @@ -74,7 +76,7 @@ module Spree end def currency - #TODO calculate from first variant? + # TODO calculate from first variant? end def shipping_categories @@ -82,7 +84,7 @@ module Spree end def shipping_methods - shipping_categories.map { |sc| sc.shipping_methods }.flatten.uniq + shipping_categories.map(&:shipping_methods).flatten.uniq end def inspect @@ -100,7 +102,7 @@ module Spree shipment.shipping_rates = shipping_rates contents.each do |item| - item.quantity.times do |n| + item.quantity.times do unit = shipment.inventory_units.build unit.pending = true unit.order = order diff --git a/spec/models/spree/stock/package_spec.rb b/spec/models/spree/stock/package_spec.rb index 532ce23dae..9059f10098 100644 --- a/spec/models/spree/stock/package_spec.rb +++ b/spec/models/spree/stock/package_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' module Spree @@ -51,9 +53,9 @@ module Spree it 'set contents from flattened' do flattened = [Package::ContentItem.new(variant, 1, :on_hand), - Package::ContentItem.new(variant, 1, :on_hand), - Package::ContentItem.new(variant, 1, :backordered), - Package::ContentItem.new(variant, 1, :backordered)] + Package::ContentItem.new(variant, 1, :on_hand), + Package::ContentItem.new(variant, 1, :backordered), + Package::ContentItem.new(variant, 1, :backordered)] subject.flattened = flattened subject.on_hand.size.should eq 1 @@ -66,8 +68,10 @@ module Spree it 'builds a list of shipping methods from all categories' do shipping_method1 = create(:shipping_method) shipping_method2 = create(:shipping_method) - variant1 = mock_model(Variant, shipping_category: shipping_method1.shipping_categories.first) - variant2 = mock_model(Variant, shipping_category: shipping_method2.shipping_categories.first) + variant1 = mock_model(Variant, + shipping_category: shipping_method1.shipping_categories.first) + variant2 = mock_model(Variant, + shipping_category: shipping_method2.shipping_categories.first) variant3 = mock_model(Variant, shipping_category: nil) contents = [Package::ContentItem.new(variant1, 1), Package::ContentItem.new(variant1, 1), @@ -78,30 +82,31 @@ module Spree package.shipping_methods.size.should eq 2 end - it "can convert to a shipment" do flattened = [Package::ContentItem.new(variant, 2, :on_hand), - Package::ContentItem.new(variant, 1, :backordered)] + Package::ContentItem.new(variant, 1, :backordered)] subject.flattened = flattened shipping_method = build(:shipping_method) - subject.shipping_rates = [ Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) ] + subject.shipping_rates = [ + Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) + ] shipment = subject.to_shipment - shipment.order.should == subject.order - shipment.stock_location.should == subject.stock_location - shipment.inventory_units.size.should == 3 + expect(shipment.order).to eq subject.order + expect(shipment.stock_location).to eq subject.stock_location + expect(shipment.inventory_units.size).to eq 3 first_unit = shipment.inventory_units.first - first_unit.variant.should == variant - first_unit.state.should == 'on_hand' - first_unit.order.should == subject.order + expect(first_unit.variant).to eq variant + expect(first_unit.state).to eq 'on_hand' + expect(first_unit.order).to eq subject.order first_unit.should be_pending last_unit = shipment.inventory_units.last - last_unit.variant.should == variant - last_unit.state.should == 'backordered' - last_unit.order.should == subject.order + expect(last_unit.variant).to eq variant + expect(last_unit.state).to eq 'backordered' + expect(last_unit.order).to eq subject.order shipment.shipping_method.should eq shipping_method end From 55a4021157ba7c4ae15614a268ed9e466e9305da Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:25:19 +0100 Subject: [PATCH 131/261] Convert to modern rspec syntax --- spec/models/spree/stock/package_spec.rb | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/spec/models/spree/stock/package_spec.rb b/spec/models/spree/stock/package_spec.rb index 9059f10098..6b27b405ac 100644 --- a/spec/models/spree/stock/package_spec.rb +++ b/spec/models/spree/stock/package_spec.rb @@ -13,42 +13,42 @@ module Spree it 'calculates the weight of all the contents' do subject.add variant, 4 - subject.weight.should == 100.0 + expect(subject.weight).to eq 100.0 end it 'filters by on_hand and backordered' do subject.add variant, 4, :on_hand subject.add variant, 3, :backordered - subject.on_hand.count.should eq 1 - subject.backordered.count.should eq 1 + expect(subject.on_hand.count).to eq 1 + expect(subject.backordered.count).to eq 1 end it 'calculates the quantity by state' do subject.add variant, 4, :on_hand subject.add variant, 3, :backordered - subject.quantity.should eq 7 - subject.quantity(:on_hand).should eq 4 - subject.quantity(:backordered).should eq 3 + expect(subject.quantity).to eq 7 + expect(subject.quantity(:on_hand)).to eq 4 + expect(subject.quantity(:backordered)).to eq 3 end it 'returns nil for content item not found' do item = subject.find_item(variant, :on_hand) - item.should be_nil + expect(item).to be_nil end it 'finds content item for a variant' do subject.add variant, 4, :on_hand item = subject.find_item(variant, :on_hand) - item.quantity.should eq 4 + expect(item.quantity).to eq 4 end it 'get flattened contents' do subject.add variant, 4, :on_hand subject.add variant, 2, :backordered flattened = subject.flattened - flattened.select { |i| i.state == :on_hand }.size.should eq 4 - flattened.select { |i| i.state == :backordered }.size.should eq 2 + expect(flattened.select { |i| i.state == :on_hand }.size).to eq 4 + expect(flattened.select { |i| i.state == :backordered }.size).to eq 2 end it 'set contents from flattened' do @@ -58,28 +58,28 @@ module Spree Package::ContentItem.new(variant, 1, :backordered)] subject.flattened = flattened - subject.on_hand.size.should eq 1 - subject.on_hand.first.quantity.should eq 2 + expect(subject.on_hand.size).to eq 1 + expect(subject.on_hand.first.quantity).to eq 2 - subject.backordered.size.should eq 1 + expect(subject.backordered.size).to eq 1 end # Contains regression test for #2804 it 'builds a list of shipping methods from all categories' do shipping_method1 = create(:shipping_method) shipping_method2 = create(:shipping_method) - variant1 = mock_model(Variant, - shipping_category: shipping_method1.shipping_categories.first) - variant2 = mock_model(Variant, - shipping_category: shipping_method2.shipping_categories.first) - variant3 = mock_model(Variant, shipping_category: nil) + variant1 = create(:variant, + shipping_category: shipping_method1.shipping_categories.first) + variant2 = create(:variant, + shipping_category: shipping_method2.shipping_categories.first) + variant3 = create(:variant, shipping_category: nil) contents = [Package::ContentItem.new(variant1, 1), Package::ContentItem.new(variant1, 1), Package::ContentItem.new(variant2, 1), Package::ContentItem.new(variant3, 1)] package = Package.new(stock_location, order, contents) - package.shipping_methods.size.should eq 2 + expect(package.shipping_methods.size).to eq 2 end it "can convert to a shipment" do @@ -101,14 +101,14 @@ module Spree expect(first_unit.variant).to eq variant expect(first_unit.state).to eq 'on_hand' expect(first_unit.order).to eq subject.order - first_unit.should be_pending + expect(first_unit).to be_pending last_unit = shipment.inventory_units.last expect(last_unit.variant).to eq variant expect(last_unit.state).to eq 'backordered' expect(last_unit.order).to eq subject.order - shipment.shipping_method.should eq shipping_method + expect(shipment.shipping_method).to eq shipping_method end end end From 4e5259f4911f3c49171e1cf6cc84ce8473695c10 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:29:18 +0100 Subject: [PATCH 132/261] Bring shipment from spree_core --- app/models/spree/shipment.rb | 290 ++++++++++++++++++ spec/models/spree/shipment_spec.rb | 476 +++++++++++++++++++++++++++-- 2 files changed, 745 insertions(+), 21 deletions(-) create mode 100644 app/models/spree/shipment.rb diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb new file mode 100644 index 0000000000..b49f8f5bdc --- /dev/null +++ b/app/models/spree/shipment.rb @@ -0,0 +1,290 @@ +require 'ostruct' + +module Spree + class Shipment < ActiveRecord::Base + belongs_to :order, class_name: 'Spree::Order' + belongs_to :address, class_name: 'Spree::Address' + belongs_to :stock_location, class_name: 'Spree::StockLocation' + + has_many :shipping_rates, dependent: :delete_all + has_many :shipping_methods, through: :shipping_rates + has_many :state_changes, as: :stateful + has_many :inventory_units, dependent: :delete_all + has_one :adjustment, as: :source, dependent: :destroy + + before_create :generate_shipment_number + after_save :ensure_correct_adjustment, :update_order + + attr_accessor :special_instructions + + accepts_nested_attributes_for :address + accepts_nested_attributes_for :inventory_units + + make_permalink field: :number + + scope :shipped, -> { with_state('shipped') } + scope :ready, -> { with_state('ready') } + scope :pending, -> { with_state('pending') } + scope :with_state, ->(*s) { where(state: s) } + scope :trackable, -> { where("tracking IS NOT NULL AND tracking != ''") } + + # shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details) + state_machine initial: :pending, use_transactions: false do + event :ready do + transition from: :pending, to: :ready, if: lambda { |shipment| + # Fix for #2040 + shipment.determine_state(shipment.order) == 'ready' + } + end + + event :pend do + transition from: :ready, to: :pending + end + + event :ship do + transition from: :ready, to: :shipped + end + after_transition to: :shipped, do: :after_ship + + event :cancel do + transition to: :canceled, from: [:pending, :ready] + end + after_transition to: :canceled, do: :after_cancel + + event :resume do + transition from: :canceled, to: :ready, if: lambda { |shipment| + shipment.determine_state(shipment.order) == :ready + } + transition from: :canceled, to: :pending, if: lambda { |shipment| + shipment.determine_state(shipment.order) == :ready + } + transition from: :canceled, to: :pending + end + after_transition from: :canceled, to: [:pending, :ready], do: :after_resume + end + + def to_param + number if number + generate_shipment_number unless number + number.to_s.to_url.upcase + end + + def backordered? + inventory_units.any? { |inventory_unit| inventory_unit.backordered? } + end + + def shipped=(value) + return unless value == '1' && shipped_at.nil? + self.shipped_at = Time.now + end + + def shipping_method + selected_shipping_rate.try(:shipping_method) || shipping_rates.first.try(:shipping_method) + end + + def add_shipping_method(shipping_method, selected = false) + shipping_rates.create(shipping_method: shipping_method, selected: selected) + end + + def selected_shipping_rate + shipping_rates.where(selected: true).first + end + + def selected_shipping_rate_id + selected_shipping_rate.try(:id) + end + + def selected_shipping_rate_id=(id) + shipping_rates.update_all(selected: false) + shipping_rates.update(id, selected: true) + self.save! + end + + def refresh_rates + return shipping_rates if shipped? + + self.shipping_rates = Stock::Estimator.new(order).shipping_rates(to_package) + + if shipping_method + selected_rate = shipping_rates.detect { |rate| + rate.shipping_method_id == shipping_method.id + } + self.selected_shipping_rate_id = selected_rate.id if selected_rate + end + + shipping_rates + end + + def currency + order ? order.currency : Spree::Config[:currency] + end + + # The adjustment amount associated with this shipment (if any.) Returns only the first adjustment to match + # the shipment but there should never really be more than one. + def cost + adjustment ? adjustment.amount : 0 + end + + alias_method :amount, :cost + + def display_cost + Spree::Money.new(cost, { currency: currency }) + end + + alias_method :display_amount, :display_cost + + def item_cost + line_items.map(&:amount).sum + end + + def display_item_cost + Spree::Money.new(item_cost, { currency: currency }) + end + + def total_cost + cost + item_cost + end + + def display_total_cost + Spree::Money.new(total_cost, { currency: currency }) + end + + def editable_by?(user) + !shipped? + end + + def manifest + inventory_units.joins(:variant).includes(:variant).group_by(&:variant).map do |variant, units| + states = {} + units.group_by(&:state).each { |state, iu| states[state] = iu.count } + OpenStruct.new(variant: variant, quantity: units.length, states: states) + end + end + + def line_items + if order.complete? and Spree::Config[:track_inventory_levels] + order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) } + else + order.line_items + end + end + + def finalize! + InventoryUnit.finalize_units!(inventory_units) + manifest.each { |item| manifest_unstock(item) } + end + + def after_cancel + manifest.each { |item| manifest_restock(item) } + end + + def after_resume + manifest.each { |item| manifest_unstock(item) } + end + + # Updates various aspects of the Shipment while bypassing any callbacks. Note that this method takes an explicit reference to the + # Order object. This is necessary because the association actually has a stale (and unsaved) copy of the Order and so it will not + # yield the correct results. + def update!(order) + old_state = state + new_state = determine_state(order) + update_column :state, new_state + after_ship if new_state == 'shipped' and old_state != 'shipped' + end + + # Determines the appropriate +state+ according to the following logic: + # + # pending unless order is complete and +order.payment_state+ is +paid+ + # shipped if already shipped (ie. does not change the state) + # ready all other cases + def determine_state(order) + return 'canceled' if order.canceled? + return 'pending' unless order.can_ship? + return 'pending' if inventory_units.any? &:backordered? + return 'shipped' if state == 'shipped' + order.paid? ? 'ready' : 'pending' + end + + def tracking_url + @tracking_url ||= shipping_method.build_tracking_url(tracking) + end + + def include?(variant) + inventory_units_for(variant).present? + end + + def inventory_units_for(variant) + inventory_units.group_by(&:variant_id)[variant.id] || [] + end + + def to_package + package = Spree::Config.package_factory.new(stock_location, order) + inventory_units.includes(:variant).each do |inventory_unit| + package.add inventory_unit.variant, 1, inventory_unit.state_name + end + package + end + + def set_up_inventory(state, variant, order) + self.inventory_units.create(variant_id: variant.id, state: state, order_id: order.id) + end + + private + + def manifest_unstock(item) + stock_location.unstock item.variant, item.quantity, self + end + + def manifest_restock(item) + stock_location.restock item.variant, item.quantity, self + end + + def generate_shipment_number + return number unless number.blank? + record = true + while record + random = "H#{Array.new(11) { rand(9) }.join}" + record = self.class.where(number: random).first + end + self.number = random + end + + def description_for_shipping_charge + "#{Spree.t(:shipping)} (#{shipping_method.name})" + end + + def validate_shipping_method + unless shipping_method.nil? + errors.add :shipping_method, Spree.t(:is_not_available_to_shipment_address) unless shipping_method.include?(address) + end + end + + def after_ship + inventory_units.each &:ship! + adjustment.finalize! + send_shipped_email + touch :shipped_at + end + + def send_shipped_email + ShipmentMailer.shipped_email(self.id).deliver + end + + def ensure_correct_adjustment + if adjustment + adjustment.originator = shipping_method + adjustment.label = shipping_method.adjustment_label + adjustment.amount = selected_shipping_rate.cost if adjustment.open? + adjustment.save! + adjustment.reload + elsif selected_shipping_rate_id + shipping_method.create_adjustment shipping_method.adjustment_label, order, self, true, "open" + reload #ensure adjustment is present on later saves + end + end + + def update_order + order.update! + end + end +end diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index b37dd498ff..a9992c89c5 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -1,33 +1,467 @@ -require "spec_helper" +require 'spec_helper' +require 'benchmark' describe Spree::Shipment do - describe "manifest" do - let!(:product) { create(:product) } - let!(:order) { create(:order, distributor: product.supplier) } - let!(:deleted_variant) { create(:variant, product: product) } - let!(:other_variant) { create(:variant, product: product) } - let!(:line_item_for_deleted) { create(:line_item, order: order, variant: deleted_variant) } - let!(:line_item_for_other) { create(:line_item, order: order, variant: other_variant) } - let!(:shipment) { create(:shipment_with, :shipping_method, order: order) } + let(:order) { mock_model Spree::Order, backordered?: false, + canceled?: false, + can_ship?: true, + currency: 'USD' } + let(:shipping_method) { create(:shipping_method, name: "UPS") } + let(:shipment) do + shipment = Spree::Shipment.new order: order + shipment.stub(shipping_method: shipping_method) + shipment.state = 'pending' + shipment + end - context "when the variant is soft-deleted" do - before { deleted_variant.delete } + let(:charge) { create(:adjustment) } + let(:variant) { mock_model(Spree::Variant) } - it "can still access the variant" do - shipment.reload - variants = shipment.manifest.map(&:variant).uniq - expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + it 'is backordered if one if its inventory_units is backordered' do + shipment.stub(inventory_units: [ + mock_model(Spree::InventoryUnit, backordered?: false), + mock_model(Spree::InventoryUnit, backordered?: true) + ]) + shipment.should be_backordered + end + + context "#cost" do + it "should return the amount of any shipping charges that it originated" do + shipment.stub_chain :adjustment, amount: 10 + shipment.cost.should == 10 + end + + it "should return 0 if there are no relevant shipping adjustments" do + shipment.cost.should == 0 + end + end + + context "display_cost" do + it "retuns a Spree::Money" do + shipment.stub(:cost) { 21.22 } + shipment.display_cost.should == Spree::Money.new(21.22) + end + end + + context "display_item_cost" do + it "retuns a Spree::Money" do + shipment.stub(:item_cost) { 21.22 } + shipment.display_item_cost.should == Spree::Money.new(21.22) + end + end + + context "display_total_cost" do + it "retuns a Spree::Money" do + shipment.stub(:total_cost) { 21.22 } + shipment.display_total_cost.should == Spree::Money.new(21.22) + end + end + + it "#item_cost" do + shipment = create(:shipment, order: create(:order_with_totals)) + shipment.item_cost.should eql(10.0) + end + + context "manifest" do + let(:order) { Spree::Order.create } + let(:variant) { create(:variant) } + let!(:line_item) { order.contents.add variant } + let!(:shipment) { order.create_proposed_shipments.first } + + it "returns variant expected" do + expect(shipment.manifest.first.variant).to eq variant + end + + context "variant was removed" do + before { variant.product.destroy } + + it "still returns variant expected" do + expect(shipment.manifest.first.variant).to eq variant end end - context "when the product is soft-deleted" do - before { deleted_variant.product.delete } + describe "with soft-deleted products or variants" do + let!(:product) { create(:product) } + let!(:order) { create(:order, distributor: product.supplier) } + let!(:deleted_variant) { create(:variant, product: product) } + let!(:other_variant) { create(:variant, product: product) } + let!(:line_item_for_deleted) { create(:line_item, order: order, variant: deleted_variant) } + let!(:line_item_for_other) { create(:line_item, order: order, variant: other_variant) } + let!(:shipment) { create(:shipment_with, :shipping_method, order: order) } - it "can still access the variant" do - shipment.reload - variants = shipment.manifest.map(&:variant) - expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + context "when the variant is soft-deleted" do + before { deleted_variant.delete } + + it "can still access the variant" do + shipment.reload + variants = shipment.manifest.map(&:variant).uniq + expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + end + end + + context "when the product is soft-deleted" do + before { deleted_variant.product.delete } + + it "can still access the variant" do + shipment.reload + variants = shipment.manifest.map(&:variant) + expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + end end end end + + context 'shipping_rates' do + let(:shipment) { create(:shipment) } + let(:shipping_method1) { create(:shipping_method) } + let(:shipping_method2) { create(:shipping_method) } + let(:shipping_rates) { [ + Spree::ShippingRate.new(shipping_method: shipping_method1, cost: 10.00, selected: true), + Spree::ShippingRate.new(shipping_method: shipping_method2, cost: 20.00) + ] } + + it 'returns shipping_method from selected shipping_rate' do + shipment.shipping_rates.delete_all + shipment.shipping_rates.create shipping_method: shipping_method1, cost: 10.00, selected: true + shipment.shipping_method.should eq shipping_method1 + end + + context 'refresh_rates' do + let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) } + + it 'should request new rates, and maintain shipping_method selection' do + Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) + shipment.stub(shipping_method: shipping_method2) + + shipment.refresh_rates.should == shipping_rates + shipment.reload.selected_shipping_rate.shipping_method_id.should == shipping_method2.id + end + + it 'should handle no shipping_method selection' do + Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) + shipment.stub(shipping_method: nil) + shipment.refresh_rates.should == shipping_rates + shipment.reload.selected_shipping_rate.should_not be_nil + end + + it 'should not refresh if shipment is shipped' do + Spree::Stock::Estimator.should_not_receive(:new) + shipment.shipping_rates.delete_all + shipment.stub(shipped?: true) + shipment.refresh_rates.should == [] + end + + context 'to_package' do + it 'should use symbols for states when adding contents to package' do + shipment.stub_chain(:inventory_units, includes: [ build(:inventory_unit, variant: variant, state: 'on_hand'), + build(:inventory_unit, variant: variant, state: 'backordered') ] ) + package = shipment.to_package + package.on_hand.count.should eq 1 + package.backordered.count.should eq 1 + end + end + end + end + + it '#total_cost' do + shipment.stub cost: 5.0 + shipment.stub item_cost: 50.0 + shipment.total_cost.should eql(55.0) + end + + context "#update!" do + shared_examples_for "immutable once shipped" do + it "should remain in shipped state once shipped" do + shipment.state = 'shipped' + shipment.should_receive(:update_column).with(:state, 'shipped') + shipment.update!(order) + end + end + + shared_examples_for "pending if backordered" do + it "should have a state of pending if backordered" do + shipment.stub(inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)]) + shipment.should_receive(:update_column).with(:state, 'pending') + shipment.update!(order) + end + end + + context "when order cannot ship" do + before { order.stub can_ship?: false } + it "should result in a 'pending' state" do + shipment.should_receive(:update_column).with(:state, 'pending') + shipment.update!(order) + end + end + + context "when order is paid" do + before { order.stub paid?: true } + it "should result in a 'ready' state" do + shipment.should_receive(:update_column).with(:state, 'ready') + shipment.update!(order) + end + it_should_behave_like 'immutable once shipped' + it_should_behave_like 'pending if backordered' + end + + context "when order has balance due" do + before { order.stub paid?: false } + it "should result in a 'pending' state" do + shipment.state = 'ready' + shipment.should_receive(:update_column).with(:state, 'pending') + shipment.update!(order) + end + it_should_behave_like 'immutable once shipped' + it_should_behave_like 'pending if backordered' + end + + context "when order has a credit owed" do + before { order.stub payment_state: 'credit_owed', paid?: true } + it "should result in a 'ready' state" do + shipment.state = 'pending' + shipment.should_receive(:update_column).with(:state, 'ready') + shipment.update!(order) + end + it_should_behave_like 'immutable once shipped' + it_should_behave_like 'pending if backordered' + end + + context "when shipment state changes to shipped" do + it "should call after_ship" do + shipment.state = 'pending' + shipment.should_receive :after_ship + shipment.stub determine_state: 'shipped' + shipment.should_receive(:update_column).with(:state, 'shipped') + shipment.update!(order) + end + end + end + + context "when track_inventory is false" do + before { Spree::Config.set track_inventory_levels: false } + after { Spree::Config.set track_inventory_levels: true } + + it "should not use the line items from order when track_inventory_levels is false" do + line_items = [mock_model(Spree::LineItem)] + order.stub complete?: true + order.stub line_items: line_items + shipment.line_items.should == line_items + end + end + + context "when order is completed" do + after { Spree::Config.set track_inventory_levels: true } + + before do + order.stub completed?: true + order.stub canceled?: false + end + + context "with inventory tracking" do + before { Spree::Config.set track_inventory_levels: true } + + it "should validate with inventory" do + shipment.inventory_units = [create(:inventory_unit)] + shipment.valid?.should be_true + end + end + + context "without inventory tracking" do + before { Spree::Config.set track_inventory_levels: false } + + it "should validate with no inventory" do + shipment.valid?.should be_true + end + end + end + + context "#cancel" do + it 'cancels the shipment' do + shipment.stub(:ensure_correct_adjustment) + shipment.order.stub(:update!) + + shipment.state = 'pending' + shipment.should_receive(:after_cancel) + shipment.cancel! + shipment.state.should eq 'canceled' + end + + it 'restocks the items' do + shipment.stub_chain(:inventory_units, :joins, includes: [mock_model(Spree::InventoryUnit, variant: variant)]) + shipment.stock_location = mock_model(Spree::StockLocation) + shipment.stock_location.should_receive(:restock).with(variant, 1, shipment) + shipment.after_cancel + end + end + + context "#resume" do + it 'will determine new state based on order' do + shipment.stub(:ensure_correct_adjustment) + shipment.order.stub(:update!) + + shipment.state = 'canceled' + shipment.should_receive(:determine_state).and_return(:ready) + shipment.should_receive(:after_resume) + shipment.resume! + shipment.state.should eq 'ready' + end + + it 'unstocks them items' do + shipment.stub_chain(:inventory_units, :joins, includes: [mock_model(Spree::InventoryUnit, variant: variant)]) + shipment.stock_location = mock_model(Spree::StockLocation) + shipment.stock_location.should_receive(:unstock).with(variant, 1, shipment) + shipment.after_resume + end + + it 'will determine new state based on order' do + shipment.stub(:ensure_correct_adjustment) + shipment.order.stub(:update!) + + shipment.state = 'canceled' + shipment.should_receive(:determine_state).twice.and_return('ready') + shipment.should_receive(:after_resume) + shipment.resume! + # Shipment is pending because order is already paid + shipment.state.should eq 'pending' + end + end + + context "#ship" do + before do + order.stub(:update!) + shipment.stub(require_inventory: false, update_order: true, state: 'ready') + shipment.stub(adjustment: charge) + shipping_method.stub(:create_adjustment) + shipment.stub(:ensure_correct_adjustment) + end + + it "should update shipped_at timestamp" do + shipment.stub(:send_shipped_email) + shipment.ship! + shipment.shipped_at.should_not be_nil + # Ensure value is persisted + shipment.reload + shipment.shipped_at.should_not be_nil + end + + it "should send a shipment email" do + mail_message = double 'Mail::Message' + shipment_id = nil + Spree::ShipmentMailer.should_receive(:shipped_email) { |*args| + shipment_id = args[0] + mail_message + } + mail_message.should_receive :deliver + shipment.ship! + shipment_id.should == shipment.id + end + + it "should finalize the shipment's adjustment" do + shipment.stub(:send_shipped_email) + shipment.ship! + shipment.adjustment.state.should == 'finalized' + shipment.adjustment.should be_immutable + end + end + + context "#ready" do + # Regression test for #2040 + it "cannot ready a shipment for an order if the order is unpaid" do + order.stub(paid?: false) + assert !shipment.can_ready? + end + end + + context "ensure_correct_adjustment" do + before { shipment.stub(:reload) } + + it "should create adjustment when not present" do + shipment.stub(:selected_shipping_rate_id => 1) + shipping_method.should_receive(:create_adjustment).with(shipping_method.adjustment_label, order, shipment, true, "open") + shipment.send(:ensure_correct_adjustment) + end + + # Regression test for #3138 + it "should use the shipping method's adjustment label" do + shipment.stub(:selected_shipping_rate_id => 1) + shipping_method.stub(:adjustment_label => "Foobar") + shipping_method.should_receive(:create_adjustment).with("Foobar", order, shipment, true, "open") + shipment.send(:ensure_correct_adjustment) + end + + it "should update originator when adjustment is present" do + shipment.stub(selected_shipping_rate: mock_model(Spree::ShippingRate, cost: 10.00)) + shipment.stub(adjustment: mock_model(Spree::Adjustment, open?: true)) + shipment.adjustment.should_receive(:originator=).with(shipping_method) + shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) + shipment.adjustment.should_receive(:amount=).with(10.00) + shipment.adjustment.should_receive(:save!) + shipment.adjustment.should_receive(:reload) + shipment.send(:ensure_correct_adjustment) + end + + it 'should not update amount if adjustment is not open?' do + shipment.stub(selected_shipping_rate: mock_model(Spree::ShippingRate, cost: 10.00)) + shipment.stub(adjustment: mock_model(Spree::Adjustment, open?: false)) + shipment.adjustment.should_receive(:originator=).with(shipping_method) + shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) + shipment.adjustment.should_not_receive(:amount=).with(10.00) + shipment.adjustment.should_receive(:save!) + shipment.adjustment.should_receive(:reload) + shipment.send(:ensure_correct_adjustment) + end + end + + context "update_order" do + it "should update order" do + order.should_receive(:update!) + shipment.send(:update_order) + end + end + + context "after_save" do + it "should run correct callbacks" do + shipment.should_receive(:ensure_correct_adjustment) + shipment.should_receive(:update_order) + shipment.run_callbacks(:save) + end + end + + context "currency" do + it "returns the order currency" do + shipment.currency.should == order.currency + end + end + + context "#tracking_url" do + it "uses shipping method to determine url" do + shipping_method.should_receive(:build_tracking_url).with('1Z12345').and_return(:some_url) + shipment.tracking = '1Z12345' + + shipment.tracking_url.should == :some_url + end + end + + context "set up new inventory units" do + let(:variant) { double("Variant", id: 9) } + let(:inventory_units) { double } + let(:params) do + { variant_id: variant.id, state: 'on_hand', order_id: order.id } + end + + before { shipment.stub inventory_units: inventory_units } + + it "associates variant and order" do + expect(inventory_units).to receive(:create).with(params) + unit = shipment.set_up_inventory('on_hand', variant, order) + end + end + + # Regression test for #3349 + context "#destroy" do + it "destroys linked shipping_rates" do + reflection = Spree::Shipment.reflect_on_association(:shipping_rates) + reflection.options[:dependent] = :destroy + end + end end From 494251b7cf40f85a495378b74a7d67c5e21890df Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:43:28 +0100 Subject: [PATCH 133/261] Fix simple rubocop issues --- app/models/spree/shipment.rb | 132 ++++++++++++++++------------- spec/models/spree/shipment_spec.rb | 90 +++++++++++--------- 2 files changed, 124 insertions(+), 98 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index b49f8f5bdc..f3b0b03f0c 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'ostruct' module Spree @@ -28,7 +30,8 @@ module Spree scope :with_state, ->(*s) { where(state: s) } scope :trackable, -> { where("tracking IS NOT NULL AND tracking != ''") } - # shipment state machine (see http://github.com/pluginaweek/state_machine/tree/master for details) + # Shipment state machine + # See http://github.com/pluginaweek/state_machine/tree/master for details state_machine initial: :pending, use_transactions: false do event :ready do transition from: :pending, to: :ready, if: lambda { |shipment| @@ -70,12 +73,13 @@ module Spree end def backordered? - inventory_units.any? { |inventory_unit| inventory_unit.backordered? } + inventory_units.any?(&:backordered?) end def shipped=(value) return unless value == '1' && shipped_at.nil? - self.shipped_at = Time.now + + self.shipped_at = Time.zone.now end def shipping_method @@ -97,7 +101,7 @@ module Spree def selected_shipping_rate_id=(id) shipping_rates.update_all(selected: false) shipping_rates.update(id, selected: true) - self.save! + save! end def refresh_rates @@ -119,8 +123,9 @@ module Spree order ? order.currency : Spree::Config[:currency] end - # The adjustment amount associated with this shipment (if any.) Returns only the first adjustment to match - # the shipment but there should never really be more than one. + # The adjustment amount associated with this shipment (if any) + # Returns only the first adjustment to match the shipment + # There should never really be more than one. def cost adjustment ? adjustment.amount : 0 end @@ -149,7 +154,7 @@ module Spree Spree::Money.new(total_cost, { currency: currency }) end - def editable_by?(user) + def editable_by?(_user) !shipped? end @@ -162,7 +167,7 @@ module Spree end def line_items - if order.complete? and Spree::Config[:track_inventory_levels] + if order.complete? && Spree::Config[:track_inventory_levels] order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) } else order.line_items @@ -182,14 +187,15 @@ module Spree manifest.each { |item| manifest_unstock(item) } end - # Updates various aspects of the Shipment while bypassing any callbacks. Note that this method takes an explicit reference to the - # Order object. This is necessary because the association actually has a stale (and unsaved) copy of the Order and so it will not - # yield the correct results. + # Updates various aspects of the Shipment while bypassing any callbacks. + # Note that this method takes an explicit reference to the Order object. + # This is necessary because the association actually has a stale (and unsaved) copy of the + # Order and so it will not yield the correct results. def update!(order) old_state = state new_state = determine_state(order) update_column :state, new_state - after_ship if new_state == 'shipped' and old_state != 'shipped' + after_ship if new_state == 'shipped' && old_state != 'shipped' end # Determines the appropriate +state+ according to the following logic: @@ -200,8 +206,9 @@ module Spree def determine_state(order) return 'canceled' if order.canceled? return 'pending' unless order.can_ship? - return 'pending' if inventory_units.any? &:backordered? + return 'pending' if inventory_units.any?(&:backordered?) return 'shipped' if state == 'shipped' + order.paid? ? 'ready' : 'pending' end @@ -226,65 +233,72 @@ module Spree end def set_up_inventory(state, variant, order) - self.inventory_units.create(variant_id: variant.id, state: state, order_id: order.id) + inventory_units.create(variant_id: variant.id, state: state, order_id: order.id) end private - def manifest_unstock(item) - stock_location.unstock item.variant, item.quantity, self - end + def manifest_unstock(item) + stock_location.unstock item.variant, item.quantity, self + end - def manifest_restock(item) - stock_location.restock item.variant, item.quantity, self - end + def manifest_restock(item) + stock_location.restock item.variant, item.quantity, self + end - def generate_shipment_number - return number unless number.blank? - record = true - while record - random = "H#{Array.new(11) { rand(9) }.join}" - record = self.class.where(number: random).first - end - self.number = random - end + def generate_shipment_number + return number if number.present? - def description_for_shipping_charge - "#{Spree.t(:shipping)} (#{shipping_method.name})" + record = true + while record + random = "H#{Array.new(11) { rand(9) }.join}" + record = self.class.where(number: random).first end + self.number = random + end - def validate_shipping_method - unless shipping_method.nil? - errors.add :shipping_method, Spree.t(:is_not_available_to_shipment_address) unless shipping_method.include?(address) - end - end + def description_for_shipping_charge + "#{Spree.t(:shipping)} (#{shipping_method.name})" + end - def after_ship - inventory_units.each &:ship! - adjustment.finalize! - send_shipped_email - touch :shipped_at - end + def validate_shipping_method + return if shipping_method.nil? - def send_shipped_email - ShipmentMailer.shipped_email(self.id).deliver - end + return if shipping_method.include?(address) - def ensure_correct_adjustment - if adjustment - adjustment.originator = shipping_method - adjustment.label = shipping_method.adjustment_label - adjustment.amount = selected_shipping_rate.cost if adjustment.open? - adjustment.save! - adjustment.reload - elsif selected_shipping_rate_id - shipping_method.create_adjustment shipping_method.adjustment_label, order, self, true, "open" - reload #ensure adjustment is present on later saves - end - end + errors.add :shipping_method, Spree.t(:is_not_available_to_shipment_address) + end - def update_order - order.update! + def after_ship + inventory_units.each(&:ship!) + adjustment.finalize! + send_shipped_email + touch :shipped_at + end + + def send_shipped_email + ShipmentMailer.shipped_email(id).deliver + end + + def ensure_correct_adjustment + if adjustment + adjustment.originator = shipping_method + adjustment.label = shipping_method.adjustment_label + adjustment.amount = selected_shipping_rate.cost if adjustment.open? + adjustment.save! + adjustment.reload + elsif selected_shipping_rate_id + shipping_method.create_adjustment(shipping_method.adjustment_label, + order, + self, + true, + "open") + reload # ensure adjustment is present on later saves end + end + + def update_order + order.update! + end end end diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index a9992c89c5..0c71a3ea58 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -1,11 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' require 'benchmark' describe Spree::Shipment do - let(:order) { mock_model Spree::Order, backordered?: false, - canceled?: false, - can_ship?: true, - currency: 'USD' } + let(:order) { + create(:order, backordered?: false, canceled?: false, can_ship?: true, currency: 'USD') + } let(:shipping_method) { create(:shipping_method, name: "UPS") } let(:shipment) do shipment = Spree::Shipment.new order: order @@ -19,41 +20,41 @@ describe Spree::Shipment do it 'is backordered if one if its inventory_units is backordered' do shipment.stub(inventory_units: [ - mock_model(Spree::InventoryUnit, backordered?: false), - mock_model(Spree::InventoryUnit, backordered?: true) - ]) + create(:inventory_unit, backordered?: false), + create(:inventory_unit, backordered?: true) + ]) shipment.should be_backordered end context "#cost" do it "should return the amount of any shipping charges that it originated" do shipment.stub_chain :adjustment, amount: 10 - shipment.cost.should == 10 + expect(shipment.cost).to eq 10 end it "should return 0 if there are no relevant shipping adjustments" do - shipment.cost.should == 0 + expect(shipment.cost).to eq 0 end end context "display_cost" do it "retuns a Spree::Money" do shipment.stub(:cost) { 21.22 } - shipment.display_cost.should == Spree::Money.new(21.22) + expect(shipment.display_cost).to eq Spree::Money.new(21.22) end end context "display_item_cost" do it "retuns a Spree::Money" do shipment.stub(:item_cost) { 21.22 } - shipment.display_item_cost.should == Spree::Money.new(21.22) + expect(shipment.display_item_cost).to eq Spree::Money.new(21.22) end end context "display_total_cost" do it "retuns a Spree::Money" do shipment.stub(:total_cost) { 21.22 } - shipment.display_total_cost.should == Spree::Money.new(21.22) + expect(shipment.display_total_cost).to eq Spree::Money.new(21.22) end end @@ -115,10 +116,12 @@ describe Spree::Shipment do let(:shipment) { create(:shipment) } let(:shipping_method1) { create(:shipping_method) } let(:shipping_method2) { create(:shipping_method) } - let(:shipping_rates) { [ - Spree::ShippingRate.new(shipping_method: shipping_method1, cost: 10.00, selected: true), - Spree::ShippingRate.new(shipping_method: shipping_method2, cost: 20.00) - ] } + let(:shipping_rates) { + [ + Spree::ShippingRate.new(shipping_method: shipping_method1, cost: 10.00, selected: true), + Spree::ShippingRate.new(shipping_method: shipping_method2, cost: 20.00) + ] + } it 'returns shipping_method from selected shipping_rate' do shipment.shipping_rates.delete_all @@ -133,14 +136,14 @@ describe Spree::Shipment do Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) shipment.stub(shipping_method: shipping_method2) - shipment.refresh_rates.should == shipping_rates - shipment.reload.selected_shipping_rate.shipping_method_id.should == shipping_method2.id + expect(shipment.refresh_rates).to eq shipping_rates + expect(shipment.reload.selected_shipping_rate.shipping_method_id).to eq shipping_method2.id end it 'should handle no shipping_method selection' do Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) shipment.stub(shipping_method: nil) - shipment.refresh_rates.should == shipping_rates + expect(shipment.refresh_rates).to eq shipping_rates shipment.reload.selected_shipping_rate.should_not be_nil end @@ -148,13 +151,16 @@ describe Spree::Shipment do Spree::Stock::Estimator.should_not_receive(:new) shipment.shipping_rates.delete_all shipment.stub(shipped?: true) - shipment.refresh_rates.should == [] + expect(shipment.refresh_rates).to eq [] end context 'to_package' do it 'should use symbols for states when adding contents to package' do - shipment.stub_chain(:inventory_units, includes: [ build(:inventory_unit, variant: variant, state: 'on_hand'), - build(:inventory_unit, variant: variant, state: 'backordered') ] ) + shipment.stub_chain(:inventory_units, + includes: [build(:inventory_unit, variant: variant, + state: 'on_hand'), + build(:inventory_unit, variant: variant, + state: 'backordered')] ) package = shipment.to_package package.on_hand.count.should eq 1 package.backordered.count.should eq 1 @@ -245,7 +251,7 @@ describe Spree::Shipment do line_items = [mock_model(Spree::LineItem)] order.stub complete?: true order.stub line_items: line_items - shipment.line_items.should == line_items + expect(shipment.line_items).to eq line_items end end @@ -287,7 +293,9 @@ describe Spree::Shipment do end it 'restocks the items' do - shipment.stub_chain(:inventory_units, :joins, includes: [mock_model(Spree::InventoryUnit, variant: variant)]) + shipment.stub_chain(:inventory_units, + :joins, + includes: [mock_model(Spree::InventoryUnit, variant: variant)]) shipment.stock_location = mock_model(Spree::StockLocation) shipment.stock_location.should_receive(:restock).with(variant, 1, shipment) shipment.after_cancel @@ -307,7 +315,9 @@ describe Spree::Shipment do end it 'unstocks them items' do - shipment.stub_chain(:inventory_units, :joins, includes: [mock_model(Spree::InventoryUnit, variant: variant)]) + shipment.stub_chain(:inventory_units, + :joins, + includes: [mock_model(Spree::InventoryUnit, variant: variant)]) shipment.stock_location = mock_model(Spree::StockLocation) shipment.stock_location.should_receive(:unstock).with(variant, 1, shipment) shipment.after_resume @@ -353,13 +363,13 @@ describe Spree::Shipment do } mail_message.should_receive :deliver shipment.ship! - shipment_id.should == shipment.id + expect(shipment_id).to eq shipment.id end it "should finalize the shipment's adjustment" do shipment.stub(:send_shipped_email) shipment.ship! - shipment.adjustment.state.should == 'finalized' + expect(shipment.adjustment.state).to eq 'finalized' shipment.adjustment.should be_immutable end end @@ -376,17 +386,19 @@ describe Spree::Shipment do before { shipment.stub(:reload) } it "should create adjustment when not present" do - shipment.stub(:selected_shipping_rate_id => 1) - shipping_method.should_receive(:create_adjustment).with(shipping_method.adjustment_label, order, shipment, true, "open") - shipment.send(:ensure_correct_adjustment) + shipment.stub(selected_shipping_rate_id: 1) + shipping_method.should_receive(:create_adjustment).with(shipping_method.adjustment_label, + order, shipment, true, "open") + shipment.__send__(:ensure_correct_adjustment) end # Regression test for #3138 it "should use the shipping method's adjustment label" do - shipment.stub(:selected_shipping_rate_id => 1) - shipping_method.stub(:adjustment_label => "Foobar") - shipping_method.should_receive(:create_adjustment).with("Foobar", order, shipment, true, "open") - shipment.send(:ensure_correct_adjustment) + shipment.stub(selected_shipping_rate_id: 1) + shipping_method.stub(adjustment_label: "Foobar") + shipping_method.should_receive(:create_adjustment).with("Foobar", order, + shipment, true, "open") + shipment.__send__(:ensure_correct_adjustment) end it "should update originator when adjustment is present" do @@ -397,7 +409,7 @@ describe Spree::Shipment do shipment.adjustment.should_receive(:amount=).with(10.00) shipment.adjustment.should_receive(:save!) shipment.adjustment.should_receive(:reload) - shipment.send(:ensure_correct_adjustment) + shipment.__send__(:ensure_correct_adjustment) end it 'should not update amount if adjustment is not open?' do @@ -408,14 +420,14 @@ describe Spree::Shipment do shipment.adjustment.should_not_receive(:amount=).with(10.00) shipment.adjustment.should_receive(:save!) shipment.adjustment.should_receive(:reload) - shipment.send(:ensure_correct_adjustment) + shipment.__send__(:ensure_correct_adjustment) end end context "update_order" do it "should update order" do order.should_receive(:update!) - shipment.send(:update_order) + shipment.__send__(:update_order) end end @@ -429,7 +441,7 @@ describe Spree::Shipment do context "currency" do it "returns the order currency" do - shipment.currency.should == order.currency + expect(shipment.currency).to eq order.currency end end @@ -438,7 +450,7 @@ describe Spree::Shipment do shipping_method.should_receive(:build_tracking_url).with('1Z12345').and_return(:some_url) shipment.tracking = '1Z12345' - shipment.tracking_url.should == :some_url + expect(shipment.tracking_url).to eq :some_url end end From 7a03f57da0fed481070ceb5db8896a89e589048a Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:48:08 +0100 Subject: [PATCH 134/261] Merge shipment decorator with class brought from spree_core --- app/controllers/spree/orders_controller.rb | 2 +- app/models/spree/shipment.rb | 25 ++++++++++++- app/models/spree/shipment_decorator.rb | 41 ---------------------- 3 files changed, 25 insertions(+), 43 deletions(-) delete mode 100644 app/models/spree/shipment_decorator.rb diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 85939fe1ad..545ae1ce60 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -166,7 +166,7 @@ module Spree # recalculates the shipment taxes def update_totals_and_taxes @order.updater.update_totals - @order.shipment&.ensure_correct_adjustment_with_included_tax + @order.shipment&.ensure_correct_adjustment end # Sets the adjustments to open to perform the block's action and restores diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index f3b0b03f0c..c5fea38d2c 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -159,13 +159,18 @@ module Spree end def manifest - inventory_units.joins(:variant).includes(:variant).group_by(&:variant).map do |variant, units| + inventory_units.group_by(&:variant).map do |variant, units| states = {} units.group_by(&:state).each { |state, iu| states[state] = iu.count } + scoper.scope(variant) OpenStruct.new(variant: variant, quantity: units.length, states: states) end end + def scoper + @scoper ||= OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) + end + def line_items if order.complete? && Spree::Config[:track_inventory_levels] order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) } @@ -295,10 +300,28 @@ module Spree "open") reload # ensure adjustment is present on later saves end + + update_adjustment_included_tax if adjustment + end + + def update_adjustment_included_tax + if Config.shipment_inc_vat && (order.distributor.nil? || order.distributor.charges_sales_tax) + adjustment.set_included_tax! Config.shipping_tax_rate + else + adjustment.set_included_tax! 0 + end end def update_order order.update! end + + # NOTE: This is an override of spree's method, needed to allow orders + # without line items (ie. user invoices) to not have inventory units + def require_inventory + return false unless line_items.count > 0 # This line altered + + order.completed? && !order.canceled? + end end end diff --git a/app/models/spree/shipment_decorator.rb b/app/models/spree/shipment_decorator.rb deleted file mode 100644 index b23bd7266f..0000000000 --- a/app/models/spree/shipment_decorator.rb +++ /dev/null @@ -1,41 +0,0 @@ -module Spree - Shipment.class_eval do - def ensure_correct_adjustment_with_included_tax - ensure_correct_adjustment_without_included_tax - - update_adjustment_included_tax if adjustment - end - alias_method_chain :ensure_correct_adjustment, :included_tax - - def update_adjustment_included_tax - if Config.shipment_inc_vat && (order.distributor.nil? || order.distributor.charges_sales_tax) - adjustment.set_included_tax! Config.shipping_tax_rate - else - adjustment.set_included_tax! 0 - end - end - - def manifest - inventory_units.group_by(&:variant).map do |variant, units| - states = {} - units.group_by(&:state).each { |state, iu| states[state] = iu.count } - scoper.scope(variant) - OpenStruct.new(variant: variant, quantity: units.length, states: states) - end - end - - def scoper - @scoper ||= OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) - end - - private - - # NOTE: This is an override of spree's method, needed to allow orders - # without line items (ie. user invoices) to not have inventory units - def require_inventory - return false unless line_items.count > 0 # This line altered - - order.completed? && !order.canceled? - end - end -end From 2e33e02d7f14cc866dbffe2ec6a09f9931c20638 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 17:48:43 +0100 Subject: [PATCH 135/261] Remove dead code, this method was removed in spree 2.0.4 --- app/models/spree/shipment.rb | 8 -------- spec/models/spree/shipment_spec.rb | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index c5fea38d2c..bff7421c70 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -315,13 +315,5 @@ module Spree def update_order order.update! end - - # NOTE: This is an override of spree's method, needed to allow orders - # without line items (ie. user invoices) to not have inventory units - def require_inventory - return false unless line_items.count > 0 # This line altered - - order.completed? && !order.canceled? - end end end diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 0c71a3ea58..66561b32a9 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -339,7 +339,7 @@ describe Spree::Shipment do context "#ship" do before do order.stub(:update!) - shipment.stub(require_inventory: false, update_order: true, state: 'ready') + shipment.stub(update_order: true, state: 'ready') shipment.stub(adjustment: charge) shipping_method.stub(:create_adjustment) shipment.stub(:ensure_correct_adjustment) From 46cf106047246e58d2d9f9e3bbd2c5cd00625567 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 19:40:30 +0100 Subject: [PATCH 136/261] Fix shipment spec brought from spree --- spec/models/spree/shipment_spec.rb | 219 ++++++++++++++--------------- 1 file changed, 109 insertions(+), 110 deletions(-) diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 66561b32a9..e3b7ef9671 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -4,10 +4,8 @@ require 'spec_helper' require 'benchmark' describe Spree::Shipment do - let(:order) { - create(:order, backordered?: false, canceled?: false, can_ship?: true, currency: 'USD') - } - let(:shipping_method) { create(:shipping_method, name: "UPS") } + let(:order) { build(:order) } + let(:shipping_method) { build(:shipping_method, name: "UPS") } let(:shipment) do shipment = Spree::Shipment.new order: order shipment.stub(shipping_method: shipping_method) @@ -15,15 +13,16 @@ describe Spree::Shipment do shipment end - let(:charge) { create(:adjustment) } - let(:variant) { mock_model(Spree::Variant) } + let(:charge) { build(:adjustment) } + let(:variant) { build(:variant) } - it 'is backordered if one if its inventory_units is backordered' do - shipment.stub(inventory_units: [ - create(:inventory_unit, backordered?: false), - create(:inventory_unit, backordered?: true) - ]) - shipment.should be_backordered + it 'is backordered if one of its inventory_units is backordered' do + unit1 = create(:inventory_unit) + unit2 = create(:inventory_unit) + allow(unit1).to receive(:backordered?) { false } + allow(unit2).to receive(:backordered?) { true } + shipment.stub(inventory_units: [unit1, unit2]) + expect(shipment).to be_backordered end context "#cost" do @@ -60,7 +59,7 @@ describe Spree::Shipment do it "#item_cost" do shipment = create(:shipment, order: create(:order_with_totals)) - shipment.item_cost.should eql(10.0) + expect(shipment.item_cost).to eql(10.0) end context "manifest" do @@ -84,29 +83,22 @@ describe Spree::Shipment do describe "with soft-deleted products or variants" do let!(:product) { create(:product) } let!(:order) { create(:order, distributor: product.supplier) } - let!(:deleted_variant) { create(:variant, product: product) } - let!(:other_variant) { create(:variant, product: product) } - let!(:line_item_for_deleted) { create(:line_item, order: order, variant: deleted_variant) } - let!(:line_item_for_other) { create(:line_item, order: order, variant: other_variant) } - let!(:shipment) { create(:shipment_with, :shipping_method, order: order) } context "when the variant is soft-deleted" do - before { deleted_variant.delete } - it "can still access the variant" do - shipment.reload - variants = shipment.manifest.map(&:variant).uniq - expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + order.line_items.first.variant.delete + + variants = shipment.reload.manifest.map(&:variant).uniq + expect(variants).to eq [order.line_items.first.variant] end end context "when the product is soft-deleted" do - before { deleted_variant.product.delete } - it "can still access the variant" do - shipment.reload - variants = shipment.manifest.map(&:variant) - expect(variants.sort_by(&:id)).to eq([deleted_variant, other_variant].sort_by(&:id)) + order.line_items.first.variant.delete + + variants = shipment.reload.manifest.map(&:variant) + expect(variants).to eq [order.line_items.first.variant] end end end @@ -126,7 +118,7 @@ describe Spree::Shipment do it 'returns shipping_method from selected shipping_rate' do shipment.shipping_rates.delete_all shipment.shipping_rates.create shipping_method: shipping_method1, cost: 10.00, selected: true - shipment.shipping_method.should eq shipping_method1 + expect(shipment.shipping_method).to eq shipping_method1 end context 'refresh_rates' do @@ -144,7 +136,7 @@ describe Spree::Shipment do Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) shipment.stub(shipping_method: nil) expect(shipment.refresh_rates).to eq shipping_rates - shipment.reload.selected_shipping_rate.should_not be_nil + expect(shipment.reload.selected_shipping_rate).to_not be_nil end it 'should not refresh if shipment is shipped' do @@ -162,8 +154,8 @@ describe Spree::Shipment do build(:inventory_unit, variant: variant, state: 'backordered')] ) package = shipment.to_package - package.on_hand.count.should eq 1 - package.backordered.count.should eq 1 + expect(package.on_hand.count).to eq 1 + expect(package.backordered.count).to eq 1 end end end @@ -172,7 +164,7 @@ describe Spree::Shipment do it '#total_cost' do shipment.stub cost: 5.0 shipment.stub item_cost: 50.0 - shipment.total_cost.should eql(55.0) + expect(shipment.total_cost).to eql(55.0) end context "#update!" do @@ -186,50 +178,75 @@ describe Spree::Shipment do shared_examples_for "pending if backordered" do it "should have a state of pending if backordered" do - shipment.stub(inventory_units: [mock_model(Spree::InventoryUnit, backordered?: true)]) + unit = create(:inventory_unit) + allow(unit).to receive(:backordered?) { true } + shipment.stub(inventory_units: [unit]) shipment.should_receive(:update_column).with(:state, 'pending') shipment.update!(order) end end + context "when order is canceled" do + it "should result in a 'pending' state" do + allow(order).to receive(:canceled?) { true } + + shipment.should_receive(:update_column).with(:state, 'canceled') + shipment.update!(order) + end + end + context "when order cannot ship" do - before { order.stub can_ship?: false } it "should result in a 'pending' state" do + allow(order).to receive(:can_ship?) { false } + shipment.should_receive(:update_column).with(:state, 'pending') shipment.update!(order) end end - context "when order is paid" do - before { order.stub paid?: true } - it "should result in a 'ready' state" do - shipment.should_receive(:update_column).with(:state, 'ready') - shipment.update!(order) - end - it_should_behave_like 'immutable once shipped' - it_should_behave_like 'pending if backordered' - end + context "when order can ship" do + before { allow(order).to receive(:can_ship?) { true } } - context "when order has balance due" do - before { order.stub paid?: false } - it "should result in a 'pending' state" do - shipment.state = 'ready' - shipment.should_receive(:update_column).with(:state, 'pending') - shipment.update!(order) - end - it_should_behave_like 'immutable once shipped' - it_should_behave_like 'pending if backordered' - end + context "when order is paid" do + before { allow(order).to receive(:paid?) { true } } - context "when order has a credit owed" do - before { order.stub payment_state: 'credit_owed', paid?: true } - it "should result in a 'ready' state" do - shipment.state = 'pending' - shipment.should_receive(:update_column).with(:state, 'ready') - shipment.update!(order) + it "should result in a 'ready' state" do + shipment.should_receive(:update_column).with(:state, 'ready') + shipment.update!(order) + end + + it_should_behave_like 'immutable once shipped' + + it_should_behave_like 'pending if backordered' + + context "when order has a credit owed" do + before { allow(order).to receive(:payment_state) { 'credit_owed' } } + + it "should result in a 'ready' state" do + shipment.state = 'pending' + shipment.should_receive(:update_column).with(:state, 'ready') + shipment.update!(order) + end + + it_should_behave_like 'immutable once shipped' + + it_should_behave_like 'pending if backordered' + end + end + + context "when order has balance due" do + before { allow(order).to receive(:paid?) { false } } + + it "should result in a 'pending' state" do + shipment.state = 'ready' + shipment.should_receive(:update_column).with(:state, 'pending') + shipment.update!(order) + end + + it_should_behave_like 'immutable once shipped' + + it_should_behave_like 'pending if backordered' end - it_should_behave_like 'immutable once shipped' - it_should_behave_like 'pending if backordered' end context "when shipment state changes to shipped" do @@ -243,41 +260,15 @@ describe Spree::Shipment do end end - context "when track_inventory is false" do - before { Spree::Config.set track_inventory_levels: false } - after { Spree::Config.set track_inventory_levels: true } - - it "should not use the line items from order when track_inventory_levels is false" do - line_items = [mock_model(Spree::LineItem)] - order.stub complete?: true - order.stub line_items: line_items - expect(shipment.line_items).to eq line_items - end - end - context "when order is completed" do - after { Spree::Config.set track_inventory_levels: true } - before do order.stub completed?: true order.stub canceled?: false end - context "with inventory tracking" do - before { Spree::Config.set track_inventory_levels: true } - - it "should validate with inventory" do - shipment.inventory_units = [create(:inventory_unit)] - shipment.valid?.should be_true - end - end - - context "without inventory tracking" do - before { Spree::Config.set track_inventory_levels: false } - - it "should validate with no inventory" do - shipment.valid?.should be_true - end + it "should validate with inventory" do + shipment.inventory_units = [create(:inventory_unit)] + expect(shipment.valid?).to be_truthy end end @@ -289,14 +280,16 @@ describe Spree::Shipment do shipment.state = 'pending' shipment.should_receive(:after_cancel) shipment.cancel! - shipment.state.should eq 'canceled' + expect(shipment.state).to eq 'canceled' end it 'restocks the items' do + unit = double(:inventory_unit, variant: variant) + allow(unit).to receive(:quantity) { 1 } shipment.stub_chain(:inventory_units, - :joins, - includes: [mock_model(Spree::InventoryUnit, variant: variant)]) - shipment.stock_location = mock_model(Spree::StockLocation) + :group_by, + map: [unit]) + shipment.stock_location = build(:stock_location) shipment.stock_location.should_receive(:restock).with(variant, 1, shipment) shipment.after_cancel end @@ -311,14 +304,16 @@ describe Spree::Shipment do shipment.should_receive(:determine_state).and_return(:ready) shipment.should_receive(:after_resume) shipment.resume! - shipment.state.should eq 'ready' + expect(shipment.state).to eq 'ready' end - it 'unstocks them items' do + it 'unstocks the items' do + unit = create(:inventory_unit, variant: variant) + allow(unit).to receive(:quantity) { 1 } shipment.stub_chain(:inventory_units, - :joins, - includes: [mock_model(Spree::InventoryUnit, variant: variant)]) - shipment.stock_location = mock_model(Spree::StockLocation) + :group_by, + map: [unit]) + shipment.stock_location = create(:stock_location) shipment.stock_location.should_receive(:unstock).with(variant, 1, shipment) shipment.after_resume end @@ -332,7 +327,7 @@ describe Spree::Shipment do shipment.should_receive(:after_resume) shipment.resume! # Shipment is pending because order is already paid - shipment.state.should eq 'pending' + expect(shipment.state).to eq 'pending' end end @@ -348,10 +343,10 @@ describe Spree::Shipment do it "should update shipped_at timestamp" do shipment.stub(:send_shipped_email) shipment.ship! - shipment.shipped_at.should_not be_nil + expect(shipment.shipped_at).to_not be_nil # Ensure value is persisted shipment.reload - shipment.shipped_at.should_not be_nil + expect(shipment.shipped_at).to_not be_nil end it "should send a shipment email" do @@ -370,7 +365,7 @@ describe Spree::Shipment do shipment.stub(:send_shipped_email) shipment.ship! expect(shipment.adjustment.state).to eq 'finalized' - shipment.adjustment.should be_immutable + expect(shipment.adjustment).to be_immutable end end @@ -402,23 +397,27 @@ describe Spree::Shipment do end it "should update originator when adjustment is present" do - shipment.stub(selected_shipping_rate: mock_model(Spree::ShippingRate, cost: 10.00)) - shipment.stub(adjustment: mock_model(Spree::Adjustment, open?: true)) + shipment.stub(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + adjustment = build(:adjustment) + shipment.stub(adjustment: adjustment) + allow(adjustment).to receive(:open?) { true } shipment.adjustment.should_receive(:originator=).with(shipping_method) shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) shipment.adjustment.should_receive(:amount=).with(10.00) - shipment.adjustment.should_receive(:save!) + allow(shipment.adjustment).to receive(:save!) shipment.adjustment.should_receive(:reload) shipment.__send__(:ensure_correct_adjustment) end it 'should not update amount if adjustment is not open?' do - shipment.stub(selected_shipping_rate: mock_model(Spree::ShippingRate, cost: 10.00)) - shipment.stub(adjustment: mock_model(Spree::Adjustment, open?: false)) + shipment.stub(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + adjustment = build(:adjustment) + shipment.stub(adjustment: adjustment) + allow(adjustment).to receive(:open?) { false } shipment.adjustment.should_receive(:originator=).with(shipping_method) shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) shipment.adjustment.should_not_receive(:amount=).with(10.00) - shipment.adjustment.should_receive(:save!) + allow(shipment.adjustment).to receive(:save!) shipment.adjustment.should_receive(:reload) shipment.__send__(:ensure_correct_adjustment) end From 8e116dd58aba5ba8000e896fd312f90df63ca1bf Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 1 Jul 2020 20:55:58 +0100 Subject: [PATCH 137/261] Make ensure_correct_adjustment a public method because we call it in OFN --- app/models/spree/shipment.rb | 38 ++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index bff7421c70..d35c84ca08 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -241,6 +241,25 @@ module Spree inventory_units.create(variant_id: variant.id, state: state, order_id: order.id) end + def ensure_correct_adjustment + if adjustment + adjustment.originator = shipping_method + adjustment.label = shipping_method.adjustment_label + adjustment.amount = selected_shipping_rate.cost if adjustment.open? + adjustment.save! + adjustment.reload + elsif selected_shipping_rate_id + shipping_method.create_adjustment(shipping_method.adjustment_label, + order, + self, + true, + "open") + reload # ensure adjustment is present on later saves + end + + update_adjustment_included_tax if adjustment + end + private def manifest_unstock(item) @@ -285,25 +304,6 @@ module Spree ShipmentMailer.shipped_email(id).deliver end - def ensure_correct_adjustment - if adjustment - adjustment.originator = shipping_method - adjustment.label = shipping_method.adjustment_label - adjustment.amount = selected_shipping_rate.cost if adjustment.open? - adjustment.save! - adjustment.reload - elsif selected_shipping_rate_id - shipping_method.create_adjustment(shipping_method.adjustment_label, - order, - self, - true, - "open") - reload # ensure adjustment is present on later saves - end - - update_adjustment_included_tax if adjustment - end - def update_adjustment_included_tax if Config.shipment_inc_vat && (order.distributor.nil? || order.distributor.charges_sales_tax) adjustment.set_included_tax! Config.shipping_tax_rate From 1b28592f58f096038baf48f9d438369a2d69e5f7 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 14:28:19 +0100 Subject: [PATCH 138/261] Now that the stock code is on out side we can clean up! Remove everything related to splitters (including bringing environment.rb so we remove the splitters variable from it --- app/models/spree/stock/coordinator.rb | 7 +--- app/models/spree/stock/packer.rb | 21 ++--------- config/application.rb | 11 ------ .../order_management/stock/basic_splitter.rb | 29 --------------- .../stock/basic_splitter_spec.rb | 37 ------------------- lib/spree/core/environment.rb | 14 +++++++ spec/config/application_spec.rb | 9 ----- spec/models/spree/order/checkout_spec.rb | 3 -- spec/models/spree/stock/packer_spec.rb | 5 --- 9 files changed, 18 insertions(+), 118 deletions(-) delete mode 100644 engines/order_management/app/services/order_management/stock/basic_splitter.rb delete mode 100644 engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb create mode 100644 lib/spree/core/environment.rb delete mode 100644 spec/config/application_spec.rb diff --git a/app/models/spree/stock/coordinator.rb b/app/models/spree/stock/coordinator.rb index 4b42060bd0..bbbc176956 100644 --- a/app/models/spree/stock/coordinator.rb +++ b/app/models/spree/stock/coordinator.rb @@ -51,12 +51,7 @@ module Spree end def build_packer(stock_location, order) - Packer.new(stock_location, order, splitters(stock_location)) - end - - def splitters(_stock_location) - # extension point to return custom splitters for a location - Rails.application.config.spree.stock_splitters + Packer.new(stock_location, order) end end end diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb index 242f46536e..6fb58531c3 100644 --- a/app/models/spree/stock/packer.rb +++ b/app/models/spree/stock/packer.rb @@ -3,21 +3,16 @@ module Spree module Stock class Packer - attr_reader :stock_location, :order, :splitters, :package_factory + attr_reader :stock_location, :order, :package_factory - def initialize(stock_location, order, splitters = [OrderManagement::Stock::BasicSplitter]) + def initialize(stock_location, order) @stock_location = stock_location @order = order - @splitters = splitters @package_factory = Spree::Config.package_factory end def packages - if splitters.empty? - [default_package] - else - build_splitter.split [default_package] - end + [default_package] end def default_package @@ -35,16 +30,6 @@ module Spree end package end - - private - - def build_splitter - splitter = nil - splitters.reverse.each do |klass| - splitter = klass.new(self, splitter) - end - splitter - end end end end diff --git a/config/application.rb b/config/application.rb index 419638b236..547795ea5f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -76,17 +76,6 @@ module Openfoodnetwork ] end - # Every splitter (except Base splitter) will split the order in multiple packages - # Each package will generate a separate shipment in the order - # Base splitter does not split the packages - # So, because in OFN we have locked orders to have only one shipment, - # we must use this splitter and no other - initializer "spree.register.stock_splitters" do |app| - app.config.spree.stock_splitters = [ - OrderManagement::Stock::BasicSplitter - ] - end - # Register Spree payment methods initializer "spree.gateway.payment_methods", :after => "spree.register.payment_methods" do |app| app.config.spree.payment_methods << Spree::Gateway::Migs diff --git a/engines/order_management/app/services/order_management/stock/basic_splitter.rb b/engines/order_management/app/services/order_management/stock/basic_splitter.rb deleted file mode 100644 index eacbf05704..0000000000 --- a/engines/order_management/app/services/order_management/stock/basic_splitter.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module OrderManagement - module Stock - class BasicSplitter - attr_reader :packer, :next_splitter - - def initialize(packer, next_splitter = nil) - @packer = packer - @next_splitter = next_splitter - end - delegate :stock_location, :order, to: :packer - - def split(packages) - return_next(packages) - end - - private - - def return_next(packages) - next_splitter ? next_splitter.split(packages) : packages - end - - def build_package(contents = []) - @packer.package_factory.new(stock_location, order, contents) - end - end - end -end diff --git a/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb b/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb deleted file mode 100644 index a8265a1d01..0000000000 --- a/engines/order_management/spec/services/order_management/stock/basic_splitter_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -module OrderManagement - module Stock - describe BasicSplitter do - let(:packer) { build(:stock_packer) } - - it 'continues to splitter chain' do - splitter1 = BasicSplitter.new(packer) - splitter2 = BasicSplitter.new(packer, splitter1) - packages = [] - - expect(splitter1).to receive(:split).with(packages) - splitter2.split(packages) - end - - it 'builds package using package factory' do - # Basic extension of Base splitter used to test build_package method - class ::RealSplitter < BasicSplitter - def split(_packages) - build_package - end - end - - # Custom package used to test setting package factory - class ::CustomPackage - def initialize(stock_location, order, splitters); end - end - allow(Spree::Config).to receive(:package_factory) { CustomPackage } - - expect(::RealSplitter.new(packer).split(nil).class).to eq CustomPackage - end - end - end -end diff --git a/lib/spree/core/environment.rb b/lib/spree/core/environment.rb new file mode 100644 index 0000000000..443b110c0a --- /dev/null +++ b/lib/spree/core/environment.rb @@ -0,0 +1,14 @@ +module Spree + module Core + class Environment + include EnvironmentExtension + + attr_accessor :calculators, :payment_methods, :preferences + + def initialize + @calculators = Calculators.new + @preferences = Spree::AppConfiguration.new + end + end + end +end diff --git a/spec/config/application_spec.rb b/spec/config/application_spec.rb deleted file mode 100644 index 40c8d1c302..0000000000 --- a/spec/config/application_spec.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'spec_helper' - -describe Openfoodnetwork::Application, 'configuration' do - let(:config) { described_class.config } - - it "sets OrderManagement::Stock::BasicSplitter as the only stock splitter" do - expect(config.spree.stock_splitters).to eq [OrderManagement::Stock::BasicSplitter] - end -end diff --git a/spec/models/spree/order/checkout_spec.rb b/spec/models/spree/order/checkout_spec.rb index e2a133ebbc..8eed383c6a 100644 --- a/spec/models/spree/order/checkout_spec.rb +++ b/spec/models/spree/order/checkout_spec.rb @@ -42,9 +42,6 @@ describe Spree::Order do it "can progress to delivery" do shipping_method.shipping_categories << other_shipping_category - # If the shipping category package splitter is enabled, - # an order with products with two shipping categories will be split into two shipments - # and the spec will fail with a unique constraint error on index_spree_shipments_on_order_id order.next order.next expect(order.state).to eq "delivery" diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index cd694d87e1..fb20808644 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -20,11 +20,6 @@ module Spree expect(packages.size).to eq 1 expect(packages.first.contents.size).to eq 5 end - - it 'allows users to set splitters to an empty array' do - packages = Packer.new(stock_location, order, []).packages - expect(packages.size).to eq 1 - end end context 'default_package' do From 943cb7bf05d1dc9f90637152e6df466cdb6658c4 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 14:37:00 +0100 Subject: [PATCH 139/261] Move Stock::Package to OrderManagement::Stock::Package --- app/models/stock/package.rb | 45 -------------- config/initializers/spree.rb | 2 +- .../order_management/stock/package.rb | 49 +++++++++++++++ .../order_management/stock/package_spec.rb | 60 +++++++++++++++++++ .../flat_percent_item_total_spec.rb | 2 +- spec/models/stock/package_spec.rb | 58 ------------------ 6 files changed, 111 insertions(+), 105 deletions(-) delete mode 100644 app/models/stock/package.rb create mode 100644 engines/order_management/app/services/order_management/stock/package.rb create mode 100644 engines/order_management/spec/services/order_management/stock/package_spec.rb delete mode 100644 spec/models/stock/package_spec.rb diff --git a/app/models/stock/package.rb b/app/models/stock/package.rb deleted file mode 100644 index eada3741c1..0000000000 --- a/app/models/stock/package.rb +++ /dev/null @@ -1,45 +0,0 @@ -# Extends Spree's Package implementation to skip shipping methods that are not -# valid for OFN. -# -# It requires the following configuration in config/initializers/spree.rb: -# -# Spree.config do |config| -# ... -# config.package_factory = Stock::Package -# end -# -module Stock - class Package < Spree::Stock::Package - # Returns all existing shipping categories. - # It does not filter by the shipping categories of the products in the order. - # It allows checkout of products with categories that are not the shipping methods categories - # It disables the matching of product shipping category with shipping method's category - # - # @return [Array] - def shipping_categories - Spree::ShippingCategory.all - end - - # Skips the methods that are not used by the order's distributor - # - # @return [Array] - def shipping_methods - available_shipping_methods = super.to_a - - available_shipping_methods.keep_if do |shipping_method| - ships_with?(order.distributor.shipping_methods.to_a, shipping_method) - end - end - - private - - # Checks whether the given distributor provides the specified shipping method - # - # @param shipping_methods [Array] - # @param shipping_method [Spree::ShippingMethod] - # @return [Boolean] - def ships_with?(shipping_methods, shipping_method) - shipping_methods.include?(shipping_method) - end - end -end diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index 5aca0161f8..d331a0567f 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -30,7 +30,7 @@ Spree.config do |config| config.auto_capture = true #config.override_actionmailer_config = false - config.package_factory = Stock::Package + config.package_factory = OrderManagement::Stock::Package config.order_updater_decorator = OrderUpdater # S3 settings diff --git a/engines/order_management/app/services/order_management/stock/package.rb b/engines/order_management/app/services/order_management/stock/package.rb new file mode 100644 index 0000000000..6397c6d90e --- /dev/null +++ b/engines/order_management/app/services/order_management/stock/package.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +# Extends Spree's Package implementation to skip shipping methods that are not +# valid for OFN. +# +# It requires the following configuration in config/initializers/spree.rb: +# +# Spree.config do |config| +# ... +# config.package_factory = OrderManagement::Stock::Package +# end +# +module OrderManagement + module Stock + class Package < Spree::Stock::Package + # Returns all existing shipping categories. + # It does not filter by the shipping categories of the products in the order: it allows + # checkout of products with categories that are not the shipping method's categories + # It disables the matching of product shipping category with shipping method's category + # + # @return [Array] + def shipping_categories + Spree::ShippingCategory.all + end + + # Skips the methods that are not used by the order's distributor + # + # @return [Array] + def shipping_methods + available_shipping_methods = super.to_a + + available_shipping_methods.keep_if do |shipping_method| + ships_with?(order.distributor.shipping_methods.to_a, shipping_method) + end + end + + private + + # Checks whether the given distributor provides the specified shipping method + # + # @param shipping_methods [Array] + # @param shipping_method [Spree::ShippingMethod] + # @return [Boolean] + def ships_with?(shipping_methods, shipping_method) + shipping_methods.include?(shipping_method) + end + end + end +end diff --git a/engines/order_management/spec/services/order_management/stock/package_spec.rb b/engines/order_management/spec/services/order_management/stock/package_spec.rb new file mode 100644 index 0000000000..dd06edb775 --- /dev/null +++ b/engines/order_management/spec/services/order_management/stock/package_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +module OrderManagement + module Stock + describe Package do + let(:stock_location) { double(:stock_location) } + + subject(:package) { Package.new(stock_location, order, contents) } + + let(:enterprise) { create(:enterprise) } + let(:other_enterprise) { create(:enterprise) } + + let(:order) { build(:order, distributor: enterprise) } + + let(:variant1) do + instance_double( + Spree::Variant, + shipping_category: shipping_method1.shipping_categories.first + ) + end + let(:variant2) do + instance_double( + Spree::Variant, + shipping_category: shipping_method2.shipping_categories.first + ) + end + let(:variant3) do + instance_double(Spree::Variant, shipping_category: nil) + end + + let(:contents) do + [ + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant2, 1), + Package::ContentItem.new(variant3, 1) + ] + end + + let(:shipping_method1) { create(:shipping_method, distributors: [enterprise]) } + let(:shipping_method2) { create(:shipping_method, distributors: [other_enterprise]) } + + describe '#shipping_methods' do + it 'does not return shipping methods not used by the package\'s order distributor' do + expect(package.shipping_methods).to eq [shipping_method1] + end + end + + describe '#shipping_categories' do + it "returns shipping categories that are not shipping categories of the order's products" do + package + other_shipping_category = Spree::ShippingCategory.create(name: "Custom") + + expect(package.shipping_categories).to eq [shipping_method1.shipping_categories.first, + other_shipping_category] + end + end + end + end +end diff --git a/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/spec/models/spree/calculator/flat_percent_item_total_spec.rb index 529c2b11d9..ec4b54fc70 100644 --- a/spec/models/spree/calculator/flat_percent_item_total_spec.rb +++ b/spec/models/spree/calculator/flat_percent_item_total_spec.rb @@ -14,7 +14,7 @@ describe Spree::Calculator::FlatPercentItemTotal do it_behaves_like "a model using the LocalizedNumber module", [:preferred_flat_percent] end - it "computes amount correctly for a given Stock::Package" do + it "computes amount correctly for a given OrderManagement::Stock::Package" do order = double(:order, line_items: [line_item] ) package = double(:package, order: order) diff --git a/spec/models/stock/package_spec.rb b/spec/models/stock/package_spec.rb deleted file mode 100644 index 6a3ac355cc..0000000000 --- a/spec/models/stock/package_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'spec_helper' - -module Stock - describe Package do - let(:stock_location) { double(:stock_location) } - - subject(:package) { Package.new(stock_location, order, contents) } - - let(:enterprise) { create(:enterprise) } - let(:other_enterprise) { create(:enterprise) } - - let(:order) { build(:order, distributor: enterprise) } - - let(:variant1) do - instance_double( - Spree::Variant, - shipping_category: shipping_method1.shipping_categories.first - ) - end - let(:variant2) do - instance_double( - Spree::Variant, - shipping_category: shipping_method2.shipping_categories.first - ) - end - let(:variant3) do - instance_double(Spree::Variant, shipping_category: nil) - end - - let(:contents) do - [ - Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant2, 1), - Package::ContentItem.new(variant3, 1) - ] - end - - let(:shipping_method1) { create(:shipping_method, distributors: [enterprise]) } - let(:shipping_method2) { create(:shipping_method, distributors: [other_enterprise]) } - - describe '#shipping_methods' do - it 'does not return shipping methods not used by the package\'s order distributor' do - expect(package.shipping_methods).to eq [shipping_method1] - end - end - - describe '#shipping_categories' do - it "returns shipping categories that are not shipping categories of the order's products" do - package - other_shipping_category = Spree::ShippingCategory.create(name: "Custom") - - expect(package.shipping_categories).to eq [shipping_method1.shipping_categories.first, - other_shipping_category] - end - end - end -end From f0b3ed0d79973279174d3ce61e8be8ded4842f08 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 14:47:01 +0100 Subject: [PATCH 140/261] Merge Spree::Stock::Package into OrderManagement::Stock::Package --- .../spree/app_configuration_decorator.rb | 4 + app/models/spree/stock/package.rb | 118 ----------- config/initializers/spree.rb | 1 - .../order_management/stock/package.rb | 120 +++++++++-- .../order_management/stock/package_spec.rb | 191 ++++++++++++++---- spec/models/spree/stock/package_spec.rb | 115 ----------- spec/models/spree/stock/packer_spec.rb | 13 -- 7 files changed, 262 insertions(+), 300 deletions(-) delete mode 100644 app/models/spree/stock/package.rb delete mode 100644 spec/models/spree/stock/package_spec.rb diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index a039ddbd45..4a2be00f6e 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -41,4 +41,8 @@ Spree::AppConfiguration.class_eval do # Enable cache preference :enable_products_cache?, :boolean, default: (Rails.env.production? || Rails.env.staging?) + + def package_factory + @package_factory ||= OrderManagement::Stock::Package + end end diff --git a/app/models/spree/stock/package.rb b/app/models/spree/stock/package.rb deleted file mode 100644 index e724b3efa1..0000000000 --- a/app/models/spree/stock/package.rb +++ /dev/null @@ -1,118 +0,0 @@ -# frozen_string_literal: true - -module Spree - module Stock - class Package - ContentItem = Struct.new(:variant, :quantity, :state) - - attr_reader :stock_location, :order, :contents - attr_accessor :shipping_rates - - def initialize(stock_location, order, contents = []) - @stock_location = stock_location - @order = order - @contents = contents - @shipping_rates = [] - end - - def add(variant, quantity, state = :on_hand) - contents << ContentItem.new(variant, quantity, state) - end - - def weight - contents.sum { |item| item.variant.weight * item.quantity } - end - - def on_hand - contents.select { |item| item.state == :on_hand } - end - - def backordered - contents.select { |item| item.state == :backordered } - end - - def find_item(variant, state = :on_hand) - contents.select do |item| - item.variant == variant && - item.state == state - end.first - end - - def quantity(state = nil) - case state - when :on_hand - on_hand.sum(&:quantity) - when :backordered - backordered.sum(&:quantity) - else - contents.sum(&:quantity) - end - end - - def empty? - quantity.zero? - end - - def flattened - flat = [] - contents.each do |item| - item.quantity.times do - flat << ContentItem.new(item.variant, 1, item.state) - end - end - flat - end - - def flattened=(flattened) - contents.clear - flattened.each do |item| - current_item = find_item(item.variant, item.state) - if current_item - current_item.quantity += 1 - else - add(item.variant, item.quantity, item.state) - end - end - end - - def currency - # TODO calculate from first variant? - end - - def shipping_categories - contents.map { |item| item.variant.shipping_category }.compact.uniq - end - - def shipping_methods - shipping_categories.map(&:shipping_methods).flatten.uniq - end - - def inspect - out = "#{order} - " - out << contents.map do |content_item| - "#{content_item.variant.name} #{content_item.quantity} #{content_item.state}" - end.join('/') - out - end - - def to_shipment - shipment = Spree::Shipment.new - shipment.order = order - shipment.stock_location = stock_location - shipment.shipping_rates = shipping_rates - - contents.each do |item| - item.quantity.times do - unit = shipment.inventory_units.build - unit.pending = true - unit.order = order - unit.variant = item.variant - unit.state = item.state.to_s - end - end - - shipment - end - end - end -end diff --git a/config/initializers/spree.rb b/config/initializers/spree.rb index d331a0567f..6ff230c5f5 100644 --- a/config/initializers/spree.rb +++ b/config/initializers/spree.rb @@ -30,7 +30,6 @@ Spree.config do |config| config.auto_capture = true #config.override_actionmailer_config = false - config.package_factory = OrderManagement::Stock::Package config.order_updater_decorator = OrderUpdater # S3 settings diff --git a/engines/order_management/app/services/order_management/stock/package.rb b/engines/order_management/app/services/order_management/stock/package.rb index 6397c6d90e..3009d0b19c 100644 --- a/engines/order_management/app/services/order_management/stock/package.rb +++ b/engines/order_management/app/services/order_management/stock/package.rb @@ -1,22 +1,87 @@ # frozen_string_literal: true -# Extends Spree's Package implementation to skip shipping methods that are not -# valid for OFN. -# -# It requires the following configuration in config/initializers/spree.rb: -# -# Spree.config do |config| -# ... -# config.package_factory = OrderManagement::Stock::Package -# end -# module OrderManagement module Stock - class Package < Spree::Stock::Package + class Package + ContentItem = Struct.new(:variant, :quantity, :state) + + attr_reader :stock_location, :order, :contents + attr_accessor :shipping_rates + + def initialize(stock_location, order, contents = []) + @stock_location = stock_location + @order = order + @contents = contents + @shipping_rates = [] + end + + def add(variant, quantity, state = :on_hand) + contents << ContentItem.new(variant, quantity, state) + end + + def weight + contents.sum { |item| item.variant.weight * item.quantity } + end + + def on_hand + contents.select { |item| item.state == :on_hand } + end + + def backordered + contents.select { |item| item.state == :backordered } + end + + def find_item(variant, state = :on_hand) + contents.select do |item| + item.variant == variant && + item.state == state + end.first + end + + def quantity(state = nil) + case state + when :on_hand + on_hand.sum(&:quantity) + when :backordered + backordered.sum(&:quantity) + else + contents.sum(&:quantity) + end + end + + def empty? + quantity.zero? + end + + def flattened + flat = [] + contents.each do |item| + item.quantity.times do + flat << ContentItem.new(item.variant, 1, item.state) + end + end + flat + end + + def flattened=(flattened) + contents.clear + flattened.each do |item| + current_item = find_item(item.variant, item.state) + if current_item + current_item.quantity += 1 + else + add(item.variant, item.quantity, item.state) + end + end + end + + def currency + # TODO calculate from first variant? + end + # Returns all existing shipping categories. - # It does not filter by the shipping categories of the products in the order: it allows - # checkout of products with categories that are not the shipping method's categories # It disables the matching of product shipping category with shipping method's category + # It allows checkout of products with categories that are not the ship method's categories # # @return [Array] def shipping_categories @@ -27,13 +92,40 @@ module OrderManagement # # @return [Array] def shipping_methods - available_shipping_methods = super.to_a + available_shipping_methods = shipping_categories.map(&:shipping_methods).flatten.uniq.to_a available_shipping_methods.keep_if do |shipping_method| ships_with?(order.distributor.shipping_methods.to_a, shipping_method) end end + def inspect + out = "#{order} - " + out << contents.map do |content_item| + "#{content_item.variant.name} #{content_item.quantity} #{content_item.state}" + end.join('/') + out + end + + def to_shipment + shipment = Spree::Shipment.new + shipment.order = order + shipment.stock_location = stock_location + shipment.shipping_rates = shipping_rates + + contents.each do |item| + item.quantity.times do + unit = shipment.inventory_units.build + unit.pending = true + unit.order = order + unit.variant = item.variant + unit.state = item.state.to_s + end + end + + shipment + end + private # Checks whether the given distributor provides the specified shipping method diff --git a/engines/order_management/spec/services/order_management/stock/package_spec.rb b/engines/order_management/spec/services/order_management/stock/package_spec.rb index dd06edb775..205d50ae1a 100644 --- a/engines/order_management/spec/services/order_management/stock/package_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/package_spec.rb @@ -1,58 +1,171 @@ +# frozen_string_literal: true + require 'spec_helper' module OrderManagement module Stock describe Package do - let(:stock_location) { double(:stock_location) } + context "base tests" do + let(:variant) { build(:variant, weight: 25.0) } + let(:stock_location) { build(:stock_location) } + let(:distributor) { create(:enterprise) } + let(:order) { build(:order, distributor: distributor) } - subject(:package) { Package.new(stock_location, order, contents) } + subject { Package.new(stock_location, order) } - let(:enterprise) { create(:enterprise) } - let(:other_enterprise) { create(:enterprise) } + it 'calculates the weight of all the contents' do + subject.add variant, 4 + expect(subject.weight).to eq 100.0 + end - let(:order) { build(:order, distributor: enterprise) } + it 'filters by on_hand and backordered' do + subject.add variant, 4, :on_hand + subject.add variant, 3, :backordered + expect(subject.on_hand.count).to eq 1 + expect(subject.backordered.count).to eq 1 + end - let(:variant1) do - instance_double( - Spree::Variant, - shipping_category: shipping_method1.shipping_categories.first - ) - end - let(:variant2) do - instance_double( - Spree::Variant, - shipping_category: shipping_method2.shipping_categories.first - ) - end - let(:variant3) do - instance_double(Spree::Variant, shipping_category: nil) - end + it 'calculates the quantity by state' do + subject.add variant, 4, :on_hand + subject.add variant, 3, :backordered - let(:contents) do - [ - Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant2, 1), - Package::ContentItem.new(variant3, 1) - ] - end + expect(subject.quantity).to eq 7 + expect(subject.quantity(:on_hand)).to eq 4 + expect(subject.quantity(:backordered)).to eq 3 + end - let(:shipping_method1) { create(:shipping_method, distributors: [enterprise]) } - let(:shipping_method2) { create(:shipping_method, distributors: [other_enterprise]) } + it 'returns nil for content item not found' do + item = subject.find_item(variant, :on_hand) + expect(item).to be_nil + end - describe '#shipping_methods' do - it 'does not return shipping methods not used by the package\'s order distributor' do - expect(package.shipping_methods).to eq [shipping_method1] + it 'finds content item for a variant' do + subject.add variant, 4, :on_hand + item = subject.find_item(variant, :on_hand) + expect(item.quantity).to eq 4 + end + + it 'get flattened contents' do + subject.add variant, 4, :on_hand + subject.add variant, 2, :backordered + flattened = subject.flattened + expect(flattened.select { |i| i.state == :on_hand }.size).to eq 4 + expect(flattened.select { |i| i.state == :backordered }.size).to eq 2 + end + + it 'set contents from flattened' do + flattened = [Package::ContentItem.new(variant, 1, :on_hand), + Package::ContentItem.new(variant, 1, :on_hand), + Package::ContentItem.new(variant, 1, :backordered), + Package::ContentItem.new(variant, 1, :backordered)] + + subject.flattened = flattened + expect(subject.on_hand.size).to eq 1 + expect(subject.on_hand.first.quantity).to eq 2 + + expect(subject.backordered.size).to eq 1 + end + + # Contains regression test for #2804 + it 'builds a list of shipping methods from all categories' do + shipping_method1 = create(:shipping_method, distributors: [distributor]) + shipping_method2 = create(:shipping_method, distributors: [distributor]) + variant1 = create(:variant, + shipping_category: shipping_method1.shipping_categories.first) + variant2 = create(:variant, + shipping_category: shipping_method2.shipping_categories.first) + variant3 = create(:variant, shipping_category: nil) + contents = [Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant2, 1), + Package::ContentItem.new(variant3, 1)] + + package = Package.new(stock_location, order, contents) + expect(package.shipping_methods.size).to eq 2 + end + + it "can convert to a shipment" do + flattened = [Package::ContentItem.new(variant, 2, :on_hand), + Package::ContentItem.new(variant, 1, :backordered)] + subject.flattened = flattened + + shipping_method = build(:shipping_method) + subject.shipping_rates = [ + Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) + ] + + shipment = subject.to_shipment + expect(shipment.order).to eq subject.order + expect(shipment.stock_location).to eq subject.stock_location + expect(shipment.inventory_units.size).to eq 3 + + first_unit = shipment.inventory_units.first + expect(first_unit.variant).to eq variant + expect(first_unit.state).to eq 'on_hand' + expect(first_unit.order).to eq subject.order + expect(first_unit).to be_pending + + last_unit = shipment.inventory_units.last + expect(last_unit.variant).to eq variant + expect(last_unit.state).to eq 'backordered' + expect(last_unit.order).to eq subject.order + + expect(shipment.shipping_method).to eq shipping_method end end - describe '#shipping_categories' do - it "returns shipping categories that are not shipping categories of the order's products" do - package - other_shipping_category = Spree::ShippingCategory.create(name: "Custom") + context "#shipping_methods and #shipping_categories" do + let(:stock_location) { double(:stock_location) } - expect(package.shipping_categories).to eq [shipping_method1.shipping_categories.first, - other_shipping_category] + subject(:package) { Package.new(stock_location, order, contents) } + + let(:enterprise) { create(:enterprise) } + let(:other_enterprise) { create(:enterprise) } + + let(:order) { build(:order, distributor: enterprise) } + + let(:variant1) do + instance_double( + Spree::Variant, + shipping_category: shipping_method1.shipping_categories.first + ) + end + let(:variant2) do + instance_double( + Spree::Variant, + shipping_category: shipping_method2.shipping_categories.first + ) + end + let(:variant3) do + instance_double(Spree::Variant, shipping_category: nil) + end + + let(:contents) do + [ + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant1, 1), + Package::ContentItem.new(variant2, 1), + Package::ContentItem.new(variant3, 1) + ] + end + + let(:shipping_method1) { create(:shipping_method, distributors: [enterprise]) } + let(:shipping_method2) { create(:shipping_method, distributors: [other_enterprise]) } + + describe '#shipping_methods' do + it 'does not return shipping methods not used by the package\'s order distributor' do + expect(package.shipping_methods).to eq [shipping_method1] + end + end + + describe '#shipping_categories' do + it "returns ship categories that are not the ship categories of the order's products" do + package + other_shipping_category = Spree::ShippingCategory.create(name: "Custom") + + expect(package.shipping_categories).to eq [shipping_method1.shipping_categories.first, + other_shipping_category] + end end end end diff --git a/spec/models/spree/stock/package_spec.rb b/spec/models/spree/stock/package_spec.rb deleted file mode 100644 index 6b27b405ac..0000000000 --- a/spec/models/spree/stock/package_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -module Spree - module Stock - describe Package do - let(:variant) { build(:variant, weight: 25.0) } - let(:stock_location) { build(:stock_location) } - let(:order) { build(:order) } - - subject { Package.new(stock_location, order) } - - it 'calculates the weight of all the contents' do - subject.add variant, 4 - expect(subject.weight).to eq 100.0 - end - - it 'filters by on_hand and backordered' do - subject.add variant, 4, :on_hand - subject.add variant, 3, :backordered - expect(subject.on_hand.count).to eq 1 - expect(subject.backordered.count).to eq 1 - end - - it 'calculates the quantity by state' do - subject.add variant, 4, :on_hand - subject.add variant, 3, :backordered - - expect(subject.quantity).to eq 7 - expect(subject.quantity(:on_hand)).to eq 4 - expect(subject.quantity(:backordered)).to eq 3 - end - - it 'returns nil for content item not found' do - item = subject.find_item(variant, :on_hand) - expect(item).to be_nil - end - - it 'finds content item for a variant' do - subject.add variant, 4, :on_hand - item = subject.find_item(variant, :on_hand) - expect(item.quantity).to eq 4 - end - - it 'get flattened contents' do - subject.add variant, 4, :on_hand - subject.add variant, 2, :backordered - flattened = subject.flattened - expect(flattened.select { |i| i.state == :on_hand }.size).to eq 4 - expect(flattened.select { |i| i.state == :backordered }.size).to eq 2 - end - - it 'set contents from flattened' do - flattened = [Package::ContentItem.new(variant, 1, :on_hand), - Package::ContentItem.new(variant, 1, :on_hand), - Package::ContentItem.new(variant, 1, :backordered), - Package::ContentItem.new(variant, 1, :backordered)] - - subject.flattened = flattened - expect(subject.on_hand.size).to eq 1 - expect(subject.on_hand.first.quantity).to eq 2 - - expect(subject.backordered.size).to eq 1 - end - - # Contains regression test for #2804 - it 'builds a list of shipping methods from all categories' do - shipping_method1 = create(:shipping_method) - shipping_method2 = create(:shipping_method) - variant1 = create(:variant, - shipping_category: shipping_method1.shipping_categories.first) - variant2 = create(:variant, - shipping_category: shipping_method2.shipping_categories.first) - variant3 = create(:variant, shipping_category: nil) - contents = [Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant1, 1), - Package::ContentItem.new(variant2, 1), - Package::ContentItem.new(variant3, 1)] - - package = Package.new(stock_location, order, contents) - expect(package.shipping_methods.size).to eq 2 - end - - it "can convert to a shipment" do - flattened = [Package::ContentItem.new(variant, 2, :on_hand), - Package::ContentItem.new(variant, 1, :backordered)] - subject.flattened = flattened - - shipping_method = build(:shipping_method) - subject.shipping_rates = [ - Spree::ShippingRate.new(shipping_method: shipping_method, cost: 10.00, selected: true) - ] - - shipment = subject.to_shipment - expect(shipment.order).to eq subject.order - expect(shipment.stock_location).to eq subject.stock_location - expect(shipment.inventory_units.size).to eq 3 - - first_unit = shipment.inventory_units.first - expect(first_unit.variant).to eq variant - expect(first_unit.state).to eq 'on_hand' - expect(first_unit.order).to eq subject.order - expect(first_unit).to be_pending - - last_unit = shipment.inventory_units.last - expect(last_unit.variant).to eq variant - expect(last_unit.state).to eq 'backordered' - expect(last_unit.order).to eq subject.order - - expect(shipment.shipping_method).to eq shipping_method - end - end - end -end diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index fb20808644..c5bdefd489 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -39,19 +39,6 @@ module Spree expect(package.backordered.size).to eq 5 end - context 'when a packer factory is not specified' do - let(:package) { double(:package, add: true) } - - it 'calls Spree::Stock::Package' do - expect(Package) - .to receive(:new) - .with(stock_location, order) - .and_return(package) - - subject.default_package - end - end - context 'when a packer factory is specified' do before do allow(Spree::Config).to receive(:package_factory) { TestPackageFactory } From b487185a65a7b36276343f3f6ab0d23c6602dcb4 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 15:37:40 +0100 Subject: [PATCH 141/261] Remove package factory, it is no longer needed, we can just call the Package class in the two places where it is used --- .../spree/app_configuration_decorator.rb | 4 ---- app/models/spree/shipment.rb | 2 +- app/models/spree/stock/packer.rb | 5 ++-- spec/models/spree/stock/packer_spec.rb | 23 ------------------- 4 files changed, 3 insertions(+), 31 deletions(-) diff --git a/app/models/spree/app_configuration_decorator.rb b/app/models/spree/app_configuration_decorator.rb index 4a2be00f6e..a039ddbd45 100644 --- a/app/models/spree/app_configuration_decorator.rb +++ b/app/models/spree/app_configuration_decorator.rb @@ -41,8 +41,4 @@ Spree::AppConfiguration.class_eval do # Enable cache preference :enable_products_cache?, :boolean, default: (Rails.env.production? || Rails.env.staging?) - - def package_factory - @package_factory ||= OrderManagement::Stock::Package - end end diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index d35c84ca08..f271af3c8f 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -230,7 +230,7 @@ module Spree end def to_package - package = Spree::Config.package_factory.new(stock_location, order) + package = OrderManagement::Stock::Package.new(stock_location, order) inventory_units.includes(:variant).each do |inventory_unit| package.add inventory_unit.variant, 1, inventory_unit.state_name end diff --git a/app/models/spree/stock/packer.rb b/app/models/spree/stock/packer.rb index 6fb58531c3..a936d24c14 100644 --- a/app/models/spree/stock/packer.rb +++ b/app/models/spree/stock/packer.rb @@ -3,12 +3,11 @@ module Spree module Stock class Packer - attr_reader :stock_location, :order, :package_factory + attr_reader :stock_location, :order def initialize(stock_location, order) @stock_location = stock_location @order = order - @package_factory = Spree::Config.package_factory end def packages @@ -16,7 +15,7 @@ module Spree end def default_package - package = package_factory.new(stock_location, order) + package = OrderManagement::Stock::Package.new(stock_location, order) order.line_items.each do |line_item| if Config.track_inventory_levels next unless stock_location.stock_item(line_item.variant) diff --git a/spec/models/spree/stock/packer_spec.rb b/spec/models/spree/stock/packer_spec.rb index c5bdefd489..ab5da00dd4 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/spec/models/spree/stock/packer_spec.rb @@ -10,10 +10,6 @@ module Spree subject { Packer.new(stock_location, order) } - before do - allow(Spree::Config).to receive(:package_factory) { Package } - end - context 'packages' do it 'builds an array of packages' do packages = subject.packages @@ -38,25 +34,6 @@ module Spree expect(package.on_hand.size).to eq 5 expect(package.backordered.size).to eq 5 end - - context 'when a packer factory is specified' do - before do - allow(Spree::Config).to receive(:package_factory) { TestPackageFactory } - end - - class TestPackageFactory; end - - let(:package) { double(:package, add: true) } - - it 'calls the specified factory' do - expect(TestPackageFactory) - .to receive(:new) - .with(stock_location, order) - .and_return(package) - - subject.default_package - end - end end end end From 01b1abbd5283d3a0e2456561f3870b1d01fce5ee Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 15:42:01 +0100 Subject: [PATCH 142/261] Bring method from Spree::Order so that we can move Coordiantor to the order management engine --- app/models/spree/order_decorator.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index a36d8e1312..f45e3340a0 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -89,6 +89,18 @@ Spree::Order.class_eval do where("state != ?", state) } + def create_proposed_shipments + adjustments.shipping.delete_all + shipments.destroy_all + + packages = Spree::Stock::Coordinator.new(self).packages + packages.each do |package| + shipments << package.to_shipment + end + + shipments + end + # -- Methods def products_available_from_new_distribution # Check that the line_items in the current order are available from a newly selected distribution From 83974a832c47ffe93e04a845532d0c68769d071e Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 15:44:33 +0100 Subject: [PATCH 143/261] Move Coordinator from Spree::Stock to OrderManagement::Stock --- app/models/spree/order_decorator.rb | 2 +- .../services/order_management}/stock/coordinator.rb | 10 +++++----- .../order_management}/stock/coordinator_spec.rb | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename {app/models/spree => engines/order_management/app/services/order_management}/stock/coordinator.rb (84%) rename {spec/models/spree => engines/order_management/spec/services/order_management}/stock/coordinator_spec.rb (96%) diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index f45e3340a0..71574359a7 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -93,7 +93,7 @@ Spree::Order.class_eval do adjustments.shipping.delete_all shipments.destroy_all - packages = Spree::Stock::Coordinator.new(self).packages + packages = OrderManagement::Stock::Coordinator.new(self).packages packages.each do |package| shipments << package.to_shipment end diff --git a/app/models/spree/stock/coordinator.rb b/engines/order_management/app/services/order_management/stock/coordinator.rb similarity index 84% rename from app/models/spree/stock/coordinator.rb rename to engines/order_management/app/services/order_management/stock/coordinator.rb index bbbc176956..84cea7d9cf 100644 --- a/app/models/spree/stock/coordinator.rb +++ b/engines/order_management/app/services/order_management/stock/coordinator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Spree +module OrderManagement module Stock class Coordinator attr_reader :order @@ -25,7 +25,7 @@ module Spree # # Returns an array of Package instances def build_packages(packages = []) - StockLocation.active.each do |stock_location| + Spree::StockLocation.active.each do |stock_location| next unless stock_location.stock_items. where(variant_id: order.line_items.pluck(:variant_id)).exists? @@ -38,12 +38,12 @@ module Spree private def prioritize_packages(packages) - prioritizer = Prioritizer.new(order, packages) + prioritizer = Spree::Stock::Prioritizer.new(order, packages) prioritizer.prioritized_packages end def estimate_packages(packages) - estimator = Estimator.new(order) + estimator = Spree::Stock::Estimator.new(order) packages.each do |package| package.shipping_rates = estimator.shipping_rates(package) end @@ -51,7 +51,7 @@ module Spree end def build_packer(stock_location, order) - Packer.new(stock_location, order) + Spree::Stock::Packer.new(stock_location, order) end end end diff --git a/spec/models/spree/stock/coordinator_spec.rb b/engines/order_management/spec/services/order_management/stock/coordinator_spec.rb similarity index 96% rename from spec/models/spree/stock/coordinator_spec.rb rename to engines/order_management/spec/services/order_management/stock/coordinator_spec.rb index 63f81e96ce..c2ab44e5f7 100644 --- a/spec/models/spree/stock/coordinator_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/coordinator_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -module Spree +module OrderManagement module Stock describe Coordinator do let!(:order) { create(:order_with_line_items, distributor: create(:distributor_enterprise)) } From ee66e37521f6f7fe2d72f9a983f6bcb55e762a7f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:20:04 +0100 Subject: [PATCH 144/261] Move adjuster, estimator, packer and prioritizer to order management engine --- app/models/spree/shipment.rb | 2 +- .../app/services/order_management}/stock/adjuster.rb | 2 +- .../services/order_management/stock/coordinator.rb | 6 +++--- .../services/order_management}/stock/estimator.rb | 2 +- .../app/services/order_management}/stock/packer.rb | 4 ++-- .../services/order_management}/stock/prioritizer.rb | 4 ++-- .../order_management}/stock/estimator_spec.rb | 12 ++++++------ .../services/order_management}/stock/packer_spec.rb | 2 +- .../order_management}/stock/prioritizer_spec.rb | 2 +- spec/models/spree/shipment_spec.rb | 6 +++--- 10 files changed, 21 insertions(+), 21 deletions(-) rename {app/models/spree => engines/order_management/app/services/order_management}/stock/adjuster.rb (96%) rename {app/models/spree => engines/order_management/app/services/order_management}/stock/estimator.rb (98%) rename {app/models/spree => engines/order_management/app/services/order_management}/stock/packer.rb (92%) rename {app/models/spree => engines/order_management/app/services/order_management}/stock/prioritizer.rb (90%) rename {spec/models/spree => engines/order_management/spec/services/order_management}/stock/estimator_spec.rb (89%) rename {spec/models/spree => engines/order_management/spec/services/order_management}/stock/packer_spec.rb (98%) rename {spec/models/spree => engines/order_management/spec/services/order_management}/stock/prioritizer_spec.rb (99%) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index f271af3c8f..68002d6ee2 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -107,7 +107,7 @@ module Spree def refresh_rates return shipping_rates if shipped? - self.shipping_rates = Stock::Estimator.new(order).shipping_rates(to_package) + self.shipping_rates = OrderManagement::Stock::Estimator.new(order).shipping_rates(to_package) if shipping_method selected_rate = shipping_rates.detect { |rate| diff --git a/app/models/spree/stock/adjuster.rb b/engines/order_management/app/services/order_management/stock/adjuster.rb similarity index 96% rename from app/models/spree/stock/adjuster.rb rename to engines/order_management/app/services/order_management/stock/adjuster.rb index 4926e8a7e6..ed1337a16a 100644 --- a/app/models/spree/stock/adjuster.rb +++ b/engines/order_management/app/services/order_management/stock/adjuster.rb @@ -2,7 +2,7 @@ # Used by Prioritizer to adjust item quantities # see prioritizer_spec for use cases -module Spree +module OrderManagement module Stock class Adjuster attr_accessor :variant, :need, :status diff --git a/engines/order_management/app/services/order_management/stock/coordinator.rb b/engines/order_management/app/services/order_management/stock/coordinator.rb index 84cea7d9cf..215a82ffe3 100644 --- a/engines/order_management/app/services/order_management/stock/coordinator.rb +++ b/engines/order_management/app/services/order_management/stock/coordinator.rb @@ -38,12 +38,12 @@ module OrderManagement private def prioritize_packages(packages) - prioritizer = Spree::Stock::Prioritizer.new(order, packages) + prioritizer = OrderManagement::Stock::Prioritizer.new(order, packages) prioritizer.prioritized_packages end def estimate_packages(packages) - estimator = Spree::Stock::Estimator.new(order) + estimator = OrderManagement::Stock::Estimator.new(order) packages.each do |package| package.shipping_rates = estimator.shipping_rates(package) end @@ -51,7 +51,7 @@ module OrderManagement end def build_packer(stock_location, order) - Spree::Stock::Packer.new(stock_location, order) + OrderManagement::Stock::Packer.new(stock_location, order) end end end diff --git a/app/models/spree/stock/estimator.rb b/engines/order_management/app/services/order_management/stock/estimator.rb similarity index 98% rename from app/models/spree/stock/estimator.rb rename to engines/order_management/app/services/order_management/stock/estimator.rb index 9f14033590..c97d9c3b99 100644 --- a/app/models/spree/stock/estimator.rb +++ b/engines/order_management/app/services/order_management/stock/estimator.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Spree +module OrderManagement module Stock class Estimator attr_reader :order, :currency diff --git a/app/models/spree/stock/packer.rb b/engines/order_management/app/services/order_management/stock/packer.rb similarity index 92% rename from app/models/spree/stock/packer.rb rename to engines/order_management/app/services/order_management/stock/packer.rb index a936d24c14..867e8889dd 100644 --- a/app/models/spree/stock/packer.rb +++ b/engines/order_management/app/services/order_management/stock/packer.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -module Spree +module OrderManagement module Stock class Packer attr_reader :stock_location, :order @@ -17,7 +17,7 @@ module Spree def default_package package = OrderManagement::Stock::Package.new(stock_location, order) order.line_items.each do |line_item| - if Config.track_inventory_levels + if Spree::Config.track_inventory_levels next unless stock_location.stock_item(line_item.variant) on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) diff --git a/app/models/spree/stock/prioritizer.rb b/engines/order_management/app/services/order_management/stock/prioritizer.rb similarity index 90% rename from app/models/spree/stock/prioritizer.rb rename to engines/order_management/app/services/order_management/stock/prioritizer.rb index 41ef339702..16b992333f 100644 --- a/app/models/spree/stock/prioritizer.rb +++ b/engines/order_management/app/services/order_management/stock/prioritizer.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -module Spree +module OrderManagement module Stock class Prioritizer attr_reader :packages, :order - def initialize(order, packages, adjuster_class = Adjuster) + def initialize(order, packages, adjuster_class = OrderManagement::Stock::Adjuster) @order = order @packages = packages @adjuster_class = adjuster_class diff --git a/spec/models/spree/stock/estimator_spec.rb b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb similarity index 89% rename from spec/models/spree/stock/estimator_spec.rb rename to engines/order_management/spec/services/order_management/stock/estimator_spec.rb index 6cdf8106b2..74215b031c 100644 --- a/spec/models/spree/stock/estimator_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -module Spree +module OrderManagement module Stock describe Estimator do let!(:shipping_method) { create(:shipping_method, zones: [Spree::Zone.global] ) } @@ -13,11 +13,11 @@ module Spree context "#shipping rates" do before(:each) do shipping_method.zones.first.members.create(zoneable: order.ship_address.country) - allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(true) - allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :compute).and_return(4.00) - allow_any_instance_of(ShippingMethod). + allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(true) + allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :compute).and_return(4.00) + allow_any_instance_of(Spree::ShippingMethod). to receive_message_chain(:calculator, :preferences).and_return({ currency: order.currency }) - allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :marked_for_destruction?) + allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :marked_for_destruction?) allow(package).to receive_messages(shipping_methods: [shipping_method]) end @@ -39,7 +39,7 @@ module Spree context "the calculator is not available for that order" do it "does not return shipping rates from a shipping method" do - allow_any_instance_of(ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(false) + allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(false) shipping_rates = subject.shipping_rates(package) expect(shipping_rates).to eq [] end diff --git a/spec/models/spree/stock/packer_spec.rb b/engines/order_management/spec/services/order_management/stock/packer_spec.rb similarity index 98% rename from spec/models/spree/stock/packer_spec.rb rename to engines/order_management/spec/services/order_management/stock/packer_spec.rb index ab5da00dd4..f1e2b432bf 100644 --- a/spec/models/spree/stock/packer_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/packer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -module Spree +module OrderManagement module Stock describe Packer do let(:order) { create(:order_with_line_items, line_items_count: 5) } diff --git a/spec/models/spree/stock/prioritizer_spec.rb b/engines/order_management/spec/services/order_management/stock/prioritizer_spec.rb similarity index 99% rename from spec/models/spree/stock/prioritizer_spec.rb rename to engines/order_management/spec/services/order_management/stock/prioritizer_spec.rb index 4715da1ab8..b1783eb734 100644 --- a/spec/models/spree/stock/prioritizer_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/prioritizer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -module Spree +module OrderManagement module Stock describe Prioritizer do let(:order) { create(:order_with_line_items, line_items_count: 2) } diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index e3b7ef9671..457df53a6d 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -125,7 +125,7 @@ describe Spree::Shipment do let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) } it 'should request new rates, and maintain shipping_method selection' do - Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) + OrderManagement::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) shipment.stub(shipping_method: shipping_method2) expect(shipment.refresh_rates).to eq shipping_rates @@ -133,14 +133,14 @@ describe Spree::Shipment do end it 'should handle no shipping_method selection' do - Spree::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) + OrderManagement::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) shipment.stub(shipping_method: nil) expect(shipment.refresh_rates).to eq shipping_rates expect(shipment.reload.selected_shipping_rate).to_not be_nil end it 'should not refresh if shipment is shipped' do - Spree::Stock::Estimator.should_not_receive(:new) + OrderManagement::Stock::Estimator.should_not_receive(:new) shipment.shipping_rates.delete_all shipment.stub(shipped?: true) expect(shipment.refresh_rates).to eq [] From ee937988e8a72ed0ba0b6889e4535ce35a4efc7d Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:24:00 +0100 Subject: [PATCH 145/261] Fix easy rubocop issues --- .../order_management/stock/estimator_spec.rb | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/engines/order_management/spec/services/order_management/stock/estimator_spec.rb b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb index 74215b031c..892b7e1cf2 100644 --- a/engines/order_management/spec/services/order_management/stock/estimator_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb @@ -13,11 +13,15 @@ module OrderManagement context "#shipping rates" do before(:each) do shipping_method.zones.first.members.create(zoneable: order.ship_address.country) - allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(true) - allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :compute).and_return(4.00) allow_any_instance_of(Spree::ShippingMethod). - to receive_message_chain(:calculator, :preferences).and_return({ currency: order.currency }) - allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :marked_for_destruction?) + to receive_message_chain(:calculator, :available?).and_return(true) + allow_any_instance_of(Spree::ShippingMethod). + to receive_message_chain(:calculator, :compute).and_return(4.00) + allow_any_instance_of(Spree::ShippingMethod). + to receive_message_chain(:calculator, :preferences). + and_return({ currency: order.currency }) + allow_any_instance_of(Spree::ShippingMethod). + to receive_message_chain(:calculator, :marked_for_destruction?) allow(package).to receive_messages(shipping_methods: [shipping_method]) end @@ -39,7 +43,8 @@ module OrderManagement context "the calculator is not available for that order" do it "does not return shipping rates from a shipping method" do - allow_any_instance_of(Spree::ShippingMethod).to receive_message_chain(:calculator, :available?).and_return(false) + allow_any_instance_of(Spree::ShippingMethod). + to receive_message_chain(:calculator, :available?).and_return(false) shipping_rates = subject.shipping_rates(package) expect(shipping_rates).to eq [] end @@ -62,9 +67,12 @@ module OrderManagement it "sorts shipping rates by cost" do shipping_methods = 3.times.map { create(:shipping_method) } - allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00) - allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00) - allow(shipping_methods[2]).to receive_message_chain(:calculator, :compute).and_return(4.00) + allow(shipping_methods[0]). + to receive_message_chain(:calculator, :compute).and_return(5.00) + allow(shipping_methods[1]). + to receive_message_chain(:calculator, :compute).and_return(3.00) + allow(shipping_methods[2]). + to receive_message_chain(:calculator, :compute).and_return(4.00) allow(subject).to receive(:shipping_methods).and_return(shipping_methods) @@ -76,8 +84,10 @@ module OrderManagement let(:shipping_methods) { 2.times.map { create(:shipping_method) } } it "selects the most affordable shipping rate" do - allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(5.00) - allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(3.00) + allow(shipping_methods[0]). + to receive_message_chain(:calculator, :compute).and_return(5.00) + allow(shipping_methods[1]). + to receive_message_chain(:calculator, :compute).and_return(3.00) allow(subject).to receive(:shipping_methods).and_return(shipping_methods) @@ -86,8 +96,10 @@ module OrderManagement end it "selects the cheapest shipping rate and doesn't raise exception over nil cost" do - allow(shipping_methods[0]).to receive_message_chain(:calculator, :compute).and_return(1.00) - allow(shipping_methods[1]).to receive_message_chain(:calculator, :compute).and_return(nil) + allow(shipping_methods[0]). + to receive_message_chain(:calculator, :compute).and_return(1.00) + allow(shipping_methods[1]). + to receive_message_chain(:calculator, :compute).and_return(nil) allow(subject).to receive(:shipping_methods).and_return(shipping_methods) @@ -104,7 +116,8 @@ module OrderManagement allow(backend_method).to receive_message_chain(:calculator, :compute).and_return(0.00) allow(generic_method).to receive_message_chain(:calculator, :compute).and_return(5.00) - allow(subject).to receive(:shipping_methods).and_return([backend_method, generic_method]) + allow(subject). + to receive(:shipping_methods).and_return([backend_method, generic_method]) expect(subject.shipping_rates(package).map(&:selected)).to eq [false, true] end From ff046f7a6cd7611e79bb76a7b67e0399577534fb Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:25:14 +0100 Subject: [PATCH 146/261] Remove conditionals related to Config.track_inventory_levels, this config is always true in OFN --- app/models/spree/shipment.rb | 2 +- .../app/services/order_management/stock/packer.rb | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index 68002d6ee2..993fa0f62c 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -172,7 +172,7 @@ module Spree end def line_items - if order.complete? && Spree::Config[:track_inventory_levels] + if order.complete? order.line_items.select { |li| inventory_units.pluck(:variant_id).include?(li.variant_id) } else order.line_items diff --git a/engines/order_management/app/services/order_management/stock/packer.rb b/engines/order_management/app/services/order_management/stock/packer.rb index 867e8889dd..d66881a32b 100644 --- a/engines/order_management/app/services/order_management/stock/packer.rb +++ b/engines/order_management/app/services/order_management/stock/packer.rb @@ -17,15 +17,11 @@ module OrderManagement def default_package package = OrderManagement::Stock::Package.new(stock_location, order) order.line_items.each do |line_item| - if Spree::Config.track_inventory_levels - next unless stock_location.stock_item(line_item.variant) + next unless stock_location.stock_item(line_item.variant) - on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) - package.add line_item.variant, on_hand, :on_hand if on_hand.positive? - package.add line_item.variant, backordered, :backordered if backordered.positive? - else - package.add line_item.variant, line_item.quantity, :on_hand - end + on_hand, backordered = stock_location.fill_status(line_item.variant, line_item.quantity) + package.add line_item.variant, on_hand, :on_hand if on_hand.positive? + package.add line_item.variant, backordered, :backordered if backordered.positive? end package end From d323c5bdcb3bea36c0309c05ecf22daaafbb97b1 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:45:01 +0100 Subject: [PATCH 147/261] Simplify packer and coordinator baed on the fact that there's only one stock_location so there will only be one package per order --- .../order_management/stock/coordinator.rb | 27 +++++---------- .../services/order_management/stock/packer.rb | 6 +--- .../order_management/stock/packer_spec.rb | 33 +++++++------------ 3 files changed, 22 insertions(+), 44 deletions(-) diff --git a/engines/order_management/app/services/order_management/stock/coordinator.rb b/engines/order_management/app/services/order_management/stock/coordinator.rb index 215a82ffe3..64bbbc8cbc 100644 --- a/engines/order_management/app/services/order_management/stock/coordinator.rb +++ b/engines/order_management/app/services/order_management/stock/coordinator.rb @@ -15,24 +15,14 @@ module OrderManagement estimate_packages(packages) end - # Build packages as per stock location + # Build package with default stock location + # No need to check items are in the stock location, + # there is only one stock location so the items will be on that stock location. # - # It needs to check whether each stock location holds at least one stock - # item for the order. In case none is found it wouldn't make any sense - # to build a package because it would be empty. Plus we avoid errors down - # the stack because it would assume the stock location has stock items - # for the given order - # - # Returns an array of Package instances - def build_packages(packages = []) - Spree::StockLocation.active.each do |stock_location| - next unless stock_location.stock_items. - where(variant_id: order.line_items.pluck(:variant_id)).exists? - - packer = build_packer(stock_location, order) - packages += packer.packages - end - packages + # Returns an array with a single Package for the default stock location + def build_packages + packer = build_packer(order) + [packer.package] end private @@ -50,7 +40,8 @@ module OrderManagement packages end - def build_packer(stock_location, order) + def build_packer(order) + stock_location = DefaultStockLocation.find_or_create OrderManagement::Stock::Packer.new(stock_location, order) end end diff --git a/engines/order_management/app/services/order_management/stock/packer.rb b/engines/order_management/app/services/order_management/stock/packer.rb index d66881a32b..49141d3fef 100644 --- a/engines/order_management/app/services/order_management/stock/packer.rb +++ b/engines/order_management/app/services/order_management/stock/packer.rb @@ -10,11 +10,7 @@ module OrderManagement @order = order end - def packages - [default_package] - end - - def default_package + def package package = OrderManagement::Stock::Package.new(stock_location, order) order.line_items.each do |line_item| next unless stock_location.stock_item(line_item.variant) diff --git a/engines/order_management/spec/services/order_management/stock/packer_spec.rb b/engines/order_management/spec/services/order_management/stock/packer_spec.rb index f1e2b432bf..1100090af0 100644 --- a/engines/order_management/spec/services/order_management/stock/packer_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/packer_spec.rb @@ -10,30 +10,21 @@ module OrderManagement subject { Packer.new(stock_location, order) } - context 'packages' do - it 'builds an array of packages' do - packages = subject.packages - expect(packages.size).to eq 1 - expect(packages.first.contents.size).to eq 5 - end + before { order.line_items.first.variant.update(weight: 1) } + + it 'builds a package with all the items' do + package = subject.package + + expect(package.contents.size).to eq 5 + expect(package.weight).to be_positive end - context 'default_package' do - before { order.line_items.first.variant.update(weight: 1) } + it 'variants are added as backordered without enough on_hand' do + expect(stock_location).to receive(:fill_status).exactly(5).times.and_return([2, 3]) - it 'contains all the items' do - package = subject.default_package - expect(package.contents.size).to eq 5 - expect(package.weight).to be_positive - end - - it 'variants are added as backordered without enough on_hand' do - expect(stock_location).to receive(:fill_status).exactly(5).times.and_return([2, 3]) - - package = subject.default_package - expect(package.on_hand.size).to eq 5 - expect(package.backordered.size).to eq 5 - end + package = subject.package + expect(package.on_hand.size).to eq 5 + expect(package.backordered.size).to eq 5 end end end From 21ec6ccf0dd2b1f19786da488a7b7a6872b23b60 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:48:23 +0100 Subject: [PATCH 148/261] Remove unused sort packages from prioritizer --- .../app/services/order_management/stock/prioritizer.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/engines/order_management/app/services/order_management/stock/prioritizer.rb b/engines/order_management/app/services/order_management/stock/prioritizer.rb index 16b992333f..9e8eea4289 100644 --- a/engines/order_management/app/services/order_management/stock/prioritizer.rb +++ b/engines/order_management/app/services/order_management/stock/prioritizer.rb @@ -12,7 +12,6 @@ module OrderManagement end def prioritized_packages - sort_packages adjust_packages prune_packages packages @@ -38,10 +37,6 @@ module OrderManagement end end - def sort_packages - # order packages by preferred stock_locations - end - def prune_packages packages.reject!(&:empty?) end From 659de3d24d9a732d216ec7ca625aa787106add51 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 20:54:07 +0100 Subject: [PATCH 149/261] Replay spree commit a4622ee13a723f0dba2943967b445b9989f67fb2 to fix issue introduced in spree 2.1 --- app/models/spree/shipment.rb | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index 993fa0f62c..99d3a57fc0 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -107,11 +107,14 @@ module Spree def refresh_rates return shipping_rates if shipped? + # The call to Stock::Estimator below will replace the current shipping_method + original_shipping_method_id = shipping_method.try(:id) + self.shipping_rates = OrderManagement::Stock::Estimator.new(order).shipping_rates(to_package) - if shipping_method + if original_shipping_method_id selected_rate = shipping_rates.detect { |rate| - rate.shipping_method_id == shipping_method.id + rate.shipping_method_id == original_shipping_method_id } self.selected_shipping_rate_id = selected_rate.id if selected_rate end From 758bb17142cdb2a8291c534791f616b5924ce972 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 2 Jul 2020 21:23:32 +0100 Subject: [PATCH 150/261] Fix some easy rubocop issues and add some exceptions to to manual todo list --- .rubocop_manual_todo.yml | 12 ++++++++++++ app/models/spree/shipment.rb | 7 +++---- .../order_management/stock/estimator_spec.rb | 2 +- lib/spree/core/environment.rb | 2 ++ 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 94fdd0bd31..c5b16934f0 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -391,6 +391,7 @@ Metrics/AbcSize: - app/models/spree/order_decorator.rb - app/models/spree/payment_decorator.rb - app/models/spree/product_decorator.rb + - app/models/spree/shipment.rb - app/models/spree/taxon_decorator.rb - app/models/spree/tax_rate_decorator.rb - app/serializers/api/admin/enterprise_serializer.rb @@ -400,6 +401,9 @@ Metrics/AbcSize: - app/services/create_order_cycle.rb - app/services/order_cycle_form.rb - app/services/order_syncer.rb + - engines/order_management/app/services/order_management/stock/estimator.rb + - engines/order_management/app/services/order_management/stock/package.rb + - engines/order_management/app/services/order_management/stock/packer.rb - engines/order_management/app/services/order_management/subscriptions/validator.rb - lib/active_merchant/billing/gateways/stripe_decorator.rb - lib/active_merchant/billing/gateways/stripe_payment_intents.rb @@ -457,6 +461,7 @@ Metrics/BlockLength: "scenario" ] Exclude: + - app/models/spree/shipment.rb - lib/tasks/data.rake - spec/controllers/spree/admin/invoices_controller_spec.rb - spec/factories/enterprise_factory.rb @@ -496,6 +501,7 @@ Metrics/CyclomaticComplexity: - app/models/spree/product_decorator.rb - app/models/variant_override_set.rb - app/services/cart_service.rb + - engines/order_management/app/services/order_management/stock/estimator.rb - lib/active_merchant/billing/gateways/stripe_payment_intents.rb - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb @@ -520,6 +526,7 @@ Metrics/PerceivedComplexity: - app/models/spree/ability_decorator.rb - app/models/spree/order_decorator.rb - app/models/spree/product_decorator.rb + - engines/order_management/app/services/order_management/stock/estimator.rb - lib/active_merchant/billing/gateways/stripe_payment_intents.rb - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb @@ -585,11 +592,14 @@ Metrics/MethodLength: - app/models/spree/payment_decorator.rb - app/models/spree/payment_method_decorator.rb - app/models/spree/product_decorator.rb + - app/models/spree/shipment.rb - app/serializers/api/admin/order_cycle_serializer.rb - app/serializers/api/cached_enterprise_serializer.rb - app/services/order_cycle_form.rb - app/services/permitted_attributes/checkout.rb - engines/order_management/app/services/order_management/reports/enterprise_fee_summary/scope.rb + - engines/order_management/app/services/order_management/stock/estimator.rb + - engines/order_management/app/services/order_management/stock/package.rb - lib/active_merchant/billing/gateways/stripe_payment_intents.rb - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb @@ -652,6 +662,7 @@ Metrics/ClassLength: - app/models/product_import/entry_validator.rb - app/models/product_import/product_importer.rb - app/models/spree/ability_decorator.rb + - app/models/spree/shipment.rb - app/models/spree/user.rb - app/serializers/api/cached_enterprise_serializer.rb - app/serializers/api/enterprise_shopfront_serializer.rb @@ -676,6 +687,7 @@ Metrics/ModuleLength: - app/helpers/injection_helper.rb - app/helpers/spree/admin/base_helper.rb - app/helpers/spree/admin/navigation_helper.rb + - engines/order_management/spec/services/order_management/stock/package_spec.rb - engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb - engines/order_management/spec/services/order_management/subscriptions/form_spec.rb - engines/order_management/spec/services/order_management/subscriptions/proxy_order_syncer_spec.rb diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index 99d3a57fc0..43b0b586c0 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -67,7 +67,6 @@ module Spree end def to_param - number if number generate_shipment_number unless number number.to_s.to_url.upcase end @@ -136,7 +135,7 @@ module Spree alias_method :amount, :cost def display_cost - Spree::Money.new(cost, { currency: currency }) + Spree::Money.new(cost, currency: currency) end alias_method :display_amount, :display_cost @@ -146,7 +145,7 @@ module Spree end def display_item_cost - Spree::Money.new(item_cost, { currency: currency }) + Spree::Money.new(item_cost, currency: currency) end def total_cost @@ -154,7 +153,7 @@ module Spree end def display_total_cost - Spree::Money.new(total_cost, { currency: currency }) + Spree::Money.new(total_cost, currency: currency) end def editable_by?(_user) diff --git a/engines/order_management/spec/services/order_management/stock/estimator_spec.rb b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb index 892b7e1cf2..6d14903cbd 100644 --- a/engines/order_management/spec/services/order_management/stock/estimator_spec.rb +++ b/engines/order_management/spec/services/order_management/stock/estimator_spec.rb @@ -19,7 +19,7 @@ module OrderManagement to receive_message_chain(:calculator, :compute).and_return(4.00) allow_any_instance_of(Spree::ShippingMethod). to receive_message_chain(:calculator, :preferences). - and_return({ currency: order.currency }) + and_return(currency: order.currency) allow_any_instance_of(Spree::ShippingMethod). to receive_message_chain(:calculator, :marked_for_destruction?) diff --git a/lib/spree/core/environment.rb b/lib/spree/core/environment.rb index 443b110c0a..4cd6fb5133 100644 --- a/lib/spree/core/environment.rb +++ b/lib/spree/core/environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Core class Environment From fcaa9d1b37d8a7f5bdb2af6422d7a4a93dcdc8c5 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 10:32:09 +0100 Subject: [PATCH 151/261] Remove extra space from base translations in closing and welcome to --- config/locales/en.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/en.yml b/config/locales/en.yml index 4b62644980..3726167337 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -207,8 +207,8 @@ en: 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 ' + 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: 'Australian Producers' @@ -1839,8 +1839,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating From c726340ba304a49c2e6c0130201d944b5b4cff2e Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 11:48:39 +0200 Subject: [PATCH 152/261] Extract #save_locale_from_params comment-method --- app/helpers/i18n_helper.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index b755e85a54..83380e07dc 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -1,10 +1,6 @@ module I18nHelper def set_locale - # Save a given locale from params - if params[:locale] && available_locale?(params[:locale]) - spree_current_user&.update!(locale: params[:locale]) - cookies[:locale] = params[:locale] - end + save_locale_from_params # After logging in, check if the user chose a locale before if current_user_locale.nil? && cookies[:locale] && available_locale?(params[:locale]) @@ -30,6 +26,13 @@ module I18nHelper private + def save_locale_from_params + return unless params[:locale] && available_locale?(params[:locale]) + + spree_current_user&.update!(locale: params[:locale]) + cookies[:locale] = params[:locale] + end + def current_user_locale spree_current_user.andand.locale end From 7a00a3ba1ed914795dbe119aba17424c335a5082 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 11:52:21 +0200 Subject: [PATCH 153/261] Rename method and add explanatory comment --- app/controllers/spree/user_sessions_controller.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index 44fb56a312..d48f700581 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -12,7 +12,7 @@ module Spree ssl_allowed :login_bar before_action :set_checkout_redirect, only: :create - after_action :ensure_valid_locale, only: :create + after_action :ensure_valid_locale_persisted, only: :create def create authenticate_spree_user! @@ -51,7 +51,9 @@ module Spree session["spree_user_return_to"] = nil end - def ensure_valid_locale + def ensure_valid_locale_persisted + # When creating a new user session we have to wait until after a successful + # login to be able to persist a locale on the current user return unless spree_current_user && !available_locale?(spree_current_user.locale) spree_current_user.update!(locale: I18n.default_locale) From 02549d1b0fc00ea53152cecd8802f19c72c3695f Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 12:50:39 +0200 Subject: [PATCH 154/261] Extract all locale-setting logic to a service --- .../spree/user_sessions_controller.rb | 4 +- app/helpers/i18n_helper.rb | 44 +----------- app/services/user_locale_setter.rb | 67 +++++++++++++++++++ 3 files changed, 70 insertions(+), 45 deletions(-) create mode 100644 app/services/user_locale_setter.rb diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index d48f700581..323fff9172 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -6,7 +6,6 @@ module Spree include Spree::Core::ControllerHelpers::Common include Spree::Core::ControllerHelpers::Order include Spree::Core::ControllerHelpers::SSL - include I18nHelper ssl_required :new, :create, :destroy, :update ssl_allowed :login_bar @@ -54,9 +53,8 @@ module Spree def ensure_valid_locale_persisted # When creating a new user session we have to wait until after a successful # login to be able to persist a locale on the current user - return unless spree_current_user && !available_locale?(spree_current_user.locale) - spree_current_user.update!(locale: I18n.default_locale) + UserLocaleSetter.ensure_valid_locale_persisted(spree_current_user) end end end diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index 83380e07dc..ce128b39f6 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -1,49 +1,9 @@ module I18nHelper def set_locale - save_locale_from_params - - # After logging in, check if the user chose a locale before - if current_user_locale.nil? && cookies[:locale] && available_locale?(params[:locale]) - spree_current_user&.update!(locale: params[:locale]) - end - - I18n.locale = valid_current_locale + UserLocaleSetter.new(spree_current_user, params[:locale], cookies).call end def valid_locale(user) - if user.present? && - user.locale.present? && - available_locale?(user.locale) - user.locale - else - I18n.default_locale - end - end - - def available_locale?(locale) - Rails.application.config.i18n.available_locales.include?(locale) - end - - private - - def save_locale_from_params - return unless params[:locale] && available_locale?(params[:locale]) - - spree_current_user&.update!(locale: params[:locale]) - cookies[:locale] = params[:locale] - end - - def current_user_locale - spree_current_user.andand.locale - end - - def valid_current_locale - if available_locale?(current_user_locale) - current_user_locale - elsif available_locale?(cookies[:locale]) - cookies[:locale] - else - I18n.default_locale - end + UserLocaleSetter.valid_locale_for_user(user) end end diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb new file mode 100644 index 0000000000..c3dee48bf7 --- /dev/null +++ b/app/services/user_locale_setter.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +class UserLocaleSetter + def initialize(current_user, params_locale, cookies) + @current_user = current_user + @params_locale = params_locale + @cookies = cookies + end + + def call + save_locale_from_params + + # After logging in, check if the user chose a locale before + if current_user_locale.nil? && cookies[:locale] && available_locale?(params_locale) + current_user&.update!(locale: params_locale) + end + + I18n.locale = valid_current_locale + end + + def self.ensure_valid_locale_persisted(user) + return unless user && !available_locale?(user.locale) + + user.update!(locale: I18n.default_locale) + end + + def self.valid_locale_for_user(user) + if user.present? && user.locale.present? && available_locale?(user.locale) + user.locale + else + I18n.default_locale + end + end + + def self.available_locale?(locale) + Rails.application.config.i18n.available_locales.include?(locale) + end + + private + + attr_reader :current_user, :params_locale, :cookies + + def save_locale_from_params + return unless params_locale && available_locale?(params_locale) + + current_user&.update!(locale: params_locale) + cookies[:locale] = params_locale + end + + def available_locale?(locale) + self.class.available_locale?(locale) + end + + def current_user_locale + current_user.andand.locale + end + + def valid_current_locale + if available_locale?(current_user_locale) + current_user_locale + elsif available_locale?(cookies[:locale]) + cookies[:locale] + else + I18n.default_locale + end + end +end From faa7c0a7c595a81234dec6050554e25ea4b87b64 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:02:14 +0200 Subject: [PATCH 155/261] Extract save_cookies_from_locale comment-method --- app/services/user_locale_setter.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index c3dee48bf7..99fcd57e4e 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -9,11 +9,7 @@ class UserLocaleSetter def call save_locale_from_params - - # After logging in, check if the user chose a locale before - if current_user_locale.nil? && cookies[:locale] && available_locale?(params_locale) - current_user&.update!(locale: params_locale) - end + save_locale_from_cookies I18n.locale = valid_current_locale end @@ -47,6 +43,13 @@ class UserLocaleSetter cookies[:locale] = params_locale end + def save_locale_from_cookies + return unless current_user_locale.nil? && cookies[:locale] && + available_locale?(params_locale) + + current_user&.update!(locale: params_locale) + end + def available_locale?(locale) self.class.available_locale?(locale) end From ebffa381c6ead1a79b81c1a4253559323fb61856 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:06:05 +0200 Subject: [PATCH 156/261] Update cookies[:locale] logic --- app/services/user_locale_setter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 99fcd57e4e..3e0e5fdde4 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -45,9 +45,9 @@ class UserLocaleSetter def save_locale_from_cookies return unless current_user_locale.nil? && cookies[:locale] && - available_locale?(params_locale) + available_locale?(cookies[:locale]) - current_user&.update!(locale: params_locale) + current_user&.update!(locale: cookies[:locale]) end def available_locale?(locale) From dab0add4923cfef0fa89a37c5b100279503d301b Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:20:51 +0200 Subject: [PATCH 157/261] Make conditional more concise --- app/services/user_locale_setter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 3e0e5fdde4..6c97e268e2 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -21,7 +21,7 @@ class UserLocaleSetter end def self.valid_locale_for_user(user) - if user.present? && user.locale.present? && available_locale?(user.locale) + if user.andand.locale.present? && available_locale?(user.locale) user.locale else I18n.default_locale From 078726dccae26282e9e7148d2f6348b61308fbc8 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:21:45 +0200 Subject: [PATCH 158/261] Add explanatory comment on saving selected locale in cookies --- app/services/user_locale_setter.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 6c97e268e2..1f36f4ea66 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -44,6 +44,8 @@ class UserLocaleSetter end def save_locale_from_cookies + # If the user account has a selected locale: we ignore the locale set in cookies, + # which is persisted per-device but not per-user. return unless current_user_locale.nil? && cookies[:locale] && available_locale?(cookies[:locale]) From ab63d2234ca89275c40c63f393cc7848adbb3fd7 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 14:22:32 +0200 Subject: [PATCH 159/261] Guard against nils in conditions --- app/services/user_locale_setter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 1f36f4ea66..1a5951df20 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -61,9 +61,9 @@ class UserLocaleSetter end def valid_current_locale - if available_locale?(current_user_locale) + if current_user_locale && available_locale?(current_user_locale) current_user_locale - elsif available_locale?(cookies[:locale]) + elsif cookies[:locale] && available_locale?(cookies[:locale]) cookies[:locale] else I18n.default_locale From cd60ee2116e7d7fe18d2e642e6dc3ee035d416bc Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 10:19:53 +0100 Subject: [PATCH 160/261] Use flat_map to make ship methods selection faster --- .../app/services/order_management/stock/package.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engines/order_management/app/services/order_management/stock/package.rb b/engines/order_management/app/services/order_management/stock/package.rb index 3009d0b19c..f3bfaf38f0 100644 --- a/engines/order_management/app/services/order_management/stock/package.rb +++ b/engines/order_management/app/services/order_management/stock/package.rb @@ -92,7 +92,7 @@ module OrderManagement # # @return [Array] def shipping_methods - available_shipping_methods = shipping_categories.map(&:shipping_methods).flatten.uniq.to_a + available_shipping_methods = shipping_categories.flat_map(&:shipping_methods).uniq.to_a available_shipping_methods.keep_if do |shipping_method| ships_with?(order.distributor.shipping_methods.to_a, shipping_method) From 07a44cfaf380cdab68c0c31edf008bed4d630cec Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 10:18:56 +0100 Subject: [PATCH 161/261] Update selected shipping rate if there is an original shipping method to keep and it is different from the one selected through the Estimator process Make sure the shipment is saved (callbacks!) whenever the ship method has changed in the refresh_rates process --- app/models/spree/shipment.rb | 30 +++++++++++++++++++++++------- spec/models/spree/shipment_spec.rb | 3 ++- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index 43b0b586c0..98ea4ac982 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -108,19 +108,35 @@ module Spree # The call to Stock::Estimator below will replace the current shipping_method original_shipping_method_id = shipping_method.try(:id) - self.shipping_rates = OrderManagement::Stock::Estimator.new(order).shipping_rates(to_package) - if original_shipping_method_id - selected_rate = shipping_rates.detect { |rate| - rate.shipping_method_id == original_shipping_method_id - } - self.selected_shipping_rate_id = selected_rate.id if selected_rate - end + keep_original_shipping_method_selection(original_shipping_method_id) shipping_rates end + def keep_original_shipping_method_selection(original_shipping_method_id) + return if shipping_method&.id == original_shipping_method_id + + rate_for_original_shipping_method = find_shipping_rate_for(original_shipping_method_id) + if rate_for_original_shipping_method.present? + self.selected_shipping_rate_id = rate_for_original_shipping_method.id + else + # If there's no original ship method to keep, or if it cannot be found on the ship rates + # But there's a new ship method selected (first if clause in this method) + # We need to save the shipment so that callbacks are triggered + save! + end + end + + def find_shipping_rate_for(shipping_method_id) + return unless shipping_method_id + + shipping_rates.detect { |rate| + rate.shipping_method_id == shipping_method_id + } + end + def currency order ? order.currency : Spree::Config[:currency] end diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 457df53a6d..30f088133c 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -126,7 +126,8 @@ describe Spree::Shipment do it 'should request new rates, and maintain shipping_method selection' do OrderManagement::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) - shipment.stub(shipping_method: shipping_method2) + # The first call is for the original shippping method, the second call is after the Estimator was executed + allow(shipment).to receive(:shipping_method).and_return(shipping_method2, shipping_method1) expect(shipment.refresh_rates).to eq shipping_rates expect(shipment.reload.selected_shipping_rate.shipping_method_id).to eq shipping_method2.id From 7b89b52ab897c666ca37b8ecfe66defb51d1b996 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 13:44:25 +0100 Subject: [PATCH 162/261] Transpec shipment_spec brough from spree_core --- spec/models/spree/shipment_spec.rb | 150 ++++++++++++++--------------- 1 file changed, 75 insertions(+), 75 deletions(-) diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 30f088133c..27fac8e151 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -8,7 +8,7 @@ describe Spree::Shipment do let(:shipping_method) { build(:shipping_method, name: "UPS") } let(:shipment) do shipment = Spree::Shipment.new order: order - shipment.stub(shipping_method: shipping_method) + allow(shipment).to receive_messages(shipping_method: shipping_method) shipment.state = 'pending' shipment end @@ -21,13 +21,13 @@ describe Spree::Shipment do unit2 = create(:inventory_unit) allow(unit1).to receive(:backordered?) { false } allow(unit2).to receive(:backordered?) { true } - shipment.stub(inventory_units: [unit1, unit2]) + allow(shipment).to receive_messages(inventory_units: [unit1, unit2]) expect(shipment).to be_backordered end context "#cost" do it "should return the amount of any shipping charges that it originated" do - shipment.stub_chain :adjustment, amount: 10 + allow(shipment).to receive_message_chain :adjustment, amount: 10 expect(shipment.cost).to eq 10 end @@ -38,21 +38,21 @@ describe Spree::Shipment do context "display_cost" do it "retuns a Spree::Money" do - shipment.stub(:cost) { 21.22 } + allow(shipment).to receive(:cost) { 21.22 } expect(shipment.display_cost).to eq Spree::Money.new(21.22) end end context "display_item_cost" do it "retuns a Spree::Money" do - shipment.stub(:item_cost) { 21.22 } + allow(shipment).to receive(:item_cost) { 21.22 } expect(shipment.display_item_cost).to eq Spree::Money.new(21.22) end end context "display_total_cost" do it "retuns a Spree::Money" do - shipment.stub(:total_cost) { 21.22 } + allow(shipment).to receive(:total_cost) { 21.22 } expect(shipment.display_total_cost).to eq Spree::Money.new(21.22) end end @@ -125,7 +125,7 @@ describe Spree::Shipment do let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) } it 'should request new rates, and maintain shipping_method selection' do - OrderManagement::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) + expect(OrderManagement::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator) # The first call is for the original shippping method, the second call is after the Estimator was executed allow(shipment).to receive(:shipping_method).and_return(shipping_method2, shipping_method1) @@ -134,22 +134,22 @@ describe Spree::Shipment do end it 'should handle no shipping_method selection' do - OrderManagement::Stock::Estimator.should_receive(:new).with(shipment.order).and_return(mock_estimator) - shipment.stub(shipping_method: nil) + expect(OrderManagement::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator) + allow(shipment).to receive_messages(shipping_method: nil) expect(shipment.refresh_rates).to eq shipping_rates expect(shipment.reload.selected_shipping_rate).to_not be_nil end it 'should not refresh if shipment is shipped' do - OrderManagement::Stock::Estimator.should_not_receive(:new) + expect(OrderManagement::Stock::Estimator).not_to receive(:new) shipment.shipping_rates.delete_all - shipment.stub(shipped?: true) + allow(shipment).to receive_messages(shipped?: true) expect(shipment.refresh_rates).to eq [] end context 'to_package' do it 'should use symbols for states when adding contents to package' do - shipment.stub_chain(:inventory_units, + allow(shipment).to receive_message_chain(:inventory_units, includes: [build(:inventory_unit, variant: variant, state: 'on_hand'), build(:inventory_unit, variant: variant, @@ -163,8 +163,8 @@ describe Spree::Shipment do end it '#total_cost' do - shipment.stub cost: 5.0 - shipment.stub item_cost: 50.0 + allow(shipment).to receive_messages cost: 5.0 + allow(shipment).to receive_messages item_cost: 50.0 expect(shipment.total_cost).to eql(55.0) end @@ -172,7 +172,7 @@ describe Spree::Shipment do shared_examples_for "immutable once shipped" do it "should remain in shipped state once shipped" do shipment.state = 'shipped' - shipment.should_receive(:update_column).with(:state, 'shipped') + expect(shipment).to receive(:update_column).with(:state, 'shipped') shipment.update!(order) end end @@ -181,8 +181,8 @@ describe Spree::Shipment do it "should have a state of pending if backordered" do unit = create(:inventory_unit) allow(unit).to receive(:backordered?) { true } - shipment.stub(inventory_units: [unit]) - shipment.should_receive(:update_column).with(:state, 'pending') + allow(shipment).to receive_messages(inventory_units: [unit]) + expect(shipment).to receive(:update_column).with(:state, 'pending') shipment.update!(order) end end @@ -191,7 +191,7 @@ describe Spree::Shipment do it "should result in a 'pending' state" do allow(order).to receive(:canceled?) { true } - shipment.should_receive(:update_column).with(:state, 'canceled') + expect(shipment).to receive(:update_column).with(:state, 'canceled') shipment.update!(order) end end @@ -200,7 +200,7 @@ describe Spree::Shipment do it "should result in a 'pending' state" do allow(order).to receive(:can_ship?) { false } - shipment.should_receive(:update_column).with(:state, 'pending') + expect(shipment).to receive(:update_column).with(:state, 'pending') shipment.update!(order) end end @@ -212,7 +212,7 @@ describe Spree::Shipment do before { allow(order).to receive(:paid?) { true } } it "should result in a 'ready' state" do - shipment.should_receive(:update_column).with(:state, 'ready') + expect(shipment).to receive(:update_column).with(:state, 'ready') shipment.update!(order) end @@ -225,7 +225,7 @@ describe Spree::Shipment do it "should result in a 'ready' state" do shipment.state = 'pending' - shipment.should_receive(:update_column).with(:state, 'ready') + expect(shipment).to receive(:update_column).with(:state, 'ready') shipment.update!(order) end @@ -240,7 +240,7 @@ describe Spree::Shipment do it "should result in a 'pending' state" do shipment.state = 'ready' - shipment.should_receive(:update_column).with(:state, 'pending') + expect(shipment).to receive(:update_column).with(:state, 'pending') shipment.update!(order) end @@ -253,9 +253,9 @@ describe Spree::Shipment do context "when shipment state changes to shipped" do it "should call after_ship" do shipment.state = 'pending' - shipment.should_receive :after_ship - shipment.stub determine_state: 'shipped' - shipment.should_receive(:update_column).with(:state, 'shipped') + expect(shipment).to receive :after_ship + allow(shipment).to receive_messages determine_state: 'shipped' + expect(shipment).to receive(:update_column).with(:state, 'shipped') shipment.update!(order) end end @@ -263,8 +263,8 @@ describe Spree::Shipment do context "when order is completed" do before do - order.stub completed?: true - order.stub canceled?: false + allow(order).to receive_messages completed?: true + allow(order).to receive_messages canceled?: false end it "should validate with inventory" do @@ -275,11 +275,11 @@ describe Spree::Shipment do context "#cancel" do it 'cancels the shipment' do - shipment.stub(:ensure_correct_adjustment) - shipment.order.stub(:update!) + allow(shipment).to receive(:ensure_correct_adjustment) + allow(shipment.order).to receive(:update!) shipment.state = 'pending' - shipment.should_receive(:after_cancel) + expect(shipment).to receive(:after_cancel) shipment.cancel! expect(shipment.state).to eq 'canceled' end @@ -287,23 +287,23 @@ describe Spree::Shipment do it 'restocks the items' do unit = double(:inventory_unit, variant: variant) allow(unit).to receive(:quantity) { 1 } - shipment.stub_chain(:inventory_units, + allow(shipment).to receive_message_chain(:inventory_units, :group_by, map: [unit]) shipment.stock_location = build(:stock_location) - shipment.stock_location.should_receive(:restock).with(variant, 1, shipment) + expect(shipment.stock_location).to receive(:restock).with(variant, 1, shipment) shipment.after_cancel end end context "#resume" do it 'will determine new state based on order' do - shipment.stub(:ensure_correct_adjustment) - shipment.order.stub(:update!) + allow(shipment).to receive(:ensure_correct_adjustment) + allow(shipment.order).to receive(:update!) shipment.state = 'canceled' - shipment.should_receive(:determine_state).and_return(:ready) - shipment.should_receive(:after_resume) + expect(shipment).to receive(:determine_state).and_return(:ready) + expect(shipment).to receive(:after_resume) shipment.resume! expect(shipment.state).to eq 'ready' end @@ -311,21 +311,21 @@ describe Spree::Shipment do it 'unstocks the items' do unit = create(:inventory_unit, variant: variant) allow(unit).to receive(:quantity) { 1 } - shipment.stub_chain(:inventory_units, + allow(shipment).to receive_message_chain(:inventory_units, :group_by, map: [unit]) shipment.stock_location = create(:stock_location) - shipment.stock_location.should_receive(:unstock).with(variant, 1, shipment) + expect(shipment.stock_location).to receive(:unstock).with(variant, 1, shipment) shipment.after_resume end it 'will determine new state based on order' do - shipment.stub(:ensure_correct_adjustment) - shipment.order.stub(:update!) + allow(shipment).to receive(:ensure_correct_adjustment) + allow(shipment.order).to receive(:update!) shipment.state = 'canceled' - shipment.should_receive(:determine_state).twice.and_return('ready') - shipment.should_receive(:after_resume) + expect(shipment).to receive(:determine_state).twice.and_return('ready') + expect(shipment).to receive(:after_resume) shipment.resume! # Shipment is pending because order is already paid expect(shipment.state).to eq 'pending' @@ -334,15 +334,15 @@ describe Spree::Shipment do context "#ship" do before do - order.stub(:update!) - shipment.stub(update_order: true, state: 'ready') - shipment.stub(adjustment: charge) - shipping_method.stub(:create_adjustment) - shipment.stub(:ensure_correct_adjustment) + allow(order).to receive(:update!) + allow(shipment).to receive_messages(update_order: true, state: 'ready') + allow(shipment).to receive_messages(adjustment: charge) + allow(shipping_method).to receive(:create_adjustment) + allow(shipment).to receive(:ensure_correct_adjustment) end it "should update shipped_at timestamp" do - shipment.stub(:send_shipped_email) + allow(shipment).to receive(:send_shipped_email) shipment.ship! expect(shipment.shipped_at).to_not be_nil # Ensure value is persisted @@ -353,17 +353,17 @@ describe Spree::Shipment do it "should send a shipment email" do mail_message = double 'Mail::Message' shipment_id = nil - Spree::ShipmentMailer.should_receive(:shipped_email) { |*args| + expect(Spree::ShipmentMailer).to receive(:shipped_email) { |*args| shipment_id = args[0] mail_message } - mail_message.should_receive :deliver + expect(mail_message).to receive :deliver shipment.ship! expect(shipment_id).to eq shipment.id end it "should finalize the shipment's adjustment" do - shipment.stub(:send_shipped_email) + allow(shipment).to receive(:send_shipped_email) shipment.ship! expect(shipment.adjustment.state).to eq 'finalized' expect(shipment.adjustment).to be_immutable @@ -373,68 +373,68 @@ describe Spree::Shipment do context "#ready" do # Regression test for #2040 it "cannot ready a shipment for an order if the order is unpaid" do - order.stub(paid?: false) + allow(order).to receive_messages(paid?: false) assert !shipment.can_ready? end end context "ensure_correct_adjustment" do - before { shipment.stub(:reload) } + before { allow(shipment).to receive(:reload) } it "should create adjustment when not present" do - shipment.stub(selected_shipping_rate_id: 1) - shipping_method.should_receive(:create_adjustment).with(shipping_method.adjustment_label, + allow(shipment).to receive_messages(selected_shipping_rate_id: 1) + expect(shipping_method).to receive(:create_adjustment).with(shipping_method.adjustment_label, order, shipment, true, "open") shipment.__send__(:ensure_correct_adjustment) end # Regression test for #3138 it "should use the shipping method's adjustment label" do - shipment.stub(selected_shipping_rate_id: 1) - shipping_method.stub(adjustment_label: "Foobar") - shipping_method.should_receive(:create_adjustment).with("Foobar", order, + allow(shipment).to receive_messages(selected_shipping_rate_id: 1) + allow(shipping_method).to receive_messages(adjustment_label: "Foobar") + expect(shipping_method).to receive(:create_adjustment).with("Foobar", order, shipment, true, "open") shipment.__send__(:ensure_correct_adjustment) end it "should update originator when adjustment is present" do - shipment.stub(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + allow(shipment).to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) adjustment = build(:adjustment) - shipment.stub(adjustment: adjustment) + allow(shipment).to receive_messages(adjustment: adjustment) allow(adjustment).to receive(:open?) { true } - shipment.adjustment.should_receive(:originator=).with(shipping_method) - shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) - shipment.adjustment.should_receive(:amount=).with(10.00) + expect(shipment.adjustment).to receive(:originator=).with(shipping_method) + expect(shipment.adjustment).to receive(:label=).with(shipping_method.adjustment_label) + expect(shipment.adjustment).to receive(:amount=).with(10.00) allow(shipment.adjustment).to receive(:save!) - shipment.adjustment.should_receive(:reload) + expect(shipment.adjustment).to receive(:reload) shipment.__send__(:ensure_correct_adjustment) end it 'should not update amount if adjustment is not open?' do - shipment.stub(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + allow(shipment).to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) adjustment = build(:adjustment) - shipment.stub(adjustment: adjustment) + allow(shipment).to receive_messages(adjustment: adjustment) allow(adjustment).to receive(:open?) { false } - shipment.adjustment.should_receive(:originator=).with(shipping_method) - shipment.adjustment.should_receive(:label=).with(shipping_method.adjustment_label) - shipment.adjustment.should_not_receive(:amount=).with(10.00) + expect(shipment.adjustment).to receive(:originator=).with(shipping_method) + expect(shipment.adjustment).to receive(:label=).with(shipping_method.adjustment_label) + expect(shipment.adjustment).not_to receive(:amount=).with(10.00) allow(shipment.adjustment).to receive(:save!) - shipment.adjustment.should_receive(:reload) + expect(shipment.adjustment).to receive(:reload) shipment.__send__(:ensure_correct_adjustment) end end context "update_order" do it "should update order" do - order.should_receive(:update!) + expect(order).to receive(:update!) shipment.__send__(:update_order) end end context "after_save" do it "should run correct callbacks" do - shipment.should_receive(:ensure_correct_adjustment) - shipment.should_receive(:update_order) + expect(shipment).to receive(:ensure_correct_adjustment) + expect(shipment).to receive(:update_order) shipment.run_callbacks(:save) end end @@ -447,7 +447,7 @@ describe Spree::Shipment do context "#tracking_url" do it "uses shipping method to determine url" do - shipping_method.should_receive(:build_tracking_url).with('1Z12345').and_return(:some_url) + expect(shipping_method).to receive(:build_tracking_url).with('1Z12345').and_return(:some_url) shipment.tracking = '1Z12345' expect(shipment.tracking_url).to eq :some_url @@ -461,7 +461,7 @@ describe Spree::Shipment do { variant_id: variant.id, state: 'on_hand', order_id: order.id } end - before { shipment.stub inventory_units: inventory_units } + before { allow(shipment).to receive_messages inventory_units: inventory_units } it "associates variant and order" do expect(inventory_units).to receive(:create).with(params) From b883a0eb75321f7343bdaee702369c126e358574 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 13:47:46 +0100 Subject: [PATCH 163/261] Fix easy rubocop issues in shipment_spec --- spec/models/spree/shipment_spec.rb | 38 +++++++++++++++++------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 27fac8e151..e24cebb801 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -125,8 +125,10 @@ describe Spree::Shipment do let(:mock_estimator) { double('estimator', shipping_rates: shipping_rates) } it 'should request new rates, and maintain shipping_method selection' do - expect(OrderManagement::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator) - # The first call is for the original shippping method, the second call is after the Estimator was executed + expect(OrderManagement::Stock::Estimator). + to receive(:new).with(shipment.order).and_return(mock_estimator) + # The first call is for the original shippping method, + # the second call is for the shippping method after the Estimator was executed allow(shipment).to receive(:shipping_method).and_return(shipping_method2, shipping_method1) expect(shipment.refresh_rates).to eq shipping_rates @@ -134,7 +136,8 @@ describe Spree::Shipment do end it 'should handle no shipping_method selection' do - expect(OrderManagement::Stock::Estimator).to receive(:new).with(shipment.order).and_return(mock_estimator) + expect(OrderManagement::Stock::Estimator). + to receive(:new).with(shipment.order).and_return(mock_estimator) allow(shipment).to receive_messages(shipping_method: nil) expect(shipment.refresh_rates).to eq shipping_rates expect(shipment.reload.selected_shipping_rate).to_not be_nil @@ -149,11 +152,12 @@ describe Spree::Shipment do context 'to_package' do it 'should use symbols for states when adding contents to package' do - allow(shipment).to receive_message_chain(:inventory_units, - includes: [build(:inventory_unit, variant: variant, - state: 'on_hand'), - build(:inventory_unit, variant: variant, - state: 'backordered')] ) + allow(shipment). + to receive_message_chain(:inventory_units, + includes: [build(:inventory_unit, variant: variant, + state: 'on_hand'), + build(:inventory_unit, variant: variant, + state: 'backordered')] ) package = shipment.to_package expect(package.on_hand.count).to eq 1 expect(package.backordered.count).to eq 1 @@ -288,8 +292,8 @@ describe Spree::Shipment do unit = double(:inventory_unit, variant: variant) allow(unit).to receive(:quantity) { 1 } allow(shipment).to receive_message_chain(:inventory_units, - :group_by, - map: [unit]) + :group_by, + map: [unit]) shipment.stock_location = build(:stock_location) expect(shipment.stock_location).to receive(:restock).with(variant, 1, shipment) shipment.after_cancel @@ -312,8 +316,8 @@ describe Spree::Shipment do unit = create(:inventory_unit, variant: variant) allow(unit).to receive(:quantity) { 1 } allow(shipment).to receive_message_chain(:inventory_units, - :group_by, - map: [unit]) + :group_by, + map: [unit]) shipment.stock_location = create(:stock_location) expect(shipment.stock_location).to receive(:unstock).with(variant, 1, shipment) shipment.after_resume @@ -384,7 +388,7 @@ describe Spree::Shipment do it "should create adjustment when not present" do allow(shipment).to receive_messages(selected_shipping_rate_id: 1) expect(shipping_method).to receive(:create_adjustment).with(shipping_method.adjustment_label, - order, shipment, true, "open") + order, shipment, true, "open") shipment.__send__(:ensure_correct_adjustment) end @@ -393,12 +397,13 @@ describe Spree::Shipment do allow(shipment).to receive_messages(selected_shipping_rate_id: 1) allow(shipping_method).to receive_messages(adjustment_label: "Foobar") expect(shipping_method).to receive(:create_adjustment).with("Foobar", order, - shipment, true, "open") + shipment, true, "open") shipment.__send__(:ensure_correct_adjustment) end it "should update originator when adjustment is present" do - allow(shipment).to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + allow(shipment). + to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) adjustment = build(:adjustment) allow(shipment).to receive_messages(adjustment: adjustment) allow(adjustment).to receive(:open?) { true } @@ -411,7 +416,8 @@ describe Spree::Shipment do end it 'should not update amount if adjustment is not open?' do - allow(shipment).to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) + allow(shipment). + to receive_messages(selected_shipping_rate: Spree::ShippingRate.new(cost: 10.00)) adjustment = build(:adjustment) allow(shipment).to receive_messages(adjustment: adjustment) allow(adjustment).to receive(:open?) { false } From 804450bcc57447d7c58c14040232973d0e6b3267 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 3 Jul 2020 15:35:13 +0100 Subject: [PATCH 164/261] Fix buggy spec The different shipping method was in the page but only as an option in the dropdown, not as the final selected shipping method! That was the cause of bug #5694. We now check for the label Shipping which preceeds the final shipping method selection in the order page --- spec/features/admin/order_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/admin/order_spec.rb b/spec/features/admin/order_spec.rb index 0017d6b72a..009092686b 100644 --- a/spec/features/admin/order_spec.rb +++ b/spec/features/admin/order_spec.rb @@ -285,7 +285,7 @@ feature ' from: 'selected_shipping_rate_id' find('.save-method').click - expect(page).to have_content different_shipping_method_for_distributor1.name + expect(page).to have_content "Shipping: #{different_shipping_method_for_distributor1.name}" end end From cc7b5e2df359ac4be63e876ffbeb03084413d991 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 16:28:18 +0200 Subject: [PATCH 165/261] Add pending test for setting locale from cookies during login This test currently fails --- spec/features/consumer/authentication_spec.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index 3e676b4c1e..75f3d519d0 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -169,6 +169,24 @@ feature "Authentication", js: true do expect(user.reload.locale).to eq "en" end end + + context "when the user has never selected a locale, but one has been selected before login" do + before do + user.update!(locale: nil) + end + + xit "logs in successfully and uses the locale from cookies" do + page.driver.browser.manage.add_cookie(name: 'locale', value: 'es') + + fill_in_and_submit_login_form(user) + expect_logged_in + + expect(page).to have_content I18n.t(:home_shop, locale: :es).upcase + expect(user.reload.locale).to eq "es" + + page.driver.browser.manage.delete_cookie('locale') + end + end end end end From 0c2fd4bfd20d5df69116e0a37eff956ff7fbac8d Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 16:32:46 +0200 Subject: [PATCH 166/261] Fix ensure_valid_locale_persisted and change public interface of service --- app/controllers/spree/user_sessions_controller.rb | 5 +++-- app/helpers/i18n_helper.rb | 2 +- app/services/user_locale_setter.rb | 8 ++++---- spec/features/consumer/authentication_spec.rb | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/controllers/spree/user_sessions_controller.rb b/app/controllers/spree/user_sessions_controller.rb index 323fff9172..df42f622e1 100644 --- a/app/controllers/spree/user_sessions_controller.rb +++ b/app/controllers/spree/user_sessions_controller.rb @@ -52,9 +52,10 @@ module Spree def ensure_valid_locale_persisted # When creating a new user session we have to wait until after a successful - # login to be able to persist a locale on the current user + # login to be able to persist a selected locale on the current user - UserLocaleSetter.ensure_valid_locale_persisted(spree_current_user) + UserLocaleSetter.new(spree_current_user, params[:locale], cookies). + ensure_valid_locale_persisted end end end diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index ce128b39f6..f1142472f1 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -1,6 +1,6 @@ module I18nHelper def set_locale - UserLocaleSetter.new(spree_current_user, params[:locale], cookies).call + UserLocaleSetter.new(spree_current_user, params[:locale], cookies).set_locale end def valid_locale(user) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 1a5951df20..22ca113a70 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -7,17 +7,17 @@ class UserLocaleSetter @cookies = cookies end - def call + def set_locale save_locale_from_params save_locale_from_cookies I18n.locale = valid_current_locale end - def self.ensure_valid_locale_persisted(user) - return unless user && !available_locale?(user.locale) + def ensure_valid_locale_persisted + return unless current_user && !available_locale?(current_user.locale) - user.update!(locale: I18n.default_locale) + current_user.update!(locale: valid_current_locale) end def self.valid_locale_for_user(user) diff --git a/spec/features/consumer/authentication_spec.rb b/spec/features/consumer/authentication_spec.rb index 75f3d519d0..c172f40f38 100644 --- a/spec/features/consumer/authentication_spec.rb +++ b/spec/features/consumer/authentication_spec.rb @@ -175,7 +175,7 @@ feature "Authentication", js: true do user.update!(locale: nil) end - xit "logs in successfully and uses the locale from cookies" do + it "logs in successfully and uses the locale from cookies" do page.driver.browser.manage.add_cookie(name: 'locale', value: 'es') fill_in_and_submit_login_form(user) From 05c1f093b229ab31fb44ca8b05bd455e94410709 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 16:44:37 +0200 Subject: [PATCH 167/261] Delete dead code There's nothing done in this bit of code that isn't already done somewhere else, and more effectively. --- app/services/user_locale_setter.rb | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index 22ca113a70..c51760ee70 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -9,7 +9,6 @@ class UserLocaleSetter def set_locale save_locale_from_params - save_locale_from_cookies I18n.locale = valid_current_locale end @@ -43,15 +42,6 @@ class UserLocaleSetter cookies[:locale] = params_locale end - def save_locale_from_cookies - # If the user account has a selected locale: we ignore the locale set in cookies, - # which is persisted per-device but not per-user. - return unless current_user_locale.nil? && cookies[:locale] && - available_locale?(cookies[:locale]) - - current_user&.update!(locale: cookies[:locale]) - end - def available_locale?(locale) self.class.available_locale?(locale) end From 46c40bdf336089a9cfabf225d4012bb720c1d66e Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 22:58:29 +0200 Subject: [PATCH 168/261] Fix default image display in admin order edit --- app/views/spree/admin/orders/_shipment_manifest.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/spree/admin/orders/_shipment_manifest.html.haml b/app/views/spree/admin/orders/_shipment_manifest.html.haml index fb9e51148f..2706d1bfd6 100644 --- a/app/views/spree/admin/orders/_shipment_manifest.html.haml +++ b/app/views/spree/admin/orders/_shipment_manifest.html.haml @@ -4,7 +4,7 @@ - if line_item.present? %tr.stock-item{ "data-item-quantity" => "#{item.quantity}" } %td.item-image - = mini_image(item.variant) + = render 'spree/shared/variant_thumbnail', variant: item.variant %td.item-name = item.variant.product_and_full_name %td.item-price.align-center From e2626a0c3bf478c825be640ac2445dcae2a3ac59 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Fri, 3 Jul 2020 18:06:23 +0200 Subject: [PATCH 169/261] Add unit tests for UserLocaleSetter service --- spec/services/user_locale_setter_spec.rb | 157 +++++++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 spec/services/user_locale_setter_spec.rb diff --git a/spec/services/user_locale_setter_spec.rb b/spec/services/user_locale_setter_spec.rb new file mode 100644 index 0000000000..443e6e2f7f --- /dev/null +++ b/spec/services/user_locale_setter_spec.rb @@ -0,0 +1,157 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe UserLocaleSetter do + let(:user) { create(:user) } + let(:default_locale) { I18n.default_locale } + let(:locale_params) { {} } + let(:cookies) { {} } + let(:service) { UserLocaleSetter.new(user, locale_params, cookies) } + + describe "#set_locale" do + describe "persists selected locale from params" do + let(:locale_params) { "es" } + + context "when the user is logged in" do + it "saves selected locale to user.locale and cookies[:locale]" do + service.set_locale + + expect(user.reload.locale).to eq "es" + expect(cookies).to eq({ locale: "es" }) + end + end + + context "when the user is not logged in" do + it "saves selected locale to cookies[:locale]" do + service.set_locale + + expect(cookies).to eq({ locale: "es" }) + end + end + end + + describe "sets the current locale" do + context "when the user is logged in" do + context "and has a valid locale saved" do + before { user.update(locale: "es") } + + it "applies the user's locale" do + service.set_locale + + expect(I18n.locale).to eq :es + end + end + + context "and has an invalid locale saved" do + before { user.update(locale: "xx") } + + it "applies the default locale" do + service.set_locale + + expect(I18n.locale).to eq I18n.default_locale + end + end + + context "and has no locale saved" do + before { user.update(locale: nil) } + + it "applies the locale from cookies if present" do + cookies[:locale] = "es" + service.set_locale + + expect(I18n.locale).to eq :es + end + + it "applies the default locale otherwise " do + service.set_locale + + expect(I18n.locale).to eq I18n.default_locale + end + end + end + + context "when the user is not logged in" do + let(:user) { nil } + + context "with a locale set in cookies" do + it "applies the value from cookies" do + cookies[:locale] = "es" + service.set_locale + + expect(I18n.locale).to eq :es + end + end + + context "with no locale set in cookies" do + it "applies the default locale" do + service.set_locale + + expect(I18n.locale).to eq I18n.default_locale + end + end + end + end + end + + describe "#ensure_valid_locale_persisted" do + context "when a user is present" do + context "and has an unavailable locale saved" do + before { user.update(locale: "xx") } + + context "with no locale set in cookies" do + it "set the user's locale to the default" do + service.ensure_valid_locale_persisted + + expect(user.reload.locale).to eq default_locale.to_s + end + end + + context "with a locale set in cookies" do + let(:cookies) { {locale: "es"} } + + it "set the user's locale to the cookie value" do + service.ensure_valid_locale_persisted + + expect(user.reload.locale).to eq "es" + end + end + end + end + end + + describe "self#valid_locale_for_user" do + context "when the user has a locale set" do + it "returns the user's locale" do + user.update(locale: "es") + expect(UserLocaleSetter.valid_locale_for_user(user)).to eq "es" + end + end + + context "when the user has no locale set" do + it "returns the default locale" do + expect(UserLocaleSetter.valid_locale_for_user(user)).to eq default_locale + end + end + + context "when the given user argument is nil" do + it "returns the default locale" do + expect(UserLocaleSetter.valid_locale_for_user(nil)).to eq default_locale + end + end + end + + describe "self#available_locale?" do + it "returns true if locale is available" do + expect(UserLocaleSetter.available_locale?("es")).to be true + end + + it "returns false if locale is not available" do + expect(UserLocaleSetter.available_locale?("xx")).to be false + end + + it "returns false if nil is given for locale" do + expect(UserLocaleSetter.available_locale?(nil)).to be false + end + end +end From 45b960a7ee0baafa4c716c52623d8726de8a98ef Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sat, 4 Jul 2020 07:39:50 +1000 Subject: [PATCH 170/261] Updating translations for config/locales/pt_BR.yml --- config/locales/pt_BR.yml | 52 +++++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml index 8d58c3b56f..ec32513c2e 100644 --- a/config/locales/pt_BR.yml +++ b/config/locales/pt_BR.yml @@ -371,7 +371,10 @@ pt_BR: title: "Configurações do Matomo" matomo_url: "Matomo URL" matomo_site_id: "Matomo Site ID" + matomo_tag_manager_url: "URL do Gestor de Tag Matomo" + info_html: "Matomo é uma aplicação de análise Mobile e Web. Você pode hospedar o Matomo localmente ou usar um serviço de hospedagem na nuvem. Veja matomo.org para mais informações." config_instructions_html: "Aqui você pode configurar a integração do OFN Matomo. O URL do Matomo abaixo deve apontar para a instância do Matomo para onde as informações de rastreamento do usuário serão enviadas; se for deixado em branco, o rastreamento de usuários do Matomo será desativado. O campo ID do site não é obrigatório, mas é útil se você estiver controlando mais de um site em uma única instância do Matomo. ele pode ser encontrado no console da instância Matomo." + config_instructions_tag_manager_html: "Ao configurar a URL para o Matomo Tag Manager, você habilita o Matomo Tag Manager. Esta ferramenta permite que você configure eventos de 'analytics'. A URL do Matomo Tag Manager é copiada do Matomo Tag Manager. Certifique-se de que você seleciou o 'container' e o 'environment' corretos, já que estas opções mudam o URL. " customers: index: new_customer: "Novo cliente" @@ -477,6 +480,7 @@ pt_BR: line_number: "Linha %{number}:" encoding_error: "Verifique a configuração de idioma do seu arquivo de origem e verifique se ele foi salvo com a codificação UTF-8" unexpected_error: "A Importação do produto encontrou um erro inesperado ao abrir o arquivo: %{error_message}" + malformed_csv: "A importação de produto encontrou um CSV com erro: %{error_message}" index: notice: "Aviso " beta_notice: "Esse recurso ainda está na versão beta: você pode encontrar alguns erros ao usá-lo. Por favor, não hesite em entrar em contato com o suporte." @@ -1144,7 +1148,12 @@ pt_BR: cart: "Carrinho" cart_sidebar: checkout: "Fechar pedido" + edit_cart: "Editar carrinho" + items_in_cart_singular: "%{num}intem no seu carrinho" + items_in_cart_plural: "%{num}itens no seu carrinho" close: "Fechado" + cart_empty: "Seu carrinho está vazio" + take_me_shopping: "Quero comprar" signed_in: profile: "Perfil" mobile_menu: @@ -1373,10 +1382,10 @@ pt_BR: cta_headline: "Compras que fazem do mundo um lugar melhor." cta_label: "Estou pronto" stats_headline: "Estamos trabalhando para relocalizar os sistemas agroalimentares" - stats_producers: "produtores de alimentos" - stats_shops: "lojas de alimentos" - stats_shoppers: "consumidores de alimentos" - stats_orders: "pedidos de alimentos" + stats_producers: "produtores" + stats_shops: "lojas" + stats_shoppers: "consumidores" + stats_orders: "pedidos" checkout_title: Fechar pedido checkout_now: Fechar pedido agora checkout_order_ready: Pedido pronto para @@ -1613,7 +1622,7 @@ pt_BR: producers_title: Produtores producers_headline: Encontre produtores locais producers_signup_title: Inscreva-se como produtor - producers_signup_headline: Produtores de alimentos, empoderados. + producers_signup_headline: Visibilidade para o pequeno produtor. producers_signup_motivation: Comercialize seus produtos e conte sua história para um mercado novo e diferenciado. Economize tempo e dinheiro em todas as despesas gerais. Nós apoiamos inovação sem risco. Nós nivelamos o campo de jogo. producers_signup_send: Junte-se agora producers_signup_enterprise: Contas de iniciativas @@ -2061,6 +2070,7 @@ pt_BR: hub_sidebar_at_least: "Pelo menos uma central deve ser selecionado" hub_sidebar_blue: "azul" hub_sidebar_red: "vermelho" + order_cycles_closed_for_hub: "A Central selecionada está temporariamente fechada para pedidos. Por favor tente mais tarde. " report_customers_distributor: "Distribuidor" report_customers_supplier: "Fornecedor" report_customers_cycle: "Ciclo de pedidos" @@ -2297,6 +2307,7 @@ pt_BR: order_cycles_email_to_producers_notice: 'E-mails a serem enviados aos produtores foram encaminhados para envio.' order_cycles_no_permission_to_coordinate_error: "Nenhuma das suas iniciativas tem permissão para coordenar um ciclo de pedidos" order_cycles_no_permission_to_create_error: "Você não tem permissão para criar um ciclo de pedidos coordenado por esta iniciativa" + order_cycle_closed: "O ciclo de pedidos selecionado acabou de fechar, por favor tente novamente depois!" back_to_orders_list: "Voltar à lista de pedidos" no_orders_found: "Nenhum pedido encontrado" order_information: "Informações sobre pedidos" @@ -2816,6 +2827,12 @@ pt_BR: void: "Vazio" login: "Login" password: "Senha" + signature: "Assinatura" + solution: "Solução" + landing_page: "Página Inicial" + server: "Servidor" + test_mode: "Modo Teste" + logourl: "url da logo" configurations: "Configurações" general_settings: "Configurações Gerais" site_name: "Nome do site" @@ -2932,6 +2949,12 @@ pt_BR: options: "Opções" actions: update: "Atualizar" + shared: + error_messages: + errors_prohibited_this_record_from_being_saved: + one: "1 erro não permitiu que este registro fosse salvo:" + other: "%{count}erros não permitiram que esse registro fosse salvo:" + there_were_problems_with_the_following_fields: "Houve problemas com os seguintes campos" errors: messages: blank: "Não pode ser vazio" @@ -3089,19 +3112,23 @@ pt_BR: zones: "Zonas" both: "Tanto Checkout quanto Área Administrativa" back_end: "Somente Área Administrativa" - deactivation_warning: "Desativar um método de envio pode fazer com que ele desapareça da sua lista. Como alternativa, você pode esconder um método de envio da página de checkout s" + deactivation_warning: "Desativar um método de envio pode fazer com que ele desapareça da sua lista. Como alternativa, você pode esconder um método de envio da página de checkout trocando a opção 'Exibição' para 'Somente área administrativa'." payment_methods: index: payment_methods: "Métodos de pagamento" new_payment_method: "Novo método de pagamento" name: "Nome" products_distributor: "Distribuidor" + provider: "Provedor" environment: "Ambiente" display: "Exibição" + active: "Ativo" both: "Ambos" + front_end: "Apenas checkout" back_end: "Somente Área Administrativa" active_yes: "Sim" active_no: "Não" + no_payment_methods_found: "Não foi encontrado nenhum método de pagamento" new: new_payment_method: "Novo método de pagamento" back_to_payment_methods_list: "Voltar à lista de formas de pagamento" @@ -3127,11 +3154,16 @@ pt_BR: description: "Descrição" environment: "Ambiente" display: "Exibição" + active: "Ativo" active_yes: "Sim" active_no: "Não" both: "Tanto Checkout quanto Área Administrativa" + front_end: "Apenas Checkout" back_end: "Somente Área Administrativa" tags: "Tags" + deactivation_warning: "Desativar o método de pagamento pode fazer com que ele desapareça da sua lista. Como alternativa, você pode escondê-lo da página de checkout, trocando " + providers: + provider: "Provedor" payments: source_forms: stripe: @@ -3300,6 +3332,14 @@ pt_BR: invalid: inváliod order_mailer: cancel_email: + customer_greeting: "Querid@ %{name}," + instructions_html: "Seu pedido com %{distributor} foi CANCELADO. Por favor guarde este aviso de cancelamento para seu registro." + dont_cancel: "Se você mudou de ideia ou não quer mais cancelar este pedido, por favor entre em contato com %{email}" + order_summary_canceled_html: "Resumo do Pedido #%{number} [CANCELADO]" + details: "Aqui estão os detalhes do seu pedido:" + unpaid_order: "O pagamento do pedido foi cancelado, portanto não houve devolução " + paid_order: "Seu pedido foi pago, então %{distributor}devolveu o valor total" + credit_order: "Seu pedido foi pago, então você ganhou créditos na sua conta" subject: "Cancelamento do Pedido" confirm_email: subject: "Confimação de Pedido" From f08a5308771b5ab754827528274cc4746c44e8c5 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 4 Jul 2020 09:51:00 +0200 Subject: [PATCH 171/261] Make #valid_locale_for_user an instance method --- app/helpers/i18n_helper.rb | 2 +- app/services/user_locale_setter.rb | 16 ++++----------- spec/services/user_locale_setter_spec.rb | 26 ++++++++---------------- 3 files changed, 13 insertions(+), 31 deletions(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index f1142472f1..f4fd4985ed 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -4,6 +4,6 @@ module I18nHelper end def valid_locale(user) - UserLocaleSetter.valid_locale_for_user(user) + UserLocaleSetter.new(user).valid_locale_for_user end end diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index c51760ee70..bf030af905 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class UserLocaleSetter - def initialize(current_user, params_locale, cookies) + def initialize(current_user, params_locale = nil, cookies = {}) @current_user = current_user @params_locale = params_locale @cookies = cookies @@ -19,16 +19,8 @@ class UserLocaleSetter current_user.update!(locale: valid_current_locale) end - def self.valid_locale_for_user(user) - if user.andand.locale.present? && available_locale?(user.locale) - user.locale - else - I18n.default_locale - end - end - - def self.available_locale?(locale) - Rails.application.config.i18n.available_locales.include?(locale) + def valid_locale_for_user + valid_current_locale end private @@ -43,7 +35,7 @@ class UserLocaleSetter end def available_locale?(locale) - self.class.available_locale?(locale) + Rails.application.config.i18n.available_locales.include?(locale) end def current_user_locale diff --git a/spec/services/user_locale_setter_spec.rb b/spec/services/user_locale_setter_spec.rb index 443e6e2f7f..46981faec5 100644 --- a/spec/services/user_locale_setter_spec.rb +++ b/spec/services/user_locale_setter_spec.rb @@ -120,38 +120,28 @@ describe UserLocaleSetter do end end - describe "self#valid_locale_for_user" do + describe "#valid_locale_for_user" do + let(:service) { UserLocaleSetter.new(user) } + context "when the user has a locale set" do it "returns the user's locale" do user.update(locale: "es") - expect(UserLocaleSetter.valid_locale_for_user(user)).to eq "es" + expect(service.valid_locale_for_user).to eq "es" end end context "when the user has no locale set" do it "returns the default locale" do - expect(UserLocaleSetter.valid_locale_for_user(user)).to eq default_locale + expect(service.valid_locale_for_user).to eq default_locale end end context "when the given user argument is nil" do + let(:user) { nil } + it "returns the default locale" do - expect(UserLocaleSetter.valid_locale_for_user(nil)).to eq default_locale + expect(service.valid_locale_for_user).to eq default_locale end end end - - describe "self#available_locale?" do - it "returns true if locale is available" do - expect(UserLocaleSetter.available_locale?("es")).to be true - end - - it "returns false if locale is not available" do - expect(UserLocaleSetter.available_locale?("xx")).to be false - end - - it "returns false if nil is given for locale" do - expect(UserLocaleSetter.available_locale?(nil)).to be false - end - end end From 96138e9129cbe76af9fcdb5d31a1b5215d60247a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Sat, 4 Jul 2020 09:53:36 +0200 Subject: [PATCH 172/261] Refactor UserLocaleSetter public methods --- app/helpers/i18n_helper.rb | 2 +- app/services/user_locale_setter.rb | 22 +++++++++------------- spec/services/user_locale_setter_spec.rb | 8 ++++---- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/app/helpers/i18n_helper.rb b/app/helpers/i18n_helper.rb index f4fd4985ed..8c827e1bba 100644 --- a/app/helpers/i18n_helper.rb +++ b/app/helpers/i18n_helper.rb @@ -4,6 +4,6 @@ module I18nHelper end def valid_locale(user) - UserLocaleSetter.new(user).valid_locale_for_user + UserLocaleSetter.new(user).valid_current_locale end end diff --git a/app/services/user_locale_setter.rb b/app/services/user_locale_setter.rb index bf030af905..cd0fa96631 100644 --- a/app/services/user_locale_setter.rb +++ b/app/services/user_locale_setter.rb @@ -19,8 +19,14 @@ class UserLocaleSetter current_user.update!(locale: valid_current_locale) end - def valid_locale_for_user - valid_current_locale + def valid_current_locale + if current_user_locale && available_locale?(current_user_locale) + current_user_locale + elsif cookies[:locale] && available_locale?(cookies[:locale]) + cookies[:locale] + else + I18n.default_locale + end end private @@ -39,16 +45,6 @@ class UserLocaleSetter end def current_user_locale - current_user.andand.locale - end - - def valid_current_locale - if current_user_locale && available_locale?(current_user_locale) - current_user_locale - elsif cookies[:locale] && available_locale?(cookies[:locale]) - cookies[:locale] - else - I18n.default_locale - end + current_user&.locale end end diff --git a/spec/services/user_locale_setter_spec.rb b/spec/services/user_locale_setter_spec.rb index 46981faec5..1c2979a286 100644 --- a/spec/services/user_locale_setter_spec.rb +++ b/spec/services/user_locale_setter_spec.rb @@ -120,19 +120,19 @@ describe UserLocaleSetter do end end - describe "#valid_locale_for_user" do + describe "#valid_current_locale" do let(:service) { UserLocaleSetter.new(user) } context "when the user has a locale set" do it "returns the user's locale" do user.update(locale: "es") - expect(service.valid_locale_for_user).to eq "es" + expect(service.valid_current_locale).to eq "es" end end context "when the user has no locale set" do it "returns the default locale" do - expect(service.valid_locale_for_user).to eq default_locale + expect(service.valid_current_locale).to eq default_locale end end @@ -140,7 +140,7 @@ describe UserLocaleSetter do let(:user) { nil } it "returns the default locale" do - expect(service.valid_locale_for_user).to eq default_locale + expect(service.valid_current_locale).to eq default_locale end end end From 7a4a673578c9bc215802e74929a5831eedd3edd1 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sat, 4 Jul 2020 23:51:45 +1000 Subject: [PATCH 173/261] Updating translations for config/locales/fr.yml --- config/locales/fr.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e7805cfee8..eb8d4e055d 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -181,8 +181,8 @@ fr: title: Autre échec (%{count} commandes) explainer: Le traitement automatique de ces commandes a échoué pour une raison inconnue. Cela n'aurait pas dû arriver, veuillez nous contacter si vous constatez quelque chose d'anormal. home: "OFF" - title: Open Food France - welcome_to: 'Bienvenue sur ' + title: "Open Food France" + welcome_to: "Bienvenue sur" site_meta_description: "Tout commence dans le sol. Avec ces paysans, agriculteurs, producteurs, engagés pour une agriculture durable et régénératrice, et désireux de partager leur histoire et leur passion avec fierté. Avec ces distributeurs souhaitant reconnecter les individus à leurs aliments et aux gens qui les produisent, soutenir les prises de conscience, dans une démarche de transparence, d'honnêteté, en assurant une juste rémunération des producteurs. Avec ces acheteurs qui croient que de meilleures décisions d'achats peuvent ..." search_by_name: Recherche par nom ou département... producers_join: Les producteurs et autres hubs basés en France sont invités à rejoindre Open Food France. @@ -1715,8 +1715,8 @@ fr: password: Mot de passe remember_me: Se souvenir de moi are_you_sure: "Confirmer?" - orders_open: Boutique ouverte - closing: "Fermeture " + orders_open: "Boutique ouverte" + closing: "Fermeture" going_back_to_home_page: "Retour à la page d'accueil" creating: Création updating: Mettre à jour From 787648eff285e2b70e83c8082060db72e7ae62b8 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sat, 4 Jul 2020 23:52:01 +1000 Subject: [PATCH 174/261] Updating translations for config/locales/en_FR.yml --- config/locales/en_FR.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/en_FR.yml b/config/locales/en_FR.yml index 39c246d2d9..c514500eff 100644 --- a/config/locales/en_FR.yml +++ b/config/locales/en_FR.yml @@ -181,8 +181,8 @@ en_FR: 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 ' + 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: Producers are now welcome to join the Open Food Network. @@ -1713,8 +1713,8 @@ en_FR: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" + closing: "Closing" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating From 6f6e8c0c9210f8e2be0379dbd85d741ef702dc3d Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sun, 5 Jul 2020 04:29:50 +1000 Subject: [PATCH 175/261] Updating translations for config/locales/en_IN.yml --- config/locales/en_IN.yml | 3445 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 3445 insertions(+) create mode 100644 config/locales/en_IN.yml diff --git a/config/locales/en_IN.yml b/config/locales/en_IN.yml new file mode 100644 index 0000000000..32afdef00c --- /dev/null +++ b/config/locales/en_IN.yml @@ -0,0 +1,3445 @@ +en_IN: + language_name: "English" + activerecord: + attributes: + enterprise_fee: + fee_type: Fee Type + 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 + spree/product: + primary_taxon: "Product Category" + supplier: "Supplier" + shipping_category_id: "Shipping Category" + variant_unit: "Variant Unit" + variant_unit_name: "Variant Unit Name" + spree/credit_card: + base: "Credit Card" + order_cycle: + orders_close_at: Close date + variant_override: + count_on_hand: "In Stock" + 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 + spree/credit_card: + attributes: + base: + card_expired: "has expired" + 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 using producer stock settings" + on_demand_but_count_on_hand_set: "must be blank if on demand" + limited_stock_but_no_count_on_hand: "must be specified because forcing limited stock" + activemodel: + attributes: + order_management/reports/enterprise_fee_summary/parameters: + start_at: "Start" + end_at: "End" + distributor_ids: "Hubs" + producer_ids: "Pricing" + order_cycle_ids: "Order Cycles" + enterprise_fee_ids: "Fees Names" + shipping_method_ids: "Shipping Methods" + payment_method_ids: "Payment Methods" + errors: + messages: + inclusion: "is not included in the list" + models: + order_management/subscriptions/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. Your changes have not been saved." + 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_confirmations: + spree_user: + send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." + confirmation_sent: "Email confirmation sent" + confirmation_not_sent: "Error sending confirmation email" + 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." + success: + logged_in_succesfully: "Logged in successfully" + user_passwords: + spree_user: + updated_not_active: "Your password has been reset, but your email has not been confirmed yet." + updated: "Your password was changed successfully. You are now signed in." + send_instructions: "You will receive an email with instructions about how to confirm your account in a few minutes." + 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}" + email_welcome: "Welcome" + 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}" + userguide: "Open Food Network User Guide" + email_admin_html: "You can manage your account by logging into the %{link} or by clicking on 'Profile' in the top right hand side of the homepage, and selecting Administration." + admin_panel: "Admin Panel" + 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" + invite_manager: + subject: "%{enterprise} has invited you to be a manager" + 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 order with us." + 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 India" + welcome_to: "Welcome to " + site_meta_description: "The Open Food Network India software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" + search_by_name: Search by name, town, State or postcode... + producers_join: India producers are now welcome to join Open Food Network India. + charges_sales_tax: Charges VAT? + 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: "Please enter your company number." + invoice: "Invoice" + more: "More" + say_no: "No" + say_yes: "Yes" + 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 + bulk_order_management: Bulk Order Management + enterprises: Enterprises + enterprise_groups: Groups + reports: Reports + variant_overrides: Inventory + import: Import + 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..." + no_pending_payments: "No pending payments" + invalid_payment_state: "Invalid payment state" + filter_results: Filter Results + quantity: Quantity + pick_up: Pick up + copy: Copy + change_my_password: "Change my password" + update_password: "Update password" + password_confirmation: Password Confirmation + reset_password_token: Reset password + expired: has expired, please request a new one + back_to_payments_list: "Back to Payments List" + maestro_or_solo_cards: "Maestro/Solo cards" + backordered: "Backordered" + on hand: "In Stock" + ship: "Ship" + shipping_category: "Shipping Category" + actions: + create_and_add_another: "Create and Add Another" + create: "Create" + cancel: "Cancel" + save: "Save" + edit: "Edit" + update: "Update" + delete: "Delete" + 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: In Stock + on_demand: Unlimited + on_demand?: Unlimited? + 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 + 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... + column_save_as_default: Save As Default + 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" + 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 Localisation Settings" + enable_localized_number: "Use the international thousand/decimal separator logic" + invoice_settings: + edit: + title: "Invoice Settings" + enable_invoices?: "Enable Invoices?" + 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" + matomo_tag_manager_url: "Matomo Tag Manager URL" + info_html: "Matomo is a Web and Mobile Analytics application. 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." + config_instructions_tag_manager_html: "Setting the Matomo Tag Manager URL enables Matomo Tag Manager. This tool allows you to set up analytics events. The Matomo Tag Manager URL is copied from the Install Code section of Matomo Tag Manager. Ensure you select the right container and environment as these options change the URL." + customers: + index: + new_customer: "New Customer" + 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 this 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 + map: Map + enterprise_fees: + index: + title: "Enterprise Fees" + enterprise: "Enterprise" + fee_type: "Fee Type" + name: "Name" + tax_category: "Tax Category" + calculator: "Calculator" + calculator_values: "Calculator Values" + search: "Search" + name_placeholder: "e.g. packing fee" + 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 + seo: + 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: + infinity: "Infinity" + to_order_tip: "Items made to order do not have a set stock level, such as loaves of bread made fresh to order." + back_to_products_list: "Back to products list" + editing_product: "Editing Product" + tabs: + product_details: "Product Details" + group_buy_options: "Group Buy Options" + images: "Images" + variants: "Variants" + product_properties: "Product Properties" + 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}" + malformed_csv: "Product Import found CSV was incorrectly formatted: %{error_message}" + index: + notice: "Notice" + beta_notice: "This feature is still in beta: you may experience some errors while using it. Please don't hesitate to contact support." + 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 defined + 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 on 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? + default_stock: "Default stock" + 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: Company Number + abn_placeholder: eg. 99 123 456 789 + acn: Charity Number + 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. Amanda Plum + email_address: Public Email Address + email_address_placeholder: eg. hello@food.co.in + 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.co.in + 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 + no_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. + ofn_uid: OFN UID + ofn_uid_tip: The unique id used to identify the enterprise on Open Food Network. + shipping_methods: + name: "Name" + applies: "Active?" + 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 message to welcome customers and explain how to shop with + you. If text is entered here it will be displayed in a home tab when + customers first arrive at your shopfront. + shopfront_message_link_tooltip: "Insert / edit link" + shopfront_message_link_prompt: "Please enter a URL to insert" + 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. the_prof" + 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: 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:' + profile: 'Profile' + producer_profile: 'Producer Profile' + invite_manager: + user_already_exists: "User already exists" + error: "Something went wrong" + order_cycles: + loading_flash: + loading_order_cycles: LOADING ORDER CYCLES + loading: LOADING... + new: + create: "Create" + cancel: "Cancel" + back_to_list: "Back To List" + edit: + advanced_settings: "Advanced Settings" + save: "Save" + save_and_next: "Save and Next" + next: "Next" + cancel: "Cancel" + back_to_list: "Back To List" + save_and_back_to_list: "Save and Back to List" + choose_products_from: "Choose Products From:" + incoming: + incoming: "Incoming" + supplier: "Supplier" + products: "Products" + receival_details: "Receival Details" + fees: "Fees" + save: "Save" + save_and_next: "Save and Next" + next: "Next" + cancel: "Cancel" + back_to_list: "Back To List" + outgoing: + outgoing: "Outgoing" + distributor: "Distributor" + products: "Products" + tags: "Tags" + delivery_details: "Delivery Details" + fees: "Fees" + previous: "Previous" + save: "Save" + save_and_back_to_list: "Save and Back to List" + cancel: "Cancel" + back_to_list: "Back To List" + wizard_progress: + edit: "1. General Settings" + incoming: "2. Incoming Products" + outgoing: "3. Outgoing Products" + 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' + remove: 'Remove' + selected: 'selected' + add_exchange_form: + add_supplier: 'Add supplier' + add_distributor: 'Add distributor' + advanced_settings: + title: Advanced Settings + choose_product_tip: You can restrict products incoming and outgoing to only %{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: + general_settings: "General Settings" + 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 + index: + schedule: Schedule + schedules: Schedules + new_schedule: New Schedule + 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 + 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 + 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 + edit: Edit Subscription + table: + edit_subscription: Edit Subscription + pause_subscription: Pause Subscription + unpause_subscription: Unpause Subscription + cancel_subscription: Cancel Subscription + filters: + query_placeholder: "Search by email..." + 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." + autocomplete: + name_or_sku: "NAME OR SKU" + quantity: "Quantity" + add: "Add" + 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 + begins_at_placeholder: "Select a Date" + ends_at_placeholder: "Optional" + loading_flash: + loading: LOADING SUBSCRIPTIONS + review: + details: Details + address: Address + products: Products + no_open_or_upcoming_order_cycle: "No Upcoming Order Cycle" + products_panel: + save: "SAVE" + saving: "SAVING" + saved: "SAVED" + product_already_in_order: This product has already been added to the order. Please edit the quantity directly. + stock: + insufficient_stock: "Insufficient stock available" + out_of_stock: "Out of Stock" + 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: "If you have an open Order Cycle in this subscription's schedule, an order will be created for this customer. 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" + orders: + failed_to_update: "Failed to update order" + checkout: + already_ordered: + cart: "cart" + message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open." + failed: "The checkout failed. Please let us know so that we can process your order." + 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: + cart: "Basket" + cart_sidebar: + checkout: "Checkout" + edit_cart: "Edit basket" + items_in_cart_singular: "%{num} item in your basket" + items_in_cart_plural: "%{num} items in your basket" + close: "Close" + cart_empty: "Your basket is empty" + take_me_shopping: "Take me shopping!" + signed_in: + profile: "Profile" + mobile_menu: + cart: "Basket" + register_call: + selling_on_ofn: "Interested in selling through the Open Food Network?" + register: "Register here" + footer: + 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" + shop: + messages: + customer_required: + login: "login" + signup: "signup" + contact: "contact" + require_customer_login: "Only approved customers can access this shop." + require_login_html: "If you're already an approved customer, %{login} or %{signup} to proceed." + require_login_2_html: "Want to start shopping here? Please %{contact} %{enterprise} and ask about joining." + require_customer_html: "If you'd like to start shopping here, please %{contact} %{enterprise} to ask about joining." + select_oc: + select_oc_html: "Please choose when you want your order, to see what products are available." + 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: "VAT" + 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: "VAT Total:" + tax_invoice: "TAX INVOICE" + tax_total: "Total tax (%{rate}):" + total_excl_tax: "Total (Excl. tax):" + total_incl_tax: "Total (Incl. tax):" + abn: "Company Number:" + acn: "Charity Number:" + 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: "Pricing" + menu_3_url: "https://about.openfoodindia.org/pricing/" + menu_4_title: "Groups" + menu_4_url: "/groups" + menu_5_title: "About" + menu_5_url: "https://about.openfoodindia.org" + menu_6_title: "Blog" + menu_6_url: "https://about.openfoodindia.org/blog" + menu_7_title: "Support" + menu_7_url: "https://about.openfoodindia.org/support" + 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. Newcastle + postcode: Postcode + postcode_placeholder: eg. 3070 + suburb: Suburb + state: State + country: Country + unauthorized: Unauthorized + terms_of_service: "Terms of service" + on_demand: Unlimited + 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 + authorization_failure: "Authorisation Failure" + 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: "Community Forum" + 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 + invalid_credit_card: "Invalid credit card" + 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_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: "Would you like to opt-out of Matomo analytics? We use Matomo to help us improve our service, but we don't collect any personal data." + 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: "Growing Local Food Online" + brandstory_intro: "THE online community helping you to build a successful food enterprise" + brandstory_part1: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" + brandstory_part2: "Food Producers can create an online shop, collect payments, sell through other shops on the platform and access reduced-rate courier services." + brandstory_part3: "Wholesalers can integrate OFN with their existing systems and manage buying groups to  supply customers with their produce through our national network of food hubs and shops." + brandstory_part4: "Communities can bring together producers in their local area to create virtual farmers’ markets, building a resilient local food economy." + brandstory_part5_strong: "And what’s just as important as the software itself are the values which underpin it. " + brandstory_part6: "If you sell good food - as a farmer, farmer’s market, food co-op, or food hub- then choose software that aligns with your values to build food systems for people and planet, not profit. By working collectively rather than competitively, we share the costs of developing new software, and we ensure that our project is resilient!" + 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: "Selling on OFN - 3 easy steps" + system_step1: "1. Create Your Enterprise" + system_step1_text: "Set up your enterprise with a name, description, photos, contact details and social media links." + system_step2: "2. Add Your Products" + system_step2_text: "Add products to your shop - your own and/or from other producers around you. Set images, descriptions, prices, stock levels and flexible weights and measures." + system_step3: "3. Plan your Deliveries" + system_step3_text: "Set up payment methods. Create multiple pick-up points and delivery details. Create recurring orders and regular distributions." + cta_headline: "The sustainable Food Network of the future." + 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_confirmed: "Thank you for confirming your email address." + 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_sku: "Product Code" + 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 delivery." + 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_oc_select: "Select..." + shopping_tabs_home: "Notices" + shopping_tabs_shop: "Shop" + shopping_tabs_about: "About" + 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: "Showing results for" + 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: Clear + products_showing: "Showing:" + products_results_for: "Results for" + products_or: "or" + products_and: "and" + products_filters_in: "in" + products_with: with + products_search: "Search..." + products_filter_by: "Filter by" + products_filter_selected: "selected" + products_filter_heading: "Filters" + products_filter_clear: "Clear" + products_filter_done: "Done" + 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." + products_no_results_html: "Sorry, no results found for %{query}" + products_clear_search: "Clear search" + 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" + 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. Meet OFN. + producers_signup_motivation: Sell your food and tell your stories. Save time and money on every overhead. We support innovation without the risk. We're levelling the playing field. + producers_signup_send: Register + producers_signup_enterprise: Why the Open Food Network? + producers_signup_studies: Stories from our producers. + producers_signup_cta_headline: Join now! + producers_signup_cta_action: Register + producers_signup_detail: Got a question? + products_item: Item + products_description: Description + products_variant: Variant + products_quantity: Quantity + products_available: Available? + products_producer: "Producer" + products_price: "Price" + name_or_sku: "NAME OR SKU" + register_title: Find out more + 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 a profile on OFN India is free. Plans for shops and hubs start from as little as £1 per month. For more detail on pricing visit https://about.openfoodindia.org/pricing/ ." + sell_embed: "We collectively budget for new feature development from the international OFN community. This way the huge cost of good software development can be shared. If you want a new feature, chances are someone in France, South Africa, Australia, India or Brazil might want it too! Use the Community Forum to suggest features you'd like to see." + 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? + order_processed_successfully: "Your order has been processed successfully" + 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. + 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" + forgot_password: "Forgot password?" + password_reset_sent: "An email with instructions on resetting your password has been sent!" + reset_password: "Reset password" + update_and_recalculate_fees: "Update And Recalculate Fees" + registration: + steps: + introduction: + registration_greeting: "Hi there!" + registration_intro: "You can now create a profile for your Producer or Hub" + registration_checklist: "What do I 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: "Yippee! First need to know a little bit about your enterprise:" + producer: "Great! 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 Chilli Farm" + producer_name_field_error: "Sorry, this name has already been taken. Please try another." + address1_field: "Address line 1:" + address1_field_placeholder: "e.g. 123 Apple Drive" + address1_field_error: "Please enter an address" + address2_field: "Address line 2:" + suburb_field: "Town:" + suburb_field_placeholder: "eg. Taunton" + suburb_field_error: "Please enter a postal town" + postcode_field: "Postcode:" + postcode_field_placeholder: "eg. TA1 TAA" + 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: "Please enter a primary contact." + phone_field: "Phone number" + phone_field_placeholder: "eg. 07123123123" + type: + title: "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 tasty things to eat and/or drink. You're a producer if you grow, rear, brew, bake, ferment ... etc." + 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" + 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: "Company Number" + enterprise_abn_placeholder: "eg. 99 123 456 789" + enterprise_acn: "Charity Number" + 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 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: "Go to Enterprise Dashboard" + back: "Back" + continue: "Continue" + action_or: "OR" + enterprise_limit: Enterprise Limit + shipping_method_destroy_error: "That shipping method cannot be deleted as it is referenced by an order: %{number}." + 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" + show_only_complete_orders: "Only show complete orders" + successfully_created: '%{resource} has been successfully created!' + successfully_removed: '%{resource} has been successfully removed!' + successfully_updated: '%{resource} has been successfully updated!' + 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_relationships_to: "to" + 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. Newcastle" + 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.co.in" + 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" + calculator_settings_warning: "If you are changing the calculator type, you must save first before you can edit the calculator settings" + 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: "In stock" + review: "Review" + 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 + unit_name: "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, Newcastle, NE1 1AA'" + 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" + 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: "Surname 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" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." + 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: Product Code + 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: 20%(VAT on Income) + report_header_gst_free_income: Zero Rated 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: "Invoice 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" + payment_processing_failed: "Payment could not be processed, please check the details you entered" + payment_method_not_supported: "That payment method is unsupported. Please choose another one." + payment_updated: "Payment Updated" + 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_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_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' + enterprise_shop_show_error: "The shop you are looking for doesn't exist or is inactive on OFN. Please check other shops." + 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" + order_cycle_closed: "The order cycle you've selected has just closed." + 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 + cart: + add_to_cart_failed: > + There was a problem adding this product to your basket. Perhaps it has become + unavailable or the shop is closing. + 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: Visit our Pricing page for more detail" + 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: > + As a producer, making connections within your local food system through + the Open Food Network will always be free. + hub_shop: Hub Shop + hub_shop_text1: > + Hubs can take many forms - CSA, veg box scheme, food co-op, community + buying group, farmers’ market, an online shop front for an independent + shop and many others… + hub_shop_text2: > + Products aggregated from lots of local food enterprises can be stocked + and sold via your shop front. Hubs can form the backbone of your local + food economy. + hub_shop_text3: > + Open Food Network aims to provide the tools and support for you to run + your organisation or business in a manner which suits you. + + 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: "There is no cost for a Producer Profile without a shop front." + profile_only_text1: > + A profile makes you visible and contactable to others and is a way to + share your story. + profile_only_text2: > + You can set up your products and invite other people to sell them for + you. + profile_only_text3: > + You can choose which Open Food Network ‘hubs’ you would like to stock + and sell your products.  Leave the hassle of selling your food to someone + else and focus on growing, making, brewing, baking... + producer_shop: Producer Shop + producer_shop_text1: > + Sell only your own products directly to customers and buyers with your + own Open Food Network shopfront. + producer_shop_text2: > + If you would also like to stock items grown/baked/made by others, please + select ‘Hub’. + producer_hub: Producer Hub + producer_hub_text1: > + Hubs can take many forms - CSA, veg box scheme, food co-op, community + buying group, farmers’ market, an online shop front for an independent + shop and many others… + producer_hub_text2: > + Products aggregated from lots of local food enterprises (including your + own, if you are also a food producer) can be stocked and sold via your + shop front. Hubs can form the backbone of your local food economy. + producer_hub_text3: > + Open Food Network aims to provide the tools and support for you to run + your organisation or business in a manner which suits you. + get_listing: Get a listing + always_free: Visit our Pricing page for more detail + sell_produce_others: Sell produce from others + sell_own_produce: Sell your own produce + sell_both: Sell products from multiple producers. + enterprise_producer: + producer: Producer + producer_text1: > + Farmers, growers, small holders, crofters, cottage enterprises, market + gardens, CSAs, community gardens, city farms that make yummy things + to eat or drink. You're a food producer if you grow it, raise it, brew + it, bake it, ferment it, milk it or mould it. + producer_text2: > + Food producers can also sell their products (and those of others) through + Shops or Hubs on the Open Food Network. + non_producer: Non-producer + non_producer_text1: > + A ‘Non-producer’, such as a Farmers’ Market or veg box co-ordinator, + specialises in aggregating food from local producers (eg. farmers, growers, + cottage enterprises, community/city gardens) to sell to customers. They + do not offer food that they produced themselves for sale. + non_producer_text2: > + This option is best suited for those wishing to operate Open Food Network + ‘Hubs’ but not produce their own food. + producer_desc: Producer + producer_example: eg. Farmers, growers, small holders, crofters, cottage enterprises, market gardens, CSAs, community gardens, city farms... + non_producer_desc: Non-producer + non_producer_example: eg. Farmers’ Market/Veg Box Scheme/Community group co-ordinators, Food Hubs, Retail Shops, Wholesale Distributors, Buying Groups, Food Co-ops… + enterprise_status: + status_title: "%{name} is set up and ready to go!" + severity: Severity + description: Description + resolve: Resolve + exchange_products: + load_more_variants: "Load More Variants" + load_all_variants: "Load All Variants" + select_all_variants: "Select All %{total_number_of_variants} Variants" + variants_loaded: "%{num_of_variants_loaded} of %{total_number_of_variants} Variants Loaded" + loading_variants: "Loading Variants" + tag_rules: + shipping_method_tagged_top: "Shipping methods tagged" + shipping_method_tagged_bottom: "are:" + payment_method_tagged_top: "Payment methods tagged" + payment_method_tagged_bottom: "are:" + order_cycle_tagged_top: "Order Cycles tagged" + order_cycle_tagged_bottom: "are:" + inventory_tagged_top: "Inventory variants tagged" + inventory_tagged_bottom: "are:" + new_tag_rule_dialog: + select_rule_type: "Select a rule type:" + add_rule: "Add Rule" + enterprise_fees: + inherit_from_product: "Inherit From Product" + 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 window." + 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" + 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" + resend_user_email_confirmation: + resend: "Resend" + sending: "Resend..." + done: "Resend done ✓" + failed: "Resend failed ✗" + order_cycles: + schedules: + adding_a_new_schedule: "Adding A New Schedule" + updating_a_schedule: "Updating A Schedule" + create_schedule: "Create Schedule" + update_schedule: "Update Schedule" + delete_schedule: "Delete Schedule" + schedule_name_placeholder: "Schedule Name" + created_schedule: "Created schedule" + updated_schedule: "Updated schedule" + deleted_schedule: "Deleted schedule" + name_required_error: "Please enter a name for this schedule" + no_order_cycles_error: "Please select at least one order cycle (drag and drop)" + available: "Available" + selected: "Selected" + customers: + index: + add_customer: "Add Customer" + add_a_new_customer_for: "Add a new customer for %{shop_name}" + customer_placeholder: "customer@example.org" + valid_email_error: "Please enter a valid email address" + subscriptions: + error_saving: "Error saving subscription" + new: + please_select_a_shop: "Please select a shop" + insufficient_stock: "Insufficient stock available, only %{on_hand} remaining" + 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': "Unlimited" + 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 'in stock' 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 + 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." + inflections: + each: + one: "each" + other: "each" + bunch: + one: "bunch" + other: "bunches" + pack: + one: "pack" + other: "packs" + box: + one: "box" + other: "boxes" + bottle: + one: "bottle" + other: "bottles" + jar: + one: "jar" + other: "jars" + head: + one: "head" + other: "heads" + bag: + one: "bag" + other: "bags" + loaf: + one: "loaf" + other: "loaves" + single: + one: "single" + other: "singles" + tub: + one: "tub" + other: "tubs" + punnet: + one: "punnet" + other: "punnets" + packet: + one: "packet" + other: "packets" + item: + one: "item" + other: "items" + dozen: + one: "dozen" + other: "dozens" + unit: + one: "unit" + other: "units" + serve: + one: "serve" + other: "serves" + tray: + one: "tray" + other: "trays" + piece: + one: "piece" + other: "pieces" + pot: + one: "pot" + other: "pots" + bundle: + one: "bundle" + other: "bundles" + flask: + one: "flask" + other: "flasks" + basket: + one: "basket" + other: "baskets" + sack: + one: "sack" + other: "sacks" + producers: + signup: + start_free_profile: "Start with a free profile, and expand when you're ready!" + order_management: + reports: + 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." + enterprise_fee_summary: + date_end_before_start_error: "must be after start" + parameter_not_allowed_error: "You are not authorised 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." + order: "Order" + distribution: "Distribution" + order_details: "Order Details" + customer_details: "Customer Details" + adjustments: "Adjustments" + payments: "Payments" + return_authorizations: "Return Authorisations" + 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" + end: "End" + stop: "Stop" + first: "First" + previous: "Previous" + last: "Last" + spree: + more: "More" + 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 + return_authorizations: Return Authorisations + cannot_create_returns: Cannot create returns as this order has no shipped units. + select_stock: "Select stock" + location: "Location" + count_on_hand: "Count In Stock" + quantity: "Quantity" + on_demand: "Unlimited" + on_hand: "In Stock" + 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: "Postcode" + 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" + capture: "Capture" + void: "Void" + login: "Login" + password: "Password" + signature: "Signature" + solution: "Solution" + landing_page: "Landing Page" + server: "Server" + test_mode: "Test Mode" + logourl: "Logo url" + 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" + currency_decimal_mark: "Currency decimal mark" + currency_settings: "Currency Settings" + currency_symbol_position: Put "currency symbol before or after pound amount?" + currency_thousands_separator: "Currency thousands separator" + hide_cents: "Hide pence" + 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." + 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: "Counties Required" + editing_country: "Editing Country" + back_to_countries_list: "Back to Countries List" + states: "Counties" + abbreviation: "Abbreviation" + new_state: "New State" + payment_methods: "Payment Methods" + 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: "New Shipping Category" + back_to_shipping_categories: "Back To Shipping Categories" + 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" + flat_percent: "Flat Percent" + per_kg: "Per Kg" + amount: "Amount" + currency: "Currency" + first_item: "First Item Cost" + additional_item: "Additional Item Cost" + max_items: "Max Items" + minimal_amount: "Minimal Amount" + normal_amount: "Normal Amount" + discount_amount: "Discount Amount" + no_images_found: "No Images Found" + new_image: "New Image" + filename: "Filename" + alt_text: "Alternative Text" + thumbnail: "Thumbnail" + back_to_images_list: "Back To Images List" + email: Email + account_updated: "Account updated!" + email_updated: "The account will be updated once the new email is confirmed." + my_account: "My account" + 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) + error_user_destroy_with_orders: "Users with completed orders may not be deleted" + cannot_create_payment_without_payment_methods: "You cannot create a payment for an order without any payment methods defined." + please_define_payment_methods: "Please define some payment methods first." + options: "Options" + actions: + update: "Update" + shared: + error_messages: + errors_prohibited_this_record_from_being_saved: + one: "1 error prohibited this record from being saved:" + other: "%{count} errors prohibited this record from being saved:" + there_were_problems_with_the_following_fields: "There were problems with the following fields" + errors: + messages: + blank: "can't be blank" + layouts: + admin: + login_nav: + header: + store: Store + admin: + tab: + dashboard: "Dashboard" + orders: "Orders" + bulk_order_management: "Bulk Order Management" + subscriptions: "Subscriptions" + products: "Products" + option_types: "Option Types" + properties: "Properties" + variant_overrides: "Inventory" + reports: "Reports" + configuration: "Configuration" + users: "Users" + roles: "Roles" + order_cycles: "Order Cycles" + enterprises: "Enterprises" + enterprise_relationships: "Permissions" + customers: "Customers" + groups: "Groups" + product_properties: + index: + inherits_properties_checkbox_hint: "Inherit properties from %{supplier}? (unless overridden above)" + add_product_properties: "Add Product Properties" + select_from_prototype: "Select From Prototype" + properties: + index: + properties: "Properties" + new_property: "New Property" + name: "Name" + presentation: "Presentation" + new: + new_property: "New Property" + edit: + editing_property: "Editing Property" + back_to_properties_list: "Back To Properties List" + form: + name: "Name" + presentation: "Presentation" + return_authorizations: + index: + new_return_authorization: "New Return Authorisation" + return_authorizations: "Return Authorisations" + back_to_orders_list: "Back To Orders List" + rma_number: "RMA Number" + status: "Status" + amount: "Amount" + cannot_create_returns: "Cannot create returns as this order has no shipped units." + continue: "Continue" + new: + new_return_authorization: "New Return Authorisation" + back_to_return_authorizations_list: "Back To Return Authorisation List" + continue: "Continue" + edit: + receive: "receive" + are_you_sure: "Are you sure?" + return_authorization: "Return Authorisation" + form: + product: "Product" + quantity_shipped: "Quantity Shipped" + quantity_returned: "Quantity Returned" + return_quantity: "Return Quantity" + amount: "Amount" + rma_value: "RMA Value" + reason: "Reason" + stock_location: "Stock Location" + states: + authorized: "Authorised" + received: "Received" + canceled: "Canceled" + orders: + index: + listing_orders: "Listing Orders" + new_order: "New Order" + capture: "Capture" + ship: "Ship" + edit: "Edit" + order_not_updated: "The order could not be updated" + 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" + 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: "Bill to" + shipping: "Shipping" + form: + distribution_fields: + title: "Distribution" + distributor: "Distributor:" + order_cycle: "Order cycle:" + line_item_adjustments: "Line Item Adjustments" + order_adjustments: "Order Adjustments" + order_total: "Order Total" + overview: + enterprises_header: + ofn_with_tip: Enterprises are Producers and/or Hubs and are the basic unit of organisation within the Open Food Network. + 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" + shipping_methods: + index: + shipping_methods: "Shipping Methods" + new_shipping_method: "New Shipping Method" + name: "Name" + products_distributor: "Distributor" + zone: "Zone" + calculator: "Calculator" + display: "Display" + both: "Both Checkout and Back office" + back_end: "Back office only" + no_shipping_methods_found: "No shipping methods found" + new: + new_shipping_method: "New Shipping Method" + back_to_shipping_methods_list: "Back To Shipping Methods List" + edit: + editing_shipping_method: "Editing Shipping Method" + new: "New" + back_to_shipping_methods_list: "Back To Shipping Methods List" + form: + categories: "Categories" + zones: "Zones" + both: "Both Checkout and Back office" + back_end: "Back office only" + deactivation_warning: "De-activating a shipping method can make the shipping method disappear from your list. Alternatively, you can hide a shipping method from the checkout page by setting the option 'Display' to 'back office only'." + payment_methods: + index: + payment_methods: "Payment Methods" + new_payment_method: "New Payment Method" + name: "Name" + products_distributor: "Distributor" + provider: "Provider" + environment: "Environment" + display: "Display" + active: "Active" + both: "Both" + front_end: "Checkout only" + back_end: "Back office only" + active_yes: "Yes" + active_no: "No" + no_payment_methods_found: "No payment methods found" + new: + new_payment_method: "New Payment Method" + back_to_payment_methods_list: "Back To Payment Methods List" + edit: + new: "New" + 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 + form: + name: "Name" + description: "Description" + environment: "Environment" + display: "Display" + active: "Active" + active_yes: "Yes" + active_no: "No" + both: "Both Checkout and Back office" + front_end: "Checkout only" + back_end: "Back office only" + tags: "Tags" + deactivation_warning: "De-activating a payment method can make the payment method disappear from your list. Alternatively, you can hide a payment method from the checkout page by setting the option 'Display' to 'back office only'." + providers: + provider: "Provider" + payments: + source_forms: + stripe: + error_saving_payment: Error saving payment + submitting_payment: Submitting payment... + products: + image_upload_error: "The product image was not recognised. Please upload an image in PNG or JPG format." + new: + title: "New Product" + new_product: "New Product" + supplier: "Supplier" + product_name: "Product Name" + units: "Unit Size" + value: "Value" + unit_name: "Unit name" + price: "Price" + on_hand: "In Stock" + on_demand: "Unlimited" + product_description: "Product Description" + image: "Image" + or: "or" + 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' + 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: + index: + sku: "Product Code" + price: "Price" + options: "Options" + no_results: "No results" + to_add_variants_you_must_first_define: "To add variants, you must first define" + option_types: "Option Types" + option_values: "Option Values" + and: "and" + new_variant: "New Variant" + show_active: "Show Active" + show_deleted: "Show Deleted" + new: + new_variant: "New Variant" + form: + cost_price: "Cost Price" + sku: "Product Code" + price: "Price" + display_as: "Display As" + display_name: "Display Name" + display_as_placeholder: 'eg. 2 kg' + display_name_placeholder: 'eg. Tomatoes' + autocomplete: + out_of_stock: "Out of Stock" + producer_name: "Producer" + unit: "Unit" + shared: + sortable_header: + name: "Name" + number: "Number" + state: "State" + payment_state: "Payment State" + shipment_state: "Shipment State" + email: "Email" + total: "Total" + 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" + 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? + stripe_sca: + 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' + orders: + error_flash_for_unavailable_items: "An item in your basket has become unavailable. Please update the selected quantities." + edit: + login_to_view_order: "Please log in to view your order." + bought: + item: "Already ordered in this order cycle" + line_item: + insufficient_stock: "Insufficient stock available, only %{on_hand} remaining" + out_of_stock: "Out of Stock" + unavailable_item: "Currently unavailable" + 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 + order_mailer: + cancel_email: + customer_greeting: "Dear %{name}," + instructions_html: "Your order with %{distributor} has been CANCELED. Please retain this cancellation information for your records." + dont_cancel: "If you have changed your mind or don't wish to cancel this order please contact %{email}" + order_summary_canceled_html: "Order Summary #%{number} [CANCELED]" + details: "Here are the details of what you ordered:" + unpaid_order: "Your order was unpaid so no refund has been made" + paid_order: "Your order was paid so %{distributor} has refunded the full amount" + credit_order: "Your order was paid so your account has been credited" + subject: "Cancellation of Order" + confirm_email: + subject: "Order Confirmation" + 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 + 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 + 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. + api: + invalid_api_key: "Invalid API key (%{key}) specified." + unauthorized: "You are not authorised to perform that action." + invalid_resource: "Invalid resource. Please fix errors and try again." + resource_not_found: "The resource you were looking for could not be found." + access: "API Access" + key: "Key" + clear_key: "Clear key" + regenerate_key: "Regenerate Key" + no_key: "No key" + generate_key: "Generate API key" + key_generated: "Key generated" + key_cleared: "Key cleared" + shipment: + cannot_ready: "Cannot ready shipment." + invalid_taxonomy_id: "Invalid taxonomy id." From b951bcc379cd8eea46a2d4d26cc9ef1d61609e6d Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Sun, 5 Jul 2020 04:34:29 +1000 Subject: [PATCH 176/261] Updating translations for config/locales/en_IN.yml --- config/locales/en_IN.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/en_IN.yml b/config/locales/en_IN.yml index 32afdef00c..e3ea0153f7 100644 --- a/config/locales/en_IN.yml +++ b/config/locales/en_IN.yml @@ -1651,7 +1651,7 @@ en_IN: 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 a profile on OFN India is free. Plans for shops and hubs start from as little as £1 per month. For more detail on pricing visit https://about.openfoodindia.org/pricing/ ." + sell_listing_price: "Listing a profile on OFN India is free. Plans for shops and hubs start from as little as ₹100 per month. For more detail on pricing visit https://about.openfoodindia.org/pricing/ ." sell_embed: "We collectively budget for new feature development from the international OFN community. This way the huge cost of good software development can be shared. If you want a new feature, chances are someone in France, South Africa, Australia, India or Brazil might want it too! Use the Community Forum to suggest features you'd like to see." sell_ask_services: "Ask us about OFN services." shops_title: Shops From 3dfabdc1174cccba9fa9de81af6583dc2f820f95 Mon Sep 17 00:00:00 2001 From: Dany Marcoux Date: Mon, 8 Jun 2020 23:17:02 +0200 Subject: [PATCH 177/261] Filter orders on inclusive dates in admin/orders Closes #5555 Co-authored-by: Luis Ramos --- .../orders/controllers/orders_controller.js.coffee | 12 ++++++++++-- app/views/spree/admin/orders/_filters.html.haml | 4 ++-- .../controllers/orders_controller_spec.js.coffee | 11 +++++++++++ 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee b/app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee index f6d4c964d6..0b934999e9 100644 --- a/app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee +++ b/app/assets/javascripts/admin/orders/controllers/orders_controller.js.coffee @@ -23,10 +23,13 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, Reque $scope.fetchResults() $scope.fetchResults = (page=1) -> + startDateWithTime = $scope.appendStringIfNotEmpty($scope['q']['completed_at_gteq'], ' 00:00:00') + endDateWithTime = $scope.appendStringIfNotEmpty($scope['q']['completed_at_lteq'], ' 23:59:59') + $scope.resetSelected() params = { - 'q[completed_at_lt]': $scope['q']['completed_at_lt'], - 'q[completed_at_gt]': $scope['q']['completed_at_gt'], + 'q[completed_at_gteq]': startDateWithTime, + 'q[completed_at_lteq]': endDateWithTime, 'q[state_eq]': $scope['q']['state_eq'], 'q[number_cont]': $scope['q']['number_cont'], 'q[email_cont]': $scope['q']['email_cont'], @@ -42,6 +45,11 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, $timeout, Reque } RequestMonitor.load(Orders.index(params).$promise) + $scope.appendStringIfNotEmpty = (baseString, stringToAppend) -> + return baseString unless baseString + + baseString + stringToAppend + $scope.resetSelected = -> $scope.selected_orders.length = 0 $scope.selected = false diff --git a/app/views/spree/admin/orders/_filters.html.haml b/app/views/spree/admin/orders/_filters.html.haml index b41c2d194a..987e340e55 100644 --- a/app/views/spree/admin/orders/_filters.html.haml +++ b/app/views/spree/admin/orders/_filters.html.haml @@ -4,10 +4,10 @@ .date-range-filter.field = label_tag nil, t(:date_range) .date-range-fields - = text_field_tag "q[completed_at_gt]", nil, class: 'datepicker', datepicker: 'q.completed_at_gt', 'ng-model' => 'q.completed_at_gt', :placeholder => t(:start) + = text_field_tag "q[completed_at_gteq]", nil, class: 'datepicker', datepicker: 'q.completed_at_gteq', 'ng-model' => 'q.completed_at_gteq', :placeholder => t(:start) %span.range-divider %i.icon-arrow-right - = text_field_tag "q[completed_at_lt]", nil, class: 'datepicker', datepicker: 'q.completed_at_lt', 'ng-model' => 'q.completed_at_lt', :placeholder => t(:stop) + = text_field_tag "q[completed_at_lteq]", nil, class: 'datepicker', datepicker: 'q.completed_at_lteq', 'ng-model' => 'q.completed_at_lteq', :placeholder => t(:stop) .field = label_tag nil, t(:status) = select_tag("q[state_eq]", diff --git a/spec/javascripts/unit/admin/orders/controllers/orders_controller_spec.js.coffee b/spec/javascripts/unit/admin/orders/controllers/orders_controller_spec.js.coffee index 2fa1efbac3..0ccbbe3b9a 100644 --- a/spec/javascripts/unit/admin/orders/controllers/orders_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/orders/controllers/orders_controller_spec.js.coffee @@ -63,3 +63,14 @@ describe "ordersCtrl", -> expect(Orders.index).toHaveBeenCalledWith(jasmine.objectContaining({ 'q[order_cycle_id_in][]': ['4', '5'] })) + + it "filters orders on inclusive dates", -> + $scope['q']['completed_at_gteq'] = '2020-06-08' + $scope['q']['completed_at_lteq'] = '2020-06-09' + + $scope.fetchResults() + + expect(Orders.index).toHaveBeenCalledWith(jasmine.objectContaining({ + 'q[completed_at_gteq]': '2020-06-08 00:00:00' + 'q[completed_at_lteq]': '2020-06-09 23:59:59' + })) From b0dd83b77354faaa66c244208339d73fcd514896 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sun, 5 Jul 2020 19:55:53 +0100 Subject: [PATCH 178/261] Update ams dependency comment --- Gemfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gemfile b/Gemfile index a389ced8fb..393d7684cc 100644 --- a/Gemfile +++ b/Gemfile @@ -75,8 +75,8 @@ gem 'truncate_html', '0.9.2' gem 'unicorn' gem 'actionpack-action_caching' -# AMS is pinned to 0.8.4 because 0.9.x is a complete re-write, as is 0.10.x -# Once Rails is updated to 5.x we should bump directly to 0.10.x +# AMS 0.9.x and 0.10.x are very different from 0.8.4 and the upgrade is not straight forward +# AMS is deprecated, we will introduce an alternative at some point gem "active_model_serializers", "0.8.4" gem 'activerecord-session_store' gem 'acts-as-taggable-on', '~> 4.0' From 2a68e0fbbab763028d6e89fc2cdeb3b68f2a01f7 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Tue, 7 Jul 2020 03:55:56 +1000 Subject: [PATCH 179/261] Updating translations for config/locales/tr.yml --- config/locales/tr.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 856613867e..e097157353 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -181,8 +181,8 @@ tr: title: Diğer Hatalar (%{count} sipariş) explainer: Bu siparişlerin otomatik olarak işlenmesi bilinmeyen bir nedenden dolayı başarısız oldu. Bu gerçekleşmemesi gereken bir durum, bu hatayı alıyorsanız lütfen bizimle iletişime geçin. home: "AGA" - title: Açık Gıda Ağı - welcome_to: 'Hoşgeldiniz' + title: "Açık Gıda Ağı" + welcome_to: "Hoşgeldiniz" site_meta_description: "Açık Gıda Ağı, bağımsız, adil ve temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dayanışma ve şeffaflığı destekler." search_by_name: Üretici adına veya konuma göre arama yapın... producers_join: Bağımsız gıda üreticileri! Açık Gıda Ağı sizler için kullanıma açıldı. @@ -1713,7 +1713,7 @@ tr: password: Parola remember_me: Beni Hatırla are_you_sure: "Emin misiniz?" - orders_open: Siparişler açık + orders_open: "Siparişler açık" closing: "Kapanış" going_back_to_home_page: "Ana sayfaya yönlendiriliyorsunuz.." creating: oluşturuluyor From 447a873e5c757cf43eae6ae008eadab64c3e0c33 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 00:23:43 +0200 Subject: [PATCH 180/261] Fix flaky embedded spec The new cart sidebar takes 300ms to animate in. If we try to click the button on the left during this time, we may click the button on the right as it slides in. --- spec/support/request/ui_component_helper.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/support/request/ui_component_helper.rb b/spec/support/request/ui_component_helper.rb index dd2f38bd46..1230517d38 100644 --- a/spec/support/request/ui_component_helper.rb +++ b/spec/support/request/ui_component_helper.rb @@ -67,6 +67,7 @@ module UIComponentHelper def toggle_cart page.find("#cart").click + sleep 0.3 # Allow 300ms for sidebar animation to finish end def wait_for_ajax From 4bee0381099e0f3a0f5a0ae32eec3a45eafa5770 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2020 23:50:22 +0000 Subject: [PATCH 181/261] Bump wicked_pdf from 1.4.0 to 2.1.0 Bumps [wicked_pdf](https://github.com/mileszs/wicked_pdf) from 1.4.0 to 2.1.0. - [Release notes](https://github.com/mileszs/wicked_pdf/releases) - [Changelog](https://github.com/mileszs/wicked_pdf/blob/master/CHANGELOG.md) - [Commits](https://github.com/mileszs/wicked_pdf/compare/1.4.0...2.1.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index a62f6d8384..d54855b1a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -690,7 +690,7 @@ GEM hashdiff (>= 0.4.0, < 2.0.0) whenever (1.0.0) chronic (>= 0.6.3) - wicked_pdf (1.4.0) + wicked_pdf (2.1.0) activesupport wkhtmltopdf-binary (0.12.5) xml-simple (1.1.5) From 30492157f9a37fde31480a952b512665eaa5fe01 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 11:21:18 +0200 Subject: [PATCH 182/261] Re-enable and fix flaky exchange products renderer spec For some inexplicable reason `order_cycle.exchanges.incoming.first` and `order_cycle.exchanges.incoming.second` were returning the same exchange. Subsequently the inventory items being created were for the same variant, which throws an error due to a uniqueness validation in InventoryItem on variant_id. Changing from #first and #second to #first and #last results in the correct exchanges being assigned. --- spec/services/exchange_products_renderer_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/services/exchange_products_renderer_spec.rb b/spec/services/exchange_products_renderer_spec.rb index 9e93611f7c..67233906ad 100644 --- a/spec/services/exchange_products_renderer_spec.rb +++ b/spec/services/exchange_products_renderer_spec.rb @@ -36,8 +36,8 @@ describe ExchangeProductsRenderer do expect(variants.first.product.supplier.name).to eq exchange.variants.first.product.supplier.name end - xdescribe "when OC is showing only the coordinators inventory" do - let(:exchange_with_visible_variant) { order_cycle.exchanges.incoming.second } + describe "when OC is showing only the coordinators inventory" do + let(:exchange_with_visible_variant) { order_cycle.exchanges.incoming.last } let(:exchange_with_hidden_variant) { order_cycle.exchanges.incoming.first } let!(:visible_inventory_item) { create(:inventory_item, enterprise: order_cycle.coordinator, variant: exchange_with_visible_variant.variants.first, visible: true) } let!(:hidden_inventory_item) { create(:inventory_item, enterprise: order_cycle.coordinator, variant: exchange_with_hidden_variant.variants.first, visible: false) } From f2e0b0f35adf9ca99ee4770c7b56d5352b7106af Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 13:14:11 +0200 Subject: [PATCH 183/261] Ensure products list has loaded before interacting with product list UI elements --- spec/support/request/shop_workflow.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/support/request/shop_workflow.rb b/spec/support/request/shop_workflow.rb index c6a469e6c4..9e64ea19cc 100644 --- a/spec/support/request/shop_workflow.rb +++ b/spec/support/request/shop_workflow.rb @@ -96,6 +96,7 @@ module ShopWorkflow def within_variant(variant = nil) selector = variant ? "#variant-#{variant.id}" : ".variants" + expect(page).to have_selector selector within(selector) do yield end From 6be0ae543a62ace64fb4cc39c7efad4ffcb45905 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Tue, 7 Jul 2020 21:46:44 +1000 Subject: [PATCH 184/261] Updating translations for config/locales/pt_BR.yml --- config/locales/pt_BR.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml index ec32513c2e..28038571e9 100644 --- a/config/locales/pt_BR.yml +++ b/config/locales/pt_BR.yml @@ -181,8 +181,8 @@ pt_BR: title: Outras Falhas(%{count} pedidos) explainer: O processamento automático desses pedidos falhou por um motivo desconhecido. Isso não deve ocorrer, entre em contato conosco se você está vendo isso. home: "OFB" - title: Open Food Brasil - welcome_to: 'Bem-vindo a' + title: "Open Food Brasil" + welcome_to: "Bem vindo a" site_meta_description: "A nossa proposta é conectar agricultoras/es, produtoras/es e consumidoras/es que estão próximos entre si. Buscamos, assim, potencializar a circulação e a comercialização de produtos agroecológicos, orgânicos e artesanais em circuitos curtos, bem como criar novas formas de relação, orientadas pela troca, diálogo e confiança." search_by_name: Procurar por nome ou localidade producers_join: Produtores nacionais estão convidados a se unirem à Open Food Brasil. @@ -372,7 +372,7 @@ pt_BR: matomo_url: "Matomo URL" matomo_site_id: "Matomo Site ID" matomo_tag_manager_url: "URL do Gestor de Tag Matomo" - info_html: "Matomo é uma aplicação de análise Mobile e Web. Você pode hospedar o Matomo localmente ou usar um serviço de hospedagem na nuvem. Veja matomo.org para mais informações." + info_html: "Matomo é uma aplicação de Mobile e Web Analytics . Você pode hospedar o Matomo localmente ou usar um serviço de hospedagem na nuvem. Veja matomo.org para mais informações." config_instructions_html: "Aqui você pode configurar a integração do OFN Matomo. O URL do Matomo abaixo deve apontar para a instância do Matomo para onde as informações de rastreamento do usuário serão enviadas; se for deixado em branco, o rastreamento de usuários do Matomo será desativado. O campo ID do site não é obrigatório, mas é útil se você estiver controlando mais de um site em uma única instância do Matomo. ele pode ser encontrado no console da instância Matomo." config_instructions_tag_manager_html: "Ao configurar a URL para o Matomo Tag Manager, você habilita o Matomo Tag Manager. Esta ferramenta permite que você configure eventos de 'analytics'. A URL do Matomo Tag Manager é copiada do Matomo Tag Manager. Certifique-se de que você seleciou o 'container' e o 'environment' corretos, já que estas opções mudam o URL. " customers: @@ -1711,7 +1711,7 @@ pt_BR: password: Senha remember_me: Lembre-me are_you_sure: "Tem certeza?" - orders_open: Pedidos abertos + orders_open: "Pedidos abertos" closing: "Fechando" going_back_to_home_page: "Voltando à pagina inicial" creating: Criando From c2898ba38930d2f851b99d1ff0e34e94863f69f9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 20:49:06 +0100 Subject: [PATCH 185/261] Bring calculators from spree_core --- app/models/spree/calculator/default_tax.rb | 59 +++++++++++++++++++ .../calculator/flat_percent_item_total.rb | 18 ++++++ app/models/spree/calculator/flat_rate.rb | 16 +++++ app/models/spree/calculator/flexi_rate.rb | 33 +++++++++++ app/models/spree/calculator/per_item.rb | 41 +++++++++++++ app/models/spree/calculator/price_sack.rb | 31 ++++++++++ 6 files changed, 198 insertions(+) create mode 100644 app/models/spree/calculator/default_tax.rb create mode 100644 app/models/spree/calculator/flat_percent_item_total.rb create mode 100644 app/models/spree/calculator/flat_rate.rb create mode 100644 app/models/spree/calculator/flexi_rate.rb create mode 100644 app/models/spree/calculator/per_item.rb create mode 100644 app/models/spree/calculator/price_sack.rb diff --git a/app/models/spree/calculator/default_tax.rb b/app/models/spree/calculator/default_tax.rb new file mode 100644 index 0000000000..dc054f416c --- /dev/null +++ b/app/models/spree/calculator/default_tax.rb @@ -0,0 +1,59 @@ +require_dependency 'spree/calculator' + +module Spree + class Calculator::DefaultTax < Calculator + def self.description + Spree.t(:default_tax) + end + + def compute(computable) + case computable + when Spree::Order + compute_order(computable) + when Spree::LineItem + compute_line_item(computable) + end + end + + + private + + def rate + self.calculable + end + + def compute_order(order) + matched_line_items = order.line_items.select do |line_item| + line_item.tax_category == rate.tax_category + end + + line_items_total = matched_line_items.sum(&:total) + if rate.included_in_price + deduced_total_by_rate(line_items_total, rate) + else + round_to_two_places(line_items_total * rate.amount) + end + end + + def compute_line_item(line_item) + if line_item.tax_category == rate.tax_category + if rate.included_in_price + deduced_total_by_rate(line_item.total, rate) + else + round_to_two_places(line_item.total * rate.amount) + end + else + 0 + end + end + + def round_to_two_places(amount) + BigDecimal.new(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP) + end + + def deduced_total_by_rate(total, rate) + round_to_two_places(total - ( total / (1 + rate.amount) ) ) + end + + end +end diff --git a/app/models/spree/calculator/flat_percent_item_total.rb b/app/models/spree/calculator/flat_percent_item_total.rb new file mode 100644 index 0000000000..145e3555bc --- /dev/null +++ b/app/models/spree/calculator/flat_percent_item_total.rb @@ -0,0 +1,18 @@ +require_dependency 'spree/calculator' + +module Spree + class Calculator::FlatPercentItemTotal < Calculator + preference :flat_percent, :decimal, default: 0 + + def self.description + Spree.t(:flat_percent) + end + + def compute(object) + return unless object.present? and object.respond_to?(:item_total) + item_total = object.item_total + value = item_total * BigDecimal(self.preferred_flat_percent.to_s) / 100.0 + (value * 100).round.to_f / 100 + end + end +end diff --git a/app/models/spree/calculator/flat_rate.rb b/app/models/spree/calculator/flat_rate.rb new file mode 100644 index 0000000000..db4413ba86 --- /dev/null +++ b/app/models/spree/calculator/flat_rate.rb @@ -0,0 +1,16 @@ +require_dependency 'spree/calculator' + +module Spree + class Calculator::FlatRate < Calculator + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + def self.description + Spree.t(:flat_rate_per_order) + end + + def compute(object=nil) + self.preferred_amount + end + end +end diff --git a/app/models/spree/calculator/flexi_rate.rb b/app/models/spree/calculator/flexi_rate.rb new file mode 100644 index 0000000000..b718efea50 --- /dev/null +++ b/app/models/spree/calculator/flexi_rate.rb @@ -0,0 +1,33 @@ +require_dependency 'spree/calculator' + +module Spree + class Calculator::FlexiRate < Calculator + preference :first_item, :decimal, default: 0.0 + preference :additional_item, :decimal, default: 0.0 + preference :max_items, :integer, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + def self.description + Spree.t(:flexible_rate) + end + + def self.available?(object) + true + end + + def compute(object) + sum = 0 + max = self.preferred_max_items.to_i + items_count = object.line_items.map(&:quantity).sum + items_count.times do |i| + if i == 0 + sum += self.preferred_first_item.to_f + elsif ((max > 0) && (i <= (max - 1))) || (max == 0) + sum += self.preferred_additional_item.to_f + end + end + + sum + end + end +end diff --git a/app/models/spree/calculator/per_item.rb b/app/models/spree/calculator/per_item.rb new file mode 100644 index 0000000000..eec5df7655 --- /dev/null +++ b/app/models/spree/calculator/per_item.rb @@ -0,0 +1,41 @@ +require_dependency 'spree/calculator' + +module Spree + class Calculator::PerItem < Calculator + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + def self.description + Spree.t(:flat_rate_per_item) + end + + def compute(object=nil) + return 0 if object.nil? + self.preferred_amount * object.line_items.reduce(0) do |sum, value| + if matching_products.blank? || matching_products.include?(value.product) + value_to_add = value.quantity + else + value_to_add = 0 + end + sum + value_to_add + end + end + + # Returns all products that match this calculator, but only if the calculator + # is attached to a promotion. If attached to a ShippingMethod, nil is returned. + def matching_products + # Regression check for #1596 + # Calculator::PerItem can be used in two cases. + # The first is in a typical promotion, providing a discount per item of a particular item + # The second is a ShippingMethod, where it applies to an entire order + # + # Shipping methods do not have promotions attached, but promotions do + # Therefore we must check for promotions + if self.calculable.respond_to?(:promotion) + self.calculable.promotion.rules.map do |rule| + rule.respond_to?(:products) ? rule.products : [] + end.flatten + end + end + end +end diff --git a/app/models/spree/calculator/price_sack.rb b/app/models/spree/calculator/price_sack.rb new file mode 100644 index 0000000000..1130410468 --- /dev/null +++ b/app/models/spree/calculator/price_sack.rb @@ -0,0 +1,31 @@ +require_dependency 'spree/calculator' +# For #to_d method on Ruby 1.8 +require 'bigdecimal/util' + +module Spree + class Calculator::PriceSack < Calculator + preference :minimal_amount, :decimal, default: 0 + preference :normal_amount, :decimal, default: 0 + preference :discount_amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + def self.description + Spree.t(:price_sack) + end + + # as object we always get line items, as calculable we have Coupon, ShippingMethod + def compute(object) + if object.is_a?(Array) + base = object.map { |o| o.respond_to?(:amount) ? o.amount : BigDecimal(o.to_s) }.sum + else + base = object.respond_to?(:amount) ? object.amount : BigDecimal(object.to_s) + end + + if base < self.preferred_minimal_amount + self.preferred_normal_amount + else + self.preferred_discount_amount + end + end + end +end From 6b04df0dea8e200b1e8a2d1bd532e78d38dae2a7 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 20:54:45 +0100 Subject: [PATCH 186/261] Fix indentation and extract Calculator as a separate module declaration --- app/models/spree/calculator/default_tax.rb | 20 +++--- .../calculator/flat_percent_item_total.rb | 23 ++++--- app/models/spree/calculator/flat_rate.rb | 18 +++--- app/models/spree/calculator/flexi_rate.rb | 50 ++++++++------- app/models/spree/calculator/per_item.rb | 64 ++++++++++--------- app/models/spree/calculator/price_sack.rb | 40 ++++++------ 6 files changed, 113 insertions(+), 102 deletions(-) diff --git a/app/models/spree/calculator/default_tax.rb b/app/models/spree/calculator/default_tax.rb index dc054f416c..bfacafddef 100644 --- a/app/models/spree/calculator/default_tax.rb +++ b/app/models/spree/calculator/default_tax.rb @@ -1,22 +1,22 @@ require_dependency 'spree/calculator' module Spree - class Calculator::DefaultTax < Calculator - def self.description - Spree.t(:default_tax) - end + module Calculator + class DefaultTax < Calculator + def self.description + Spree.t(:default_tax) + end - def compute(computable) - case computable + def compute(computable) + case computable when Spree::Order compute_order(computable) when Spree::LineItem compute_line_item(computable) + end end - end - - private + private def rate self.calculable @@ -54,6 +54,6 @@ module Spree def deduced_total_by_rate(total, rate) round_to_two_places(total - ( total / (1 + rate.amount) ) ) end - + end end end diff --git a/app/models/spree/calculator/flat_percent_item_total.rb b/app/models/spree/calculator/flat_percent_item_total.rb index 145e3555bc..8b897397e4 100644 --- a/app/models/spree/calculator/flat_percent_item_total.rb +++ b/app/models/spree/calculator/flat_percent_item_total.rb @@ -1,18 +1,21 @@ require_dependency 'spree/calculator' module Spree - class Calculator::FlatPercentItemTotal < Calculator - preference :flat_percent, :decimal, default: 0 + module Calculator + class FlatPercentItemTotal < Calculator + preference :flat_percent, :decimal, default: 0 - def self.description - Spree.t(:flat_percent) - end + def self.description + Spree.t(:flat_percent) + end - def compute(object) - return unless object.present? and object.respond_to?(:item_total) - item_total = object.item_total - value = item_total * BigDecimal(self.preferred_flat_percent.to_s) / 100.0 - (value * 100).round.to_f / 100 + def compute(object) + return unless object.present? && object.respond_to?(:item_total) + + item_total = object.item_total + value = item_total * BigDecimal(self.preferred_flat_percent.to_s) / 100.0 + (value * 100).round.to_f / 100 + end end end end diff --git a/app/models/spree/calculator/flat_rate.rb b/app/models/spree/calculator/flat_rate.rb index db4413ba86..3cfb94dd4c 100644 --- a/app/models/spree/calculator/flat_rate.rb +++ b/app/models/spree/calculator/flat_rate.rb @@ -1,16 +1,18 @@ require_dependency 'spree/calculator' module Spree - class Calculator::FlatRate < Calculator - preference :amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] + module Calculator + class FlatRate < Calculator + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] - def self.description - Spree.t(:flat_rate_per_order) - end + def self.description + Spree.t(:flat_rate_per_order) + end - def compute(object=nil) - self.preferred_amount + def compute(object=nil) + self.preferred_amount + end end end end diff --git a/app/models/spree/calculator/flexi_rate.rb b/app/models/spree/calculator/flexi_rate.rb index b718efea50..9e8f16cc00 100644 --- a/app/models/spree/calculator/flexi_rate.rb +++ b/app/models/spree/calculator/flexi_rate.rb @@ -1,33 +1,35 @@ require_dependency 'spree/calculator' module Spree - class Calculator::FlexiRate < Calculator - preference :first_item, :decimal, default: 0.0 - preference :additional_item, :decimal, default: 0.0 - preference :max_items, :integer, default: 0 - preference :currency, :string, default: Spree::Config[:currency] + module Calculator + class FlexiRate < Calculator + preference :first_item, :decimal, default: 0.0 + preference :additional_item, :decimal, default: 0.0 + preference :max_items, :integer, default: 0 + preference :currency, :string, default: Spree::Config[:currency] - def self.description - Spree.t(:flexible_rate) - end - - def self.available?(object) - true - end - - def compute(object) - sum = 0 - max = self.preferred_max_items.to_i - items_count = object.line_items.map(&:quantity).sum - items_count.times do |i| - if i == 0 - sum += self.preferred_first_item.to_f - elsif ((max > 0) && (i <= (max - 1))) || (max == 0) - sum += self.preferred_additional_item.to_f - end + def self.description + Spree.t(:flexible_rate) end - sum + def self.available?(object) + true + end + + def compute(object) + sum = 0 + max = self.preferred_max_items.to_i + items_count = object.line_items.map(&:quantity).sum + items_count.times do |i| + if i == 0 + sum += self.preferred_first_item.to_f + elsif ((max > 0) && (i <= (max - 1))) || (max == 0) + sum += self.preferred_additional_item.to_f + end + end + + sum + end end end end diff --git a/app/models/spree/calculator/per_item.rb b/app/models/spree/calculator/per_item.rb index eec5df7655..a2ce2f4348 100644 --- a/app/models/spree/calculator/per_item.rb +++ b/app/models/spree/calculator/per_item.rb @@ -1,40 +1,42 @@ require_dependency 'spree/calculator' module Spree - class Calculator::PerItem < Calculator - preference :amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] + module Calculator + class PerItem < Calculator + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] - def self.description - Spree.t(:flat_rate_per_item) - end - - def compute(object=nil) - return 0 if object.nil? - self.preferred_amount * object.line_items.reduce(0) do |sum, value| - if matching_products.blank? || matching_products.include?(value.product) - value_to_add = value.quantity - else - value_to_add = 0 - end - sum + value_to_add + def self.description + Spree.t(:flat_rate_per_item) end - end - # Returns all products that match this calculator, but only if the calculator - # is attached to a promotion. If attached to a ShippingMethod, nil is returned. - def matching_products - # Regression check for #1596 - # Calculator::PerItem can be used in two cases. - # The first is in a typical promotion, providing a discount per item of a particular item - # The second is a ShippingMethod, where it applies to an entire order - # - # Shipping methods do not have promotions attached, but promotions do - # Therefore we must check for promotions - if self.calculable.respond_to?(:promotion) - self.calculable.promotion.rules.map do |rule| - rule.respond_to?(:products) ? rule.products : [] - end.flatten + def compute(object=nil) + return 0 if object.nil? + self.preferred_amount * object.line_items.reduce(0) do |sum, value| + if matching_products.blank? || matching_products.include?(value.product) + value_to_add = value.quantity + else + value_to_add = 0 + end + sum + value_to_add + end + end + + # Returns all products that match this calculator, but only if the calculator + # is attached to a promotion. If attached to a ShippingMethod, nil is returned. + def matching_products + # Regression check for #1596 + # Calculator::PerItem can be used in two cases. + # The first is in a typical promotion, providing a discount per item of a particular item + # The second is a ShippingMethod, where it applies to an entire order + # + # Shipping methods do not have promotions attached, but promotions do + # Therefore we must check for promotions + if self.calculable.respond_to?(:promotion) + self.calculable.promotion.rules.map do |rule| + rule.respond_to?(:products) ? rule.products : [] + end.flatten + end end end end diff --git a/app/models/spree/calculator/price_sack.rb b/app/models/spree/calculator/price_sack.rb index 1130410468..d3a05e0229 100644 --- a/app/models/spree/calculator/price_sack.rb +++ b/app/models/spree/calculator/price_sack.rb @@ -3,28 +3,30 @@ require_dependency 'spree/calculator' require 'bigdecimal/util' module Spree - class Calculator::PriceSack < Calculator - preference :minimal_amount, :decimal, default: 0 - preference :normal_amount, :decimal, default: 0 - preference :discount_amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] + module Calculator + class PriceSack < Calculator + preference :minimal_amount, :decimal, default: 0 + preference :normal_amount, :decimal, default: 0 + preference :discount_amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] - def self.description - Spree.t(:price_sack) - end - - # as object we always get line items, as calculable we have Coupon, ShippingMethod - def compute(object) - if object.is_a?(Array) - base = object.map { |o| o.respond_to?(:amount) ? o.amount : BigDecimal(o.to_s) }.sum - else - base = object.respond_to?(:amount) ? object.amount : BigDecimal(object.to_s) + def self.description + Spree.t(:price_sack) end - if base < self.preferred_minimal_amount - self.preferred_normal_amount - else - self.preferred_discount_amount + # as object we always get line items, as calculable we have Coupon, ShippingMethod + def compute(object) + if object.is_a?(Array) + base = object.map { |o| o.respond_to?(:amount) ? o.amount : BigDecimal(o.to_s) }.sum + else + base = object.respond_to?(:amount) ? object.amount : BigDecimal(object.to_s) + end + + if base < self.preferred_minimal_amount + self.preferred_normal_amount + else + self.preferred_discount_amount + end end end end From f2a46d2ceff1002057b1aa715c53fea55ed96363 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:06:32 +0100 Subject: [PATCH 187/261] Merge decorators into original classes brought from spree_core --- app/models/spree/calculator/default_tax.rb | 36 ++++++++++++++--- .../spree/calculator/default_tax_decorator.rb | 40 ------------------- .../calculator/flat_percent_item_total.rb | 13 ++++-- .../flat_percent_item_total_decorator.rb | 15 ------- app/models/spree/calculator/flat_rate.rb | 13 ++++-- .../spree/calculator/flat_rate_decorator.rb | 13 ------ app/models/spree/calculator/flexi_rate.rb | 27 ++++++++----- .../spree/calculator/flexi_rate_decorator.rb | 30 -------------- app/models/spree/calculator/per_item.rb | 25 ++++++++---- .../spree/calculator/per_item_decorator.rb | 27 ------------- app/models/spree/calculator/price_sack.rb | 29 +++++++++----- .../spree/calculator/price_sack_decorator.rb | 28 ------------- 12 files changed, 102 insertions(+), 194 deletions(-) delete mode 100644 app/models/spree/calculator/default_tax_decorator.rb delete mode 100644 app/models/spree/calculator/flat_percent_item_total_decorator.rb delete mode 100644 app/models/spree/calculator/flat_rate_decorator.rb delete mode 100644 app/models/spree/calculator/flexi_rate_decorator.rb delete mode 100644 app/models/spree/calculator/per_item_decorator.rb delete mode 100644 app/models/spree/calculator/price_sack_decorator.rb diff --git a/app/models/spree/calculator/default_tax.rb b/app/models/spree/calculator/default_tax.rb index bfacafddef..87ea942067 100644 --- a/app/models/spree/calculator/default_tax.rb +++ b/app/models/spree/calculator/default_tax.rb @@ -1,4 +1,7 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' +require 'open_food_network/enterprise_fee_calculator' module Spree module Calculator @@ -19,19 +22,40 @@ module Spree private def rate - self.calculable + calculable end + # Enable calculation of tax for enterprise fees with tax rates where included_in_price = false def compute_order(order) matched_line_items = order.line_items.select do |line_item| - line_item.tax_category == rate.tax_category + line_item.product.tax_category == rate.tax_category end line_items_total = matched_line_items.sum(&:total) - if rate.included_in_price - deduced_total_by_rate(line_items_total, rate) - else - round_to_two_places(line_items_total * rate.amount) + + # Added this line + calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) + + # Added this block, finds relevant fees for each line_item, calculates the tax on them, and returns the total tax + per_item_fees_total = order.line_items.sum do |line_item| + calculator.per_item_enterprise_fee_applicators_for(line_item.variant) + .select { |applicator| + (!applicator.enterprise_fee.inherits_tax_category && applicator.enterprise_fee.tax_category == rate.tax_category) || + (applicator.enterprise_fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) + } + .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } + end + + # Added this block, finds relevant fees for whole order, calculates the tax on them, and returns the total tax + per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) + .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } + .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } + + # round_to_two_places(line_items_total * rate.amount) # Removed this line + + # Added this block + [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| + round_to_two_places(total * rate.amount) end end diff --git a/app/models/spree/calculator/default_tax_decorator.rb b/app/models/spree/calculator/default_tax_decorator.rb deleted file mode 100644 index ccc73abb9f..0000000000 --- a/app/models/spree/calculator/default_tax_decorator.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'open_food_network/enterprise_fee_calculator' - -Spree::Calculator::DefaultTax.class_eval do - private - - # Override this method to enable calculation of tax for - # enterprise fees with tax rates where included_in_price = false - def compute_order(order) - matched_line_items = order.line_items.select do |line_item| - line_item.product.tax_category == rate.tax_category - end - - line_items_total = matched_line_items.sum(&:total) - - # Added this line - calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) - - # Added this block, finds relevant fees for each line_item, calculates the tax on them, and returns the total tax - per_item_fees_total = order.line_items.sum do |line_item| - calculator.per_item_enterprise_fee_applicators_for(line_item.variant) - .select { |applicator| - (!applicator.enterprise_fee.inherits_tax_category && applicator.enterprise_fee.tax_category == rate.tax_category) || - (applicator.enterprise_fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) - } - .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } - end - - # Added this block, finds relevant fees for whole order, calculates the tax on them, and returns the total tax - per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) - .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } - .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - - # round_to_two_places(line_items_total * rate.amount) # Removed this line - - # Added this block - [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| - round_to_two_places(total * rate.amount) - end - end -end diff --git a/app/models/spree/calculator/flat_percent_item_total.rb b/app/models/spree/calculator/flat_percent_item_total.rb index 8b897397e4..0d2dc7e0db 100644 --- a/app/models/spree/calculator/flat_percent_item_total.rb +++ b/app/models/spree/calculator/flat_percent_item_total.rb @@ -1,19 +1,24 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' +require 'spree/localized_number' module Spree module Calculator class FlatPercentItemTotal < Calculator + extend Spree::LocalizedNumber + preference :flat_percent, :decimal, default: 0 + localize_number :preferred_flat_percent + def self.description Spree.t(:flat_percent) end def compute(object) - return unless object.present? && object.respond_to?(:item_total) - - item_total = object.item_total - value = item_total * BigDecimal(self.preferred_flat_percent.to_s) / 100.0 + item_total = line_items_for(object).map(&:amount).sum + value = item_total * BigDecimal(preferred_flat_percent.to_s) / 100.0 (value * 100).round.to_f / 100 end end diff --git a/app/models/spree/calculator/flat_percent_item_total_decorator.rb b/app/models/spree/calculator/flat_percent_item_total_decorator.rb deleted file mode 100644 index ae95f59ca2..0000000000 --- a/app/models/spree/calculator/flat_percent_item_total_decorator.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spree/localized_number' - -module Spree - Calculator::FlatPercentItemTotal.class_eval do - extend Spree::LocalizedNumber - - localize_number :preferred_flat_percent - - def compute(object) - item_total = line_items_for(object).map(&:amount).sum - value = item_total * BigDecimal(preferred_flat_percent.to_s) / 100.0 - (value * 100).round.to_f / 100 - end - end -end diff --git a/app/models/spree/calculator/flat_rate.rb b/app/models/spree/calculator/flat_rate.rb index 3cfb94dd4c..a2d6d9c55b 100644 --- a/app/models/spree/calculator/flat_rate.rb +++ b/app/models/spree/calculator/flat_rate.rb @@ -1,17 +1,24 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' +require 'spree/localized_number' module Spree module Calculator class FlatRate < Calculator + extend Spree::LocalizedNumber + preference :amount, :decimal, default: 0 preference :currency, :string, default: Spree::Config[:currency] + localize_number :preferred_amount + def self.description - Spree.t(:flat_rate_per_order) + I18n.t(:flat_rate_per_order) end - def compute(object=nil) - self.preferred_amount + def compute(_object = nil) + preferred_amount end end end diff --git a/app/models/spree/calculator/flat_rate_decorator.rb b/app/models/spree/calculator/flat_rate_decorator.rb deleted file mode 100644 index d7abe3cf1b..0000000000 --- a/app/models/spree/calculator/flat_rate_decorator.rb +++ /dev/null @@ -1,13 +0,0 @@ -require 'spree/localized_number' - -module Spree - Calculator::FlatRate.class_eval do - extend Spree::LocalizedNumber - - localize_number :preferred_amount - - def self.description - I18n.t(:flat_rate_per_order) - end - end -end diff --git a/app/models/spree/calculator/flexi_rate.rb b/app/models/spree/calculator/flexi_rate.rb index 9e8f16cc00..fe80c45883 100644 --- a/app/models/spree/calculator/flexi_rate.rb +++ b/app/models/spree/calculator/flexi_rate.rb @@ -1,30 +1,39 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' +require 'spree/localized_number' module Spree module Calculator class FlexiRate < Calculator + extend Spree::LocalizedNumber + preference :first_item, :decimal, default: 0.0 preference :additional_item, :decimal, default: 0.0 preference :max_items, :integer, default: 0 preference :currency, :string, default: Spree::Config[:currency] + localize_number :preferred_first_item, + :preferred_additional_item + def self.description - Spree.t(:flexible_rate) + I18n.t(:flexible_rate) end - def self.available?(object) + def self.available?(_object) true end def compute(object) sum = 0 - max = self.preferred_max_items.to_i - items_count = object.line_items.map(&:quantity).sum - items_count.times do |i| - if i == 0 - sum += self.preferred_first_item.to_f - elsif ((max > 0) && (i <= (max - 1))) || (max == 0) - sum += self.preferred_additional_item.to_f + max = preferred_max_items.to_i + items_count = line_items_for(object).map(&:quantity).sum + # check max value to avoid divide by 0 errors + unless max == 0 + if items_count > max + sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + elsif items_count <= max + sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f end end diff --git a/app/models/spree/calculator/flexi_rate_decorator.rb b/app/models/spree/calculator/flexi_rate_decorator.rb deleted file mode 100644 index de112f4f0b..0000000000 --- a/app/models/spree/calculator/flexi_rate_decorator.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'spree/localized_number' - -module Spree - Calculator::FlexiRate.class_eval do - extend Spree::LocalizedNumber - - localize_number :preferred_first_item, - :preferred_additional_item - - def self.description - I18n.t(:flexible_rate) - end - - def compute(object) - sum = 0 - max = preferred_max_items.to_i - items_count = line_items_for(object).map(&:quantity).sum - # check max value to avoid divide by 0 errors - unless max == 0 - if items_count > max - sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - elsif items_count <= max - sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - end - end - - sum - end - end -end diff --git a/app/models/spree/calculator/per_item.rb b/app/models/spree/calculator/per_item.rb index a2ce2f4348..10c7965c0d 100644 --- a/app/models/spree/calculator/per_item.rb +++ b/app/models/spree/calculator/per_item.rb @@ -1,25 +1,34 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' +require 'spree/localized_number' module Spree module Calculator class PerItem < Calculator + extend Spree::LocalizedNumber + preference :amount, :decimal, default: 0 preference :currency, :string, default: Spree::Config[:currency] + localize_number :preferred_amount + def self.description - Spree.t(:flat_rate_per_item) + I18n.t(:flat_rate_per_item) end - def compute(object=nil) + def compute(object = nil) return 0 if object.nil? - self.preferred_amount * object.line_items.reduce(0) do |sum, value| - if matching_products.blank? || matching_products.include?(value.product) - value_to_add = value.quantity - else - value_to_add = 0 - end + + number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item| + value_to_add = if matching_products.blank? || matching_products.include?(line_item.product) + line_item.quantity + else + 0 + end sum + value_to_add end + preferred_amount * number_of_line_items end # Returns all products that match this calculator, but only if the calculator diff --git a/app/models/spree/calculator/per_item_decorator.rb b/app/models/spree/calculator/per_item_decorator.rb deleted file mode 100644 index e385ad8bf8..0000000000 --- a/app/models/spree/calculator/per_item_decorator.rb +++ /dev/null @@ -1,27 +0,0 @@ -require 'spree/localized_number' - -module Spree - Calculator::PerItem.class_eval do - extend Spree::LocalizedNumber - - localize_number :preferred_amount - - def self.description - I18n.t(:flat_rate_per_item) - end - - def compute(object = nil) - return 0 if object.nil? - - number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item| - value_to_add = if matching_products.blank? || matching_products.include?(line_item.product) - line_item.quantity - else - 0 - end - sum + value_to_add - end - preferred_amount * number_of_line_items - end - end -end diff --git a/app/models/spree/calculator/price_sack.rb b/app/models/spree/calculator/price_sack.rb index d3a05e0229..ac6bf0b653 100644 --- a/app/models/spree/calculator/price_sack.rb +++ b/app/models/spree/calculator/price_sack.rb @@ -1,32 +1,39 @@ +# frozen_string_literal: false + require_dependency 'spree/calculator' # For #to_d method on Ruby 1.8 require 'bigdecimal/util' +require 'spree/localized_number' module Spree module Calculator class PriceSack < Calculator + extend Spree::LocalizedNumber + preference :minimal_amount, :decimal, default: 0 preference :normal_amount, :decimal, default: 0 preference :discount_amount, :decimal, default: 0 preference :currency, :string, default: Spree::Config[:currency] + localize_number :preferred_minimal_amount, + :preferred_normal_amount, + :preferred_discount_amount + def self.description - Spree.t(:price_sack) + I18n.t(:price_sack) end - # as object we always get line items, as calculable we have Coupon, ShippingMethod def compute(object) - if object.is_a?(Array) - base = object.map { |o| o.respond_to?(:amount) ? o.amount : BigDecimal(o.to_s) }.sum - else - base = object.respond_to?(:amount) ? object.amount : BigDecimal(object.to_s) + min = preferred_minimal_amount.to_f + order_amount = line_items_for(object).map { |x| x.price * x.quantity }.sum + + if order_amount < min + cost = preferred_normal_amount.to_f + elsif order_amount >= min + cost = preferred_discount_amount.to_f end - if base < self.preferred_minimal_amount - self.preferred_normal_amount - else - self.preferred_discount_amount - end + cost end end end diff --git a/app/models/spree/calculator/price_sack_decorator.rb b/app/models/spree/calculator/price_sack_decorator.rb deleted file mode 100644 index 389649f916..0000000000 --- a/app/models/spree/calculator/price_sack_decorator.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spree/localized_number' - -module Spree - Calculator::PriceSack.class_eval do - extend Spree::LocalizedNumber - - localize_number :preferred_minimal_amount, - :preferred_normal_amount, - :preferred_discount_amount - - def self.description - I18n.t(:price_sack) - end - - def compute(object) - min = preferred_minimal_amount.to_f - order_amount = line_items_for(object).map { |x| x.price * x.quantity }.sum - - if order_amount < min - cost = preferred_normal_amount.to_f - elsif order_amount >= min - cost = preferred_discount_amount.to_f - end - - cost - end - end -end From a544102b1b34ed06f567691a78caa1371e4cee3f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:11:51 +0100 Subject: [PATCH 188/261] Fix some rubocop issues --- app/models/spree/calculator/default_tax.rb | 21 +++++++++++---------- app/models/spree/calculator/flexi_rate.rb | 3 ++- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/models/spree/calculator/default_tax.rb b/app/models/spree/calculator/default_tax.rb index 87ea942067..8a4e1fa053 100644 --- a/app/models/spree/calculator/default_tax.rb +++ b/app/models/spree/calculator/default_tax.rb @@ -33,27 +33,28 @@ module Spree line_items_total = matched_line_items.sum(&:total) - # Added this line - calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) + calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, + order.order_cycle) - # Added this block, finds relevant fees for each line_item, calculates the tax on them, and returns the total tax + # Finds relevant fees for each line_item, + # calculates the tax on them, and returns the total tax per_item_fees_total = order.line_items.sum do |line_item| calculator.per_item_enterprise_fee_applicators_for(line_item.variant) .select { |applicator| - (!applicator.enterprise_fee.inherits_tax_category && applicator.enterprise_fee.tax_category == rate.tax_category) || - (applicator.enterprise_fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) + (!applicator.enterprise_fee.inherits_tax_category && + applicator.enterprise_fee.tax_category == rate.tax_category) || + (applicator.enterprise_fee.inherits_tax_category && + line_item.product.tax_category == rate.tax_category) } .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } end - # Added this block, finds relevant fees for whole order, calculates the tax on them, and returns the total tax + # Finds relevant fees for whole order, + # calculates the tax on them, and returns the total tax per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - # round_to_two_places(line_items_total * rate.amount) # Removed this line - - # Added this block [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| round_to_two_places(total * rate.amount) end @@ -72,7 +73,7 @@ module Spree end def round_to_two_places(amount) - BigDecimal.new(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP) + BigDecimal(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP) end def deduced_total_by_rate(total, rate) diff --git a/app/models/spree/calculator/flexi_rate.rb b/app/models/spree/calculator/flexi_rate.rb index fe80c45883..78db514970 100644 --- a/app/models/spree/calculator/flexi_rate.rb +++ b/app/models/spree/calculator/flexi_rate.rb @@ -28,8 +28,9 @@ module Spree sum = 0 max = preferred_max_items.to_i items_count = line_items_for(object).map(&:quantity).sum + # check max value to avoid divide by 0 errors - unless max == 0 + unless max.zero? if items_count > max sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f elsif items_count <= max From 9c3eb3725ea50388eb368deef163e30c4314b7db Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:12:45 +0100 Subject: [PATCH 189/261] Remove dead code related to promotions, we dont have promotions in OFN --- app/models/spree/calculator/per_item.rb | 23 +---------------------- 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/app/models/spree/calculator/per_item.rb b/app/models/spree/calculator/per_item.rb index 10c7965c0d..fdd9aa4a5b 100644 --- a/app/models/spree/calculator/per_item.rb +++ b/app/models/spree/calculator/per_item.rb @@ -21,32 +21,11 @@ module Spree return 0 if object.nil? number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item| - value_to_add = if matching_products.blank? || matching_products.include?(line_item.product) - line_item.quantity - else - 0 - end + value_to_add = line_item.quantity sum + value_to_add end preferred_amount * number_of_line_items end - - # Returns all products that match this calculator, but only if the calculator - # is attached to a promotion. If attached to a ShippingMethod, nil is returned. - def matching_products - # Regression check for #1596 - # Calculator::PerItem can be used in two cases. - # The first is in a typical promotion, providing a discount per item of a particular item - # The second is a ShippingMethod, where it applies to an entire order - # - # Shipping methods do not have promotions attached, but promotions do - # Therefore we must check for promotions - if self.calculable.respond_to?(:promotion) - self.calculable.promotion.rules.map do |rule| - rule.respond_to?(:products) ? rule.products : [] - end.flatten - end - end end end end From 5e8438c446932cec3575b8c4e1f792d228741e39 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:29:53 +0100 Subject: [PATCH 190/261] Move all calculators outside the spree namespace --- .../{spree => }/calculator/default_tax.rb | 2 +- .../calculator/flat_percent_item_total.rb | 24 ++++++++++ app/models/calculator/flat_rate.rb | 23 ++++++++++ app/models/calculator/flexi_rate.rb | 43 ++++++++++++++++++ app/models/calculator/per_item.rb | 29 ++++++++++++ app/models/calculator/price_sack.rb | 38 ++++++++++++++++ app/models/enterprise_fee.rb | 2 +- .../calculator/flat_percent_item_total.rb | 26 ----------- app/models/spree/calculator/flat_rate.rb | 25 ----------- app/models/spree/calculator/flexi_rate.rb | 45 ------------------- app/models/spree/calculator/per_item.rb | 31 ------------- app/models/spree/calculator/price_sack.rb | 40 ----------------- app/models/spree/payment_method_decorator.rb | 2 +- config/application.rb | 28 ++++++------ .../subscriptions/estimator_spec.rb | 12 ++--- .../sample_data/payment_method_factory.rb | 4 +- .../sample_data/shipping_method_factory.rb | 2 +- .../admin/enterprises_controller_spec.rb | 4 +- .../admin/adjustments_controller_spec.rb | 2 +- .../admin/shipping_methods_controller_spec.rb | 4 +- .../calculated_adjustment_factory.rb | 2 +- spec/factories/calculator_factory.rb | 2 +- spec/factories/product_factory.rb | 2 +- spec/factories/shipping_method_factory.rb | 4 +- spec/factories/tag_rule_factory.rb | 2 +- spec/features/admin/payments_spec.rb | 2 +- spec/features/admin/reports_spec.rb | 6 +-- spec/features/consumer/shopping/cart_spec.rb | 2 +- .../consumer/shopping/checkout_spec.rb | 6 +-- .../enterprise_fee_calculator_spec.rb | 4 +- spec/mailers/producer_mailer_spec.rb | 2 +- spec/models/enterprise_fee_spec.rb | 20 ++++----- .../flat_percent_item_total_spec.rb | 4 +- .../models/spree/calculator/flat_rate_spec.rb | 4 +- .../spree/calculator/flexi_rate_spec.rb | 6 +-- spec/models/spree/calculator/per_item_spec.rb | 4 +- .../spree/calculator/price_sack_spec.rb | 4 +- spec/models/spree/line_item_spec.rb | 4 +- spec/models/spree/order_spec.rb | 12 ++--- spec/models/spree/payment_spec.rb | 4 +- spec/models/spree/tax_rate_spec.rb | 2 +- spec/models/tag_rule/discount_order_spec.rb | 2 +- .../requests/checkout/failed_checkout_spec.rb | 2 +- spec/requests/checkout/paypal_spec.rb | 2 +- spec/requests/checkout/stripe_connect_spec.rb | 2 +- spec/requests/checkout/stripe_sca_spec.rb | 2 +- spec/services/tax_rate_finder_spec.rb | 2 +- 47 files changed, 243 insertions(+), 253 deletions(-) rename app/models/{spree => }/calculator/default_tax.rb (98%) create mode 100644 app/models/calculator/flat_percent_item_total.rb create mode 100644 app/models/calculator/flat_rate.rb create mode 100644 app/models/calculator/flexi_rate.rb create mode 100644 app/models/calculator/per_item.rb create mode 100644 app/models/calculator/price_sack.rb delete mode 100644 app/models/spree/calculator/flat_percent_item_total.rb delete mode 100644 app/models/spree/calculator/flat_rate.rb delete mode 100644 app/models/spree/calculator/flexi_rate.rb delete mode 100644 app/models/spree/calculator/per_item.rb delete mode 100644 app/models/spree/calculator/price_sack.rb diff --git a/app/models/spree/calculator/default_tax.rb b/app/models/calculator/default_tax.rb similarity index 98% rename from app/models/spree/calculator/default_tax.rb rename to app/models/calculator/default_tax.rb index 8a4e1fa053..1910990945 100644 --- a/app/models/spree/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -5,7 +5,7 @@ require 'open_food_network/enterprise_fee_calculator' module Spree module Calculator - class DefaultTax < Calculator + class DefaultTax < Spree::Calculator def self.description Spree.t(:default_tax) end diff --git a/app/models/calculator/flat_percent_item_total.rb b/app/models/calculator/flat_percent_item_total.rb new file mode 100644 index 0000000000..79c2f1f400 --- /dev/null +++ b/app/models/calculator/flat_percent_item_total.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: false + +require_dependency 'spree/calculator' +require 'spree/localized_number' + +module Calculator + class FlatPercentItemTotal < Spree::Calculator + extend Spree::LocalizedNumber + + preference :flat_percent, :decimal, default: 0 + + localize_number :preferred_flat_percent + + def self.description + Spree.t(:flat_percent) + end + + def compute(object) + item_total = line_items_for(object).map(&:amount).sum + value = item_total * BigDecimal(preferred_flat_percent.to_s) / 100.0 + (value * 100).round.to_f / 100 + end + end +end diff --git a/app/models/calculator/flat_rate.rb b/app/models/calculator/flat_rate.rb new file mode 100644 index 0000000000..d8bc14ca8f --- /dev/null +++ b/app/models/calculator/flat_rate.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: false + +require_dependency 'spree/calculator' +require 'spree/localized_number' + +module Calculator + class FlatRate < Spree::Calculator + extend Spree::LocalizedNumber + + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + localize_number :preferred_amount + + def self.description + I18n.t(:flat_rate_per_order) + end + + def compute(_object = nil) + preferred_amount + end + end +end diff --git a/app/models/calculator/flexi_rate.rb b/app/models/calculator/flexi_rate.rb new file mode 100644 index 0000000000..b7e7974c3b --- /dev/null +++ b/app/models/calculator/flexi_rate.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: false + +require_dependency 'spree/calculator' +require 'spree/localized_number' + +module Calculator + class FlexiRate < Spree::Calculator + extend Spree::LocalizedNumber + + preference :first_item, :decimal, default: 0.0 + preference :additional_item, :decimal, default: 0.0 + preference :max_items, :integer, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + localize_number :preferred_first_item, + :preferred_additional_item + + def self.description + I18n.t(:flexible_rate) + end + + def self.available?(_object) + true + end + + def compute(object) + sum = 0 + max = preferred_max_items.to_i + items_count = line_items_for(object).map(&:quantity).sum + + # check max value to avoid divide by 0 errors + unless max.zero? + if items_count > max + sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + elsif items_count <= max + sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + end + end + + sum + end + end +end diff --git a/app/models/calculator/per_item.rb b/app/models/calculator/per_item.rb new file mode 100644 index 0000000000..49b2df35c4 --- /dev/null +++ b/app/models/calculator/per_item.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: false + +require_dependency 'spree/calculator' +require 'spree/localized_number' + +module Calculator + class PerItem < Spree::Calculator + extend Spree::LocalizedNumber + + preference :amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + localize_number :preferred_amount + + def self.description + I18n.t(:flat_rate_per_item) + end + + def compute(object = nil) + return 0 if object.nil? + + number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item| + value_to_add = line_item.quantity + sum + value_to_add + end + preferred_amount * number_of_line_items + end + end +end diff --git a/app/models/calculator/price_sack.rb b/app/models/calculator/price_sack.rb new file mode 100644 index 0000000000..cb6d185bd6 --- /dev/null +++ b/app/models/calculator/price_sack.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: false + +require_dependency 'spree/calculator' +# For #to_d method on Ruby 1.8 +require 'bigdecimal/util' +require 'spree/localized_number' + +module Calculator + class PriceSack < Spree::Calculator + extend Spree::LocalizedNumber + + preference :minimal_amount, :decimal, default: 0 + preference :normal_amount, :decimal, default: 0 + preference :discount_amount, :decimal, default: 0 + preference :currency, :string, default: Spree::Config[:currency] + + localize_number :preferred_minimal_amount, + :preferred_normal_amount, + :preferred_discount_amount + + def self.description + I18n.t(:price_sack) + end + + def compute(object) + min = preferred_minimal_amount.to_f + order_amount = line_items_for(object).map { |x| x.price * x.quantity }.sum + + if order_amount < min + cost = preferred_normal_amount.to_f + elsif order_amount >= min + cost = preferred_discount_amount.to_f + end + + cost + end + end +end diff --git a/app/models/enterprise_fee.rb b/app/models/enterprise_fee.rb index bbcafa01dc..1bea6701e7 100644 --- a/app/models/enterprise_fee.rb +++ b/app/models/enterprise_fee.rb @@ -11,7 +11,7 @@ class EnterpriseFee < ActiveRecord::Base has_many :exchanges, through: :exchange_fees FEE_TYPES = %w(packing transport admin sales fundraising).freeze - PER_ORDER_CALCULATORS = ['Spree::Calculator::FlatRate', 'Spree::Calculator::FlexiRate', 'Spree::Calculator::PriceSack'].freeze + PER_ORDER_CALCULATORS = ['Calculator::FlatRate', 'Calculator::FlexiRate', 'Calculator::PriceSack'].freeze validates :fee_type, inclusion: { in: FEE_TYPES } validates :name, presence: true diff --git a/app/models/spree/calculator/flat_percent_item_total.rb b/app/models/spree/calculator/flat_percent_item_total.rb deleted file mode 100644 index 0d2dc7e0db..0000000000 --- a/app/models/spree/calculator/flat_percent_item_total.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: false - -require_dependency 'spree/calculator' -require 'spree/localized_number' - -module Spree - module Calculator - class FlatPercentItemTotal < Calculator - extend Spree::LocalizedNumber - - preference :flat_percent, :decimal, default: 0 - - localize_number :preferred_flat_percent - - def self.description - Spree.t(:flat_percent) - end - - def compute(object) - item_total = line_items_for(object).map(&:amount).sum - value = item_total * BigDecimal(preferred_flat_percent.to_s) / 100.0 - (value * 100).round.to_f / 100 - end - end - end -end diff --git a/app/models/spree/calculator/flat_rate.rb b/app/models/spree/calculator/flat_rate.rb deleted file mode 100644 index a2d6d9c55b..0000000000 --- a/app/models/spree/calculator/flat_rate.rb +++ /dev/null @@ -1,25 +0,0 @@ -# frozen_string_literal: false - -require_dependency 'spree/calculator' -require 'spree/localized_number' - -module Spree - module Calculator - class FlatRate < Calculator - extend Spree::LocalizedNumber - - preference :amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] - - localize_number :preferred_amount - - def self.description - I18n.t(:flat_rate_per_order) - end - - def compute(_object = nil) - preferred_amount - end - end - end -end diff --git a/app/models/spree/calculator/flexi_rate.rb b/app/models/spree/calculator/flexi_rate.rb deleted file mode 100644 index 78db514970..0000000000 --- a/app/models/spree/calculator/flexi_rate.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: false - -require_dependency 'spree/calculator' -require 'spree/localized_number' - -module Spree - module Calculator - class FlexiRate < Calculator - extend Spree::LocalizedNumber - - preference :first_item, :decimal, default: 0.0 - preference :additional_item, :decimal, default: 0.0 - preference :max_items, :integer, default: 0 - preference :currency, :string, default: Spree::Config[:currency] - - localize_number :preferred_first_item, - :preferred_additional_item - - def self.description - I18n.t(:flexible_rate) - end - - def self.available?(_object) - true - end - - def compute(object) - sum = 0 - max = preferred_max_items.to_i - items_count = line_items_for(object).map(&:quantity).sum - - # check max value to avoid divide by 0 errors - unless max.zero? - if items_count > max - sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - elsif items_count <= max - sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - end - end - - sum - end - end - end -end diff --git a/app/models/spree/calculator/per_item.rb b/app/models/spree/calculator/per_item.rb deleted file mode 100644 index fdd9aa4a5b..0000000000 --- a/app/models/spree/calculator/per_item.rb +++ /dev/null @@ -1,31 +0,0 @@ -# frozen_string_literal: false - -require_dependency 'spree/calculator' -require 'spree/localized_number' - -module Spree - module Calculator - class PerItem < Calculator - extend Spree::LocalizedNumber - - preference :amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] - - localize_number :preferred_amount - - def self.description - I18n.t(:flat_rate_per_item) - end - - def compute(object = nil) - return 0 if object.nil? - - number_of_line_items = line_items_for(object).reduce(0) do |sum, line_item| - value_to_add = line_item.quantity - sum + value_to_add - end - preferred_amount * number_of_line_items - end - end - end -end diff --git a/app/models/spree/calculator/price_sack.rb b/app/models/spree/calculator/price_sack.rb deleted file mode 100644 index ac6bf0b653..0000000000 --- a/app/models/spree/calculator/price_sack.rb +++ /dev/null @@ -1,40 +0,0 @@ -# frozen_string_literal: false - -require_dependency 'spree/calculator' -# For #to_d method on Ruby 1.8 -require 'bigdecimal/util' -require 'spree/localized_number' - -module Spree - module Calculator - class PriceSack < Calculator - extend Spree::LocalizedNumber - - preference :minimal_amount, :decimal, default: 0 - preference :normal_amount, :decimal, default: 0 - preference :discount_amount, :decimal, default: 0 - preference :currency, :string, default: Spree::Config[:currency] - - localize_number :preferred_minimal_amount, - :preferred_normal_amount, - :preferred_discount_amount - - def self.description - I18n.t(:price_sack) - end - - def compute(object) - min = preferred_minimal_amount.to_f - order_amount = line_items_for(object).map { |x| x.price * x.quantity }.sum - - if order_amount < min - cost = preferred_normal_amount.to_f - elsif order_amount >= min - cost = preferred_discount_amount.to_f - end - - cost - end - end - end -end diff --git a/app/models/spree/payment_method_decorator.rb b/app/models/spree/payment_method_decorator.rb index 3da3919bf0..4c2770daea 100644 --- a/app/models/spree/payment_method_decorator.rb +++ b/app/models/spree/payment_method_decorator.rb @@ -49,7 +49,7 @@ Spree::PaymentMethod.class_eval do self.class.include Spree::Core::CalculatedAdjustments end - self.calculator ||= Spree::Calculator::FlatRate.new(preferred_amount: 0) + self.calculator ||= Calculator::FlatRate.new(preferred_amount: 0) end def has_distributor?(distributor) diff --git a/config/application.rb b/config/application.rb index 547795ea5f..3860b0b928 100644 --- a/config/application.rb +++ b/config/application.rb @@ -49,30 +49,30 @@ module Openfoodnetwork # Register Spree calculators initializer 'spree.register.calculators' do |app| app.config.spree.calculators.shipping_methods = [ - Spree::Calculator::FlatPercentItemTotal, - Spree::Calculator::FlatRate, - Spree::Calculator::FlexiRate, - Spree::Calculator::PerItem, - Spree::Calculator::PriceSack, + Calculator::FlatPercentItemTotal, + Calculator::FlatRate, + Calculator::FlexiRate, + Calculator::PerItem, + Calculator::PriceSack, Calculator::Weight ] app.config.spree.calculators.add_class('enterprise_fees') config.spree.calculators.enterprise_fees = [ Calculator::FlatPercentPerItem, - Spree::Calculator::FlatRate, - Spree::Calculator::FlexiRate, - Spree::Calculator::PerItem, - Spree::Calculator::PriceSack, + Calculator::FlatRate, + Calculator::FlexiRate, + Calculator::PerItem, + Calculator::PriceSack, Calculator::Weight ] app.config.spree.calculators.add_class('payment_methods') config.spree.calculators.payment_methods = [ - Spree::Calculator::FlatPercentItemTotal, - Spree::Calculator::FlatRate, - Spree::Calculator::FlexiRate, - Spree::Calculator::PerItem, - Spree::Calculator::PriceSack + Calculator::FlatPercentItemTotal, + Calculator::FlatRate, + Calculator::FlexiRate, + Calculator::PerItem, + Calculator::PriceSack ] end diff --git a/engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb b/engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb index 9e7bd15c06..ad14253a98 100644 --- a/engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb +++ b/engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb @@ -99,11 +99,11 @@ module OrderManagement context "using flat rate calculators" do let(:shipping_method) { create(:shipping_method, - calculator: Spree::Calculator::FlatRate.new(preferred_amount: 12.34)) + calculator: Calculator::FlatRate.new(preferred_amount: 12.34)) } let(:payment_method) { create(:payment_method, - calculator: Spree::Calculator::FlatRate.new(preferred_amount: 9.12)) + calculator: Calculator::FlatRate.new(preferred_amount: 9.12)) } it "calculates fees based on the rates provided" do @@ -116,13 +116,13 @@ module OrderManagement context "using flat percent item total calculators" do let(:shipping_method) { create(:shipping_method, - calculator: Spree::Calculator::FlatPercentItemTotal.new( + calculator: Calculator::FlatPercentItemTotal.new( preferred_flat_percent: 10 )) } let(:payment_method) { create(:payment_method, - calculator: Spree::Calculator::FlatPercentItemTotal.new( + calculator: Calculator::FlatPercentItemTotal.new( preferred_flat_percent: 20 )) } @@ -154,11 +154,11 @@ module OrderManagement context "using per item calculators" do let(:shipping_method) { create(:shipping_method, - calculator: Spree::Calculator::PerItem.new(preferred_amount: 1.2)) + calculator: Calculator::PerItem.new(preferred_amount: 1.2)) } let(:payment_method) { create(:payment_method, - calculator: Spree::Calculator::PerItem.new(preferred_amount: 0.3)) + calculator: Calculator::PerItem.new(preferred_amount: 0.3)) } it "calculates fees based on the number of items and rate provided" do diff --git a/lib/tasks/sample_data/payment_method_factory.rb b/lib/tasks/sample_data/payment_method_factory.rb index 27dc5404cf..b8430c3d96 100644 --- a/lib/tasks/sample_data/payment_method_factory.rb +++ b/lib/tasks/sample_data/payment_method_factory.rb @@ -29,7 +29,7 @@ class PaymentMethodFactory enterprise, "Cash on collection", "Pay on collection!", - Spree::Calculator::FlatRate.new + Calculator::FlatRate.new ) end @@ -39,7 +39,7 @@ class PaymentMethodFactory enterprise, "Credit card (fake)", "We charge 1%, but won't ask for your details. ;-)", - Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 1) + Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 1) ) end diff --git a/lib/tasks/sample_data/shipping_method_factory.rb b/lib/tasks/sample_data/shipping_method_factory.rb index 5bfb382318..889765775a 100644 --- a/lib/tasks/sample_data/shipping_method_factory.rb +++ b/lib/tasks/sample_data/shipping_method_factory.rb @@ -39,7 +39,7 @@ class ShippingMethodFactory name: "Home delivery #{enterprise.name}", description: "yummy food delivered at your door", require_ship_address: true, - calculator_type: "Spree::Calculator::FlatRate" + calculator_type: "Calculator::FlatRate" ) delivery.calculator.preferred_amount = 2 delivery.calculator.save! diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb index 054b37e2de..78678e03e2 100644 --- a/spec/controllers/admin/enterprises_controller_spec.rb +++ b/spec/controllers/admin/enterprises_controller_spec.rb @@ -192,7 +192,7 @@ describe Admin::EnterprisesController, type: :controller do id: tag_rule, type: "TagRule::DiscountOrder", preferred_customer_tags: "some,new,tags", - calculator_type: "Spree::Calculator::FlatPercentItemTotal", + calculator_type: "Calculator::FlatPercentItemTotal", calculator_attributes: { id: tag_rule.calculator.id, preferred_flat_percent: "15" } } } @@ -211,7 +211,7 @@ describe Admin::EnterprisesController, type: :controller do id: "", type: "TagRule::DiscountOrder", preferred_customer_tags: "tags,are,awesome", - calculator_type: "Spree::Calculator::FlatPercentItemTotal", + calculator_type: "Calculator::FlatPercentItemTotal", calculator_attributes: { id: "", preferred_flat_percent: "24" } } } diff --git a/spec/controllers/spree/admin/adjustments_controller_spec.rb b/spec/controllers/spree/admin/adjustments_controller_spec.rb index fc60008c00..4ad02b73c7 100644 --- a/spec/controllers/spree/admin/adjustments_controller_spec.rb +++ b/spec/controllers/spree/admin/adjustments_controller_spec.rb @@ -8,7 +8,7 @@ module Spree describe "setting included tax" do let(:order) { create(:order) } - let(:tax_rate) { create(:tax_rate, amount: 0.1, calculator: Spree::Calculator::DefaultTax.new) } + let(:tax_rate) { create(:tax_rate, amount: 0.1, calculator: Calculator::DefaultTax.new) } describe "creating an adjustment" do it "sets included tax to zero when no tax rate is specified" do diff --git a/spec/controllers/spree/admin/shipping_methods_controller_spec.rb b/spec/controllers/spree/admin/shipping_methods_controller_spec.rb index 531d01c11e..105d55563c 100644 --- a/spec/controllers/spree/admin/shipping_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/shipping_methods_controller_spec.rb @@ -50,7 +50,7 @@ describe Spree::Admin::ShippingMethodsController, type: :controller do end it "updates details of a FlexiRate calculator" do - shipping_method.calculator = Spree::Calculator::FlexiRate.new(calculable: shipping_method) + shipping_method.calculator = Calculator::FlexiRate.new(calculable: shipping_method) params[:shipping_method][:calculator_attributes][:preferred_first_item] = 10 params[:shipping_method][:calculator_attributes][:preferred_additional_item] = 20 params[:shipping_method][:calculator_attributes][:preferred_max_items] = 30 @@ -63,7 +63,7 @@ describe Spree::Admin::ShippingMethodsController, type: :controller do end it "updates details of a PriceSack calculator" do - shipping_method.calculator = Spree::Calculator::PriceSack.new(calculable: shipping_method) + shipping_method.calculator = Calculator::PriceSack.new(calculable: shipping_method) params[:shipping_method][:calculator_attributes][:preferred_minimal_amount] = 10 params[:shipping_method][:calculator_attributes][:preferred_normal_amount] = 20 params[:shipping_method][:calculator_attributes][:preferred_discount_amount] = 30 diff --git a/spec/factories/calculated_adjustment_factory.rb b/spec/factories/calculated_adjustment_factory.rb index 3e9c6f5cc2..5654b62746 100644 --- a/spec/factories/calculated_adjustment_factory.rb +++ b/spec/factories/calculated_adjustment_factory.rb @@ -1,5 +1,5 @@ FactoryBot.define do - factory :calculator_flat_rate, class: Spree::Calculator::FlatRate do + factory :calculator_flat_rate, class: Calculator::FlatRate do preferred_amount { generate(:calculator_amount) } end end diff --git a/spec/factories/calculator_factory.rb b/spec/factories/calculator_factory.rb index 25dd9b0a13..0c8acaf3e5 100644 --- a/spec/factories/calculator_factory.rb +++ b/spec/factories/calculator_factory.rb @@ -1,6 +1,6 @@ FactoryBot.define do sequence(:calculator_amount) - factory :calculator_per_item, class: Spree::Calculator::PerItem do + factory :calculator_per_item, class: Calculator::PerItem do preferred_amount { generate(:calculator_amount) } end diff --git a/spec/factories/product_factory.rb b/spec/factories/product_factory.rb index e546abbac4..3ca3fdb77e 100644 --- a/spec/factories/product_factory.rb +++ b/spec/factories/product_factory.rb @@ -36,7 +36,7 @@ FactoryBot.define do create(:tax_rate, amount: proxy.tax_rate_amount, tax_category: product.tax_category, included_in_price: true, - calculator: Spree::Calculator::DefaultTax.new, + calculator: Calculator::DefaultTax.new, zone: proxy.zone, name: proxy.tax_rate_name) end diff --git a/spec/factories/shipping_method_factory.rb b/spec/factories/shipping_method_factory.rb index 516dfb6b66..87cec39be9 100644 --- a/spec/factories/shipping_method_factory.rb +++ b/spec/factories/shipping_method_factory.rb @@ -9,13 +9,13 @@ FactoryBot.define do end trait :flat_rate do - calculator { Spree::Calculator::FlatRate.new(preferred_amount: 50.0) } + calculator { Calculator::FlatRate.new(preferred_amount: 50.0) } end trait :expensive_name do name { "Shipping" } description { "Expensive" } - calculator { Spree::Calculator::FlatRate.new(preferred_amount: 100.55) } + calculator { Calculator::FlatRate.new(preferred_amount: 100.55) } end trait :distributor do diff --git a/spec/factories/tag_rule_factory.rb b/spec/factories/tag_rule_factory.rb index 9663913820..4a4f5b1130 100644 --- a/spec/factories/tag_rule_factory.rb +++ b/spec/factories/tag_rule_factory.rb @@ -18,7 +18,7 @@ FactoryBot.define do factory :tag_rule, class: TagRule::DiscountOrder do enterprise { FactoryBot.create :distributor_enterprise } before(:create) do |tr| - tr.calculator = Spree::Calculator::FlatPercentItemTotal.new(calculable: tr) + tr.calculator = Calculator::FlatPercentItemTotal.new(calculable: tr) end end end diff --git a/spec/features/admin/payments_spec.rb b/spec/features/admin/payments_spec.rb index 2ea666f121..adce888db2 100644 --- a/spec/features/admin/payments_spec.rb +++ b/spec/features/admin/payments_spec.rb @@ -21,7 +21,7 @@ feature ' # This calculator doesn't handle a `nil` order well. # That has been useful in finding bugs. ;-) - payment_method.calculator = Spree::Calculator::FlatPercentItemTotal.new + payment_method.calculator = Calculator::FlatPercentItemTotal.new payment_method.save! end diff --git a/spec/features/admin/reports_spec.rb b/spec/features/admin/reports_spec.rb index 5ebd118fd7..b8eb70f010 100644 --- a/spec/features/admin/reports_spec.rb +++ b/spec/features/admin/reports_spec.rb @@ -170,7 +170,7 @@ feature ' let(:user1) { create_enterprise_user enterprises: [distributor1] } let(:user2) { create_enterprise_user enterprises: [distributor2] } let!(:shipping_method) { create(:shipping_method_with, :expensive_name, distributors: [distributor1]) } - let(:enterprise_fee) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 120.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 120.0)) } let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee], distributors: [distributor1], variants: [product1.master]) } let!(:zone) { create(:zone_with_member) } @@ -384,8 +384,8 @@ feature ' let(:shipping_method) { create(:shipping_method_with, :expensive_name) } let(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method) } - let(:enterprise_fee1) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 10)) } - let(:enterprise_fee2) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 20)) } + let(:enterprise_fee1) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 10)) } + let(:enterprise_fee2) { create(:enterprise_fee, enterprise: user1.enterprises.first, tax_category: product2.tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 20)) } let(:order_cycle) { create(:simple_order_cycle, coordinator: distributor1, coordinator_fees: [enterprise_fee1, enterprise_fee2], distributors: [distributor1], variants: [product1.master]) } let!(:zone) { create(:zone_with_member) } diff --git a/spec/features/consumer/shopping/cart_spec.rb b/spec/features/consumer/shopping/cart_spec.rb index 194b202d26..0bc4523a24 100644 --- a/spec/features/consumer/shopping/cart_spec.rb +++ b/spec/features/consumer/shopping/cart_spec.rb @@ -80,7 +80,7 @@ feature "full-page cart", js: true do describe "admin and handling flat fees" do context "when there are fees" do let(:handling_fee) { - create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 1), + create(:enterprise_fee, calculator: Calculator::FlatRate.new(preferred_amount: 1), enterprise: order_cycle.coordinator, fee_type: 'admin') } diff --git a/spec/features/consumer/shopping/checkout_spec.rb b/spec/features/consumer/shopping/checkout_spec.rb index 76983d030b..342c699a43 100644 --- a/spec/features/consumer/shopping/checkout_spec.rb +++ b/spec/features/consumer/shopping/checkout_spec.rb @@ -26,11 +26,11 @@ feature "As a consumer I want to check out my cart", js: true do end describe "with shipping and payment methods" do - let(:free_shipping) { create(:shipping_method, require_ship_address: true, name: "Frogs", description: "yellow", calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0.00)) } - let(:shipping_with_fee) { create(:shipping_method, require_ship_address: false, name: "Donkeys", description: "blue", calculator: Spree::Calculator::FlatRate.new(preferred_amount: 4.56)) } + let(:free_shipping) { create(:shipping_method, require_ship_address: true, name: "Frogs", description: "yellow", calculator: Calculator::FlatRate.new(preferred_amount: 0.00)) } + let(:shipping_with_fee) { create(:shipping_method, require_ship_address: false, name: "Donkeys", description: "blue", calculator: Calculator::FlatRate.new(preferred_amount: 4.56)) } let(:tagged_shipping) { create(:shipping_method, require_ship_address: false, name: "Local", tag_list: "local") } let!(:check_without_fee) { create(:payment_method, distributors: [distributor], name: "Roger rabbit", type: "Spree::PaymentMethod::Check") } - let!(:check_with_fee) { create(:payment_method, distributors: [distributor], calculator: Spree::Calculator::FlatRate.new(preferred_amount: 5.67)) } + let!(:check_with_fee) { create(:payment_method, distributors: [distributor], calculator: Calculator::FlatRate.new(preferred_amount: 5.67)) } let!(:paypal) do Spree::Gateway::PayPalExpress.create!(name: "Paypal", environment: 'test', distributor_ids: [distributor.id]).tap do |pm| pm.preferred_login = 'devnull-facilitator_api1.rohanmitchell.com' diff --git a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb index c1e361503e..2f613393f9 100644 --- a/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb +++ b/spec/lib/open_food_network/enterprise_fee_calculator_spec.rb @@ -16,7 +16,7 @@ module OpenFoodNetwork describe "summing all the per-item fees for the variant in the specified hub + order cycle" do let(:enterprise_fee1) { create(:enterprise_fee, amount: 20) } let(:enterprise_fee2) { create(:enterprise_fee, amount: 3) } - let(:enterprise_fee3) { create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 2)) } + let(:enterprise_fee3) { create(:enterprise_fee, calculator: Calculator::FlatRate.new(preferred_amount: 2)) } describe "supplier fees" do let!(:exchange1) { @@ -131,7 +131,7 @@ module OpenFoodNetwork let(:order) { create(:order, distributor: distributor, order_cycle: order_cycle) } let!(:line_item) { create(:line_item, order: order, variant: product1.master) } let(:enterprise_fee_line_item) { create(:enterprise_fee) } - let(:enterprise_fee_order) { create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 2)) } + let(:enterprise_fee_order) { create(:enterprise_fee, calculator: Calculator::FlatRate.new(preferred_amount: 2)) } let!(:exchange) { create(:exchange, order_cycle: order_cycle, sender: coordinator, receiver: distributor, incoming: false, variants: [product1.master]) } before { order.reload } diff --git a/spec/mailers/producer_mailer_spec.rb b/spec/mailers/producer_mailer_spec.rb index 66dd425f95..57c548f73e 100644 --- a/spec/mailers/producer_mailer_spec.rb +++ b/spec/mailers/producer_mailer_spec.rb @@ -7,7 +7,7 @@ describe ProducerMailer, type: :mailer do before { setup_email } let!(:zone) { create(:zone_with_member) } - let!(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, zone: zone, amount: 0.1) } + let!(:tax_rate) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, zone: zone, amount: 0.1) } let!(:tax_category) { create(:tax_category, tax_rates: [tax_rate]) } let(:s1) { create(:supplier_enterprise) } let(:s2) { create(:supplier_enterprise) } diff --git a/spec/models/enterprise_fee_spec.rb b/spec/models/enterprise_fee_spec.rb index a422358bb8..903d22f757 100644 --- a/spec/models/enterprise_fee_spec.rb +++ b/spec/models/enterprise_fee_spec.rb @@ -60,17 +60,17 @@ describe EnterpriseFee do describe "scopes" do describe "finding per-item enterprise fees" do it "does not return fees with FlatRate, FlexiRate and PriceSack calculators" do - create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new) - create(:enterprise_fee, calculator: Spree::Calculator::FlexiRate.new) - create(:enterprise_fee, calculator: Spree::Calculator::PriceSack.new) + create(:enterprise_fee, calculator: Calculator::FlatRate.new) + create(:enterprise_fee, calculator: Calculator::FlexiRate.new) + create(:enterprise_fee, calculator: Calculator::PriceSack.new) expect(EnterpriseFee.per_item).to be_empty end it "returns fees with any other calculator" do - ef1 = create(:enterprise_fee, calculator: Spree::Calculator::DefaultTax.new) + ef1 = create(:enterprise_fee, calculator: Calculator::DefaultTax.new) ef2 = create(:enterprise_fee, calculator: Calculator::FlatPercentPerItem.new) - ef3 = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new) + ef3 = create(:enterprise_fee, calculator: Calculator::PerItem.new) expect(EnterpriseFee.per_item).to match_array [ef1, ef2, ef3] end @@ -78,17 +78,17 @@ describe EnterpriseFee do describe "finding per-order enterprise fees" do it "returns fees with FlatRate, FlexiRate and PriceSack calculators" do - ef1 = create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new) - ef2 = create(:enterprise_fee, calculator: Spree::Calculator::FlexiRate.new) - ef3 = create(:enterprise_fee, calculator: Spree::Calculator::PriceSack.new) + ef1 = create(:enterprise_fee, calculator: Calculator::FlatRate.new) + ef2 = create(:enterprise_fee, calculator: Calculator::FlexiRate.new) + ef3 = create(:enterprise_fee, calculator: Calculator::PriceSack.new) expect(EnterpriseFee.per_order).to match_array [ef1, ef2, ef3] end it "does not return fees with any other calculator" do - ef1 = create(:enterprise_fee, calculator: Spree::Calculator::DefaultTax.new) + ef1 = create(:enterprise_fee, calculator: Calculator::DefaultTax.new) ef2 = create(:enterprise_fee, calculator: Calculator::FlatPercentPerItem.new) - ef3 = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new) + ef3 = create(:enterprise_fee, calculator: Calculator::PerItem.new) expect(EnterpriseFee.per_order).to be_empty end diff --git a/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/spec/models/spree/calculator/flat_percent_item_total_spec.rb index ec4b54fc70..b0ee8f1aa0 100644 --- a/spec/models/spree/calculator/flat_percent_item_total_spec.rb +++ b/spec/models/spree/calculator/flat_percent_item_total_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe Spree::Calculator::FlatPercentItemTotal do - let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new } +describe Calculator::FlatPercentItemTotal do + let(:calculator) { Calculator::FlatPercentItemTotal.new } let(:line_item) { build(:line_item, price: 10, quantity: 1) } before { allow(calculator).to receive_messages preferred_flat_percent: 10 } diff --git a/spec/models/spree/calculator/flat_rate_spec.rb b/spec/models/spree/calculator/flat_rate_spec.rb index 3e3bba064b..5036d6b180 100644 --- a/spec/models/spree/calculator/flat_rate_spec.rb +++ b/spec/models/spree/calculator/flat_rate_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe Spree::Calculator::FlatRate do - let(:calculator) { Spree::Calculator::FlatRate.new } +describe Calculator::FlatRate do + let(:calculator) { Calculator::FlatRate.new } before { allow(calculator).to receive_messages preferred_amount: 10 } diff --git a/spec/models/spree/calculator/flexi_rate_spec.rb b/spec/models/spree/calculator/flexi_rate_spec.rb index 0440e87ca8..9192aecdb5 100644 --- a/spec/models/spree/calculator/flexi_rate_spec.rb +++ b/spec/models/spree/calculator/flexi_rate_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' -describe Spree::Calculator::FlexiRate do +describe Calculator::FlexiRate do let(:line_item) { build(:line_item, quantity: quantity) } let(:calculator) do - Spree::Calculator::FlexiRate.new( + Calculator::FlexiRate.new( preferred_first_item: 2, preferred_additional_item: 1, preferred_max_items: 3 @@ -27,7 +27,7 @@ describe Spree::Calculator::FlexiRate do end it "allows creation of new object with all the attributes" do - Spree::Calculator::FlexiRate.new(preferred_first_item: 1, preferred_additional_item: 1, preferred_max_items: 1) + Calculator::FlexiRate.new(preferred_first_item: 1, preferred_additional_item: 1, preferred_max_items: 1) end context "extends LocalizedNumber" do diff --git a/spec/models/spree/calculator/per_item_spec.rb b/spec/models/spree/calculator/per_item_spec.rb index 640c4b32f6..7ce41251f4 100644 --- a/spec/models/spree/calculator/per_item_spec.rb +++ b/spec/models/spree/calculator/per_item_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe Spree::Calculator::PerItem do - let(:calculator) { Spree::Calculator::PerItem.new(preferred_amount: 10) } +describe Calculator::PerItem do + let(:calculator) { Calculator::PerItem.new(preferred_amount: 10) } let(:shipping_calculable) { double(:calculable) } let(:line_item) { build(:line_item, quantity: 5) } diff --git a/spec/models/spree/calculator/price_sack_spec.rb b/spec/models/spree/calculator/price_sack_spec.rb index 703bea1531..83a6ae84fb 100644 --- a/spec/models/spree/calculator/price_sack_spec.rb +++ b/spec/models/spree/calculator/price_sack_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' -describe Spree::Calculator::PriceSack do +describe Calculator::PriceSack do let(:calculator) do - calculator = Spree::Calculator::PriceSack.new + calculator = Calculator::PriceSack.new calculator.preferred_minimal_amount = 5 calculator.preferred_normal_amount = 10 calculator.preferred_discount_amount = 1 diff --git a/spec/models/spree/line_item_spec.rb b/spec/models/spree/line_item_spec.rb index ca4a5353d9..bef32dc8d7 100644 --- a/spec/models/spree/line_item_spec.rb +++ b/spec/models/spree/line_item_spec.rb @@ -35,7 +35,7 @@ module Spree end describe "finding line items with and without tax" do - let(:tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new) } + let(:tax_rate) { create(:tax_rate, calculator: Calculator::DefaultTax.new) } let!(:adjustment1) { create(:adjustment, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) } before do @@ -311,7 +311,7 @@ module Spree describe "tax" do let(:li_no_tax) { create(:line_item) } let(:li_tax) { create(:line_item) } - let(:tax_rate) { create(:tax_rate, calculator: Spree::Calculator::DefaultTax.new) } + let(:tax_rate) { create(:tax_rate, calculator: Calculator::DefaultTax.new) } let!(:adjustment) { create(:adjustment, adjustable: li_tax, originator: tax_rate, label: "TR", amount: 123, included_tax: 10.00) } context "checking if a line item has tax included" do diff --git a/spec/models/spree/order_spec.rb b/spec/models/spree/order_spec.rb index 11ac15fa27..0c2c3d33e5 100644 --- a/spec/models/spree/order_spec.rb +++ b/spec/models/spree/order_spec.rb @@ -137,7 +137,7 @@ describe Spree::Order do let(:li) { create(:line_item, order: o) } it "returns the sum of eligible enterprise fee adjustments" do - ef = create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new ) + ef = create(:enterprise_fee, calculator: Calculator::FlatRate.new ) ef.calculator.set_preference :amount, 123.45 a = ef.create_adjustment("adjustment", o, o, true) @@ -145,7 +145,7 @@ describe Spree::Order do end it "does not include ineligible adjustments" do - ef = create(:enterprise_fee, calculator: Spree::Calculator::FlatRate.new ) + ef = create(:enterprise_fee, calculator: Calculator::FlatRate.new ) ef.calculator.set_preference :amount, 123.45 a = ef.create_adjustment("adjustment", o, o, true) @@ -155,7 +155,7 @@ describe Spree::Order do end it "does not include adjustments that do not originate from enterprise fees" do - sm = create(:shipping_method, calculator: Spree::Calculator::FlatRate.new ) + sm = create(:shipping_method, calculator: Calculator::FlatRate.new ) sm.calculator.set_preference :amount, 123.45 sm.create_adjustment("adjustment", o, o, true) @@ -163,7 +163,7 @@ describe Spree::Order do end it "does not include adjustments whose source is a line item" do - ef = create(:enterprise_fee, calculator: Spree::Calculator::PerItem.new ) + ef = create(:enterprise_fee, calculator: Calculator::PerItem.new ) ef.calculator.set_preference :amount, 123.45 ef.create_adjustment("adjustment", li.order, li, true) @@ -669,7 +669,7 @@ describe Spree::Order do end context "changing the shipping method to one without fees" do - let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0)) } + let(:shipping_method) { create(:shipping_method, calculator: Calculator::FlatRate.new(preferred_amount: 0)) } it "updates shipping fees" do order.shipments = [create(:shipment_with, :shipping_method, shipping_method: shipping_method)] @@ -681,7 +681,7 @@ describe Spree::Order do end context "changing the payment method to one without fees" do - let(:payment_method) { create(:payment_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0)) } + let(:payment_method) { create(:payment_method, calculator: Calculator::FlatRate.new(preferred_amount: 0)) } it "removes transaction fees" do # Change the payment method diff --git a/spec/models/spree/payment_spec.rb b/spec/models/spree/payment_spec.rb index 46a493fa96..eb148a736c 100644 --- a/spec/models/spree/payment_spec.rb +++ b/spec/models/spree/payment_spec.rb @@ -138,7 +138,7 @@ module Spree let!(:payment_method) { create(:payment_method, calculator: calculator) } let!(:calculator) do - Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) + Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) end context "when order complete and inventory tracking enabled" do @@ -159,7 +159,7 @@ module Spree let(:shop) { create(:enterprise) } let(:payment_method) { create(:stripe_payment_method, distributor_ids: [create(:distributor_enterprise).id], preferred_enterprise_id: shop.id) } let(:payment) { create(:payment, order: order, payment_method: payment_method, amount: order.total) } - let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } + let(:calculator) { Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } before do payment_method.calculator = calculator diff --git a/spec/models/spree/tax_rate_spec.rb b/spec/models/spree/tax_rate_spec.rb index 888b25c890..61938c5d0f 100644 --- a/spec/models/spree/tax_rate_spec.rb +++ b/spec/models/spree/tax_rate_spec.rb @@ -33,7 +33,7 @@ module Spree end describe "ensuring that tax rate is marked as tax included_in_price" do - let(:tax_rate) { create(:tax_rate, included_in_price: false, calculator: Spree::Calculator::DefaultTax.new) } + let(:tax_rate) { create(:tax_rate, included_in_price: false, calculator: Calculator::DefaultTax.new) } it "sets included_in_price to true" do tax_rate.send(:with_tax_included_in_price) do diff --git a/spec/models/tag_rule/discount_order_spec.rb b/spec/models/tag_rule/discount_order_spec.rb index 2a1260f7e3..831f2faf01 100644 --- a/spec/models/tag_rule/discount_order_spec.rb +++ b/spec/models/tag_rule/discount_order_spec.rb @@ -73,7 +73,7 @@ describe TagRule::DiscountOrder, type: :model do end context "when shipping charges apply" do - let!(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new( preferred_amount: 25.00 ) ) } + let!(:shipping_method) { create(:shipping_method, calculator: Calculator::FlatRate.new( preferred_amount: 25.00 ) ) } before do shipping_method.create_adjustment("Shipping", order, order, true) end diff --git a/spec/requests/checkout/failed_checkout_spec.rb b/spec/requests/checkout/failed_checkout_spec.rb index f45efe3951..41062d97d0 100644 --- a/spec/requests/checkout/failed_checkout_spec.rb +++ b/spec/requests/checkout/failed_checkout_spec.rb @@ -32,7 +32,7 @@ describe "checking out an order that initially fails", type: :request do end context "when shipping and payment fees apply" do - let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } + let(:calculator) { Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } before do payment_method.calculator = calculator.dup diff --git a/spec/requests/checkout/paypal_spec.rb b/spec/requests/checkout/paypal_spec.rb index 96c1baf4e9..e309d0ea5d 100644 --- a/spec/requests/checkout/paypal_spec.rb +++ b/spec/requests/checkout/paypal_spec.rb @@ -50,7 +50,7 @@ describe "checking out an order with a paypal express payment method", type: :re end context "with a flat percent calculator" do - let(:calculator) { Spree::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } + let(:calculator) { Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } before do payment_method.calculator = calculator diff --git a/spec/requests/checkout/stripe_connect_spec.rb b/spec/requests/checkout/stripe_connect_spec.rb index 5c1561c13c..000b2250a8 100644 --- a/spec/requests/checkout/stripe_connect_spec.rb +++ b/spec/requests/checkout/stripe_connect_spec.rb @@ -10,7 +10,7 @@ describe "checking out an order with a Stripe Connect payment method", type: :re let!(:shipping_method) do create( :shipping_method, - calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0), + calculator: Calculator::FlatRate.new(preferred_amount: 0), distributors: [enterprise] ) end diff --git a/spec/requests/checkout/stripe_sca_spec.rb b/spec/requests/checkout/stripe_sca_spec.rb index 5018ad321c..d2734f66d4 100644 --- a/spec/requests/checkout/stripe_sca_spec.rb +++ b/spec/requests/checkout/stripe_sca_spec.rb @@ -12,7 +12,7 @@ describe "checking out an order with a Stripe SCA payment method", type: :reques let!(:shipping_method) do create( :shipping_method, - calculator: Spree::Calculator::FlatRate.new(preferred_amount: 0), + calculator: Calculator::FlatRate.new(preferred_amount: 0), distributors: [enterprise] ) end diff --git a/spec/services/tax_rate_finder_spec.rb b/spec/services/tax_rate_finder_spec.rb index 3f5daadfcf..6881d66ebf 100644 --- a/spec/services/tax_rate_finder_spec.rb +++ b/spec/services/tax_rate_finder_spec.rb @@ -66,7 +66,7 @@ describe TaxRateFinder do create( :tax_rate, amount: amount, - calculator: Spree::Calculator::DefaultTax.new, + calculator: Calculator::DefaultTax.new, zone: zone ) end From 9c7cb23262ff87525dcf90e99e3b35fbf0b38b9f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:33:46 +0100 Subject: [PATCH 191/261] Move calculator specs out of the spree namespace --- .../models/{spree => }/calculator/flat_percent_item_total_spec.rb | 0 spec/models/{spree => }/calculator/flat_rate_spec.rb | 0 spec/models/{spree => }/calculator/flexi_rate_spec.rb | 0 spec/models/{spree => }/calculator/per_item_spec.rb | 0 spec/models/{spree => }/calculator/price_sack_spec.rb | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename spec/models/{spree => }/calculator/flat_percent_item_total_spec.rb (100%) rename spec/models/{spree => }/calculator/flat_rate_spec.rb (100%) rename spec/models/{spree => }/calculator/flexi_rate_spec.rb (100%) rename spec/models/{spree => }/calculator/per_item_spec.rb (100%) rename spec/models/{spree => }/calculator/price_sack_spec.rb (100%) diff --git a/spec/models/spree/calculator/flat_percent_item_total_spec.rb b/spec/models/calculator/flat_percent_item_total_spec.rb similarity index 100% rename from spec/models/spree/calculator/flat_percent_item_total_spec.rb rename to spec/models/calculator/flat_percent_item_total_spec.rb diff --git a/spec/models/spree/calculator/flat_rate_spec.rb b/spec/models/calculator/flat_rate_spec.rb similarity index 100% rename from spec/models/spree/calculator/flat_rate_spec.rb rename to spec/models/calculator/flat_rate_spec.rb diff --git a/spec/models/spree/calculator/flexi_rate_spec.rb b/spec/models/calculator/flexi_rate_spec.rb similarity index 100% rename from spec/models/spree/calculator/flexi_rate_spec.rb rename to spec/models/calculator/flexi_rate_spec.rb diff --git a/spec/models/spree/calculator/per_item_spec.rb b/spec/models/calculator/per_item_spec.rb similarity index 100% rename from spec/models/spree/calculator/per_item_spec.rb rename to spec/models/calculator/per_item_spec.rb diff --git a/spec/models/spree/calculator/price_sack_spec.rb b/spec/models/calculator/price_sack_spec.rb similarity index 100% rename from spec/models/spree/calculator/price_sack_spec.rb rename to spec/models/calculator/price_sack_spec.rb From 6a94168ee5176a3e15a2a74f02123763c57c4ff2 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 15 Jun 2020 21:52:59 +0100 Subject: [PATCH 192/261] Remove Spree namespace from DefaultTax --- app/models/calculator/default_tax.rb | 126 +++++++++++++-------------- 1 file changed, 62 insertions(+), 64 deletions(-) diff --git a/app/models/calculator/default_tax.rb b/app/models/calculator/default_tax.rb index 1910990945..d0dd8c8ea3 100644 --- a/app/models/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -3,82 +3,80 @@ require_dependency 'spree/calculator' require 'open_food_network/enterprise_fee_calculator' -module Spree - module Calculator - class DefaultTax < Spree::Calculator - def self.description - Spree.t(:default_tax) +module Calculator + class DefaultTax < Spree::Calculator + def self.description + Spree.t(:default_tax) + end + + def compute(computable) + case computable + when Spree::Order + compute_order(computable) + when Spree::LineItem + compute_line_item(computable) + end + end + + private + + def rate + calculable + end + + # Enable calculation of tax for enterprise fees with tax rates where included_in_price = false + def compute_order(order) + matched_line_items = order.line_items.select do |line_item| + line_item.product.tax_category == rate.tax_category end - def compute(computable) - case computable - when Spree::Order - compute_order(computable) - when Spree::LineItem - compute_line_item(computable) - end + line_items_total = matched_line_items.sum(&:total) + + calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, + order.order_cycle) + + # Finds relevant fees for each line_item, + # calculates the tax on them, and returns the total tax + per_item_fees_total = order.line_items.sum do |line_item| + calculator.per_item_enterprise_fee_applicators_for(line_item.variant) + .select { |applicator| + (!applicator.enterprise_fee.inherits_tax_category && + applicator.enterprise_fee.tax_category == rate.tax_category) || + (applicator.enterprise_fee.inherits_tax_category && + line_item.product.tax_category == rate.tax_category) + } + .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } end - private + # Finds relevant fees for whole order, + # calculates the tax on them, and returns the total tax + per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) + .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } + .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - def rate - calculable + [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| + round_to_two_places(total * rate.amount) end + end - # Enable calculation of tax for enterprise fees with tax rates where included_in_price = false - def compute_order(order) - matched_line_items = order.line_items.select do |line_item| - line_item.product.tax_category == rate.tax_category - end - - line_items_total = matched_line_items.sum(&:total) - - calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, - order.order_cycle) - - # Finds relevant fees for each line_item, - # calculates the tax on them, and returns the total tax - per_item_fees_total = order.line_items.sum do |line_item| - calculator.per_item_enterprise_fee_applicators_for(line_item.variant) - .select { |applicator| - (!applicator.enterprise_fee.inherits_tax_category && - applicator.enterprise_fee.tax_category == rate.tax_category) || - (applicator.enterprise_fee.inherits_tax_category && - line_item.product.tax_category == rate.tax_category) - } - .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } - end - - # Finds relevant fees for whole order, - # calculates the tax on them, and returns the total tax - per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) - .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } - .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - - [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| - round_to_two_places(total * rate.amount) - end - end - - def compute_line_item(line_item) - if line_item.tax_category == rate.tax_category - if rate.included_in_price - deduced_total_by_rate(line_item.total, rate) - else - round_to_two_places(line_item.total * rate.amount) - end + def compute_line_item(line_item) + if line_item.tax_category == rate.tax_category + if rate.included_in_price + deduced_total_by_rate(line_item.total, rate) else - 0 + round_to_two_places(line_item.total * rate.amount) end + else + 0 end + end - def round_to_two_places(amount) - BigDecimal(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP) - end + def round_to_two_places(amount) + BigDecimal(amount.to_s).round(2, BigDecimal::ROUND_HALF_UP) + end - def deduced_total_by_rate(total, rate) - round_to_two_places(total - ( total / (1 + rate.amount) ) ) - end + def deduced_total_by_rate(total, rate) + round_to_two_places(total - ( total / (1 + rate.amount) ) ) end end end From f62546254fa82fc7f7482d0b9abb2f58d05a9c86 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 17:25:21 +0100 Subject: [PATCH 193/261] Define DefaultTax calculator outside of spree namespace the tax_rate to be used by the app and make spree specs use calculators outside the spree namespace --- config/application.rb | 6 ++++++ spec/models/spree/adjustment_spec.rb | 12 ++++++------ spec/models/spree/payment_spec.rb | 7 +++---- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/config/application.rb b/config/application.rb index 3860b0b928..3d061b97be 100644 --- a/config/application.rb +++ b/config/application.rb @@ -66,6 +66,7 @@ module Openfoodnetwork Calculator::PriceSack, Calculator::Weight ] + app.config.spree.calculators.add_class('payment_methods') config.spree.calculators.payment_methods = [ Calculator::FlatPercentItemTotal, @@ -74,6 +75,11 @@ module Openfoodnetwork Calculator::PerItem, Calculator::PriceSack ] + + app.config.spree.calculators.add_class('tax_rates') + config.spree.calculators.tax_rates = [ + Calculator::DefaultTax + ] end # Register Spree payment methods diff --git a/spec/models/spree/adjustment_spec.rb b/spec/models/spree/adjustment_spec.rb index 57047457ac..0ea3eea273 100644 --- a/spec/models/spree/adjustment_spec.rb +++ b/spec/models/spree/adjustment_spec.rb @@ -127,7 +127,7 @@ module Spree describe "EnterpriseFee adjustments" do let(:zone) { create(:zone_with_member) } - let(:fee_tax_rate) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, zone: zone, amount: 0.1) } + let(:fee_tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.1) } let(:fee_tax_category) { create(:tax_category, tax_rates: [fee_tax_rate]) } let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) } @@ -143,7 +143,7 @@ module Spree end context "when enterprise fees are taxed per-order" do - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: Calculator::FlatRate.new(preferred_amount: 50.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: ::Calculator::FlatRate.new(preferred_amount: 50.0)) } describe "when the tax rate includes the tax in the price" do it "records the tax on the enterprise fee adjustments" do @@ -181,7 +181,7 @@ module Spree end context "when enterprise fees are taxed per-item" do - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: Calculator::PerItem.new(preferred_amount: 50.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: fee_tax_category, calculator: ::Calculator::PerItem.new(preferred_amount: 50.0)) } describe "when the tax rate includes the tax in the price" do it "records the tax on the enterprise fee adjustments" do @@ -205,7 +205,7 @@ module Spree end context "when enterprise fees inherit their tax_category from the product they are applied to" do - let(:product_tax_rate) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, zone: zone, amount: 0.2) } + let(:product_tax_rate) { create(:tax_rate, included_in_price: true, calculator: ::Calculator::DefaultTax.new, zone: zone, amount: 0.2) } let(:product_tax_category) { create(:tax_category, tax_rates: [product_tax_rate]) } before do @@ -216,7 +216,7 @@ module Spree end context "when enterprise fees are taxed per-order" do - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: Calculator::FlatRate.new(preferred_amount: 50.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: ::Calculator::FlatRate.new(preferred_amount: 50.0)) } describe "when the tax rate includes the tax in the price" do it "records no tax on the enterprise fee adjustments" do @@ -246,7 +246,7 @@ module Spree end context "when enterprise fees are taxed per-item" do - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: Calculator::PerItem.new(preferred_amount: 50.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, inherits_tax_category: true, calculator: ::Calculator::PerItem.new(preferred_amount: 50.0)) } describe "when the tax rate includes the tax in the price" do it "records the tax on the enterprise fee adjustments" do diff --git a/spec/models/spree/payment_spec.rb b/spec/models/spree/payment_spec.rb index eb148a736c..1ca723566c 100644 --- a/spec/models/spree/payment_spec.rb +++ b/spec/models/spree/payment_spec.rb @@ -136,12 +136,11 @@ module Spree context "when order-based calculator" do let!(:shop) { create(:enterprise) } let!(:payment_method) { create(:payment_method, calculator: calculator) } - let!(:calculator) do - Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) + ::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) end - context "when order complete and inventory tracking enabled" do + context "when order complete" do let!(:order) { create(:completed_order_with_totals, distributor: shop) } let!(:variant) { order.line_items.first.variant } let!(:inventory_item) { create(:inventory_item, enterprise: shop, variant: variant) } @@ -159,7 +158,7 @@ module Spree let(:shop) { create(:enterprise) } let(:payment_method) { create(:stripe_payment_method, distributor_ids: [create(:distributor_enterprise).id], preferred_enterprise_id: shop.id) } let(:payment) { create(:payment, order: order, payment_method: payment_method, amount: order.total) } - let(:calculator) { Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } + let(:calculator) { ::Calculator::FlatPercentItemTotal.new(preferred_flat_percent: 10) } before do payment_method.calculator = calculator From e225c5ce3a1ecc745196dcafb0bb654c94f27fd9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 17:47:36 +0100 Subject: [PATCH 194/261] Migrate calculators to outside spree namespace --- ...calculators_outside_the_spree_namespace.rb | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb diff --git a/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb b/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb new file mode 100644 index 0000000000..78f132303a --- /dev/null +++ b/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +class MoveAllCalculatorsOutsideTheSpreeNamespace < ActiveRecord::Migration + def up + convert_calculator("Spree::Calculator::DefaultTax", "Calculator::DefaultTax") + convert_calculator("Spree::Calculator::FlatPercentItemTotal", + "Calculator::FlatPercentItemTotal") + convert_calculator("Spree::Calculator::FlatRate", "Calculator::FlatRate") + convert_calculator("Spree::Calculator::FlexiRate", "Calculator::FlexiRate") + convert_calculator("Spree::Calculator::PerItem", "Calculator::PerItem") + convert_calculator("Spree::Calculator::PriceSack", "Calculator::PriceSack") + end + + def down + convert_calculator("Calculator::DefaultTax", "Spree::Calculator::DefaultTax") + convert_calculator("Calculator::FlatPercentItemTotal", + "Spree::Calculator::FlatPercentItemTotal") + convert_calculator("Calculator::FlatRate", "Spree::Calculator::FlatRate") + convert_calculator("Calculator::FlexiRate", "Spree::Calculator::FlexiRate") + convert_calculator("Calculator::PerItem", "Spree::Calculator::PerItem") + convert_calculator("Calculator::PriceSack", "Spree::Calculator::PriceSack") + end + + private + + def convert_calculator(from, to) + Spree::Calculator.connection.execute( + "UPDATE spree_calculators SET type = '" + to + "' WHERE type = '" + from + "'" + ) + end +end From eedf31e44910daf566a87229040a4bf53baa5522 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 17:50:43 +0100 Subject: [PATCH 195/261] Make migration a bit easier to read --- ...calculators_outside_the_spree_namespace.rb | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb b/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb index 78f132303a..b357242db2 100644 --- a/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb +++ b/db/migrate/20200616162646_move_all_calculators_outside_the_spree_namespace.rb @@ -2,28 +2,36 @@ class MoveAllCalculatorsOutsideTheSpreeNamespace < ActiveRecord::Migration def up - convert_calculator("Spree::Calculator::DefaultTax", "Calculator::DefaultTax") - convert_calculator("Spree::Calculator::FlatPercentItemTotal", - "Calculator::FlatPercentItemTotal") - convert_calculator("Spree::Calculator::FlatRate", "Calculator::FlatRate") - convert_calculator("Spree::Calculator::FlexiRate", "Calculator::FlexiRate") - convert_calculator("Spree::Calculator::PerItem", "Calculator::PerItem") - convert_calculator("Spree::Calculator::PriceSack", "Calculator::PriceSack") + convert_calculator("DefaultTax") + convert_calculator("FlatPercentItemTotal") + convert_calculator("FlatRate") + convert_calculator("FlexiRate") + convert_calculator("PerItem") + convert_calculator("PriceSack") end def down - convert_calculator("Calculator::DefaultTax", "Spree::Calculator::DefaultTax") - convert_calculator("Calculator::FlatPercentItemTotal", - "Spree::Calculator::FlatPercentItemTotal") - convert_calculator("Calculator::FlatRate", "Spree::Calculator::FlatRate") - convert_calculator("Calculator::FlexiRate", "Spree::Calculator::FlexiRate") - convert_calculator("Calculator::PerItem", "Spree::Calculator::PerItem") - convert_calculator("Calculator::PriceSack", "Spree::Calculator::PriceSack") + revert_calculator("DefaultTax") + revert_calculator("FlatPercentItemTotal") + revert_calculator("FlatRate") + revert_calculator("FlexiRate") + revert_calculator("PerItem") + revert_calculator("PriceSack") end private - def convert_calculator(from, to) + def convert_calculator(calculator_base_name) + update_calculator("Spree::Calculator::" + calculator_base_name, + "Calculator::" + calculator_base_name) + end + + def revert_calculator(calculator_base_name) + update_calculator("Calculator::" + calculator_base_name, + "Spree::Calculator::" + calculator_base_name) + end + + def update_calculator(from, to) Spree::Calculator.connection.execute( "UPDATE spree_calculators SET type = '" + to + "' WHERE type = '" + from + "'" ) From 4b12a5f592f6091fbc05b1dcf7559b01ea3293c9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:01:29 +0100 Subject: [PATCH 196/261] Extract line_items_total from compute_order --- app/models/calculator/default_tax.rb | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/models/calculator/default_tax.rb b/app/models/calculator/default_tax.rb index d0dd8c8ea3..d1bb5a0a52 100644 --- a/app/models/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -26,12 +26,6 @@ module Calculator # Enable calculation of tax for enterprise fees with tax rates where included_in_price = false def compute_order(order) - matched_line_items = order.line_items.select do |line_item| - line_item.product.tax_category == rate.tax_category - end - - line_items_total = matched_line_items.sum(&:total) - calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) @@ -54,11 +48,19 @@ module Calculator .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - [line_items_total, per_item_fees_total, per_order_fees_total].sum do |total| + [line_items_total(order), per_item_fees_total, per_order_fees_total].sum do |total| round_to_two_places(total * rate.amount) end end + def line_items_total(order) + matched_line_items = order.line_items.select do |line_item| + line_item.product.tax_category == rate.tax_category + end + + matched_line_items.sum(&:total) + end + def compute_line_item(line_item) if line_item.tax_category == rate.tax_category if rate.included_in_price From 21120dd6ab9e94022bf142dab3328b38f9eb4a18 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:04:16 +0100 Subject: [PATCH 197/261] Extract per_item_fees_total out of compute_order --- app/models/calculator/default_tax.rb | 30 +++++++++++++++------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/app/models/calculator/default_tax.rb b/app/models/calculator/default_tax.rb index d1bb5a0a52..b3030226ce 100644 --- a/app/models/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -29,26 +29,13 @@ module Calculator calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) - # Finds relevant fees for each line_item, - # calculates the tax on them, and returns the total tax - per_item_fees_total = order.line_items.sum do |line_item| - calculator.per_item_enterprise_fee_applicators_for(line_item.variant) - .select { |applicator| - (!applicator.enterprise_fee.inherits_tax_category && - applicator.enterprise_fee.tax_category == rate.tax_category) || - (applicator.enterprise_fee.inherits_tax_category && - line_item.product.tax_category == rate.tax_category) - } - .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } - end - # Finds relevant fees for whole order, # calculates the tax on them, and returns the total tax per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - [line_items_total(order), per_item_fees_total, per_order_fees_total].sum do |total| + [line_items_total(order), per_item_fees_total(order, calculator), per_order_fees_total].sum do |total| round_to_two_places(total * rate.amount) end end @@ -61,6 +48,21 @@ module Calculator matched_line_items.sum(&:total) end + # Finds relevant fees for each line_item, + # calculates the tax on them, and returns the total tax + def per_item_fees_total(order, calculator) + order.line_items.sum do |line_item| + calculator.per_item_enterprise_fee_applicators_for(line_item.variant) + .select { |applicator| + (!applicator.enterprise_fee.inherits_tax_category && + applicator.enterprise_fee.tax_category == rate.tax_category) || + (applicator.enterprise_fee.inherits_tax_category && + line_item.product.tax_category == rate.tax_category) + } + .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } + end + end + def compute_line_item(line_item) if line_item.tax_category == rate.tax_category if rate.included_in_price From b096717172a8c2530fbab56f7b2820e522ee378f Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:06:26 +0100 Subject: [PATCH 198/261] Extract per_order_fees_total out of compute_order --- app/models/calculator/default_tax.rb | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/app/models/calculator/default_tax.rb b/app/models/calculator/default_tax.rb index b3030226ce..073fdcbeef 100644 --- a/app/models/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -29,13 +29,11 @@ module Calculator calculator = OpenFoodNetwork::EnterpriseFeeCalculator.new(order.distributor, order.order_cycle) - # Finds relevant fees for whole order, - # calculates the tax on them, and returns the total tax - per_order_fees_total = calculator.per_order_enterprise_fee_applicators_for(order) - .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } - .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } - - [line_items_total(order), per_item_fees_total(order, calculator), per_order_fees_total].sum do |total| + [ + line_items_total(order), + per_item_fees_total(order, calculator), + per_order_fees_total(order, calculator) + ].sum do |total| round_to_two_places(total * rate.amount) end end @@ -63,6 +61,14 @@ module Calculator end end + # Finds relevant fees for whole order, + # calculates the tax on them, and returns the total tax + def per_order_fees_total(order, calculator) + calculator.per_order_enterprise_fee_applicators_for(order) + .select { |applicator| applicator.enterprise_fee.tax_category == rate.tax_category } + .sum { |applicator| applicator.enterprise_fee.compute_amount(order) } + end + def compute_line_item(line_item) if line_item.tax_category == rate.tax_category if rate.included_in_price From fbe0a3246d03f5e493ba92d4df84dfcc97d4a063 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:09:56 +0100 Subject: [PATCH 199/261] Extract applicable_rate? and thus resolve rubocop complexity issue --- app/models/calculator/default_tax.rb | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/models/calculator/default_tax.rb b/app/models/calculator/default_tax.rb index 073fdcbeef..de888c9283 100644 --- a/app/models/calculator/default_tax.rb +++ b/app/models/calculator/default_tax.rb @@ -51,16 +51,17 @@ module Calculator def per_item_fees_total(order, calculator) order.line_items.sum do |line_item| calculator.per_item_enterprise_fee_applicators_for(line_item.variant) - .select { |applicator| - (!applicator.enterprise_fee.inherits_tax_category && - applicator.enterprise_fee.tax_category == rate.tax_category) || - (applicator.enterprise_fee.inherits_tax_category && - line_item.product.tax_category == rate.tax_category) - } + .select { |applicator| applicable_rate?(applicator, line_item) } .sum { |applicator| applicator.enterprise_fee.compute_amount(line_item) } end end + def applicable_rate?(applicator, line_item) + fee = applicator.enterprise_fee + (!fee.inherits_tax_category && fee.tax_category == rate.tax_category) || + (fee.inherits_tax_category && line_item.product.tax_category == rate.tax_category) + end + # Finds relevant fees for whole order, # calculates the tax on them, and returns the total tax def per_order_fees_total(order, calculator) From 70432e301db69f1076601761782f57e977bf299c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:11:54 +0100 Subject: [PATCH 200/261] Early exit if max is zero to make method shorted --- app/models/calculator/flexi_rate.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/calculator/flexi_rate.rb b/app/models/calculator/flexi_rate.rb index b7e7974c3b..e4a666b897 100644 --- a/app/models/calculator/flexi_rate.rb +++ b/app/models/calculator/flexi_rate.rb @@ -29,12 +29,12 @@ module Calculator items_count = line_items_for(object).map(&:quantity).sum # check max value to avoid divide by 0 errors - unless max.zero? - if items_count > max - sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - elsif items_count <= max - sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f - end + return 0 if max.zero? + + if items_count > max + sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + elsif items_count <= max + sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f end sum From 68359d4d1a4ce64a7cf8b30542638326379c62a5 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:14:46 +0100 Subject: [PATCH 201/261] Remove unnecessary variable (this sum and += come from the original spree code and is not necessary here now) --- app/models/calculator/flexi_rate.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/app/models/calculator/flexi_rate.rb b/app/models/calculator/flexi_rate.rb index e4a666b897..4f56f10a41 100644 --- a/app/models/calculator/flexi_rate.rb +++ b/app/models/calculator/flexi_rate.rb @@ -24,7 +24,6 @@ module Calculator end def compute(object) - sum = 0 max = preferred_max_items.to_i items_count = line_items_for(object).map(&:quantity).sum @@ -32,12 +31,10 @@ module Calculator return 0 if max.zero? if items_count > max - sum += (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f elsif items_count <= max - sum += (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f end - - sum end end end From d92f97716a50312f8d1cbb29f8c5ee2073a695ee Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:17:39 +0100 Subject: [PATCH 202/261] Extract compute_for and thus resolve the rubocop complexity issue --- app/models/calculator/flexi_rate.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/models/calculator/flexi_rate.rb b/app/models/calculator/flexi_rate.rb index 4f56f10a41..76ae53379a 100644 --- a/app/models/calculator/flexi_rate.rb +++ b/app/models/calculator/flexi_rate.rb @@ -31,10 +31,16 @@ module Calculator return 0 if max.zero? if items_count > max - (max - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + compute_for(max - 1) elsif items_count <= max - (items_count - 1) * preferred_additional_item.to_f + preferred_first_item.to_f + compute_for(items_count - 1) end end + + private + + def compute_for(count) + count * preferred_additional_item.to_f + preferred_first_item.to_f + end end end From 0b79e7c48c119d7e026f57d37d8acbcd3e31e8e7 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 16 Jun 2020 18:18:34 +0100 Subject: [PATCH 203/261] Fix rubucop issue in enterprise_fee model --- .rubocop_manual_todo.yml | 1 - app/models/enterprise_fee.rb | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index c5b16934f0..e4eea50ed8 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -54,7 +54,6 @@ Layout/LineLength: - app/models/concerns/variant_stock.rb - app/models/content_configuration.rb - app/models/customer.rb - - app/models/enterprise_fee.rb - app/models/enterprise_group.rb - app/models/enterprise_role.rb - app/models/inventory_item.rb diff --git a/app/models/enterprise_fee.rb b/app/models/enterprise_fee.rb index 1bea6701e7..e973419ece 100644 --- a/app/models/enterprise_fee.rb +++ b/app/models/enterprise_fee.rb @@ -11,7 +11,9 @@ class EnterpriseFee < ActiveRecord::Base has_many :exchanges, through: :exchange_fees FEE_TYPES = %w(packing transport admin sales fundraising).freeze - PER_ORDER_CALCULATORS = ['Calculator::FlatRate', 'Calculator::FlexiRate', 'Calculator::PriceSack'].freeze + PER_ORDER_CALCULATORS = ['Calculator::FlatRate', + 'Calculator::FlexiRate', + 'Calculator::PriceSack'].freeze validates :fee_type, inclusion: { in: FEE_TYPES } validates :name, presence: true From 99e12b6f075ba16000facd4bbea8353b5eb7177e Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 17 Jun 2020 19:43:08 +0100 Subject: [PATCH 204/261] Convert calculators in new spec --- spec/services/order_tax_adjustments_fetcher_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/services/order_tax_adjustments_fetcher_spec.rb b/spec/services/order_tax_adjustments_fetcher_spec.rb index 2b06e5c4a2..fd0ce52372 100644 --- a/spec/services/order_tax_adjustments_fetcher_spec.rb +++ b/spec/services/order_tax_adjustments_fetcher_spec.rb @@ -7,17 +7,17 @@ describe OrderTaxAdjustmentsFetcher do let(:zone) { create(:zone_with_member) } let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) } - let(:tax_rate10) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.1, zone: zone) } - let(:tax_rate15) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.15, zone: zone) } - let(:tax_rate20) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.2, zone: zone) } - let(:tax_rate25) { create(:tax_rate, included_in_price: true, calculator: Spree::Calculator::DefaultTax.new, amount: 0.25, zone: zone) } + let(:tax_rate10) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.1, zone: zone) } + let(:tax_rate15) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.15, zone: zone) } + let(:tax_rate20) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.2, zone: zone) } + let(:tax_rate25) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.25, zone: zone) } let(:tax_category10) { create(:tax_category, tax_rates: [tax_rate10]) } let(:tax_category15) { create(:tax_category, tax_rates: [tax_rate15]) } let(:tax_category20) { create(:tax_category, tax_rates: [tax_rate20]) } let(:tax_category25) { create(:tax_category, tax_rates: [tax_rate25]) } let(:variant) { create(:variant, product: create(:product, tax_category: tax_category10)) } - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category20, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 48.0)) } + let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category20, calculator: Calculator::FlatRate.new(preferred_amount: 48.0)) } let(:additional_adjustment) { create(:adjustment, amount: 50.0, included_tax: tax_rate25.compute_tax(50.0)) } let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator], variants: [variant]) } @@ -38,7 +38,7 @@ describe OrderTaxAdjustmentsFetcher do allow(Spree::Config).to receive(:shipping_tax_rate).and_return(tax_rate15.amount) end - let(:shipping_method) { create(:shipping_method, calculator: Spree::Calculator::FlatRate.new(preferred_amount: 46.0)) } + let(:shipping_method) { create(:shipping_method, calculator: Calculator::FlatRate.new(preferred_amount: 46.0)) } let!(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method, order: order) } before do From 5e6739c9f7da07f82eee3e1d3ccd226e07a1c39d Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 17 Jun 2020 19:48:29 +0100 Subject: [PATCH 205/261] Fix long lines in new spec --- .../order_tax_adjustments_fetcher_spec.rb | 71 ++++++++++++++----- 1 file changed, 54 insertions(+), 17 deletions(-) diff --git a/spec/services/order_tax_adjustments_fetcher_spec.rb b/spec/services/order_tax_adjustments_fetcher_spec.rb index fd0ce52372..6707aa1abf 100644 --- a/spec/services/order_tax_adjustments_fetcher_spec.rb +++ b/spec/services/order_tax_adjustments_fetcher_spec.rb @@ -4,24 +4,57 @@ require "spec_helper" describe OrderTaxAdjustmentsFetcher do describe "#totals" do - let(:zone) { create(:zone_with_member) } - let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) } + let(:zone) { create(:zone_with_member) } + let(:coordinator) { create(:distributor_enterprise, charges_sales_tax: true) } - let(:tax_rate10) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.1, zone: zone) } - let(:tax_rate15) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.15, zone: zone) } - let(:tax_rate20) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.2, zone: zone) } - let(:tax_rate25) { create(:tax_rate, included_in_price: true, calculator: Calculator::DefaultTax.new, amount: 0.25, zone: zone) } - let(:tax_category10) { create(:tax_category, tax_rates: [tax_rate10]) } - let(:tax_category15) { create(:tax_category, tax_rates: [tax_rate15]) } - let(:tax_category20) { create(:tax_category, tax_rates: [tax_rate20]) } - let(:tax_category25) { create(:tax_category, tax_rates: [tax_rate25]) } + let(:tax_rate10) do + create(:tax_rate, included_in_price: true, + calculator: Calculator::DefaultTax.new, + amount: 0.1, + zone: zone) + end + let(:tax_rate15) do + create(:tax_rate, included_in_price: true, + calculator: Calculator::DefaultTax.new, + amount: 0.15, + zone: zone) + end + let(:tax_rate20) do + create(:tax_rate, included_in_price: true, + calculator: Calculator::DefaultTax.new, + amount: 0.2, + zone: zone) + end + let(:tax_rate25) do + create(:tax_rate, included_in_price: true, + calculator: Calculator::DefaultTax.new, + amount: 0.25, + zone: zone) + end + let(:tax_category10) { create(:tax_category, tax_rates: [tax_rate10]) } + let(:tax_category15) { create(:tax_category, tax_rates: [tax_rate15]) } + let(:tax_category20) { create(:tax_category, tax_rates: [tax_rate20]) } + let(:tax_category25) { create(:tax_category, tax_rates: [tax_rate25]) } - let(:variant) { create(:variant, product: create(:product, tax_category: tax_category10)) } - let(:enterprise_fee) { create(:enterprise_fee, enterprise: coordinator, tax_category: tax_category20, calculator: Calculator::FlatRate.new(preferred_amount: 48.0)) } - let(:additional_adjustment) { create(:adjustment, amount: 50.0, included_tax: tax_rate25.compute_tax(50.0)) } + let(:variant) do + create(:variant, product: create(:product, tax_category: tax_category10)) + end + let(:enterprise_fee) do + create(:enterprise_fee, enterprise: coordinator, + tax_category: tax_category20, + calculator: Calculator::FlatRate.new(preferred_amount: 48.0)) + end + let(:additional_adjustment) do + create(:adjustment, amount: 50.0, included_tax: tax_rate25.compute_tax(50.0)) + end - let(:order_cycle) { create(:simple_order_cycle, coordinator: coordinator, coordinator_fees: [enterprise_fee], distributors: [coordinator], variants: [variant]) } - let(:line_item) { create(:line_item, variant: variant, price: 44.0) } + let(:order_cycle) do + create(:simple_order_cycle, coordinator: coordinator, + coordinator_fees: [enterprise_fee], + distributors: [coordinator], + variants: [variant]) + end + let(:line_item) { create(:line_item, variant: variant, price: 44.0) } let(:order) do create( :order, @@ -38,8 +71,12 @@ describe OrderTaxAdjustmentsFetcher do allow(Spree::Config).to receive(:shipping_tax_rate).and_return(tax_rate15.amount) end - let(:shipping_method) { create(:shipping_method, calculator: Calculator::FlatRate.new(preferred_amount: 46.0)) } - let!(:shipment) { create(:shipment_with, :shipping_method, shipping_method: shipping_method, order: order) } + let(:shipping_method) do + create(:shipping_method, calculator: Calculator::FlatRate.new(preferred_amount: 46.0)) + end + let!(:shipment) do + create(:shipment_with, :shipping_method, shipping_method: shipping_method, order: order) + end before do order.create_tax_charge! From a1e8c8ad030f26d7db272214de6f8343bf85befd Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Wed, 8 Jul 2020 10:59:13 +0200 Subject: [PATCH 206/261] Remove dead specs helper method I found it while reviewing https://github.com/openfoodfoundation/openfoodnetwork/pull/5718#discussion_r451390809. --- spec/support/request/authentication_workflow.rb | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/spec/support/request/authentication_workflow.rb b/spec/support/request/authentication_workflow.rb index e07327d3e7..c06baf8eac 100644 --- a/spec/support/request/authentication_workflow.rb +++ b/spec/support/request/authentication_workflow.rb @@ -46,23 +46,6 @@ module AuthenticationWorkflow # click_button 'Login' end - def login_to_consumer_section - user_role = Spree::Role.find_or_create_by!(name: 'user') - user = create_enterprise_user( - email: 'someone@ofn.org', - password: 'passw0rd', - password_confirmation: 'passw0rd', - remember_me: false, - persistence_token: 'pass', - login: 'someone@ofn.org' - ) - - user.spree_roles << user_role - - visit spree.login_path - fill_in_and_submit_login_form user - end - def fill_in_and_submit_login_form(user) fill_in "email", with: user.email fill_in "password", with: user.password From be1e39f0cb6c1bcfa346dab7227d96e5b267459e Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 10:31:54 +0200 Subject: [PATCH 207/261] Ensure next page has loaded before interacting with form elements --- .../admin/order_cycles/complex_updating_specific_time_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb index 258caa1080..fb90552e88 100644 --- a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb +++ b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb @@ -87,6 +87,7 @@ feature ' select 'Supplier fee 2', from: 'order_cycle_incoming_exchange_2_enterprise_fees_0_enterprise_fee_id' click_button 'Save and Next' + expect(page).to have_content 'Your order cycle has been updated.' # And I add a distributor and some products select 'My distributor', from: 'new_distributor_id' From c8254b833886f84deed2c3532cd6a65cc8fa3e9d Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 10:38:06 +0200 Subject: [PATCH 208/261] Adjust exchange_row assertion to use slightly more specific criteria --- .../order_cycles/complex_updating_specific_time_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb index fb90552e88..52c7d45f78 100644 --- a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb +++ b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb @@ -109,8 +109,10 @@ feature ' exchange_rows = page.all("table.exchanges tbody") exchange_rows.each do |exchange_row| exchange_row.find("td.products").click - # Wait for the products panel to be visible. - expect(exchange_row).to have_selector "tr", count: 2 + within(exchange_row) do + # Wait for the products panel to be visible. + expect(page).to have_selector ".exchange-distributed-products" + end end uncheck "order_cycle_outgoing_exchange_2_variants_#{v1.id}" From e74206995900757182bd17423e3b03e582312eae Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Tue, 7 Jul 2020 12:10:43 +0200 Subject: [PATCH 209/261] Refactor UI interactions for opening exchange product tabs in OC edit --- .../complex_updating_specific_time_spec.rb | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb index 52c7d45f78..2094a83f7e 100644 --- a/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb +++ b/spec/features/admin/order_cycles/complex_updating_specific_time_spec.rb @@ -69,7 +69,8 @@ feature ' select 'My supplier', from: 'new_supplier_id' click_button 'Add supplier' expect(page).to have_selector("table.exchanges tr.supplier", text: "My supplier") - page.all("table.exchanges tr.supplier td.products").each(&:click) + + open_all_exchange_product_tabs expect(page).to have_selector "#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true page.find("#order_cycle_incoming_exchange_1_variants_#{initial_variants.last.id}", visible: true).click # uncheck (with visible:true filter) @@ -106,14 +107,7 @@ feature ' find(:css, "tags-input .tags input").set "wholesale\n" end - exchange_rows = page.all("table.exchanges tbody") - exchange_rows.each do |exchange_row| - exchange_row.find("td.products").click - within(exchange_row) do - # Wait for the products panel to be visible. - expect(page).to have_selector ".exchange-distributed-products" - end - end + open_all_exchange_product_tabs uncheck "order_cycle_outgoing_exchange_2_variants_#{v1.id}" check "order_cycle_outgoing_exchange_2_variants_#{v2.id}" @@ -168,4 +162,15 @@ feature ' def wait_for_edit_form_to_load_order_cycle(order_cycle) expect(page).to have_field "order_cycle_name", with: order_cycle.name end + + def open_all_exchange_product_tabs + exchange_rows = page.all("table.exchanges tbody") + exchange_rows.each do |exchange_row| + exchange_row.find("td.products").click + within(exchange_row) do + # Wait for the products panel to be visible. + expect(page).to have_selector ".exchange-products" + end + end + end end From a763a5ee0bd43968fc54e7c883e38ebd8f68cb2a Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 8 Jul 2020 12:49:20 +0200 Subject: [PATCH 210/261] Update all locales with the latest Transifex translations --- config/locales/ar.yml | 6 ++---- config/locales/ca.yml | 6 ++---- config/locales/de_DE.yml | 6 ++---- config/locales/en_AU.yml | 6 ++---- config/locales/en_BE.yml | 6 ++---- config/locales/en_CA.yml | 6 ++---- config/locales/en_DE.yml | 6 ++---- config/locales/en_GB.yml | 6 ++---- config/locales/en_IE.yml | 6 ++---- config/locales/en_NZ.yml | 6 ++---- config/locales/en_PH.yml | 6 ++---- config/locales/en_US.yml | 6 ++---- config/locales/en_ZA.yml | 6 ++---- config/locales/es.yml | 6 ++---- config/locales/es_CR.yml | 6 ++---- config/locales/fil_PH.yml | 6 ++---- config/locales/fr_BE.yml | 6 ++---- config/locales/fr_CA.yml | 6 ++---- config/locales/it.yml | 6 ++---- config/locales/nb.yml | 6 ++---- config/locales/nl_BE.yml | 6 ++---- config/locales/pt.yml | 6 ++---- config/locales/pt_BR.yml | 2 +- config/locales/sv.yml | 6 ++---- config/locales/tr.yml | 34 +++++++++++++++++----------------- 25 files changed, 64 insertions(+), 110 deletions(-) diff --git a/config/locales/ar.yml b/config/locales/ar.yml index 01ada3d77c..a2dc262509 100644 --- a/config/locales/ar.yml +++ b/config/locales/ar.yml @@ -177,8 +177,7 @@ ar: title: فشل آخر (%{count} أوامر) explainer: فشلت المعالجة التلقائية لهذه الطلبات لسبب غير معروف. لا ينبغي أن يحدث هذا ، يرجى الاتصال بنا إذا كنت ترى هذا. home: "OFN" - title: شبكة الغذاء المفتوح - welcome_to: 'مرحبا بك في' + title: "شبكة الغذاء المفتوح" site_meta_description: "نبدأ من الألف إلى الياء. مع المزارعين والمزارعين على استعداد لرواية قصصهم بفخر وحق. مع الموزعين على استعداد لتوصيل الأشخاص بالمنتجات بطريقة عادلة وبصدق. مع المشترين الذين يعتقدون أن أفضل قرارات التسوق الأسبوعية يمكن ..." search_by_name: البحث بالاسم أو الضاحية ... producers_join: المنتجون الأستراليون مدعوون الآن للانضمام إلى شبكة الغذاء المفتوح. @@ -1692,8 +1691,7 @@ ar: password: كلمه السر remember_me: تذكرنى are_you_sure: "هل أنت واثق؟" - orders_open: الطلب مفتوح - closing: "إغلاق" + orders_open: "الطلب مفتوح" going_back_to_home_page: "الرجوع إلى الصفحة الرئيسية" creating: انشاء updating: تحديث diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 7c4ac98c2e..a71b762573 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -181,8 +181,7 @@ ca: title: Altres errors (%{count} comandes) explainer: El processament automàtic d'aquestes comandes va fallar per un motiu desconegut. Això no hauria de passar, si us plau, contacteu amb nosaltres si esteu veient això. home: "OFN" - title: Open Food Network - welcome_to: 'Benvingut a ' + title: "Open Food Network" site_meta_description: "Comencem des de baix. Amb agricultors i productors disposats a explicar les seves històries amb orgull i sinceritat. Amb distribuïdors connectant persones i productes de manera justa i honesta. Amb compradors que creuen que millors decisions de compra setmanal poden ..." search_by_name: Cercar per nom o barri ... producers_join: Els productors australians son ara benvinguts a unir-se a Open Food Network. @@ -1716,8 +1715,7 @@ ca: password: Contrasenya remember_me: Recorda'm are_you_sure: "Estàs segur?" - orders_open: Comandes obertes - closing: "Tancant" + orders_open: "Comandes obertes" going_back_to_home_page: "Tornant a la pàgina d'inici" creating: Creant updating: Actualitzant diff --git a/config/locales/de_DE.yml b/config/locales/de_DE.yml index df3d7e29c1..de1588cf38 100644 --- a/config/locales/de_DE.yml +++ b/config/locales/de_DE.yml @@ -181,8 +181,7 @@ de_DE: title: Andere Fehler (%{count} Bestellungen) explainer: Die automatische Verarbeitung dieser Aufträge ist aus einem unbekannten Grund fehlgeschlagen. Dies sollte nicht geschehen, bitte kontaktieren Sie uns, wenn Sie dies sehen. home: "OFN" - title: Open Food Network - welcome_to: 'Willkommen bei' + title: "Open Food Network" site_meta_description: "Wir starten ganz grundsätzlich. Mit LandwirtInnen und GärtnerInnen, die stolz und ehrlich ihre Geschichte erzählen. Mit Lieferanten, die Menschen fair und vertrauenswürdig mit Produkten verbinden. Mit KonsumentInnen, die glauben, daß ihre wöchentlichen Einkaufsentscheidungen..." search_by_name: Suche nach Name oder Ort... producers_join: 'Wir laden Deutsche Produzenten ein, jetzt dem Open Food Network beizutreten. ' @@ -1688,8 +1687,7 @@ de_DE: password: Passwort remember_me: Erinnere dich an mich are_you_sure: "Bist du sicher?" - orders_open: Bestellungen öffnen - closing: "Schließen" + orders_open: "Bestellungen öffnen" going_back_to_home_page: "Bring dich zurück auf die Homepage" creating: Erstellen updating: Aktualisierung diff --git a/config/locales/en_AU.yml b/config/locales/en_AU.yml index 111c9a7522..528ee44b6d 100644 --- a/config/locales/en_AU.yml +++ b/config/locales/en_AU.yml @@ -175,8 +175,7 @@ en_AU: 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 ' + title: "Open Food Network" 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. @@ -1686,8 +1685,7 @@ en_AU: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_BE.yml b/config/locales/en_BE.yml index 73e6f2c1b8..ff1dc8bbc1 100644 --- a/config/locales/en_BE.yml +++ b/config/locales/en_BE.yml @@ -172,8 +172,7 @@ en_BE: 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 ' + title: "Open Food Network" 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. @@ -1646,8 +1645,7 @@ en_BE: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index cd9e2ba69c..a267d6397d 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -181,8 +181,7 @@ en_CA: 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 ' + title: "Open Food Network" 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 city producers_join: Producers are welcome to join the Open Food Network. @@ -1713,8 +1712,7 @@ en_CA: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_DE.yml b/config/locales/en_DE.yml index d8d0b20675..62e613451c 100644 --- a/config/locales/en_DE.yml +++ b/config/locales/en_DE.yml @@ -175,8 +175,7 @@ en_DE: 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 ' + title: "Open Food Network" 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. @@ -1656,8 +1655,7 @@ en_DE: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 794411e0d1..2250c91bb5 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -181,8 +181,7 @@ en_GB: 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 ' + title: "Open Food Network" site_meta_description: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" search_by_name: Search by name, town, county or postcode... producers_join: UK producers are now welcome to join Open Food Network UK. @@ -1713,8 +1712,7 @@ en_GB: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_IE.yml b/config/locales/en_IE.yml index 2693a59bb6..c9112cfb88 100644 --- a/config/locales/en_IE.yml +++ b/config/locales/en_IE.yml @@ -181,8 +181,7 @@ en_IE: 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 ' + title: "Open Food Network" site_meta_description: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" search_by_name: Search by name, town, county or eircode... producers_join: Producers are now welcome to join Open Food Network Ireland. @@ -1713,8 +1712,7 @@ en_IE: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_NZ.yml b/config/locales/en_NZ.yml index cfff4ec299..226b98a5f6 100644 --- a/config/locales/en_NZ.yml +++ b/config/locales/en_NZ.yml @@ -181,8 +181,7 @@ en_NZ: 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 ' + title: "Open Food Network" site_meta_description: "We begin from the ground up. With farmers, growers, and producers 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: New Zealand producers are now welcome to join the Open Food Network. @@ -1713,8 +1712,7 @@ en_NZ: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_PH.yml b/config/locales/en_PH.yml index 77dad9a54e..7ac90cfc1b 100644 --- a/config/locales/en_PH.yml +++ b/config/locales/en_PH.yml @@ -181,8 +181,7 @@ en_PH: 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 ' + title: "Open Food Network" 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 city... producers_join: Philippine producers are now welcome to join the Open Food Network. @@ -1690,8 +1689,7 @@ en_PH: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_US.yml b/config/locales/en_US.yml index 5cdc1914cf..f8c377e354 100644 --- a/config/locales/en_US.yml +++ b/config/locales/en_US.yml @@ -181,8 +181,7 @@ en_US: 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 ' + title: "Open Food Network" 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 seriously change the world." search_by_name: Search by name or city... producers_join: US producers are now welcome to join the Open Food Network. @@ -1713,8 +1712,7 @@ en_US: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/en_ZA.yml b/config/locales/en_ZA.yml index 191b96311d..aa488086cc 100644 --- a/config/locales/en_ZA.yml +++ b/config/locales/en_ZA.yml @@ -181,8 +181,7 @@ en_ZA: 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 ' + title: "Open Food Network" site_meta_description: "We begin with healthy soil. With organic farmers and growers proudly rising to tell their stories. With distributors ready to connect people with green, nutritious, fair and affordable products. With buyers who believe that better, more local shopping decisions can seriously change the world." search_by_name: Search by name, town, province or postcode... producers_join: South African producers are now welcome to join Open Food Network SA. @@ -1703,8 +1702,7 @@ en_ZA: password: Password remember_me: Remember Me are_you_sure: "Are you sure?" - orders_open: Orders open - closing: "Closing " + orders_open: "Orders open" going_back_to_home_page: "Taking you back to the home page" creating: Creating updating: Updating diff --git a/config/locales/es.yml b/config/locales/es.yml index ad2e732f52..75eed08b9d 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -181,8 +181,7 @@ es: title: Otros fallos (%{count} pedidos) explainer: El procesamiento automático de estas órdenes falló por un motivo desconocido. Esto no debería ocurrir, contáctanos si estás viendo esto. home: "OFN" - title: Open Food Network - welcome_to: 'Bienvenido a ' + title: "Open Food Network" site_meta_description: "Nosotros empezamos desde abajo. Con granjeros y productoras listas para contar sus historias con orgullo y autenticidad. Con distribuidoras listas para conectar gente con productos de forma justa y honesta. Con compradores que creen que mejores decisiones de compras semanales pueden..." search_by_name: Buscar por nombre o municipio... producers_join: Las productoras australianas ahora son bienvenidas a unirse a Open Food Network. @@ -1710,8 +1709,7 @@ es: password: Contraseña remember_me: Recordarme are_you_sure: "¿Está seguro?" - orders_open: Pedidos abiertos - closing: "Cerrando " + orders_open: "Pedidos abiertos" going_back_to_home_page: "Le estamos llevando de vuelta a la página de inicio" creating: Creando updating: Actualizando diff --git a/config/locales/es_CR.yml b/config/locales/es_CR.yml index 17883da027..d22b5cdff1 100644 --- a/config/locales/es_CR.yml +++ b/config/locales/es_CR.yml @@ -181,8 +181,7 @@ es_CR: title: Otros fallos (%{count} pedidos) explainer: El procesamiento automático de estas órdenes falló por un motivo desconocido. Esto no debería ocurrir, contáctanos si estás viendo esto. home: "OFN" - title: Open Food Network - welcome_to: 'Bienvenido a ' + title: "Open Food Network" site_meta_description: "Nosotros empezamos desde abajo. Con granjeros y productores listos para contar sus historias con orgullo y autenticidad. Con distribuidores listos para conectar gente con productos de forma justa y honesta. Con compradores que creen que mejores decisiones de compras semanales pueden..." search_by_name: Buscar por nombre o cantón... producers_join: Los productores costarricenses son bienvenidos a unirse ahora a Open Food Network (LaFeriaCR). @@ -1693,8 +1692,7 @@ es_CR: password: Contraseña remember_me: Recordarme are_you_sure: "¿Está seguro?" - orders_open: Pedidos abiertos - closing: "Cerrando " + orders_open: "Pedidos abiertos" going_back_to_home_page: "Le estamos llevando de vuelta a la página de inicio" creating: Creando updating: Actualizando diff --git a/config/locales/fil_PH.yml b/config/locales/fil_PH.yml index af89a9a22f..94f2cac702 100644 --- a/config/locales/fil_PH.yml +++ b/config/locales/fil_PH.yml @@ -181,8 +181,7 @@ fil_PH: title: Iba Pang Dahilan ng Error (%{count}na order) explainer: Hindi naging matagumpay ang awtomatikong pagproseso ng mga order na ito dahil sa hindi maipaliwanag na kadahilanan. Makipag-uganayan sa amin kung nakikita ang mensaheng ito. home: "OFN" - title: Open Food Network - welcome_to: 'Maligayang Pagdating sa' + title: "Open Food Network" site_meta_description: "Kami ay nagsimula sa pinakaibaba pataas. Kasama ang mga magsasaka at tagatanim na handang ibahagi at ipagmalaki ang kanilang mga kuwento. May mga tapat at patas na Distributors na handang makipag-usap sa mga gumagawa ng produkto. At mga mamimili na naniniwala na ang mabusising lingguhang pamimili ay..." search_by_name: Hanapin gamit ang pangalan o lungsod... producers_join: Ang mga Pilipinong producers ay inaanyayahang naming sumali sa Open Food Network. @@ -1693,8 +1692,7 @@ fil_PH: password: Password remember_me: tandaan ako are_you_sure: "Sigurado ka ba?" - orders_open: bukas ang mga order - closing: "sinasara" + orders_open: "bukas ang mga order" going_back_to_home_page: "binabalik ka sa homepage" creating: ginagawa updating: ina-update diff --git a/config/locales/fr_BE.yml b/config/locales/fr_BE.yml index 2fa3fccab6..a8822f7337 100644 --- a/config/locales/fr_BE.yml +++ b/config/locales/fr_BE.yml @@ -181,8 +181,7 @@ fr_BE: title: Autre échec (%{count} commandes) explainer: Le traitement automatique de ces commandes a échoué pour une raison inconnue. Cela n'aurait pas dû arriver, veuillez nous contacter si vous constatez quelque chose d'anormal. home: "OFN" - title: Open Food Network - welcome_to: 'Bienvenue sur ' + title: "Open Food Network" site_meta_description: "C’est ce que nous faisons en créant une plateforme qui veut mettre en contact :\n● des paysans passionnés, engagés pour une agriculture durable et régénératrice,\n● des distributeurs de produits locaux, adeptes de circuits courts, qui agissent en toute transparence et assurent une juste rémunération des producteurs,\n● des acheteurs qui veulent changer le monde en mangeant mieux," search_by_name: Recherche par nom ou province... producers_join: Les producteurs et autres magasins basés en Belgique sont invités à rejoindre Open Food Network. @@ -1697,8 +1696,7 @@ fr_BE: password: Mot de passe remember_me: Se souvenir de moi are_you_sure: "Confirmer?" - orders_open: Comptoir ouvert - closing: "Fermeture " + orders_open: "Comptoir ouvert" going_back_to_home_page: "Retour à la page d'accueil" creating: Création updating: Mettre à jour diff --git a/config/locales/fr_CA.yml b/config/locales/fr_CA.yml index 47e23fb486..2e57fa8dd7 100644 --- a/config/locales/fr_CA.yml +++ b/config/locales/fr_CA.yml @@ -182,8 +182,7 @@ fr_CA: title: Autre échec (%{count} commandes) explainer: Le traitement automatique de ces commandes a échoué pour une raison inconnue. Cela n'aurait pas dû arriver, veuillez nous contacter si vous lisez ce message. home: "OFN" - title: 'Open Food Network ' - welcome_to: 'Bienvenue sur ' + title: "Open Food Network " site_meta_description: "Tout commence dans le sol. Avec ces paysans, agriculteurs, producteurs, engagés pour une agriculture durable et régénératrice, et désireux de partager leur histoire et leur passion avec fierté. Avec ces distributeurs souhaitant reconnecter les individus à leurs aliments et aux gens qui les produisent, soutenir les prises de conscience, dans une démarche de transparence, d'honnêteté, en assurant une juste rémunération des producteurs. Avec ces acheteurs qui croient que de meilleures décisions d'achats peuvent ..." search_by_name: Recherche par nom ou ville... producers_join: Les producteurs et autres hubs basés au Québec sont invités à rejoindre Open Food Network Canada. @@ -1709,8 +1708,7 @@ fr_CA: password: Mot de passe remember_me: Se souvenir de moi are_you_sure: "Confirmer?" - orders_open: Boutique ouverte - closing: "Fermeture " + orders_open: "Boutique ouverte" going_back_to_home_page: "Retour à la page d'accueil" creating: Création updating: Mettre à jour diff --git a/config/locales/it.yml b/config/locales/it.yml index 35c1d111d1..ebbf8932d0 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -181,8 +181,7 @@ it: title: Altro errore (%{count} gentili richieste) explainer: L'elaborazione automatica di queste gentili richieste non è riuscita per una ragione sconosciuta. Questo non dovrebbe accadere, ti preghiamo di contattarci se visualizzi questo messaggio. home: "OFN" - title: Open Food Network - welcome_to: 'Benvenuto su ' + title: "Open Food Network" site_meta_description: "Cominciamo da zero. Con i produttori e gli allevatori pronti a raccontare le loro storie, sinceramente e orgogliosamente. Con i distributori pronti a connettere le persone con i prodotti in modo giusto ed equo. Con i compratori che credono che migliori decisioni per l'acquisto settimanale possano..." search_by_name: Cerca per nome o zona... producers_join: I Produttori sono ora invitati ad unirsi ad Open Food Network @@ -1709,8 +1708,7 @@ it: password: Password remember_me: Ricordami are_you_sure: "Sei sicuro?" - orders_open: Richieste aperte - closing: "In chiusura " + orders_open: "Richieste aperte" going_back_to_home_page: "Reindirizzamento alla homepage" creating: In creazione updating: In aggiornamento diff --git a/config/locales/nb.yml b/config/locales/nb.yml index 52289b57dd..c47ad93636 100644 --- a/config/locales/nb.yml +++ b/config/locales/nb.yml @@ -181,8 +181,7 @@ nb: title: Annen Feil (%{count} bestillinger) explainer: Automatisk behandling av disse bestillingene mislyktes av en ukjent grunn. Dette bør ikke skje, vennligst kontakt oss hvis du ser dette. home: "OFN" - title: Open Food Network - welcome_to: 'Velkommen til ' + title: "Open Food Network" site_meta_description: "Vi begynner fra grunnen. Med bønder og dyrkere klare til å fortelle sine historier, stolt og virkelig. Med distributører klare til å koble mennesker med produkter på en rettferdig og ærlig måte. Med kunder som tror på at ukentlige innkjøpsrutiner kan..." search_by_name: Søk på navn eller sted... producers_join: Norske produsenter er nå velkommen til å bli med i Open Food Network. @@ -1713,8 +1712,7 @@ nb: password: Passord remember_me: Husk meg are_you_sure: "Er du sikker?" - orders_open: Åpen for bestilling - closing: "Stenger " + orders_open: "Åpen for bestilling" going_back_to_home_page: "Tar deg tilbake til hjemmesiden" creating: Oppretter updating: Oppdaterer diff --git a/config/locales/nl_BE.yml b/config/locales/nl_BE.yml index 2b9af3b10d..61e9b4a7d9 100644 --- a/config/locales/nl_BE.yml +++ b/config/locales/nl_BE.yml @@ -172,8 +172,7 @@ nl_BE: title: Andere mislukking (%{count}orders) explainer: De automatische verwerking van deze bestellingen is om een onbekende reden mislukt. Dit mag niet gebeuren, neem contact met ons op als u dit ziet. home: "OFN" - title: Open Food Network - welcome_to: 'Welkom op ' + title: "Open Food Network" site_meta_description: "Dit is wat we doen door een platform te creëren dat verbinding wil maken:\n● gepassioneerde boeren, die zich inzetten voor duurzame en regeneratieve landbouw,\n● handelaren van lokale producten, aanhangers van kortsluitingen, die in volledige transparantie handelen en een eerlijke vergoeding van de producenten garanderen,\n● kopers die de wereld willen veranderen door beter te eten," search_by_name: Zoeken op naam of voorstad.... producers_join: Belgische producenten zijn nu welkom om zich aan te sluiten bij het Open Food Network. @@ -1649,8 +1648,7 @@ nl_BE: password: Wachtwoord remember_me: Onthoud Me are_you_sure: "Ben je zeker?" - orders_open: Openstaande Bestellingen - closing: "Sluitend" + orders_open: "Openstaande Bestellingen" going_back_to_home_page: "Terugkerend naar de startpagina" creating: Aanmakend updating: Updatend diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 2337322325..0e9da2fb53 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -166,8 +166,7 @@ pt: title: Outra Falha (%{count} encomendas) explainer: 'O processamento automático destas encomendas falhou devido a uma razão desconhecida. Isto não deveria estar a acontecer, por favor contacte-nos se estiver a ver esta mensagem. ' home: "OFN" - title: Open Food Network - welcome_to: 'Bem-vindo à' + title: "Open Food Network" site_meta_description: "Começamos a partir da terra. Com agricultores e produtores prontos a contarem as suas histórias com um brilho nos olhos. Com distribuidores prontos a estabelecerem ligações entre pessoas e produtos de forma justa e honesta. Com consumidores que acreditam que melhores decisões no momento da compra..." search_by_name: Procurar por nome ou localidade... producers_join: Produtores e produtoras de proximidade, estão convidados a juntarem-se à Open Food Network! @@ -1623,8 +1622,7 @@ pt: password: Palavra-passe remember_me: Lembrar meu login are_you_sure: "Tem a certeza?" - orders_open: Encomendas abertas - closing: "Fechando" + orders_open: "Encomendas abertas" going_back_to_home_page: "Voltando à pagina inicial" creating: Criando updating: Atualizando diff --git a/config/locales/pt_BR.yml b/config/locales/pt_BR.yml index 28038571e9..acdf438a4d 100644 --- a/config/locales/pt_BR.yml +++ b/config/locales/pt_BR.yml @@ -2824,7 +2824,7 @@ pt_BR: fill_in_customer_info: "Por favor, preencha as informações do cliente" new_payment: "Novo Pagamento" capture: "Capturar" - void: "Vazio" + void: "Apagar" login: "Login" password: "Senha" signature: "Assinatura" diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 9877738000..92d5d360e6 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -47,8 +47,7 @@ sv: order_cycle: subject: "Sammanställning över beställningsperiod för %{producer}" home: "OFN" - title: Open Food Network - welcome_to: 'Välkommen till' + title: "Open Food Network" site_meta_description: "Vi börjar från grunden. Med bönder och odlare redo att berätta sina berättelser stolt och verkligt. Med distributörer redo att ansluta människor med produkter rättvist och ärligt. Med köpare som tror att bättre veckovisa köpbeslut kan ..." search_by_name: Sök på ortnamn eller förort... producers_join: Svenska producenter kan nu gå med i Open Food Network. Välkomna! @@ -1069,8 +1068,7 @@ sv: password: Lösenord remember_me: Kom ihåg mig are_you_sure: "Är du säker?" - orders_open: Beställningar kan göras - closing: "Stänger" + orders_open: "Beställningar kan göras" going_back_to_home_page: "Tillbaka till startsidan" creating: Skapar updating: Uppdaterar diff --git a/config/locales/tr.yml b/config/locales/tr.yml index e097157353..dae3555bb1 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -53,7 +53,7 @@ tr: end_at: "BİTİŞ" distributor_ids: "Pazarlar" producer_ids: "ÜRETİCİLER" - order_cycle_ids: "SİPARİŞ DÖNEMLERİ" + order_cycle_ids: "Sipariş Dönemleri" enterprise_fee_ids: "ÜCRET İSİMLERİ" shipping_method_ids: "TESLİMAT YÖNTEMLERİ" payment_method_ids: "ÖDEME YÖNTEMLERİ" @@ -725,7 +725,7 @@ tr: shopfront_message_link_prompt: "Lütfen eklemek için bir URL girin" shopfront_closed_message: "KAPALI DÜKKAN MESAJI" shopfront_closed_message_placeholder: > - Mağazanızın neden satışa kapalı olduğunu ve ne zaman açılacağını müşterilerinize + Dükkanınızın neden satışa kapalı olduğunu ve ne zaman açılacağını müşterilerinize açıklayan bir mesaj yazın. Bu mesaj, açık bir sipariş döneminiz olmadığında sizi ziyaret edenler tarafından görülecek. (örn. neden kapalı olduğunu ve ne zaman açılacağını belirtebilirsiniz) @@ -905,7 +905,7 @@ tr: remove: 'Kaldır' selected: 'seçildi' add_exchange_form: - add_supplier: 'Tedarikçi ekle' + add_supplier: 'TEDARİKÇİ EKLE' add_distributor: 'Dağıtımcı ekle' advanced_settings: title: Gelişmiş Ayarlar @@ -938,7 +938,7 @@ tr: new_schedule: Yeni Takvim name_and_timing_form: name: Ad - orders_open: 'SİPARİŞ AÇILIŞ:' + orders_open: Siparişler Açık coordinator: KOORDİNATÖR orders_close: SİPARİŞ KAPANIŞ row: @@ -1361,7 +1361,7 @@ tr: cookies_policy_link_desc: "Daha fazla bilgi edinmek istiyorsanız," cookies_policy_link: "çerezler politikası" cookies_accept_button: "Çerezleri kabul et" - home_shop: 'ŞİMDİ ALIŞVERİŞE BAŞLAYIN ' + home_shop: 'ALIŞVERİŞE BAŞLAYIN ' brandstory_headline: "Bağımsız, adil ve temiz gıda ..." brandstory_intro: "Bazen sistemi düzeltmenin en iyi yolu yeni bir sistem yaratmaktır…" brandstory_part1: "Açık Gıda Ağı, adil, temiz bir gıda sistemi oluşturmak için tasarlanan bir sosyal girişim projesidir. Üretici ve türeticilerin bir araya gelerek aracısız bir gıda düzeni ile her açıdan daha sağlıklı bir toplum yaratmaları için çözümler sunar. Toplum yararına çalışır, iletişim, dürüstlük ve dayanışmayı destekler." @@ -1376,7 +1376,7 @@ tr: connect_cta: "Keşfedin" system_headline: "Nasıl çalışıyor ?" system_step1: "1. Ara" - system_step1_text: "Yerel, adil, temiz ve mevsimsel gıda için, bağımsız ve cesur üreticilerimizin mağazalarından alışveriş yapın. Konuma, ürün kategorisine, üretici özelliklerine veya teslimat tercihlerine göre arama yapabilirsiniz. " + system_step1_text: "Yerel, adil, temiz ve mevsimsel gıda için, bağımsız ve cesur üreticilerimizin ve dağıtımcılarımızın dükkanlarından alışveriş yapın. Konuma, ürün kategorisine, üretici özelliklerine veya teslimat tercihlerine göre arama yapabilirsiniz. " system_step2: "2. Alışveriş Yap" system_step2_text: "Gıdanızı yerel üretici tezgahlarından, üretici ve türetici pazarlarından temin edin. Yaşanabilir bir dünya için alışkanlıklarınızı şimdi değiştirin. Gıdanızın ve onu size getiren insanların hikayelerini öğrenin!" system_step3: "3. Teslimat " @@ -1385,7 +1385,7 @@ tr: cta_label: "Hazırım" stats_headline: "Yeni bir gıda sistemi yaratıyoruz." stats_producers: "ÜRETİCİ" - stats_shops: "MAĞAZA" + stats_shops: "DÜKKAN" stats_shoppers: "TÜRETİCİ" stats_orders: "ALIŞVERİŞ" checkout_title: Ödeme Yap @@ -1713,7 +1713,7 @@ tr: password: Parola remember_me: Beni Hatırla are_you_sure: "Emin misiniz?" - orders_open: "Siparişler açık" + orders_open: "Siparişler Açık" closing: "Kapanış" going_back_to_home_page: "Ana sayfaya yönlendiriliyorsunuz.." creating: oluşturuluyor @@ -1886,7 +1886,7 @@ tr: back: "Geri" continue: "Devam et" action_or: "VEYA" - enterprise_limit: İşletme Limiti + enterprise_limit: İŞLETME LİMİTİ shipping_method_destroy_error: "Bu teslimat yöntemi silinemez çünkü tamamlanmış siparişler mevcut\n: %{number}." fees: "Ücretler" item_cost: "Ürün maliyeti" @@ -1983,7 +1983,7 @@ tr: roles: "Roller" update: "Güncelle" delete: Sil - add_producer_property: "Üretici özelliği ekle" + add_producer_property: "ÜRETİCİ ÖZELLİĞİ EKLE" in_progress: "Devam ediyor" started_at: "Başlama tarihi" queued: "sıraya eklendi" @@ -2265,7 +2265,7 @@ tr: payment_updated: "Ödeme Güncellendi" inventory_settings: "Stok Ayarları" tag_rules: "ETİKET KURALLARI" - shop_preferences: "Mağaza Tercihleri" + shop_preferences: "Dükkan Tercihleri" enterprise_fee_whole_order: Tüm sipariş enterprise_fee_by: "%{role}%{enterprise_name} tarafından%{type} ücreti" validation_msg_relationship_already_established: "^ Bu ilişki zaten kurulmuş." @@ -2591,10 +2591,10 @@ tr: unsaved_changes_message: Kaydedilmemiş değişiklikler var, şimdi kaydet veya yoksay? save: KAYDET ignore: YOKSAY - add_to_order_cycle: "sipariş dönemine ekle" - manage_products: "ürünleri yönet" - edit_profile: "profili Düzenle" - add_products_to_inventory: "Stoka ürün ekle" + add_to_order_cycle: "SİPARİŞ DÖNEMİNE EKLE" + manage_products: "ÜRÜNLERİ YÖNET" + edit_profile: "PROFİLİ DÜZENLE" + add_products_to_inventory: "STOKA ÜRÜN EKLE" resources: could_not_delete_customer: 'Müşteri silinemedi' product_import: @@ -3226,7 +3226,7 @@ tr: listing_users: "Kullanıcılar Listeleniyor" new_user: "Yeni Kullanıcı" user: "Kullanıcı" - enterprise_limit: "İşletme Limiti" + enterprise_limit: "İŞLETME LİMİTİ" search: "Ara" email: "E-posta" edit: @@ -3236,7 +3236,7 @@ tr: form: email: "E-posta" roles: "Roller" - enterprise_limit: "İşletme Limiti" + enterprise_limit: "İŞLETME LİMİTİ" confirm_password: "Parolayı Onayla" password: "Parola" email_confirmation: From 2f562809c090ac09394e49b3648151c6ca0e9abb Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 8 Jul 2020 21:31:52 +1000 Subject: [PATCH 211/261] Ensure the hero image doesn't attempt to use the full height of all page content Not sure exactly why this happens, but when the mobile nav is opened the hero image at #tagline:before uses the height of the full window - often around 4000px. Adding max-height of 100% to the nearest safe parent prevents this behaviour. --- app/assets/stylesheets/darkswarm/layout/offcanvas.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss index de54f0ef54..f6fe7a0455 100644 --- a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss +++ b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss @@ -15,3 +15,6 @@ transform: none; margin-left: -15.625rem; } +.off-canvas-wrap .inner-wrap { + max-height:100%; +} \ No newline at end of file From e6a2eb8af972d721bf6b8d7feb6a66589688ab93 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Thu, 9 Jul 2020 07:53:34 +1000 Subject: [PATCH 212/261] Updating translations for config/locales/en_CA.yml --- config/locales/en_CA.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index a267d6397d..5b3886a906 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -182,6 +182,7 @@ en_CA: 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 city producers_join: Producers are welcome to join the Open Food Network. @@ -1713,6 +1714,7 @@ en_CA: 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 @@ -2070,6 +2072,7 @@ en_CA: hub_sidebar_at_least: "At least one hub must be selected" hub_sidebar_blue: "blue" hub_sidebar_red: "red" + order_cycles_closed_for_hub: "The hub you have selected is temporarily closed for orders. Please try again later." report_customers_distributor: "Distributor" report_customers_supplier: "Supplier" report_customers_cycle: "Order Cycle" @@ -2306,6 +2309,7 @@ en_CA: 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" + order_cycle_closed: "The order cycle you've selected has just closed. Please try again!" back_to_orders_list: "Back to order list" no_orders_found: "No Orders Found" order_information: "Order Information" From e3980521ea6c5f37775c6ab24d3330e2a00f9258 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Thu, 9 Jul 2020 07:58:41 +1000 Subject: [PATCH 213/261] Updating translations for config/locales/fr_CA.yml --- config/locales/fr_CA.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/config/locales/fr_CA.yml b/config/locales/fr_CA.yml index 2e57fa8dd7..7b58f542a8 100644 --- a/config/locales/fr_CA.yml +++ b/config/locales/fr_CA.yml @@ -183,6 +183,7 @@ fr_CA: explainer: Le traitement automatique de ces commandes a échoué pour une raison inconnue. Cela n'aurait pas dû arriver, veuillez nous contacter si vous lisez ce message. home: "OFN" title: "Open Food Network " + welcome_to: "Bienvenue sur" site_meta_description: "Tout commence dans le sol. Avec ces paysans, agriculteurs, producteurs, engagés pour une agriculture durable et régénératrice, et désireux de partager leur histoire et leur passion avec fierté. Avec ces distributeurs souhaitant reconnecter les individus à leurs aliments et aux gens qui les produisent, soutenir les prises de conscience, dans une démarche de transparence, d'honnêteté, en assurant une juste rémunération des producteurs. Avec ces acheteurs qui croient que de meilleures décisions d'achats peuvent ..." search_by_name: Recherche par nom ou ville... producers_join: Les producteurs et autres hubs basés au Québec sont invités à rejoindre Open Food Network Canada. @@ -480,6 +481,7 @@ fr_CA: line_number: "Ligne :%{number}" encoding_error: "Veuillez vérifier le paramètre de langue de votre code source et vous assurer qu'il est encodé en UTF-8" unexpected_error: "L'import de fichier produits à rencontré une erreur inconnue à l'ouverture du fichier : %{error_message}" + malformed_csv: "L'outil d'import a rencontré un fichier CSV avec le ou les problèmes suivants :%{error_message}" index: notice: "Notice" beta_notice: "Cette fonctionnalité est en mode bêta : il est possible que vous rencontriez des erreurs en l'utilisant. N'hésitez pas à contacter le support utilisateurs." @@ -1150,7 +1152,12 @@ fr_CA: cart: "Panier" cart_sidebar: checkout: "Finalisation commande" + edit_cart: "Modifier le panier" + items_in_cart_singular: "%{num}élément dans le panier" + items_in_cart_plural: "%{num}éléments dans le panier" close: "Ferme" + cart_empty: "Le panier est vide" + take_me_shopping: "Continuer mes achats" signed_in: profile: "Profil" mobile_menu: @@ -1709,6 +1716,7 @@ fr_CA: remember_me: Se souvenir de moi are_you_sure: "Confirmer?" orders_open: "Boutique ouverte" + closing: "Fermeture" going_back_to_home_page: "Retour à la page d'accueil" creating: Création updating: Mettre à jour @@ -2066,6 +2074,7 @@ fr_CA: hub_sidebar_at_least: "Sélectionnez un/des hubs" hub_sidebar_blue: "bleu" hub_sidebar_red: "rouge" + order_cycles_closed_for_hub: "La boutique sélectionnée a fermé temporairement ses commandes. Veuillez essayez à nouveau ultérieurement." report_customers_distributor: "Distributeur" report_customers_supplier: "Fournisseurs" report_customers_cycle: "Cycle de vente" @@ -2304,6 +2313,7 @@ fr_CA: order_cycles_email_to_producers_notice: 'Les emails à destination des producteurs ont été mis en file d''attente pour envoi.' order_cycles_no_permission_to_coordinate_error: "Aucune de vos entreprises n'a les droits requis pour coordonner un cycle de vente" order_cycles_no_permission_to_create_error: "Vous n'avez pas les droits requis pour créer un cycle de vente coordonné par cette entreprise" + order_cycle_closed: "Le cycle de vente que vous avez sélectionné a fermé. " back_to_orders_list: "Retour à la liste des commandes" no_orders_found: "Aucune commande trouvée" order_information: "Info commande" From 1a132924d269255ac267d1c645137f4062b33d88 Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Thu, 9 Jul 2020 10:00:02 +0200 Subject: [PATCH 214/261] Fix StrongParameters for groups images --- app/controllers/admin/enterprise_groups_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/enterprise_groups_controller.rb b/app/controllers/admin/enterprise_groups_controller.rb index 9d5bc6c665..d5dbccda3a 100644 --- a/app/controllers/admin/enterprise_groups_controller.rb +++ b/app/controllers/admin/enterprise_groups_controller.rb @@ -60,8 +60,8 @@ module Admin def permitted_resource_params params.require(:enterprise_group).permit( - :name, :description, :long_description, :on_front_page, :owner_id, :permalink, - :email, :website, :facebook, :instagram, :linkedin, :twitter, + :name, :description, :long_description, :logo, :promo_image, :on_front_page, + :owner_id, :permalink, :email, :website, :facebook, :instagram, :linkedin, :twitter, enterprise_ids: [], address_attributes: PermittedAttributes::Address.attributes ) end From 50427472c41ae4e338641844279f8dd619b5525a Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 10 Jul 2020 20:25:20 +1000 Subject: [PATCH 215/261] Updating translations for config/locales/en_NZ.yml --- config/locales/en_NZ.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/config/locales/en_NZ.yml b/config/locales/en_NZ.yml index 226b98a5f6..e45ca43439 100644 --- a/config/locales/en_NZ.yml +++ b/config/locales/en_NZ.yml @@ -182,6 +182,7 @@ en_NZ: 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, growers, and producers 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: New Zealand producers are now welcome to join the Open Food Network. @@ -1160,7 +1161,7 @@ en_NZ: mobile_menu: cart: "Cart" register_call: - selling_on_ofn: "Interested in getting on the Open Food Network?" + selling_on_ofn: "Want to set up a shop on the Open Food Network?" register: "Register here" footer: footer_secure: "Secure and trusted." @@ -1713,6 +1714,7 @@ en_NZ: 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 From eb4d648a2387bfdeb5561d457d81741a34a03fae Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 10 Jul 2020 19:27:31 +0100 Subject: [PATCH 216/261] Comment this very flaky spec for now --- spec/models/variant_override_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/models/variant_override_spec.rb b/spec/models/variant_override_spec.rb index 22b93a06d4..c6620351a2 100644 --- a/spec/models/variant_override_spec.rb +++ b/spec/models/variant_override_spec.rb @@ -33,7 +33,7 @@ describe VariantOverride do expect(VariantOverride.indexed(hub2)).to eq( variant => vo2 ) end - it "does not include overrides for soft-deleted variants" do + xit "does not include overrides for soft-deleted variants" do variant.delete expect(VariantOverride.indexed(hub1)).to eq( nil => vo1 ) end From f4cb14ab1a1847809003a17c1c14ec5086d7ba0d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 14 Jul 2020 00:10:40 +0000 Subject: [PATCH 217/261] Bump oj from 3.10.6 to 3.10.7 Bumps [oj](https://github.com/ohler55/oj) from 3.10.6 to 3.10.7. - [Release notes](https://github.com/ohler55/oj/releases) - [Changelog](https://github.com/ohler55/oj/blob/develop/CHANGELOG.md) - [Commits](https://github.com/ohler55/oj/compare/v3.10.6...v3.10.7) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 9b627cb940..537c4f330d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -478,7 +478,7 @@ GEM multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - oj (3.10.6) + oj (3.10.7) optimist (3.0.0) orm_adapter (0.5.0) paper_trail (5.2.3) From 60870a1215af3abb5d093ef873035403a1c6fb7a Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Tue, 14 Jul 2020 12:58:48 +1000 Subject: [PATCH 218/261] Fix linting errors --- app/assets/stylesheets/darkswarm/layout/offcanvas.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss index f6fe7a0455..83c488afab 100644 --- a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss +++ b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss @@ -15,6 +15,7 @@ transform: none; margin-left: -15.625rem; } + .off-canvas-wrap .inner-wrap { - max-height:100%; -} \ No newline at end of file + max-height: 100%; +} From f79269e96bdb00ba31917be5b49a5184525909be Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Tue, 14 Jul 2020 17:46:12 +1000 Subject: [PATCH 219/261] Updating translations for config/locales/ca.yml --- config/locales/ca.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/config/locales/ca.yml b/config/locales/ca.yml index a71b762573..2bc956f2ba 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -182,6 +182,7 @@ ca: explainer: El processament automàtic d'aquestes comandes va fallar per un motiu desconegut. Això no hauria de passar, si us plau, contacteu amb nosaltres si esteu veient això. home: "OFN" title: "Open Food Network" + welcome_to: "Benvingut a " site_meta_description: "Comencem des de baix. Amb agricultors i productors disposats a explicar les seves històries amb orgull i sinceritat. Amb distribuïdors connectant persones i productes de manera justa i honesta. Amb compradors que creuen que millors decisions de compra setmanal poden ..." search_by_name: Cercar per nom o barri ... producers_join: Els productors australians son ara benvinguts a unir-se a Open Food Network. @@ -1716,6 +1717,7 @@ ca: remember_me: Recorda'm are_you_sure: "Estàs segur?" orders_open: "Comandes obertes" + closing: "Tancant" going_back_to_home_page: "Tornant a la pàgina d'inici" creating: Creant updating: Actualitzant @@ -2073,6 +2075,7 @@ ca: hub_sidebar_at_least: "Cal seleccionar almenys un grup " hub_sidebar_blue: "blau" hub_sidebar_red: "vermell" + order_cycles_closed_for_hub: "La botiga que has triat està temporalment tancada per a fer comandes. Sisplau, prova una mica més tard" report_customers_distributor: "Distribuïdora" report_customers_supplier: "Proveïdora" report_customers_cycle: "Cicle de Comanda" @@ -2309,6 +2312,7 @@ ca: order_cycles_email_to_producers_notice: 'Els correus electrònics per enviar a les productores estan en cua.' order_cycles_no_permission_to_coordinate_error: "Cap de les vostres organitzacions té permís per coordinar un cicle de comanda" order_cycles_no_permission_to_create_error: "No teniu permís per crear un cicle de comandes coordinat per aquesta organització" + order_cycle_closed: "El cicle de comandes que has triat acaba de tancar. Sisplau prova en un altre moment." back_to_orders_list: "Torna a la llista de comandes" no_orders_found: "No s'han trobat comandes" order_information: "Informació de la comanda" From c4d7899a99c5607a0ec3d05acd815e17529b9a8e Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Tue, 14 Jul 2020 19:26:12 +1000 Subject: [PATCH 220/261] Use vh units for new browsers and align tagline bg to top. --- app/assets/stylesheets/darkswarm/home_tagline.scss | 3 ++- app/assets/stylesheets/darkswarm/layout/offcanvas.scss | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/assets/stylesheets/darkswarm/home_tagline.scss b/app/assets/stylesheets/darkswarm/home_tagline.scss index c6cc15c9e8..ac187c38f5 100644 --- a/app/assets/stylesheets/darkswarm/home_tagline.scss +++ b/app/assets/stylesheets/darkswarm/home_tagline.scss @@ -17,10 +17,11 @@ position: fixed; left: 0; right: 0; - bottom: 0; + top: 0; z-index: -1; width: 100%; height: 100%; + height: 100vh; } h1 { diff --git a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss index 83c488afab..de54f0ef54 100644 --- a/app/assets/stylesheets/darkswarm/layout/offcanvas.scss +++ b/app/assets/stylesheets/darkswarm/layout/offcanvas.scss @@ -15,7 +15,3 @@ transform: none; margin-left: -15.625rem; } - -.off-canvas-wrap .inner-wrap { - max-height: 100%; -} From dbc7632c4ed2277ed1194100337367fbaeb4052a Mon Sep 17 00:00:00 2001 From: Steve Roberts Date: Wed, 15 Jul 2020 09:52:04 +1000 Subject: [PATCH 221/261] Add inline comment to explain two height properties --- app/assets/stylesheets/darkswarm/home_tagline.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/stylesheets/darkswarm/home_tagline.scss b/app/assets/stylesheets/darkswarm/home_tagline.scss index ac187c38f5..7ad1ea0241 100644 --- a/app/assets/stylesheets/darkswarm/home_tagline.scss +++ b/app/assets/stylesheets/darkswarm/home_tagline.scss @@ -21,6 +21,7 @@ z-index: -1; width: 100%; height: 100%; + // Use vh units for new browsers - fixed issue 1253 height: 100vh; } From 25155cab188ebf1c593ffc4c27f8ed0d516f177b Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Wed, 15 Jul 2020 17:13:46 +1000 Subject: [PATCH 222/261] Provide credit card brand to Pin Payments Spree replaced the Ruby code providing the credit card brand with a jquery plugin providing it on the checkout screen. I re-added Ruby code because it's easier and more robust than updating the user interface with new Javascript. --- app/services/checkout/form_data_adapter.rb | 14 +++++++++++++ .../checkout/form_data_adapter_spec.rb | 20 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/app/services/checkout/form_data_adapter.rb b/app/services/checkout/form_data_adapter.rb index a374444637..60bb9257c5 100644 --- a/app/services/checkout/form_data_adapter.rb +++ b/app/services/checkout/form_data_adapter.rb @@ -12,6 +12,8 @@ module Checkout move_payment_source_to_payment_attributes! + fill_in_card_type + set_amount_in_payments_attributes construct_saved_card_attributes if @params[:order][:existing_card_id] @@ -31,6 +33,18 @@ module Checkout @params[:order][:payments_attributes].first[:source_attributes] = payment_source_params end + def fill_in_card_type + payment = params[:order][:payments_attributes]&.first&.dig(:source_attributes) + + return if payment&.dig(:number).blank? + + payment[:cc_type] ||= card_brand(payment[:number]) + end + + def card_brand(number) + ActiveMerchant::Billing::CreditCard.brand?(number) + end + def delete_payment_source_params! @params.delete(:payment_source)[ @params[:order][:payments_attributes].first[:payment_method_id].underscore diff --git a/spec/services/checkout/form_data_adapter_spec.rb b/spec/services/checkout/form_data_adapter_spec.rb index be248a2af0..e2b3c38a94 100644 --- a/spec/services/checkout/form_data_adapter_spec.rb +++ b/spec/services/checkout/form_data_adapter_spec.rb @@ -36,6 +36,26 @@ describe Checkout::FormDataAdapter do end end + describe "and a credit card is provided" do + before do + params[:order][:payments_attributes].first[:source_attributes] = {number: "4444333322221111"} + end + + it "fills in missing credit card brand" do + expect(adapter.params[:order][:payments_attributes].first[:source_attributes][:cc_type]).to eq "visa" + end + + it "leaves an existing credit card brand" do + params[:order][:payments_attributes].first[:source_attributes][:cc_type] = "test" + expect(adapter.params[:order][:payments_attributes].first[:source_attributes][:cc_type]).to eq "test" + end + + it "doesn't touch the credit card brand without a number" do + params[:order][:payments_attributes].first[:source_attributes][:number] = "" + expect(adapter.params[:order][:payments_attributes].first[:source_attributes].key?(:cc_type)).to eq false + end + end + describe "and existing credit card is provided" do before { params[:order][:existing_card_id] = credit_card.id } From 5fae2c08c8a120251532030d205877a40ad25c0d Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2020 08:13:42 +0000 Subject: [PATCH 223/261] Bump i18n-js from 3.7.0 to 3.7.1 Bumps [i18n-js](https://github.com/fnando/i18n-js) from 3.7.0 to 3.7.1. - [Release notes](https://github.com/fnando/i18n-js/releases) - [Changelog](https://github.com/fnando/i18n-js/blob/master/CHANGELOG.md) - [Commits](https://github.com/fnando/i18n-js/compare/v3.7.0...v3.7.1) Signed-off-by: dependabot-preview[bot] --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index eb91b2c147..0c442ca2c6 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ ruby "2.3.7" git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" } gem 'i18n', '~> 0.6.11' -gem 'i18n-js', '~> 3.7.0' +gem 'i18n-js', '~> 3.7.1' gem 'rails', '~> 4.0.13' gem 'rails-i18n', '~> 4.0' gem 'rails_safe_tasks', '~> 1.0' diff --git a/Gemfile.lock b/Gemfile.lock index 9b627cb940..8f5d43d0eb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -420,7 +420,7 @@ GEM mime-types (~> 3.0) multi_xml (>= 0.5.2) i18n (0.6.11) - i18n-js (3.7.0) + i18n-js (3.7.1) i18n (>= 0.6.6) immigrant (0.3.6) activerecord (>= 3.0) @@ -753,7 +753,7 @@ DEPENDENCIES highline (= 1.6.18) httparty (~> 0.18) i18n (~> 0.6.11) - i18n-js (~> 3.7.0) + i18n-js (~> 3.7.1) immigrant jquery-migrate-rails jquery-rails (= 3.1.5) From c009fed6be5fe8a3fe6d5db99d0411779c0a537d Mon Sep 17 00:00:00 2001 From: Matt-Yorkley <9029026+Matt-Yorkley@users.noreply.github.com> Date: Wed, 15 Jul 2020 14:00:19 +0200 Subject: [PATCH 224/261] Update StrongParams for Pin Payments --- .../spree/admin/payment_methods_controller.rb | 2 +- .../spree/admin/payment_methods_controller_spec.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/payment_methods_controller.rb b/app/controllers/spree/admin/payment_methods_controller.rb index 8825e4ea69..950b97340b 100644 --- a/app/controllers/spree/admin/payment_methods_controller.rb +++ b/app/controllers/spree/admin/payment_methods_controller.rb @@ -97,7 +97,7 @@ module Spree :name, :description, :type, :active, :environment, :display_on, :tag_list, :preferred_enterprise_id, :preferred_server, :preferred_login, :preferred_password, - :calculator_type, + :calculator_type, :preferred_api_key, :preferred_signature, :preferred_solution, :preferred_landing_page, :preferred_logourl, :preferred_test_mode, distributor_ids: [] ) diff --git a/spec/controllers/spree/admin/payment_methods_controller_spec.rb b/spec/controllers/spree/admin/payment_methods_controller_spec.rb index dfc7dd307e..3e752170c7 100644 --- a/spec/controllers/spree/admin/payment_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/payment_methods_controller_spec.rb @@ -39,6 +39,20 @@ module Spree expect(response).to redirect_to spree.edit_admin_payment_method_path(assigns(:payment_method)) end + it "can save Pin Payment payment method details" do + expect { + spree_post :create, payment_method: { + name: "Test Method", type: "Spree::Gateway::Pin", distributor_ids: [enterprise.id], + preferred_server: "test", preferred_api_key: "apikey123", preferred_test_mode: "1" + } + }.to change(Spree::PaymentMethod, :count).by(1) + + payment_method = Spree::PaymentMethod.last + expect(payment_method.preferences[:server]).to eq "test" + expect(payment_method.preferences[:api_key]).to eq "apikey123" + expect(payment_method.preferences[:test_mode]).to eq true + end + it "can not create a payment method of an invalid type" do expect { spree_post :create, payment_method: { name: "Invalid Payment Method", type: "Spree::InvalidType", distributor_ids: [enterprise.id] } From 2ea026ea31c648a5306bc7459486429427374e99 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 26 Jun 2020 09:54:44 +0100 Subject: [PATCH 225/261] Bring controller helper auth from spree --- lib/spree/core/controller_helpers/auth.rb | 73 +++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 lib/spree/core/controller_helpers/auth.rb diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb new file mode 100644 index 0000000000..762e1b910c --- /dev/null +++ b/lib/spree/core/controller_helpers/auth.rb @@ -0,0 +1,73 @@ +module Spree + module Core + module ControllerHelpers + module Auth + extend ActiveSupport::Concern + + included do + before_filter :ensure_api_key + helper_method :try_spree_current_user + + rescue_from CanCan::AccessDenied do |exception| + unauthorized + end + end + + # Needs to be overriden so that we use Spree's Ability rather than anyone else's. + def current_ability + @current_ability ||= Spree::Ability.new(try_spree_current_user) + end + + # Redirect as appropriate when an access request fails. The default action is to redirect to the login screen. + # Override this method in your controllers if you want to have special behavior in case the user is not authorized + # to access the requested action. For example, a popup window might simply close itself. + def unauthorized + if try_spree_current_user + flash[:error] = Spree.t(:authorization_failure) + redirect_to '/unauthorized' + else + store_location + redirect_to respond_to?(:spree_login_path) ? spree_login_path : spree.root_path + end + end + + def store_location + # disallow return to login, logout, signup pages + authentication_routes = [:spree_signup_path, :spree_login_path, :spree_logout_path] + disallowed_urls = [] + authentication_routes.each do |route| + if respond_to?(route) + disallowed_urls << send(route) + end + end + + disallowed_urls.map!{ |url| url[/\/\w+$/] } + unless disallowed_urls.include?(request.fullpath) + session['spree_user_return_to'] = request.fullpath.gsub('//', '/') + end + end + + # proxy method to *possible* spree_current_user method + # Authentication extensions (such as spree_auth_devise) are meant to provide spree_current_user + def try_spree_current_user + respond_to?(:spree_current_user) ? spree_current_user : nil + end + + def redirect_back_or_default(default) + redirect_to(session["spree_user_return_to"] || default) + session["spree_user_return_to"] = nil + end + + # Need to generate an API key for a user due to some actions potentially + # requiring authentication to the Spree API + def ensure_api_key + if user = try_spree_current_user + if user.respond_to?(:spree_api_key) && user.spree_api_key.blank? + user.generate_spree_api_key! + end + end + end + end + end + end +end From c8dd841c48f6c6df1f2a067c87e25bc8fc8c114c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 26 Jun 2020 10:00:21 +0100 Subject: [PATCH 226/261] Fix some rubocop issues --- lib/spree/core/controller_helpers/auth.rb | 32 ++++++++++++----------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 762e1b910c..408415141a 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Core module ControllerHelpers @@ -8,7 +10,7 @@ module Spree before_filter :ensure_api_key helper_method :try_spree_current_user - rescue_from CanCan::AccessDenied do |exception| + rescue_from CanCan::AccessDenied do unauthorized end end @@ -18,9 +20,10 @@ module Spree @current_ability ||= Spree::Ability.new(try_spree_current_user) end - # Redirect as appropriate when an access request fails. The default action is to redirect to the login screen. - # Override this method in your controllers if you want to have special behavior in case the user is not authorized - # to access the requested action. For example, a popup window might simply close itself. + # Redirect as appropriate when an access request fails. The default action is to redirect + # to the login screen. Override this method in your controllers if you want to have + # special behavior in case the user is not authorized to access the requested action. + # For example, a popup window might simply close itself. def unauthorized if try_spree_current_user flash[:error] = Spree.t(:authorization_failure) @@ -37,18 +40,17 @@ module Spree disallowed_urls = [] authentication_routes.each do |route| if respond_to?(route) - disallowed_urls << send(route) + disallowed_urls << __send__(route) end end disallowed_urls.map!{ |url| url[/\/\w+$/] } - unless disallowed_urls.include?(request.fullpath) - session['spree_user_return_to'] = request.fullpath.gsub('//', '/') - end + return if disallowed_urls.include?(request.fullpath) + + session['spree_user_return_to'] = request.fullpath.gsub('//', '/') end - # proxy method to *possible* spree_current_user method - # Authentication extensions (such as spree_auth_devise) are meant to provide spree_current_user + # This was a proxy method in spree, in OFN this just redirects to spree_current_user def try_spree_current_user respond_to?(:spree_current_user) ? spree_current_user : nil end @@ -61,11 +63,11 @@ module Spree # Need to generate an API key for a user due to some actions potentially # requiring authentication to the Spree API def ensure_api_key - if user = try_spree_current_user - if user.respond_to?(:spree_api_key) && user.spree_api_key.blank? - user.generate_spree_api_key! - end - end + return unless (user = try_spree_current_user) + + return unless user.respond_to?(:spree_api_key) && user.spree_api_key.blank? + + user.generate_spree_api_key! end end end From 7e75581da6ee22e0f907a86d8d89a25222811898 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 26 Jun 2020 10:01:12 +0100 Subject: [PATCH 227/261] Merge class brought from spree with decorator --- lib/spree/core/controller_helpers/auth.rb | 4 ++++ lib/spree/core/controller_helpers/auth_decorator.rb | 5 ----- 2 files changed, 4 insertions(+), 5 deletions(-) delete mode 100644 lib/spree/core/controller_helpers/auth_decorator.rb diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 408415141a..8f28c27cb1 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -69,6 +69,10 @@ module Spree user.generate_spree_api_key! end + + def require_login_then_redirect_to(url) + redirect_to main_app.root_path(anchor: "login?after_login=#{url}") + end end end end diff --git a/lib/spree/core/controller_helpers/auth_decorator.rb b/lib/spree/core/controller_helpers/auth_decorator.rb deleted file mode 100644 index 7342450c74..0000000000 --- a/lib/spree/core/controller_helpers/auth_decorator.rb +++ /dev/null @@ -1,5 +0,0 @@ -Spree::Core::ControllerHelpers::Auth.class_eval do - def require_login_then_redirect_to(url) - redirect_to main_app.root_path(anchor: "login?after_login=#{url}") - end -end From 4ee30d7cac0bf2ed5dc9005cefad1ae52b7cb6b2 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 26 Jun 2020 10:05:26 +0100 Subject: [PATCH 228/261] Remove spree.root route and respective controller. Also move unauthorized route to main app. This route is no longer used in OFN --- app/controllers/spree/home_controller.rb | 7 ------- config/routes.rb | 1 + config/routes/spree.rb | 4 ---- lib/spree/core/controller_helpers/auth.rb | 2 +- 4 files changed, 2 insertions(+), 12 deletions(-) delete mode 100644 app/controllers/spree/home_controller.rb diff --git a/app/controllers/spree/home_controller.rb b/app/controllers/spree/home_controller.rb deleted file mode 100644 index 9fbdabe940..0000000000 --- a/app/controllers/spree/home_controller.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Spree - class HomeController < Spree::StoreController - respond_to :html - - def index; end - end -end diff --git a/config/routes.rb b/config/routes.rb index ef3380ea79..a657f7f234 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,6 +9,7 @@ Openfoodnetwork::Application.routes.draw do get "/about_us", to: redirect(ContentConfig.footer_about_url) get "/login", to: redirect("/#/login") + get '/unauthorized', :to => 'home#unauthorized', :as => :unauthorized get "/discourse/login", to: "discourse_sso#login" get "/discourse/sso", to: "discourse_sso#sso" diff --git a/config/routes/spree.rb b/config/routes/spree.rb index ca5993aca5..3d29f74486 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -1,7 +1,5 @@ # Overriding Devise routes to use our own controller Spree::Core::Engine.routes.draw do - root to: 'home#index' - devise_for :spree_user, :class_name => 'Spree::User', :controllers => { :sessions => 'spree/user_sessions', @@ -174,8 +172,6 @@ Spree::Core::Engine.routes.draw do # Used by spree_paypal_express get '/checkout/:state', :to => 'checkout#edit', :as => :checkout_state - - get '/unauthorized', :to => 'home#unauthorized', :as => :unauthorized get '/content/cvv', :to => 'content#cvv', :as => :cvv get '/content/*path', :to => 'content#show', :as => :content end diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 8f28c27cb1..7fb5672eff 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -30,7 +30,7 @@ module Spree redirect_to '/unauthorized' else store_location - redirect_to respond_to?(:spree_login_path) ? spree_login_path : spree.root_path + redirect_to(respond_to?(:spree_login_path) ? spree_login_path : main_app.root_path) end end From 96839a03aa3f0a9cfccc42ffa1fbafc6baf696cb Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:23:21 +0100 Subject: [PATCH 229/261] Move lib/spree/core/controller_helpers.rb from spree --- lib/spree/core/controller_helpers.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lib/spree/core/controller_helpers.rb diff --git a/lib/spree/core/controller_helpers.rb b/lib/spree/core/controller_helpers.rb new file mode 100644 index 0000000000..3df5251c9a --- /dev/null +++ b/lib/spree/core/controller_helpers.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Spree + module Core + module ControllerHelpers + def self.included(klass) + klass.class_eval do + include Spree::Core::ControllerHelpers::Common + include Spree::Core::ControllerHelpers::Auth + include Spree::Core::ControllerHelpers::RespondWith + include Spree::Core::ControllerHelpers::Order + end + end + end + end +end From 2452202e92d2770eccf4e96ceda5bdc6be656205 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:24:12 +0100 Subject: [PATCH 230/261] Move lib/spree/core/controller_helpers/common.rb from spree --- lib/spree/core/controller_helpers/common.rb | 86 +++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 lib/spree/core/controller_helpers/common.rb diff --git a/lib/spree/core/controller_helpers/common.rb b/lib/spree/core/controller_helpers/common.rb new file mode 100644 index 0000000000..93fbb3b8c0 --- /dev/null +++ b/lib/spree/core/controller_helpers/common.rb @@ -0,0 +1,86 @@ +module Spree + module Core + module ControllerHelpers + module Common + extend ActiveSupport::Concern + included do + helper_method :title + helper_method :title= + helper_method :accurate_title + + layout :get_layout + + before_filter :set_user_language + + protected + + # Convenience method for firing instrumentation events with the default payload hash + def fire_event(name, extra_payload = {}) + ActiveSupport::Notifications.instrument(name, default_notification_payload.merge(extra_payload)) + end + + # Creates the hash that is sent as the payload for all notifications. Specific notifications will + # add additional keys as appropriate. Override this method if you need additional data when + # responding to a notification + def default_notification_payload + {:user => try_spree_current_user, :order => current_order} + end + + # can be used in views as well as controllers. + # e.g. <% self.title = 'This is a custom title for this view' %> + attr_writer :title + + def title + title_string = @title.present? ? @title : accurate_title + if title_string.present? + if Spree::Config[:always_put_site_name_in_title] + [title_string, default_title].join(' - ') + else + title_string + end + else + default_title + end + end + + def default_title + Spree::Config[:site_name] + end + + # this is a hook for subclasses to provide title + def accurate_title + Spree::Config[:default_seo_title] + end + + def render_404(exception = nil) + respond_to do |type| + type.html { render :status => :not_found, :file => "#{::Rails.root}/public/404", :formats => [:html], :layout => nil} + type.all { render :status => :not_found, :nothing => true } + end + end + + private + + def set_user_language + locale = session[:locale] + locale ||= config_locale if respond_to?(:config_locale, true) + locale ||= Rails.application.config.i18n.default_locale + locale ||= I18n.default_locale unless I18n.available_locales.map(&:to_s).include?(locale) + I18n.locale = locale + end + + # Returns which layout to render. + # + # You can set the layout you want to render inside your Spree configuration with the +:layout+ option. + # + # Default layout is: +app/views/spree/layouts/spree_application+ + # + def get_layout + layout ||= Spree::Config[:layout] + end + + end + end + end + end +end From 10849504c300416290d1b1751494a0ec69c25021 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:31:20 +0100 Subject: [PATCH 231/261] Fix easy rubocop issues --- lib/spree/core/controller_helpers/common.rb | 39 ++++++++++++--------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/lib/spree/core/controller_helpers/common.rb b/lib/spree/core/controller_helpers/common.rb index 93fbb3b8c0..ca95fe79da 100644 --- a/lib/spree/core/controller_helpers/common.rb +++ b/lib/spree/core/controller_helpers/common.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Core module ControllerHelpers @@ -16,22 +18,24 @@ module Spree # Convenience method for firing instrumentation events with the default payload hash def fire_event(name, extra_payload = {}) - ActiveSupport::Notifications.instrument(name, default_notification_payload.merge(extra_payload)) + ActiveSupport::Notifications.instrument(name, default_notification_payload. + merge(extra_payload)) end - # Creates the hash that is sent as the payload for all notifications. Specific notifications will - # add additional keys as appropriate. Override this method if you need additional data when + # Creates the hash that is sent as the payload for all notifications. + # Specific notifications will add additional keys as appropriate. + # This method can be overriden to provide additional data when # responding to a notification def default_notification_payload - {:user => try_spree_current_user, :order => current_order} + { user: try_spree_current_user, order: current_order } end - # can be used in views as well as controllers. + # This can be used in views as well as controllers. # e.g. <% self.title = 'This is a custom title for this view' %> attr_writer :title def title - title_string = @title.present? ? @title : accurate_title + title_string = @title.presence || accurate_title if title_string.present? if Spree::Config[:always_put_site_name_in_title] [title_string, default_title].join(' - ') @@ -47,15 +51,20 @@ module Spree Spree::Config[:site_name] end - # this is a hook for subclasses to provide title + # This is a hook for subclasses to provide title def accurate_title Spree::Config[:default_seo_title] end - def render_404(exception = nil) + def render_404(_exception = nil) respond_to do |type| - type.html { render :status => :not_found, :file => "#{::Rails.root}/public/404", :formats => [:html], :layout => nil} - type.all { render :status => :not_found, :nothing => true } + type.html { + render status: :not_found, + file: "#{::Rails.root}/public/404", + formats: [:html], + layout: nil + } + type.all { render status: :not_found, nothing: true } end end @@ -65,20 +74,18 @@ module Spree locale = session[:locale] locale ||= config_locale if respond_to?(:config_locale, true) locale ||= Rails.application.config.i18n.default_locale - locale ||= I18n.default_locale unless I18n.available_locales.map(&:to_s).include?(locale) + unless I18n.available_locales.map(&:to_s).include?(locale) + locale ||= I18n.default_locale + end I18n.locale = locale end # Returns which layout to render. - # - # You can set the layout you want to render inside your Spree configuration with the +:layout+ option. - # + # The layout to render can be set inside Spree configuration with the +:layout+ option. # Default layout is: +app/views/spree/layouts/spree_application+ - # def get_layout layout ||= Spree::Config[:layout] end - end end end From 23ff9d6fbb7c51b8bd418aba5fc53010f03aa6fb Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:32:12 +0100 Subject: [PATCH 232/261] Bring controller_helpers/order to OFN --- lib/spree/core/controller_helpers/order.rb | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/spree/core/controller_helpers/order.rb diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb new file mode 100644 index 0000000000..1501aa9c93 --- /dev/null +++ b/lib/spree/core/controller_helpers/order.rb @@ -0,0 +1,77 @@ +module Spree + module Core + module ControllerHelpers + module Order + def self.included(base) + base.class_eval do + helper_method :current_order + helper_method :current_currency + before_filter :set_current_order + end + end + + # The current incomplete order from the session for use in cart and during checkout + def current_order(create_order_if_necessary = false) + return @current_order if @current_order + if session[:order_id] + current_order = Spree::Order.includes(:adjustments).find_by(id: session[:order_id], currency: current_currency) + @current_order = current_order unless current_order.try(:completed?) + end + if create_order_if_necessary and (@current_order.nil? or @current_order.completed?) + @current_order = Spree::Order.new(currency: current_currency) + @current_order.user ||= try_spree_current_user + # See issue #3346 for reasons why this line is here + @current_order.created_by ||= try_spree_current_user + @current_order.save! + + # make sure the user has permission to access the order (if they are a guest) + if try_spree_current_user.nil? + session[:access_token] = @current_order.token + end + end + if @current_order + @current_order.last_ip_address = ip_address + session[:order_id] = @current_order.id + return @current_order + end + end + + def associate_user + @order ||= current_order + if try_spree_current_user && @order + @order.associate_user!(try_spree_current_user) if @order.user.blank? || @order.email.blank? + end + + # This will trigger any "first order" promotions to be triggered + # Assuming of course that this session variable was set correctly in + # the authentication provider's registrations controller + if session[:spree_user_signup] && @order + fire_event('spree.user.signup', user: try_spree_current_user, order: @order) + session[:spree_user_signup] = nil + end + + session[:guest_token] = nil + end + + def set_current_order + if user = try_spree_current_user + last_incomplete_order = user.last_incomplete_spree_order + if session[:order_id].nil? && last_incomplete_order + session[:order_id] = last_incomplete_order.id + elsif current_order(true) && last_incomplete_order && current_order != last_incomplete_order + current_order.merge!(last_incomplete_order) + end + end + end + + def current_currency + Spree::Config[:currency] + end + + def ip_address + request.env['HTTP_X_REAL_IP'] || request.env['REMOTE_ADDR'] + end + end + end + end +end From d5744572f7a02a93966b8e0c2ec1c6e677e297a3 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:39:09 +0100 Subject: [PATCH 233/261] Fix easy rubocop issues --- lib/spree/core/controller_helpers/order.rb | 49 +++++++++++++--------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb index 1501aa9c93..2e4da0c5cd 100644 --- a/lib/spree/core/controller_helpers/order.rb +++ b/lib/spree/core/controller_helpers/order.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Core module ControllerHelpers @@ -10,43 +12,50 @@ module Spree end end - # The current incomplete order from the session for use in cart and during checkout + # The current incomplete session order used in cart and checkout def current_order(create_order_if_necessary = false) return @current_order if @current_order + if session[:order_id] - current_order = Spree::Order.includes(:adjustments).find_by(id: session[:order_id], currency: current_currency) + current_order = Spree::Order.includes(:adjustments) + .find_by(id: session[:order_id], currency: current_currency) @current_order = current_order unless current_order.try(:completed?) end - if create_order_if_necessary and (@current_order.nil? or @current_order.completed?) + + if create_order_if_necessary && (@current_order.nil? || @current_order.completed?) @current_order = Spree::Order.new(currency: current_currency) @current_order.user ||= try_spree_current_user - # See issue #3346 for reasons why this line is here + # See https://github.com/spree/spree/issues/3346 for reasons why this line is here @current_order.created_by ||= try_spree_current_user @current_order.save! - # make sure the user has permission to access the order (if they are a guest) + # Verify that the user has access to the order (if they are a guest) if try_spree_current_user.nil? session[:access_token] = @current_order.token end end - if @current_order - @current_order.last_ip_address = ip_address - session[:order_id] = @current_order.id - return @current_order - end + + return unless @current_order + + @current_order.last_ip_address = ip_address + session[:order_id] = @current_order.id + @current_order end def associate_user @order ||= current_order if try_spree_current_user && @order - @order.associate_user!(try_spree_current_user) if @order.user.blank? || @order.email.blank? + if @order.user.blank? || @order.email.blank? + @order.associate_user!(try_spree_current_user) + end end # This will trigger any "first order" promotions to be triggered # Assuming of course that this session variable was set correctly in # the authentication provider's registrations controller if session[:spree_user_signup] && @order - fire_event('spree.user.signup', user: try_spree_current_user, order: @order) + fire_event('spree.user.signup', user: try_spree_current_user, + order: @order) session[:spree_user_signup] = nil end @@ -54,13 +63,15 @@ module Spree end def set_current_order - if user = try_spree_current_user - last_incomplete_order = user.last_incomplete_spree_order - if session[:order_id].nil? && last_incomplete_order - session[:order_id] = last_incomplete_order.id - elsif current_order(true) && last_incomplete_order && current_order != last_incomplete_order - current_order.merge!(last_incomplete_order) - end + return unless (user = try_spree_current_user) + + last_incomplete_order = user.last_incomplete_spree_order + if session[:order_id].nil? && last_incomplete_order + session[:order_id] = last_incomplete_order.id + elsif current_order(true) && + last_incomplete_order && + current_order != last_incomplete_order + current_order.merge!(last_incomplete_order) end end From 20f610fbee4f6a9e22bb77e3baa7fc6cb684a628 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:46:03 +0100 Subject: [PATCH 234/261] Merge controller_helpers/order with decorator --- lib/spree/core/controller_helpers/order.rb | 22 +++++++++++-- .../controller_helpers/order_decorator.rb | 32 ------------------- 2 files changed, 20 insertions(+), 34 deletions(-) delete mode 100644 lib/spree/core/controller_helpers/order_decorator.rb diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb index 2e4da0c5cd..cfdce6b9b5 100644 --- a/lib/spree/core/controller_helpers/order.rb +++ b/lib/spree/core/controller_helpers/order.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require 'open_food_network/scope_variant_to_hub' + module Spree module Core module ControllerHelpers @@ -12,8 +14,21 @@ module Spree end end - # The current incomplete session order used in cart and checkout def current_order(create_order_if_necessary = false) + order = spree_current_order(create_order_if_necessary) + + if order + scoper = OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) + order.line_items.each do |li| + scoper.scope(li.variant) + end + end + + order + end + + # The current incomplete session order used in cart and checkout + def spree_current_order(create_order_if_necessary = false) return @current_order if @current_order if session[:order_id] @@ -62,16 +77,19 @@ module Spree session[:guest_token] = nil end + # Do not attempt to merge incomplete and current orders. + # Instead, destroy the incomplete orders. def set_current_order return unless (user = try_spree_current_user) last_incomplete_order = user.last_incomplete_spree_order + if session[:order_id].nil? && last_incomplete_order session[:order_id] = last_incomplete_order.id elsif current_order(true) && last_incomplete_order && current_order != last_incomplete_order - current_order.merge!(last_incomplete_order) + last_incomplete_order.destroy end end diff --git a/lib/spree/core/controller_helpers/order_decorator.rb b/lib/spree/core/controller_helpers/order_decorator.rb deleted file mode 100644 index 6da1b42ee6..0000000000 --- a/lib/spree/core/controller_helpers/order_decorator.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'open_food_network/scope_variant_to_hub' - -Spree::Core::ControllerHelpers::Order.class_eval do - def current_order_with_scoped_variants(create_order_if_necessary = false) - order = current_order_without_scoped_variants(create_order_if_necessary) - - if order - scoper = OpenFoodNetwork::ScopeVariantToHub.new(order.distributor) - order.line_items.each do |li| - scoper.scope(li.variant) - end - end - - order - end - alias_method_chain :current_order, :scoped_variants - - # Override definition in Spree::Core::ControllerHelpers::Order - # Do not attempt to merge incomplete and current orders. Instead, destroy the incomplete orders. - def set_current_order - if user = try_spree_current_user - last_incomplete_order = user.last_incomplete_spree_order - - if session[:order_id].nil? && last_incomplete_order - session[:order_id] = last_incomplete_order.id - - elsif current_order && last_incomplete_order && current_order != last_incomplete_order - last_incomplete_order.destroy - end - end - end -end From 1167a1a9bb5a78cfe04deaa5b3eccf90b79b2618 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:46:52 +0100 Subject: [PATCH 235/261] Bring ControllerHelpers respond_with from spree --- .../core/controller_helpers/respond_with.rb | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 lib/spree/core/controller_helpers/respond_with.rb diff --git a/lib/spree/core/controller_helpers/respond_with.rb b/lib/spree/core/controller_helpers/respond_with.rb new file mode 100644 index 0000000000..e85777cb74 --- /dev/null +++ b/lib/spree/core/controller_helpers/respond_with.rb @@ -0,0 +1,70 @@ +module ActionController + class Base + def respond_with(*resources, &block) + raise "In order to use respond_with, first you need to declare the formats your " << + "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? + + if collector = retrieve_collector_from_mimes(&block) + options = resources.size == 1 ? {} : resources.extract_options! + + if defined_response = collector.response and !Spree::BaseController.spree_responders.keys.include?(self.class.to_s.to_sym) + if action = options.delete(:action) + render :action => action + else + defined_response.call + end + else + # The action name is needed for processing + options.merge!(:action_name => action_name.to_sym) + # If responder is not specified then pass in Spree::Responder + (options.delete(:responder) || Spree::Responder).call(self, resources, options) + end + end + end + end +end + +module Spree + module Core + module ControllerHelpers + module RespondWith + extend ActiveSupport::Concern + + included do + cattr_accessor :spree_responders + self.spree_responders = {} + end + + module ClassMethods + def clear_overrides! + self.spree_responders = {} + end + + def respond_override(options={}) + unless options.blank? + action_name = options.keys.first + action_value = options.values.first + + if action_name.blank? || action_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" + end + + format_name = action_value.keys.first + format_value = action_value.values.first + + if format_name.blank? || format_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" + end + + if format_value.is_a?(Proc) + options = {action_name.to_sym => {format_name.to_sym => {:success => format_value}}} + end + + self.spree_responders.deep_merge!(self.name.to_sym => options) + end + end + end + end + end + end +end From a3ea4b757d7d6fc3016f769d537ee1f6e93b30c2 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:48:12 +0100 Subject: [PATCH 236/261] Merge decorator into the class brought from spree --- .../core/controller_helpers/respond_with.rb | 13 +++++---- .../respond_with_decorator.rb | 28 ------------------- 2 files changed, 8 insertions(+), 33 deletions(-) delete mode 100644 lib/spree/core/controller_helpers/respond_with_decorator.rb diff --git a/lib/spree/core/controller_helpers/respond_with.rb b/lib/spree/core/controller_helpers/respond_with.rb index e85777cb74..5e83391d78 100644 --- a/lib/spree/core/controller_helpers/respond_with.rb +++ b/lib/spree/core/controller_helpers/respond_with.rb @@ -1,21 +1,24 @@ module ActionController class Base def respond_with(*resources, &block) - raise "In order to use respond_with, first you need to declare the formats your " << - "controller responds to in the class level" if self.class.mimes_for_respond_to.empty? + if self.class.mimes_for_respond_to.empty? + raise "In order to use respond_with, first you need to declare the formats your " \ + "controller responds to in the class level" + end if collector = retrieve_collector_from_mimes(&block) options = resources.size == 1 ? {} : resources.extract_options! - if defined_response = collector.response and !Spree::BaseController.spree_responders.keys.include?(self.class.to_s.to_sym) + # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) + if (defined_response = collector.response) && !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], action_name.to_sym) if action = options.delete(:action) - render :action => action + render action: action else defined_response.call end else # The action name is needed for processing - options.merge!(:action_name => action_name.to_sym) + options[:action_name] = action_name.to_sym # If responder is not specified then pass in Spree::Responder (options.delete(:responder) || Spree::Responder).call(self, resources, options) end diff --git a/lib/spree/core/controller_helpers/respond_with_decorator.rb b/lib/spree/core/controller_helpers/respond_with_decorator.rb deleted file mode 100644 index 522247ea01..0000000000 --- a/lib/spree/core/controller_helpers/respond_with_decorator.rb +++ /dev/null @@ -1,28 +0,0 @@ -module ActionController - class Base - def respond_with(*resources, &block) - if self.class.mimes_for_respond_to.empty? - raise "In order to use respond_with, first you need to declare the formats your " \ - "controller responds to in the class level" - end - - if collector = retrieve_collector_from_mimes(&block) - options = resources.size == 1 ? {} : resources.extract_options! - - # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) - if (defined_response = collector.response) && !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], action_name.to_sym) - if action = options.delete(:action) - render action: action - else - defined_response.call - end - else - # The action name is needed for processing - options[:action_name] = action_name.to_sym - # If responder is not specified then pass in Spree::Responder - (options.delete(:responder) || Spree::Responder).call(self, resources, options) - end - end - end - end -end From 643a82c73c672d66721d573979340b2cc4f4912b Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:52:18 +0100 Subject: [PATCH 237/261] Fix easy rubocop issues, some early returns make the indentation changes --- .../core/controller_helpers/respond_with.rb | 70 ++++++++++--------- 1 file changed, 38 insertions(+), 32 deletions(-) diff --git a/lib/spree/core/controller_helpers/respond_with.rb b/lib/spree/core/controller_helpers/respond_with.rb index 5e83391d78..6b3e7129ca 100644 --- a/lib/spree/core/controller_helpers/respond_with.rb +++ b/lib/spree/core/controller_helpers/respond_with.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActionController class Base def respond_with(*resources, &block) @@ -6,22 +8,24 @@ module ActionController "controller responds to in the class level" end - if collector = retrieve_collector_from_mimes(&block) - options = resources.size == 1 ? {} : resources.extract_options! + return unless (collector = retrieve_collector_from_mimes(&block)) - # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) - if (defined_response = collector.response) && !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], action_name.to_sym) - if action = options.delete(:action) - render action: action - else - defined_response.call - end + options = resources.size == 1 ? {} : resources.extract_options! + + # Fix spree issues #3531 and #2210 (patch provided by leiyangyou) + if (defined_response = collector.response) && + !Spree::BaseController.spree_responders[self.class.to_s.to_sym].try(:[], + action_name.to_sym) + if action = options.delete(:action) + render action: action else - # The action name is needed for processing - options[:action_name] = action_name.to_sym - # If responder is not specified then pass in Spree::Responder - (options.delete(:responder) || Spree::Responder).call(self, resources, options) + defined_response.call end + else + # The action name is needed for processing + options[:action_name] = action_name.to_sym + # If responder is not specified then pass in Spree::Responder + (options.delete(:responder) || Spree::Responder).call(self, resources, options) end end end @@ -43,28 +47,30 @@ module Spree self.spree_responders = {} end - def respond_override(options={}) - unless options.blank? - action_name = options.keys.first - action_value = options.values.first + def respond_override(options = {}) + return if options.blank? - if action_name.blank? || action_value.blank? - raise ArgumentError, "invalid values supplied #{options.inspect}" - end + action_name = options.keys.first + action_value = options.values.first - format_name = action_value.keys.first - format_value = action_value.values.first - - if format_name.blank? || format_value.blank? - raise ArgumentError, "invalid values supplied #{options.inspect}" - end - - if format_value.is_a?(Proc) - options = {action_name.to_sym => {format_name.to_sym => {:success => format_value}}} - end - - self.spree_responders.deep_merge!(self.name.to_sym => options) + if action_name.blank? || action_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" end + + format_name = action_value.keys.first + format_value = action_value.values.first + + if format_name.blank? || format_value.blank? + raise ArgumentError, "invalid values supplied #{options.inspect}" + end + + if format_value.is_a?(Proc) + options = { + action_name.to_sym => { format_name.to_sym => { success: format_value } } + } + end + + spree_responders.deep_merge!(name.to_sym => options) end end end From 97f00153ad94a16ed9167d8c7f425c1fe8d0c362 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 12:55:33 +0100 Subject: [PATCH 238/261] Bring controller_helpers/ssl.rb from spree --- lib/spree/core/controller_helpers/ssl.rb | 53 ++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 lib/spree/core/controller_helpers/ssl.rb diff --git a/lib/spree/core/controller_helpers/ssl.rb b/lib/spree/core/controller_helpers/ssl.rb new file mode 100644 index 0000000000..feb0487377 --- /dev/null +++ b/lib/spree/core/controller_helpers/ssl.rb @@ -0,0 +1,53 @@ +module Spree + module Core + module ControllerHelpers + module SSL + extend ActiveSupport::Concern + + included do + before_filter :force_non_ssl_redirect, :if => Proc.new { Spree::Config[:redirect_https_to_http] } + + def self.ssl_allowed(*actions) + class_attribute :ssl_allowed_actions + self.ssl_allowed_actions = actions + end + + def self.ssl_required(*actions) + class_attribute :ssl_required_actions + self.ssl_required_actions = actions + if ssl_supported? + if ssl_required_actions.empty? or Rails.application.config.force_ssl + force_ssl + else + force_ssl :only => ssl_required_actions + end + end + end + + def self.ssl_supported? + return Spree::Config[:allow_ssl_in_production] if Rails.env.production? + return Spree::Config[:allow_ssl_in_staging] if Rails.env.staging? + return Spree::Config[:allow_ssl_in_development_and_test] if (Rails.env.development? or Rails.env.test?) + end + + private + + # Redirect the existing request to use the HTTP protocol. + # + # ==== Parameters + # * host - Redirect to a different host name + def force_non_ssl_redirect(host = nil) + return true if defined?(ssl_allowed_actions) and ssl_allowed_actions.include?(action_name.to_sym) + if request.ssl? and (!defined?(ssl_required_actions) or !ssl_required_actions.include?(action_name.to_sym)) + redirect_options = {:protocol => 'http://', :status => :moved_permanently} + redirect_options.merge!(:host => host) if host + redirect_options.merge!(:params => request.query_parameters) + flash.keep if respond_to?(:flash) + redirect_to redirect_options + end + end + end + end + end + end +end From 046c5f65852685d4db9c577a2f297856e62dd6b6 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 13:00:32 +0100 Subject: [PATCH 239/261] Fix easy rubocop issues --- lib/spree/core/controller_helpers/ssl.rb | 52 ++++++++++++++---------- 1 file changed, 30 insertions(+), 22 deletions(-) diff --git a/lib/spree/core/controller_helpers/ssl.rb b/lib/spree/core/controller_helpers/ssl.rb index feb0487377..6c923e4977 100644 --- a/lib/spree/core/controller_helpers/ssl.rb +++ b/lib/spree/core/controller_helpers/ssl.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Spree module Core module ControllerHelpers @@ -5,7 +7,7 @@ module Spree extend ActiveSupport::Concern included do - before_filter :force_non_ssl_redirect, :if => Proc.new { Spree::Config[:redirect_https_to_http] } + before_filter :force_non_ssl_redirect, if: proc { Spree::Config[:redirect_https_to_http] } def self.ssl_allowed(*actions) class_attribute :ssl_allowed_actions @@ -15,37 +17,43 @@ module Spree def self.ssl_required(*actions) class_attribute :ssl_required_actions self.ssl_required_actions = actions - if ssl_supported? - if ssl_required_actions.empty? or Rails.application.config.force_ssl - force_ssl - else - force_ssl :only => ssl_required_actions - end + return unless ssl_supported? + + if ssl_required_actions.empty? || Rails.application.config.force_ssl + force_ssl + else + force_ssl only: ssl_required_actions end end def self.ssl_supported? return Spree::Config[:allow_ssl_in_production] if Rails.env.production? return Spree::Config[:allow_ssl_in_staging] if Rails.env.staging? - return Spree::Config[:allow_ssl_in_development_and_test] if (Rails.env.development? or Rails.env.test?) + return unless Rails.env.development? || Rails.env.test? + + Spree::Config[:allow_ssl_in_development_and_test] end private - # Redirect the existing request to use the HTTP protocol. - # - # ==== Parameters - # * host - Redirect to a different host name - def force_non_ssl_redirect(host = nil) - return true if defined?(ssl_allowed_actions) and ssl_allowed_actions.include?(action_name.to_sym) - if request.ssl? and (!defined?(ssl_required_actions) or !ssl_required_actions.include?(action_name.to_sym)) - redirect_options = {:protocol => 'http://', :status => :moved_permanently} - redirect_options.merge!(:host => host) if host - redirect_options.merge!(:params => request.query_parameters) - flash.keep if respond_to?(:flash) - redirect_to redirect_options - end - end + # Redirect the existing request to use the HTTP protocol. + # + # ==== Parameters + # * host - Redirect to a different host name + def force_non_ssl_redirect(host = nil) + return true if defined?(ssl_allowed_actions) && + ssl_allowed_actions.include?(action_name.to_sym) + + return unless request.ssl? && + (!defined?(ssl_required_actions) || + !ssl_required_actions.include?(action_name.to_sym)) + + redirect_options = { protocol: 'http://', status: :moved_permanently } + redirect_options.merge!(host: host) if host + redirect_options.merge!(params: request.query_parameters) + flash.keep if respond_to?(:flash) + redirect_to redirect_options + end end end end From d2e52f3136c078b6159c96d226e9ca7eb804bed5 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 13:51:02 +0100 Subject: [PATCH 240/261] Update rubocop manual todo --- .rubocop_manual_todo.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index e4eea50ed8..446be30aec 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -108,7 +108,6 @@ Layout/LineLength: - lib/open_food_network/scope_variants_for_search.rb - lib/open_food_network/variant_and_line_item_naming.rb - lib/open_food_network/xero_invoices_report.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb - lib/spree/localized_number.rb - lib/spree/product_filters.rb - lib/tasks/data.rake @@ -427,7 +426,9 @@ Metrics/AbcSize: - lib/open_food_network/variant_and_line_item_naming.rb - lib/open_food_network/xero_invoices_report.rb - lib/spree/api/controller_setup.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - lib/stripe/account_connector.rb - lib/tasks/enterprises.rake @@ -461,6 +462,8 @@ Metrics/BlockLength: ] Exclude: - app/models/spree/shipment.rb + - lib/spree/core/controller_helpers/common.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/tasks/data.rake - spec/controllers/spree/admin/invoices_controller_spec.rb - spec/factories/enterprise_factory.rb @@ -505,8 +508,9 @@ Metrics/CyclomaticComplexity: - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb - lib/open_food_network/enterprise_issue_validator.rb - - lib/spree/core/controller_helpers/order_decorator.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - spec/models/product_importer_spec.rb @@ -530,8 +534,9 @@ Metrics/PerceivedComplexity: - lib/discourse/single_sign_on.rb - lib/open_food_network/bulk_coop_report.rb - lib/open_food_network/enterprise_issue_validator.rb - - lib/spree/core/controller_helpers/order_decorator.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - spec/models/product_importer_spec.rb @@ -626,7 +631,10 @@ Metrics/MethodLength: - lib/open_food_network/users_and_enterprises_report.rb - lib/open_food_network/xero_invoices_report.rb - lib/spree/api/controller_setup.rb - - lib/spree/core/controller_helpers/respond_with_decorator.rb + - lib/spree/core/controller_helpers/auth.rb + - lib/spree/core/controller_helpers/order.rb + - lib/spree/core/controller_helpers/respond_with.rb + - lib/spree/core/controller_helpers/ssl.rb - lib/spree/localized_number.rb - lib/stripe/profile_storer.rb - lib/tasks/data/truncate_data.rb From 144811268ebe411191e9a1a87d1153c56ccd03c0 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 13:52:53 +0100 Subject: [PATCH 241/261] Adapt require statements to new undecorated classes --- app/controllers/base_controller.rb | 2 +- app/controllers/cart_controller.rb | 2 +- app/controllers/spree/orders_controller.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/controllers/base_controller.rb b/app/controllers/base_controller.rb index 6cf878a077..8fcdac8fe4 100644 --- a/app/controllers/base_controller.rb +++ b/app/controllers/base_controller.rb @@ -1,4 +1,4 @@ -require 'spree/core/controller_helpers/respond_with_decorator' +require 'spree/core/controller_helpers/respond_with' require 'open_food_network/tag_rule_applicator' class BaseController < ApplicationController diff --git a/app/controllers/cart_controller.rb b/app/controllers/cart_controller.rb index 997573899c..1fbf1b2b94 100644 --- a/app/controllers/cart_controller.rb +++ b/app/controllers/cart_controller.rb @@ -1,4 +1,4 @@ -require 'spree/core/controller_helpers/order_decorator' +require 'spree/core/controller_helpers/order' class CartController < BaseController before_action :check_authorization diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 545ae1ce60..102cca2520 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -1,5 +1,5 @@ -require 'spree/core/controller_helpers/order_decorator' -require 'spree/core/controller_helpers/auth_decorator' +require 'spree/core/controller_helpers/order' +require 'spree/core/controller_helpers/auth' module Spree class OrdersController < Spree::StoreController From 1666ffb191c30e2fe673991daadf0d58c92aebdd Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 16:08:52 +0100 Subject: [PATCH 242/261] Remove try_spree_current_user This can be done because the method is defined in OFN's ApplicationController, so spree_current_user is available in all controllers --- app/controllers/api/base_controller.rb | 2 +- app/controllers/enterprises_controller.rb | 2 +- app/controllers/spree/admin/base_controller.rb | 2 +- .../spree/admin/mail_methods_controller.rb | 2 +- app/controllers/spree/admin/orders_controller.rb | 2 +- app/views/spree/layouts/_admin_body.html.haml | 2 +- lib/spree/core/controller_helpers/auth.rb | 12 +++--------- lib/spree/core/controller_helpers/common.rb | 2 +- lib/spree/core/controller_helpers/order.rb | 14 +++++++------- spec/controllers/api/base_controller_spec.rb | 2 +- .../spree/admin/mail_methods_controller_spec.rb | 6 ++++-- 11 files changed, 22 insertions(+), 26 deletions(-) diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index 344dd89174..423a4fb104 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -53,7 +53,7 @@ module Api # Use logged in user (spree_current_user) for API authentication (current_api_user) def authenticate_user - return if @current_api_user = try_spree_current_user + return if @current_api_user = spree_current_user if api_key.blank? # An anonymous user diff --git a/app/controllers/enterprises_controller.rb b/app/controllers/enterprises_controller.rb index 6d640b5d7b..7488fa8c4d 100644 --- a/app/controllers/enterprises_controller.rb +++ b/app/controllers/enterprises_controller.rb @@ -68,7 +68,7 @@ class EnterprisesController < BaseController # reset_distributor must be called before any call to current_customer or current_distributor order_cart_reset = OrderCartReset.new(order, params[:id]) order_cart_reset.reset_distributor - order_cart_reset.reset_other!(try_spree_current_user, current_customer) + order_cart_reset.reset_other!(spree_current_user, current_customer) rescue ActiveRecord::RecordNotFound flash[:error] = I18n.t(:enterprise_shop_show_error) redirect_to shops_path diff --git a/app/controllers/spree/admin/base_controller.rb b/app/controllers/spree/admin/base_controller.rb index 7ce02d4a38..4f9cdbb4d0 100644 --- a/app/controllers/spree/admin/base_controller.rb +++ b/app/controllers/spree/admin/base_controller.rb @@ -24,7 +24,7 @@ module Spree # This is in Spree::Core::ControllerHelpers::Auth # But you can't easily reopen modules in Ruby def unauthorized - if try_spree_current_user + if spree_current_user flash[:error] = t(:authorization_failure) redirect_to '/unauthorized' else diff --git a/app/controllers/spree/admin/mail_methods_controller.rb b/app/controllers/spree/admin/mail_methods_controller.rb index aba6ad239f..70d573f319 100644 --- a/app/controllers/spree/admin/mail_methods_controller.rb +++ b/app/controllers/spree/admin/mail_methods_controller.rb @@ -15,7 +15,7 @@ module Spree end def testmail - if TestMailer.test_email(try_spree_current_user).deliver + if TestMailer.test_email(spree_current_user).deliver flash[:success] = Spree.t('admin.mail_methods.testmail.delivery_success') else flash[:error] = Spree.t('admin.mail_methods.testmail.delivery_error') diff --git a/app/controllers/spree/admin/orders_controller.rb b/app/controllers/spree/admin/orders_controller.rb index 22715108e9..8cde99be81 100644 --- a/app/controllers/spree/admin/orders_controller.rb +++ b/app/controllers/spree/admin/orders_controller.rb @@ -27,7 +27,7 @@ module Spree def new @order = Order.create - @order.created_by = try_spree_current_user + @order.created_by = spree_current_user @order.save redirect_to edit_admin_order_url(@order) end diff --git a/app/views/spree/layouts/_admin_body.html.haml b/app/views/spree/layouts/_admin_body.html.haml index d5aa05dbee..7b1d643dee 100644 --- a/app/views/spree/layouts/_admin_body.html.haml +++ b/app/views/spree/layouts/_admin_body.html.haml @@ -66,4 +66,4 @@ %div{"data-hook" => "admin_footer_scripts"} %script - = raw "Spree.api_key = \"#{try_spree_current_user.try(:spree_api_key).to_s}\";" + = raw "Spree.api_key = \"#{spree_current_user.try(:spree_api_key).to_s}\";" diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 7fb5672eff..494d45eaa9 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -8,7 +8,6 @@ module Spree included do before_filter :ensure_api_key - helper_method :try_spree_current_user rescue_from CanCan::AccessDenied do unauthorized @@ -17,7 +16,7 @@ module Spree # Needs to be overriden so that we use Spree's Ability rather than anyone else's. def current_ability - @current_ability ||= Spree::Ability.new(try_spree_current_user) + @current_ability ||= Spree::Ability.new(spree_current_user) end # Redirect as appropriate when an access request fails. The default action is to redirect @@ -25,7 +24,7 @@ module Spree # special behavior in case the user is not authorized to access the requested action. # For example, a popup window might simply close itself. def unauthorized - if try_spree_current_user + if spree_current_user flash[:error] = Spree.t(:authorization_failure) redirect_to '/unauthorized' else @@ -50,11 +49,6 @@ module Spree session['spree_user_return_to'] = request.fullpath.gsub('//', '/') end - # This was a proxy method in spree, in OFN this just redirects to spree_current_user - def try_spree_current_user - respond_to?(:spree_current_user) ? spree_current_user : nil - end - def redirect_back_or_default(default) redirect_to(session["spree_user_return_to"] || default) session["spree_user_return_to"] = nil @@ -63,7 +57,7 @@ module Spree # Need to generate an API key for a user due to some actions potentially # requiring authentication to the Spree API def ensure_api_key - return unless (user = try_spree_current_user) + return unless (user = spree_current_user) return unless user.respond_to?(:spree_api_key) && user.spree_api_key.blank? diff --git a/lib/spree/core/controller_helpers/common.rb b/lib/spree/core/controller_helpers/common.rb index ca95fe79da..e88920eaf6 100644 --- a/lib/spree/core/controller_helpers/common.rb +++ b/lib/spree/core/controller_helpers/common.rb @@ -27,7 +27,7 @@ module Spree # This method can be overriden to provide additional data when # responding to a notification def default_notification_payload - { user: try_spree_current_user, order: current_order } + { user: spree_current_user, order: current_order } end # This can be used in views as well as controllers. diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb index cfdce6b9b5..0d979b33d6 100644 --- a/lib/spree/core/controller_helpers/order.rb +++ b/lib/spree/core/controller_helpers/order.rb @@ -39,13 +39,13 @@ module Spree if create_order_if_necessary && (@current_order.nil? || @current_order.completed?) @current_order = Spree::Order.new(currency: current_currency) - @current_order.user ||= try_spree_current_user + @current_order.user ||= spree_current_user # See https://github.com/spree/spree/issues/3346 for reasons why this line is here - @current_order.created_by ||= try_spree_current_user + @current_order.created_by ||= spree_current_user @current_order.save! # Verify that the user has access to the order (if they are a guest) - if try_spree_current_user.nil? + if spree_current_user.nil? session[:access_token] = @current_order.token end end @@ -59,9 +59,9 @@ module Spree def associate_user @order ||= current_order - if try_spree_current_user && @order + if spree_current_user && @order if @order.user.blank? || @order.email.blank? - @order.associate_user!(try_spree_current_user) + @order.associate_user!(spree_current_user) end end @@ -69,7 +69,7 @@ module Spree # Assuming of course that this session variable was set correctly in # the authentication provider's registrations controller if session[:spree_user_signup] && @order - fire_event('spree.user.signup', user: try_spree_current_user, + fire_event('spree.user.signup', user: spree_current_user, order: @order) session[:spree_user_signup] = nil end @@ -80,7 +80,7 @@ module Spree # Do not attempt to merge incomplete and current orders. # Instead, destroy the incomplete orders. def set_current_order - return unless (user = try_spree_current_user) + return unless (user = spree_current_user) last_incomplete_order = user.last_incomplete_spree_order diff --git a/spec/controllers/api/base_controller_spec.rb b/spec/controllers/api/base_controller_spec.rb index d501aa98fb..1ebd3eca15 100644 --- a/spec/controllers/api/base_controller_spec.rb +++ b/spec/controllers/api/base_controller_spec.rb @@ -14,7 +14,7 @@ describe Api::BaseController do context "signed in as a user using an authentication extension" do before do - allow(controller).to receive_messages try_spree_current_user: + allow(controller).to receive_messages spree_current_user: double(email: "ofn@example.com") end diff --git a/spec/controllers/spree/admin/mail_methods_controller_spec.rb b/spec/controllers/spree/admin/mail_methods_controller_spec.rb index 422491660e..1a706462a7 100644 --- a/spec/controllers/spree/admin/mail_methods_controller_spec.rb +++ b/spec/controllers/spree/admin/mail_methods_controller_spec.rb @@ -18,8 +18,10 @@ describe Spree::Admin::MailMethodsController do spree_api_key: 'fake', id: nil, owned_groups: nil) - allow(user).to receive_messages(enterprises: [create(:enterprise)], has_spree_role?: true) - allow(controller).to receive_messages(try_spree_current_user: user) + allow(user).to receive_messages(enterprises: [create(:enterprise)], + has_spree_role?: true, + locale: nil) + allow(controller).to receive_messages(spree_current_user: user) Spree::Config[:enable_mail_delivery] = "1" ActionMailer::Base.perform_deliveries = true From bf3150ddc8e105910973cc48b7148f10b8acca1d Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 16:44:46 +0100 Subject: [PATCH 243/261] Delete spree_user_signup which is from spree promotions code that we dont use --- app/controllers/spree/user_registrations_controller.rb | 1 - app/controllers/user_registrations_controller.rb | 1 - lib/spree/core/controller_helpers/order.rb | 9 --------- 3 files changed, 11 deletions(-) diff --git a/app/controllers/spree/user_registrations_controller.rb b/app/controllers/spree/user_registrations_controller.rb index a55d327ae2..98ad3c8d1c 100644 --- a/app/controllers/spree/user_registrations_controller.rb +++ b/app/controllers/spree/user_registrations_controller.rb @@ -23,7 +23,6 @@ module Spree if resource.save set_flash_message(:notice, :signed_up) sign_in(:spree_user, @user) - session[:spree_user_signup] = true associate_user respond_with resource, location: after_sign_up_path_for(resource) else diff --git a/app/controllers/user_registrations_controller.rb b/app/controllers/user_registrations_controller.rb index d6fdf5ac76..f02309bf71 100644 --- a/app/controllers/user_registrations_controller.rb +++ b/app/controllers/user_registrations_controller.rb @@ -16,7 +16,6 @@ class UserRegistrationsController < Spree::UserRegistrationsController return render_error(@user.errors) end - session[:spree_user_signup] = true session[:confirmation_return_url] = params[:return_url] associate_user diff --git a/lib/spree/core/controller_helpers/order.rb b/lib/spree/core/controller_helpers/order.rb index 0d979b33d6..1df01e286a 100644 --- a/lib/spree/core/controller_helpers/order.rb +++ b/lib/spree/core/controller_helpers/order.rb @@ -65,15 +65,6 @@ module Spree end end - # This will trigger any "first order" promotions to be triggered - # Assuming of course that this session variable was set correctly in - # the authentication provider's registrations controller - if session[:spree_user_signup] && @order - fire_event('spree.user.signup', user: spree_current_user, - order: @order) - session[:spree_user_signup] = nil - end - session[:guest_token] = nil end From 7f1797de5833e7ee241c503b7a912e618cc0d9d9 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 17:43:57 +0100 Subject: [PATCH 244/261] Adapt specs to the move of unauthorized route from the spree routes to the main app routes --- .../admin/bulk_line_items_controller_spec.rb | 6 +++--- .../admin/customers_controller_spec.rb | 4 ++-- .../admin/enterprises_controller_spec.rb | 4 ++-- .../admin/inventory_items_controller_spec.rb | 8 ++++---- .../admin/proxy_orders_controller_spec.rb | 8 ++++---- .../admin/schedules_controller_spec.rb | 2 +- .../admin/stripe_accounts_controller_spec.rb | 4 ++-- ...stripe_connect_settings_controller_spec.rb | 4 ++-- .../admin/subscriptions_controller_spec.rb | 20 +++++++++---------- .../admin/tag_rules_controller_spec.rb | 2 +- .../variant_overrides_controller_spec.rb | 10 +++++----- .../spree/admin/orders_controller_spec.rb | 10 +++++----- .../spree/admin/products_controller_spec.rb | 2 +- .../spree/credit_cards_controller_spec.rb | 4 ++-- .../stripe/callbacks_controller_spec.rb | 2 +- 15 files changed, 45 insertions(+), 45 deletions(-) diff --git a/spec/controllers/admin/bulk_line_items_controller_spec.rb b/spec/controllers/admin/bulk_line_items_controller_spec.rb index 941b44eb0c..553e796558 100644 --- a/spec/controllers/admin/bulk_line_items_controller_spec.rb +++ b/spec/controllers/admin/bulk_line_items_controller_spec.rb @@ -21,7 +21,7 @@ describe Admin::BulkLineItemsController, type: :controller do it "should deny me access to the index action" do spree_get :index, format: :json - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -94,7 +94,7 @@ describe Admin::BulkLineItemsController, type: :controller do end it "does not display line items for which my enterprise is a supplier" do - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -172,7 +172,7 @@ describe Admin::BulkLineItemsController, type: :controller do end it "does not allow access" do - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/customers_controller_spec.rb b/spec/controllers/admin/customers_controller_spec.rb index b1503d89f7..8e344879a2 100644 --- a/spec/controllers/admin/customers_controller_spec.rb +++ b/spec/controllers/admin/customers_controller_spec.rb @@ -90,7 +90,7 @@ describe Admin::CustomersController, type: :controller do it "prevents me from updating the customer" do spree_put :update, format: :json, id: customer.id, customer: { email: 'new.email@gmail.com' } - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path expect(assigns(:customer)).to eq nil expect(customer.email).to_not eq 'new.email@gmail.com' end @@ -166,7 +166,7 @@ describe Admin::CustomersController, type: :controller do it "prevents me from updating the customer" do spree_get :show, format: :json, id: customer.id - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end end diff --git a/spec/controllers/admin/enterprises_controller_spec.rb b/spec/controllers/admin/enterprises_controller_spec.rb index 78678e03e2..c8a0a9ac29 100644 --- a/spec/controllers/admin/enterprises_controller_spec.rb +++ b/spec/controllers/admin/enterprises_controller_spec.rb @@ -294,7 +294,7 @@ describe Admin::EnterprisesController, type: :controller do it "does not allow access" do spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -306,7 +306,7 @@ describe Admin::EnterprisesController, type: :controller do it "does not allow access" do spree_post :register, id: enterprise.id, sells: 'none' - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/inventory_items_controller_spec.rb b/spec/controllers/admin/inventory_items_controller_spec.rb index 741f329663..9fce5711a6 100644 --- a/spec/controllers/admin/inventory_items_controller_spec.rb +++ b/spec/controllers/admin/inventory_items_controller_spec.rb @@ -21,7 +21,7 @@ describe Admin::InventoryItemsController, type: :controller do it "redirects to unauthorized" do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -33,7 +33,7 @@ describe Admin::InventoryItemsController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -84,7 +84,7 @@ describe Admin::InventoryItemsController, type: :controller do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -96,7 +96,7 @@ describe Admin::InventoryItemsController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/proxy_orders_controller_spec.rb b/spec/controllers/admin/proxy_orders_controller_spec.rb index 1d612e2c57..0bc63e3cb8 100644 --- a/spec/controllers/admin/proxy_orders_controller_spec.rb +++ b/spec/controllers/admin/proxy_orders_controller_spec.rb @@ -20,7 +20,7 @@ describe Admin::ProxyOrdersController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -31,7 +31,7 @@ describe Admin::ProxyOrdersController, type: :controller do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -89,7 +89,7 @@ describe Admin::ProxyOrdersController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :resume, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -100,7 +100,7 @@ describe Admin::ProxyOrdersController, type: :controller do it 'redirects to unauthorized' do spree_put :resume, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/schedules_controller_spec.rb b/spec/controllers/admin/schedules_controller_spec.rb index 99b73f4e03..8a0ac86c78 100644 --- a/spec/controllers/admin/schedules_controller_spec.rb +++ b/spec/controllers/admin/schedules_controller_spec.rb @@ -106,7 +106,7 @@ describe Admin::SchedulesController, type: :controller do it "prevents me from updating the schedule" do spree_put :update, format: :json, id: coordinated_schedule.id, schedule: { name: "my awesome schedule" } - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path expect(assigns(:schedule)).to eq nil expect(coordinated_schedule.name).to_not eq "my awesome schedule" end diff --git a/spec/controllers/admin/stripe_accounts_controller_spec.rb b/spec/controllers/admin/stripe_accounts_controller_spec.rb index 9a6854ae85..c1b0890316 100644 --- a/spec/controllers/admin/stripe_accounts_controller_spec.rb +++ b/spec/controllers/admin/stripe_accounts_controller_spec.rb @@ -46,7 +46,7 @@ describe Admin::StripeAccountsController, type: :controller do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -93,7 +93,7 @@ describe Admin::StripeAccountsController, type: :controller do it "redirects to unauthorized" do spree_get :status, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb index 11cebea66e..73331a151a 100644 --- a/spec/controllers/admin/stripe_connect_settings_controller_spec.rb +++ b/spec/controllers/admin/stripe_connect_settings_controller_spec.rb @@ -14,7 +14,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do it "does not allow access" do spree_get :edit - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -76,7 +76,7 @@ describe Admin::StripeConnectSettingsController, type: :controller do it "does not allow access" do spree_get :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/subscriptions_controller_spec.rb b/spec/controllers/admin/subscriptions_controller_spec.rb index c7f0e207a4..7eb11807bf 100644 --- a/spec/controllers/admin/subscriptions_controller_spec.rb +++ b/spec/controllers/admin/subscriptions_controller_spec.rb @@ -18,7 +18,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -55,7 +55,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -120,7 +120,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_post :create, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -272,7 +272,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_post :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -390,7 +390,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -401,7 +401,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :cancel, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -489,7 +489,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :pause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -500,7 +500,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :pause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -588,7 +588,7 @@ describe Admin::SubscriptionsController, type: :controller do context 'as a regular user' do it 'redirects to unauthorized' do spree_put :unpause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -599,7 +599,7 @@ describe Admin::SubscriptionsController, type: :controller do it 'redirects to unauthorized' do spree_put :unpause, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/tag_rules_controller_spec.rb b/spec/controllers/admin/tag_rules_controller_spec.rb index b4da011923..5d654958a4 100644 --- a/spec/controllers/admin/tag_rules_controller_spec.rb +++ b/spec/controllers/admin/tag_rules_controller_spec.rb @@ -19,7 +19,7 @@ describe Admin::TagRulesController, type: :controller do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/admin/variant_overrides_controller_spec.rb b/spec/controllers/admin/variant_overrides_controller_spec.rb index c75a265cd1..4690dba35b 100644 --- a/spec/controllers/admin/variant_overrides_controller_spec.rb +++ b/spec/controllers/admin/variant_overrides_controller_spec.rb @@ -22,7 +22,7 @@ describe Admin::VariantOverridesController, type: :controller do it "redirects to unauthorized" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -34,7 +34,7 @@ describe Admin::VariantOverridesController, type: :controller do context "but the producer has not granted VO permission" do it "redirects to unauthorized" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -78,7 +78,7 @@ describe Admin::VariantOverridesController, type: :controller do it "allows to update other variant overrides" do spree_put :bulk_update, format: format, variant_overrides: variant_override_params - expect(response).to_not redirect_to spree.unauthorized_path + expect(response).to_not redirect_to unauthorized_path variant_override.reload expect(variant_override.price).to eq 123.45 end @@ -111,7 +111,7 @@ describe Admin::VariantOverridesController, type: :controller do it "redirects to unauthorized" do spree_put :bulk_reset, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -123,7 +123,7 @@ describe Admin::VariantOverridesController, type: :controller do context "where the producer has not granted create_variant_overrides permission to the hub" do it "restricts access" do spree_put :bulk_reset, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/spree/admin/orders_controller_spec.rb b/spec/controllers/spree/admin/orders_controller_spec.rb index 8ab20c385a..5d0401c6cc 100644 --- a/spec/controllers/spree/admin/orders_controller_spec.rb +++ b/spec/controllers/spree/admin/orders_controller_spec.rb @@ -113,7 +113,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should deny me access to the index action" do spree_get :index - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -140,7 +140,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :invoice, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -150,7 +150,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :invoice, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -198,7 +198,7 @@ describe Spree::Admin::OrdersController, type: :controller do it "should prevent me from sending order invoices" do spree_get :print, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -207,7 +207,7 @@ describe Spree::Admin::OrdersController, type: :controller do before { allow(controller).to receive(:spree_current_user) { user } } it "should prevent me from sending order invoices" do spree_get :print, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/spree/admin/products_controller_spec.rb b/spec/controllers/spree/admin/products_controller_spec.rb index e8ae658e9e..efc6ce9b5b 100644 --- a/spec/controllers/spree/admin/products_controller_spec.rb +++ b/spec/controllers/spree/admin/products_controller_spec.rb @@ -16,7 +16,7 @@ describe Spree::Admin::ProductsController, type: :controller do end it "denies access" do - expect(response).to redirect_to spree.unauthorized_url + expect(response).to redirect_to unauthorized_path end it "does not update any product" do diff --git a/spec/controllers/spree/credit_cards_controller_spec.rb b/spec/controllers/spree/credit_cards_controller_spec.rb index e8996433f3..2c4f6a3a15 100644 --- a/spec/controllers/spree/credit_cards_controller_spec.rb +++ b/spec/controllers/spree/credit_cards_controller_spec.rb @@ -88,7 +88,7 @@ describe Spree::CreditCardsController, type: :controller do context "but the card is not owned by the user" do it "redirects to unauthorized" do spree_put :update, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end @@ -135,7 +135,7 @@ describe Spree::CreditCardsController, type: :controller do context "but the card is not owned by the user" do it "redirects to unauthorized" do spree_delete :destroy, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end diff --git a/spec/controllers/stripe/callbacks_controller_spec.rb b/spec/controllers/stripe/callbacks_controller_spec.rb index 33f7bd5b76..50c5433767 100644 --- a/spec/controllers/stripe/callbacks_controller_spec.rb +++ b/spec/controllers/stripe/callbacks_controller_spec.rb @@ -30,7 +30,7 @@ describe Stripe::CallbacksController, type: :controller do it "redirects to unauthorized" do spree_get :index, params - expect(response).to redirect_to spree.unauthorized_path + expect(response).to redirect_to unauthorized_path end end From 8fac1bc9cadddaf1c4b3316b119053fd53a5ac55 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 19:17:33 +0100 Subject: [PATCH 245/261] Move unauthorized view to HomeController only, all other calls to unauthorized will go through Auth which will redirect to the home controller IF the user is logged in or to login if user is not logged in --- app/controllers/home_controller.rb | 4 ++++ app/controllers/spree/store_controller.rb | 4 ---- spec/controllers/spree/store_controller_spec.rb | 14 -------------- spec/requests/home_controller_spec.rb | 14 ++++++++++++++ 4 files changed, 18 insertions(+), 18 deletions(-) delete mode 100644 spec/controllers/spree/store_controller_spec.rb create mode 100644 spec/requests/home_controller_spec.rb diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index c585b63839..c7612d3997 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -16,6 +16,10 @@ class HomeController < BaseController def sell; end + def unauthorized + render 'shared/unauthorized', status: :unauthorized + end + private # Cache the value of the query count diff --git a/app/controllers/spree/store_controller.rb b/app/controllers/spree/store_controller.rb index cc4dd9d537..5486912bd3 100644 --- a/app/controllers/spree/store_controller.rb +++ b/app/controllers/spree/store_controller.rb @@ -6,9 +6,5 @@ module Spree include I18nHelper before_action :set_locale - - def unauthorized - render 'shared/unauthorized', status: :unauthorized - end end end diff --git a/spec/controllers/spree/store_controller_spec.rb b/spec/controllers/spree/store_controller_spec.rb deleted file mode 100644 index b04ac0167e..0000000000 --- a/spec/controllers/spree/store_controller_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require 'spec_helper' - -describe Spree::StoreController, type: :controller do - controller(Spree::StoreController) do - before_filter :unauthorized - def index - render text: "" - end - end - it "redirects to home when unauthorized" do - get :index - expect(response).to render_template("shared/unauthorized", layout: 'darkswarm') - end -end diff --git a/spec/requests/home_controller_spec.rb b/spec/requests/home_controller_spec.rb new file mode 100644 index 0000000000..9400fedcd9 --- /dev/null +++ b/spec/requests/home_controller_spec.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe HomeController, type: :request do + context "#unauthorized" do + it "renders the unauthorized template" do + get "/unauthorized" + + expect(response.status).to eq 401 + expect(response).to render_template("shared/unauthorized", layout: 'darkswarm') + end + end +end From 3599cb2047c892f3a9d5e164e3c70ad7f544816b Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 19:11:35 +0100 Subject: [PATCH 246/261] Make unauthorized in ControllerHelpers::Auth the same as in Spree::Admin::BaseController It adapts the method in ControllerHelpers::Auth to also use the after_login mechanism. Ideally we would remove one of the two after_login mechanisms after_login and spree_user_return_to but they might still be in use. --- lib/spree/core/controller_helpers/auth.rb | 2 +- spec/controllers/spree/orders_controller_spec.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 494d45eaa9..89980ccfe2 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -29,7 +29,7 @@ module Spree redirect_to '/unauthorized' else store_location - redirect_to(respond_to?(:spree_login_path) ? spree_login_path : main_app.root_path) + redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}") end end diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index cee76bdc39..1f74a3915f 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -58,7 +58,7 @@ describe Spree::OrdersController, type: :controller do it "redirects to unauthorized" do spree_get :show, id: order.number - expect(response.status).to eq(401) + expect(response).to redirect_to unauthorized_path end end @@ -415,9 +415,11 @@ describe Spree::OrdersController, type: :controller do let(:params) { { id: order.number } } context "when the user does not have permission to cancel the order" do + before { allow(controller).to receive(:spree_current_user) { create(:user) } } + it "responds with unauthorized" do spree_put :cancel, params - expect(response).to render_template 'shared/unauthorized' + expect(response).to redirect_to unauthorized_path end end From 2605c4249b7e78d93b0b4321853570c1c54c4797 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Sat, 27 Jun 2020 20:18:34 +0100 Subject: [PATCH 247/261] Simplify spec, the 2 minutes wait is not necessary anylonger --- spec/features/admin/authentication_spec.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/spec/features/admin/authentication_spec.rb b/spec/features/admin/authentication_spec.rb index 6ff46d15a4..a7add975f2 100644 --- a/spec/features/admin/authentication_spec.rb +++ b/spec/features/admin/authentication_spec.rb @@ -9,17 +9,14 @@ feature "Authentication", js: true do let!(:enterprise) { create(:enterprise, owner: user) } # Required for access to admin scenario "logging into admin redirects home, then back to admin" do - # This is the first admin spec, so give a little extra load time for slow systems - Capybara.using_wait_time(120) do - visit spree.admin_dashboard_path + visit spree.admin_dashboard_path - fill_in "Email", with: user.email - fill_in "Password", with: user.password - click_login_button - expect(page).to have_content "DASHBOARD" - expect(page).to have_current_path spree.admin_dashboard_path - expect(page).to have_no_content "CONFIGURATION" - end + fill_in "Email", with: user.email + fill_in "Password", with: user.password + click_login_button + expect(page).to have_content "DASHBOARD" + expect(page).to have_current_path spree.admin_dashboard_path + expect(page).to have_no_content "CONFIGURATION" end scenario "viewing my account" do From 31e072179b5cfaf90744af929fe202326b689faa Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Wed, 15 Jul 2020 15:19:16 +0100 Subject: [PATCH 248/261] Make method a little simple by extracting method --- app/services/checkout/form_data_adapter.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/services/checkout/form_data_adapter.rb b/app/services/checkout/form_data_adapter.rb index 60bb9257c5..273a978a55 100644 --- a/app/services/checkout/form_data_adapter.rb +++ b/app/services/checkout/form_data_adapter.rb @@ -34,11 +34,16 @@ module Checkout end def fill_in_card_type - payment = params[:order][:payments_attributes]&.first&.dig(:source_attributes) + return unless payment_source_attributes - return if payment&.dig(:number).blank? + return if payment_source_attributes.dig(:number).blank? - payment[:cc_type] ||= card_brand(payment[:number]) + payment_source_attributes[:cc_type] ||= card_brand(payment_source_attributes[:number]) + end + + def payment_source_attributes + @payment_source_attributes ||= + params[:order][:payments_attributes]&.first&.dig(:source_attributes) end def card_brand(number) From 4e00c45782ac9ffee3bb0e3d8a7e3df5bf74d99b Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Wed, 15 Jul 2020 16:46:09 +0200 Subject: [PATCH 249/261] Doc defensive coding needed by pin payments [skip ci] --- app/services/checkout/form_data_adapter.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/services/checkout/form_data_adapter.rb b/app/services/checkout/form_data_adapter.rb index 273a978a55..1333ed5dbd 100644 --- a/app/services/checkout/form_data_adapter.rb +++ b/app/services/checkout/form_data_adapter.rb @@ -33,6 +33,11 @@ module Checkout @params[:order][:payments_attributes].first[:source_attributes] = payment_source_params end + # Ensures cc_type is always passed to the model by inferring the type when + # the frontend didn't provide it. This fixes Pin Payments specifically + # although it might be useful for future payment gateways. + # + # More details: app/assets/javascripts/darkswarm/services/checkout.js.coffee#L70-L98 def fill_in_card_type return unless payment_source_attributes From 2fe37b52375662d29afd2ee6b99cf3bc9a385e5e Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 16 Jul 2020 18:07:40 +0100 Subject: [PATCH 250/261] Update all locales with the latest Transifex translations --- config/locales/ca.yml | 4 ++-- config/locales/en_CA.yml | 2 +- config/locales/en_NZ.yml | 4 ++-- config/locales/fr.yml | 2 +- config/locales/tr.yml | 40 ++++++++++++++++++++-------------------- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 2bc956f2ba..2194636d75 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -43,7 +43,7 @@ ca: after_orders_open_at: s'ha de fer amb el termini obert variant_override: count_on_hand: - using_producer_stock_settings_but_count_on_hand_set: "ha d'estar en blanc perquè s'utilitza la configuració de l'inventari de la productora" + using_producer_stock_settings_but_count_on_hand_set: "ha d'estar en blanc perquè s'utilitza la configuració d'estoc de la productora" 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: @@ -2568,7 +2568,7 @@ ca: 'yes': "Sota demanda" variant_overrides: on_demand: - use_producer_settings: "Utilitzeu la configuració d'inventari de la productora" + use_producer_settings: "Utilitzeu la configuració d'estoc de la productora" 'yes': "Sí" 'no': "No" inventory_products: "Productes de l'inventari" diff --git a/config/locales/en_CA.yml b/config/locales/en_CA.yml index 5b3886a906..3750932c8e 100644 --- a/config/locales/en_CA.yml +++ b/config/locales/en_CA.yml @@ -2811,7 +2811,7 @@ en_CA: city: "City" zip: "Postal Code" country: "Country" - state: "Province" + state: "State" phone: "Phone" update: "Update" use_billing_address: "Use Billing Address" diff --git a/config/locales/en_NZ.yml b/config/locales/en_NZ.yml index e45ca43439..97f7ccf95b 100644 --- a/config/locales/en_NZ.yml +++ b/config/locales/en_NZ.yml @@ -1170,7 +1170,7 @@ en_NZ: 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_body: "Create a listing, build a 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" @@ -1378,7 +1378,7 @@ en_NZ: 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_step2_text: "Choose what you want, checkout as guest or make an account, you are good to go. Its that simple. If you'd like a box every week then ask for a subscription." 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." diff --git a/config/locales/fr.yml b/config/locales/fr.yml index eb8d4e055d..50b821e721 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -3139,7 +3139,7 @@ fr: zones: "Zones" both: "Vu par l'acheteur sur la boutique" back_end: "Visible pour l'administration uniquement" - deactivation_warning: "Désactiver une méthode de livraison peut engendre sa disparition de la liste ici. Si vous souhaitez uniquement ne plus l'afficher pour l'acheteur, modifiez-là et utilisez l'option d'affichage \"visible pour l'administrateur uniquement\"." + deactivation_warning: "Désactiver une méthode de livraison peut engendrer sa disparition de la liste ici. Si vous souhaitez uniquement ne plus l'afficher pour l'acheteur, modifiez-là et utilisez l'option d'affichage \"visible pour l'administrateur uniquement\"." payment_methods: index: payment_methods: "Méthodes de paiement" diff --git a/config/locales/tr.yml b/config/locales/tr.yml index dae3555bb1..1bcf7af309 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -221,7 +221,7 @@ tr: edit: Düzenle clone: Kopyala distributors: Dağıtımcılar - bulk_order_management: Toplu Sipariş Yönetimi + bulk_order_management: TOPLU SİPARİŞ YÖNETİMİ enterprises: İşletmeler enterprise_groups: AĞLAR reports: Raporlar @@ -256,7 +256,7 @@ tr: processing_payment: "Ödeme İşlemi Gerçekleştiriliyor.." no_pending_payments: "Bekleyen ödeme yok" invalid_payment_state: "Geçersiz ödeme durumu" - filter_results: Sonuçları Filtrele + filter_results: SONUÇLARI FİLTRELE quantity: Miktar pick_up: Teslim Alma copy: Kopyala @@ -593,7 +593,7 @@ tr: product_unit: "Ürün: Birim" weight_volume: "Ağırlık / Hacim" ask: "Sor?" - page_title: "Toplu Sipariş Yönetimi" + page_title: "TOPLU SİPARİŞ YÖNETİMİ" actions_delete: "Seçilenleri Sil" loading: "Siparişler yükleniyor" no_results: "Sipariş bulunamadı." @@ -730,8 +730,8 @@ tr: sizi ziyaret edenler tarafından görülecek. (örn. neden kapalı olduğunu ve ne zaman açılacağını belirtebilirsiniz) shopfront_category_ordering: "DÜKKAN KATEGORİ SIRALAMASI" - open_date: "Açılış Tarihi" - close_date: "Kapanış Tarih" + open_date: "AÇILIŞ TARİHİ" + close_date: "KAPANIŞ TARİHİ" social: twitter_placeholder: "Örneğin. @the_usta" instagram_placeholder: "Örneğin. the_usta" @@ -795,21 +795,21 @@ tr: producer: ÜRETİCİ change_type_form: producer_profile: ÜRETİCİ PROFİLİ - connect_ofn: AGA üzerinden bağlan + connect_ofn: AGA PLATFORMUNA KATIL always_free: HER ZAMAN ÜCRETSİZ producer_description_text: Ürünlerinizi Açık Gıda Ağı'na yükleyin. Böylece ürünleriniz pazar hesapları üzerinden satışa sunulabilir. producer_shop: ÜRETİCİ DÜKKANI - sell_your_produce: Kendi ürününü sat + sell_your_produce: KENDİ ÜRÜNÜNÜ SAT producer_shop_description_text: Açık Gıda Ağı üzerinden açtığınız bireysel dükkanınız ile ürünlerinizi doğrudan müşterilere ulaştırabilirsiniz. producer_shop_description_text2: Üretici Dükkanı sadece sizin ürünleriniz içindir. Üretiminiz haricindeki ürünleri satabilmek için lütfen 'Üretici Pazarı' seçeneğini seçin. producer_hub: ÜRETİCİ PAZARI - producer_hub_text: Kendi ürünleriniz ile beraber başkalarının ürünlerini de satın + producer_hub_text: KENDİ ÜRÜNLERİNİZ İLE BERABER BAŞKALARININ ÜRÜNLERİNİ DE SATIN producer_hub_description_text: İşletmeniz, yerel gıda sisteminizin bel kemiğidir. Açık Gıda Ağı'ndaki mağazanız aracılığıyla kendi ürünlerinizi ve çevrenizdeki diğer üreticilerin ürünlerini beraber satabilirsiniz. profile: Yalnızca Profil get_listing: Görünür ol profile_description_text: İnsanlar Açık Gıda Ağı üzerinden sizi bulabilir ve sizinle iletişim kurabilir. İşletmeniz haritada ve listelerde görünür olacak. hub_shop: Türetici Pazarı - hub_shop_text: Başkalarının ürünlerini satın + hub_shop_text: BAŞKALARININ ÜRÜNLERİNİ SATIN hub_shop_description_text: İşletmeniz yerel gıda sisteminizin belkemiğidir. Diğer işletmelerin ürünlerini bir araya getirebilir, Açık Gıda Ağı'na kayıtlı dükkanınız üzerinden alıcılara ulaştırabilirsiniz. choose_option: Lütfen yukarıdaki seçeneklerden birini seçin. change_now: Değiştir @@ -897,10 +897,10 @@ tr: outgoing: "3. GİDEN ÜRÜNLER" exchange_form: pickup_time_tip: Bu sipariş dönemine ait siparişlerin müşteriler için hazır olma tarihi - pickup_instructions_placeholder: "Teslimat Talimatları" + pickup_instructions_placeholder: "TESLİMAT DETAYLARI" pickup_instructions_tip: Bu talimatlar, siparişi tamamladıktan sonra müşterilere iletilir pickup_time_placeholder: "Teslimat (örn. Tarih / Saat)" - receival_instructions_placeholder: "Teslim Alma talimatları" + receival_instructions_placeholder: "TESLİM ALMA TALİMATLARI" add_fee: 'Ücret ekle' remove: 'Kaldır' selected: 'seçildi' @@ -1581,7 +1581,7 @@ tr: components_filters_clearfilters: "TÜM FİLTRELERİ TEMİZLE" groups_title: Gruplar groups_headline: Gruplar - groups_text: "Her üretici özeldir ve her işletmenin ortaya koyabileceği farklı bir değer vardır. Üyelerimiz, ürünlerini, emeklerini ve gıdanın ortak değerleri paylaşan üretici, türetici ve dağıtımcı kolektifleridir. Bu bileşenler, adil ve temiz gıdaya ulaşım yollarını kolaylaştırır ve bozulmuş gıda sistemini hep beraber düzeltmemize yardımcı olur." + groups_text: "Her üretici özeldir ve her işletmenin ortaya koyabileceği farklı bir değer vardır. Üyelerimiz, ürünlerini, emeklerini ve gıdanın ortak değerlerini paylaşan üretici, türetici ve dağıtımcı kolektifleridir. Bu bileşenler, adil ve temiz gıdaya ulaşım yollarını kolaylaştırır ve bozulmuş gıda sistemini düzeltmemize öncülük ederler." groups_search: "İsim veya anahtar kelime ile ara" groups_no_groups: "Ağ bulunamadı" groups_about: "Hakkımızda" @@ -1615,7 +1615,7 @@ tr: producers_about: Hakkımızda producers_buy: Alışveriş ürünleri producers_contact: İLETİŞİM - producers_contact_phone: Ara + producers_contact_phone: 'Tel:' producers_contact_social: Takip et producers_buy_at_html: "%{enterprise} ürünleri için buradan alışveriş yapın:" producers_filter: Filtrele @@ -1918,7 +1918,7 @@ tr: ok: tamam not_visible: görünmez you_have_no_orders_yet: "Henüz siparişiniz yok" - show_only_complete_orders: "Yalnızca tamamlanan siparişleri göster" + show_only_complete_orders: "YALNIZCA TAMAMLANAN SİPARİŞLERİ GÖSTER" successfully_created: '%{resource} BAŞARIYLA OLUŞTURULDU!' successfully_removed: '%{resource} BAŞARIYLA KALDIRILDI!' successfully_updated: '%{resource} BAŞARIYLA GÜNCELLENDİ!' @@ -2025,8 +2025,8 @@ tr: spree_admin_product_category: Ürün Kategorisi spree_admin_variant_unit_name: Varyant Birimi Adı unit_name: "Birim adı" - change_package: "Hesap Türünü Değiştir" - spree_admin_single_enterprise_hint: "İpucu: İnsanların sizi bulmasına izin vermek için, alttaki görünürlük kısmını açın." + change_package: "HESAP TÜRÜNÜ DEĞİŞTİR" + spree_admin_single_enterprise_hint: "İpucu: İnsanların sizi bulmasına izin vermek için 'Görünür' olmayı ayarlamayı unutmayın:" spree_admin_eg_pickup_from_school: "Örn. 'Teslimat noktası: Moda İlkokulu Bahçesi'" spree_admin_eg_collect_your_order: "Örn. Lütfen siparişinizi Moda Cad. No:17 Temiz Dükkan'dan teslim alınız." spree_classification_primary_taxon_error: "%{taxon} cinsi, %{product}ürününün birincil cinsidir ve silinemez" @@ -2129,7 +2129,7 @@ tr: report_header_incoming_transport: Gelen Nakliye report_header_special_instructions: Özel Talimatlar report_header_order_number: Sipariş numarası - report_header_date: tarih + report_header_date: Tarih report_header_confirmation_date: Onay tarihi report_header_tags: ETİKETLER report_header_items: Kalemler @@ -2429,8 +2429,8 @@ tr: en iyi şekilde yönetmeniz için tüm imkanları ve araçları sağlamaya hazırız. get_listing: Görünür Olun always_free: HER ZAMAN ÜCRETSİZ - sell_produce_others: Başkalarının ürünlerini sat - sell_own_produce: Kendi ürününü sat + sell_produce_others: BAŞKALARININ ÜRÜNLERİNİ SAT + sell_own_produce: KENDİ ÜRÜNÜNÜ SAT sell_both: Kendi ürünlerini ve başkalarının ürünlerini sat enterprise_producer: producer: Üretici @@ -2966,7 +2966,7 @@ tr: tab: dashboard: "KONTROL PANELİ" orders: "SİPARİŞLER" - bulk_order_management: "Toplu Sipariş Yönetimi" + bulk_order_management: "TOPLU SİPARİŞ YÖNETİMİ" subscriptions: "Üyelikler" products: "Ürünler" option_types: "Seçenek Türleri" From f31a1ff59c9caadb7ebad0330d574cce84881765 Mon Sep 17 00:00:00 2001 From: Transifex-Openfoodnetwork Date: Fri, 17 Jul 2020 04:10:57 +1000 Subject: [PATCH 251/261] Updating translations for config/locales/en_GB.yml --- config/locales/en_GB.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/config/locales/en_GB.yml b/config/locales/en_GB.yml index 2250c91bb5..35a9dc1a31 100644 --- a/config/locales/en_GB.yml +++ b/config/locales/en_GB.yml @@ -182,6 +182,7 @@ en_GB: 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: "The Open Food Network software platform allows farmers to sell produce online, at a price that works for them. It has been built specifically for selling food so it can handle tricky measures or stock levels that only food has - a dozen eggs, a bunch of parsley, a whole chicken that varies in weight…" search_by_name: Search by name, town, county or postcode... producers_join: UK producers are now welcome to join Open Food Network UK. @@ -1713,6 +1714,7 @@ en_GB: 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 From b0ac1884302813bb7aba015747d5037e1e2d3ab5 Mon Sep 17 00:00:00 2001 From: Maikel Linke Date: Fri, 10 Jul 2020 15:33:20 +1000 Subject: [PATCH 252/261] Make broken spec fail reliably and set it pending This spec has been broken for a long time, at least eight months. But it regularly passed because the search filter is applied with a delay and in that time the content matches. And once the filter is applied, no products are shown and the negative matchers pass. --- spec/features/consumer/shopping/shopping_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/features/consumer/shopping/shopping_spec.rb b/spec/features/consumer/shopping/shopping_spec.rb index cf825ca475..b28dcbefec 100644 --- a/spec/features/consumer/shopping/shopping_spec.rb +++ b/spec/features/consumer/shopping/shopping_spec.rb @@ -194,14 +194,16 @@ feature "As a consumer I want to shop with a distributor", js: true do end it "returns search results for products where the search term matches one of the product's variant names" do + pending "has been broken for a while" + visit shop_path fill_in "search", with: "Badg" # For variant with display_name "Badgers" within('div.pad-top') do - expect(page).to have_content product.name - expect(page).to have_content variant2.display_name expect(page).not_to have_content product2.name expect(page).not_to have_content variant3.display_name + expect(page).to have_content product.name + expect(page).to have_content variant2.display_name end end From 001d40d691814f0ba6b8b94222b364dc7b8d475e Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Fri, 17 Jul 2020 14:35:42 +0100 Subject: [PATCH 253/261] Move require_login_then_redirect_to to the only place where it is called This fixes a class loading issue where orders controllers was getting a undefined method require_login_then_redirect_to --- app/controllers/spree/orders_controller.rb | 2 +- lib/spree/core/controller_helpers/auth.rb | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 102cca2520..898ec93f99 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -194,7 +194,7 @@ module Spree return if session[:access_token] || params[:token] || spree_current_user flash[:error] = I18n.t("spree.orders.edit.login_to_view_order") - require_login_then_redirect_to request.env['PATH_INFO'] + redirect_to main_app.root_path(anchor: "login?after_login=#{request.env['PATH_INFO']}") end def order_to_update diff --git a/lib/spree/core/controller_helpers/auth.rb b/lib/spree/core/controller_helpers/auth.rb index 89980ccfe2..c6c18b9be1 100644 --- a/lib/spree/core/controller_helpers/auth.rb +++ b/lib/spree/core/controller_helpers/auth.rb @@ -63,10 +63,6 @@ module Spree user.generate_spree_api_key! end - - def require_login_then_redirect_to(url) - redirect_to main_app.root_path(anchor: "login?after_login=#{url}") - end end end end From 21227d7482a20f722f4c005bb3fa862e46705634 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Mon, 20 Jul 2020 18:18:00 +0100 Subject: [PATCH 254/261] Make charges update method update the first pending payment Updating the first overall payment could select a failed payment and ignore the pending payment that is about to be processed --- app/models/spree/order_decorator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/spree/order_decorator.rb b/app/models/spree/order_decorator.rb index 71574359a7..377b72a0f6 100644 --- a/app/models/spree/order_decorator.rb +++ b/app/models/spree/order_decorator.rb @@ -432,8 +432,8 @@ Spree::Order.class_eval do # amount here. def charge_shipping_and_payment_fees! update_totals - return unless payments.any? + return unless pending_payments.any? - payments.first.update_attribute :amount, total + pending_payments.first.update_attribute :amount, total end end From bb178c71b2f298c29729bb4ccb02e2df24540af1 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2020 23:35:34 +0000 Subject: [PATCH 255/261] Bump bugsnag from 6.13.1 to 6.14.0 Bumps [bugsnag](https://github.com/bugsnag/bugsnag-ruby) from 6.13.1 to 6.14.0. - [Release notes](https://github.com/bugsnag/bugsnag-ruby/releases) - [Changelog](https://github.com/bugsnag/bugsnag-ruby/blob/master/CHANGELOG.md) - [Commits](https://github.com/bugsnag/bugsnag-ruby/compare/v6.13.1...v6.14.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index b0713aa7f9..17bd93a6a4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -150,7 +150,7 @@ GEM bcrypt (3.1.13) bcrypt-ruby (3.1.5) bcrypt (>= 3.1.3) - bugsnag (6.13.1) + bugsnag (6.14.0) concurrent-ruby (~> 1.0) builder (3.1.4) byebug (11.0.1) From 9be199a6cc4af930a0d5376b85a109cb0f6cbbaf Mon Sep 17 00:00:00 2001 From: Pau Perez Date: Tue, 21 Jul 2020 11:55:53 +0200 Subject: [PATCH 256/261] Remove conflicting and duplicate route This Spree route conflicts with the one we define: ``` get "/login", to: redirect("/#/login") ``` for whatever reason there are 7 users that managed to hit the Spree one instead of ours when confirming their signup email. It's not clear to me though when this `/login?validation=confirmed` is really hit. The confirmation email link passes a token in the query params and this is not the case. The idea is that `GET /login` makes the login modal to show up instead of Devise's default behaviour (through inheritance) of showing a login form page. OFN was never prepared to handle this as this bug proofs. --- app/controllers/spree/users_controller.rb | 2 +- app/controllers/user_passwords_controller.rb | 2 +- config/routes/spree.rb | 1 - lib/spree/authentication_helpers.rb | 4 +++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/controllers/spree/users_controller.rb b/app/controllers/spree/users_controller.rb index f524f8d465..c6ce064b57 100644 --- a/app/controllers/spree/users_controller.rb +++ b/app/controllers/spree/users_controller.rb @@ -59,7 +59,7 @@ module Spree if @user authorize! params[:action].to_sym, @user else - redirect_to spree.login_path + redirect_to main_app.login_path end end diff --git a/app/controllers/user_passwords_controller.rb b/app/controllers/user_passwords_controller.rb index e467e915e2..9200b9b6ef 100644 --- a/app/controllers/user_passwords_controller.rb +++ b/app/controllers/user_passwords_controller.rb @@ -10,7 +10,7 @@ class UserPasswordsController < Spree::UserPasswordsController if resource.errors.empty? set_flash_message(:success, :send_instructions) if is_navigational_format? - respond_with resource, location: spree.login_path + respond_with resource, location: main_app.login_path else respond_to do |format| format.html do diff --git a/config/routes/spree.rb b/config/routes/spree.rb index ca5993aca5..4d3fde45d6 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -15,7 +15,6 @@ Spree::Core::Engine.routes.draw do resources :users, :only => [:edit, :update] devise_scope :spree_user do - get '/login' => 'user_sessions#new', :as => :login post '/login' => 'user_sessions#create', :as => :create_new_session get '/logout' => 'user_sessions#destroy', :as => :logout get '/signup' => 'user_registrations#new', :as => :signup diff --git a/lib/spree/authentication_helpers.rb b/lib/spree/authentication_helpers.rb index 49bd97542a..1f26c65f2c 100644 --- a/lib/spree/authentication_helpers.rb +++ b/lib/spree/authentication_helpers.rb @@ -11,7 +11,9 @@ module Spree current_spree_user end - delegate :login_path, to: :spree, prefix: true + def spree_login_path + main_app.login_path + end delegate :signup_path, to: :spree, prefix: true From 7ba8c5ace1303dacdec5bfc21c498780c5554e2c Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Thu, 16 Jul 2020 16:31:13 +0100 Subject: [PATCH 257/261] Make OC advanced settings work by permitting the extra parameter --- app/services/permitted_attributes/order_cycle.rb | 1 + .../admin/order_cycles_controller_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/app/services/permitted_attributes/order_cycle.rb b/app/services/permitted_attributes/order_cycle.rb index 41fd82bead..b81dccef0f 100644 --- a/app/services/permitted_attributes/order_cycle.rb +++ b/app/services/permitted_attributes/order_cycle.rb @@ -11,6 +11,7 @@ module PermittedAttributes @params.require(:order_cycle).permit( :name, :orders_open_at, :orders_close_at, :coordinator_id, + :preferred_product_selection_from_coordinator_inventory_only, incoming_exchanges: permitted_exchange_attributes, outgoing_exchanges: permitted_exchange_attributes, schedule_ids: [], coordinator_fee_ids: [] diff --git a/spec/controllers/admin/order_cycles_controller_spec.rb b/spec/controllers/admin/order_cycles_controller_spec.rb index 2ba98c9f8e..0175cc1d28 100644 --- a/spec/controllers/admin/order_cycles_controller_spec.rb +++ b/spec/controllers/admin/order_cycles_controller_spec.rb @@ -178,10 +178,22 @@ module Admin it "returns an error message" do spree_put :update, params + json_response = JSON.parse(response.body) expect(json_response['errors']).to be end end + + it "can update preference product_selection_from_coordinator_inventory_only" do + expect(OrderCycleForm).to receive(:new). + with(order_cycle, + { "preferred_product_selection_from_coordinator_inventory_only" => true }, + anything) { form_mock } + allow(form_mock).to receive(:save) { true } + + spree_put :update, params. + merge(order_cycle: { preferred_product_selection_from_coordinator_inventory_only: true }) + end end end From 9b5875a7d12566a93d055e2327fd86d4f104b235 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 21 Jul 2020 19:12:50 +0100 Subject: [PATCH 258/261] Move select out of scope visible_for because it is breaking exchange_product queries and it's just not needed there. The only other use of this product's scope visible_for is the enterprise serializer so we add the select to it. --- app/models/spree/product_decorator.rb | 3 +-- .../api/admin/for_order_cycle/enterprise_serializer.rb | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/models/spree/product_decorator.rb b/app/models/spree/product_decorator.rb index 602329b5c1..554309f687 100644 --- a/app/models/spree/product_decorator.rb +++ b/app/models/spree/product_decorator.rb @@ -63,8 +63,7 @@ Spree::Product.class_eval do scope :visible_for, lambda { |enterprise| joins('LEFT OUTER JOIN spree_variants AS o_spree_variants ON (o_spree_variants.product_id = spree_products.id)'). joins('LEFT OUTER JOIN inventory_items AS o_inventory_items ON (o_spree_variants.id = o_inventory_items.variant_id)'). - where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true). - select('DISTINCT spree_products.*') + where('o_inventory_items.enterprise_id = (?) AND visible = (?)', enterprise, true) } # -- Scopes diff --git a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb index 360f135680..66ed62b7f8 100644 --- a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb +++ b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb @@ -30,7 +30,9 @@ class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer def products_scope products_relation = object.supplied_products if order_cycle.prefers_product_selection_from_coordinator_inventory_only? - products_relation = products_relation.visible_for(order_cycle.coordinator) + products_relation = products_relation. + visible_for(order_cycle.coordinator). + select('DISTINCT spree_products.*') end products_relation.order(:name) end From aadbc9ed5d2133021a2abbabd8382f7483059f7d Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 21 Jul 2020 19:20:08 +0100 Subject: [PATCH 259/261] Remove unnecessary order statement, the relation will only be used for counting products --- .../api/admin/for_order_cycle/enterprise_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb index 66ed62b7f8..7e6fed44f7 100644 --- a/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb +++ b/app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb @@ -34,7 +34,7 @@ class Api::Admin::ForOrderCycle::EnterpriseSerializer < ActiveModel::Serializer visible_for(order_cycle.coordinator). select('DISTINCT spree_products.*') end - products_relation.order(:name) + products_relation end def products From e445fc33a1aae7912a1a22b9691fa85117036aa7 Mon Sep 17 00:00:00 2001 From: Luis Ramos Date: Tue, 21 Jul 2020 20:48:16 +0100 Subject: [PATCH 260/261] Add spec to cover SQL query issue with OCs where the only products from the coordinator inventory are renderer --- .../exchange_products_renderer_spec.rb | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/spec/services/exchange_products_renderer_spec.rb b/spec/services/exchange_products_renderer_spec.rb index 67233906ad..b2eba1c6c3 100644 --- a/spec/services/exchange_products_renderer_spec.rb +++ b/spec/services/exchange_products_renderer_spec.rb @@ -7,8 +7,9 @@ describe ExchangeProductsRenderer do describe "#exchange_products" do describe "for an incoming exchange" do + let(:exchange) { order_cycle.exchanges.incoming.first } + it "loads products" do - exchange = order_cycle.exchanges.incoming.first products = renderer.exchange_products(true, exchange.sender) expect(products.first.supplier.name).to eq exchange.variants.first.product.supplier.name @@ -16,14 +17,34 @@ describe ExchangeProductsRenderer do end describe "for an outgoing exchange" do + let(:exchange) { order_cycle.exchanges.outgoing.first } + it "loads products" do - exchange = order_cycle.exchanges.outgoing.first products = renderer.exchange_products(false, exchange.receiver) suppliers = [exchange.variants[0].product.supplier.name, exchange.variants[1].product.supplier.name] expect(suppliers).to include products.first.supplier.name expect(suppliers).to include products.second.supplier.name end + + context "showing products from coordinator inventory only" do + before { order_cycle.update prefers_product_selection_from_coordinator_inventory_only: true } + + it "loads no products if there are no products from the coordinator inventory" do + products = renderer.exchange_products(false, exchange.receiver) + + expect(products).to be_empty + end + + it "loads products from the coordinator inventory" do + # Add variant already in the exchange to the coordinator's inventory + exchange.variants.first.inventory_items = [create(:inventory_item, enterprise: order_cycle.coordinator)] + + products = renderer.exchange_products(false, exchange.receiver) + + expect(products).to eq [exchange.variants.first.product] + end + end end end From 48efb42b1a9ec93b76777c66c0a6adb66c0f602a Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 21 Jul 2020 21:27:14 +0000 Subject: [PATCH 261/261] Bump ddtrace from 0.37.0 to 0.38.0 Bumps [ddtrace](https://github.com/DataDog/dd-trace-rb) from 0.37.0 to 0.38.0. - [Release notes](https://github.com/DataDog/dd-trace-rb/releases) - [Changelog](https://github.com/DataDog/dd-trace-rb/blob/master/CHANGELOG.md) - [Commits](https://github.com/DataDog/dd-trace-rb/compare/v0.37.0...v0.38.0) Signed-off-by: dependabot-preview[bot] --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 17bd93a6a4..422ecd984c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -206,7 +206,7 @@ GEM activerecord (>= 3.2.0, < 5.0) fog (~> 1.0) rails (>= 3.2.0, < 5.0) - ddtrace (0.37.0) + ddtrace (0.38.0) msgpack debugger-linecache (1.2.0) delayed_job (4.1.8)