Merge branch 'master' into 13221-make-shipped-orders-uneditable

This commit is contained in:
Ashish Gaur
2025-05-08 21:56:46 +05:30
20 changed files with 1293 additions and 1268 deletions

View File

@@ -86,10 +86,6 @@ Metrics/MethodLength:
Enabled: true
Max: 25 # default 10
Naming/MemoizedInstanceVariableName:
Exclude:
- 'lib/open_food_network/address_finder.rb'
Metrics/ParameterLists:
CountKeywordArgs: false

View File

@@ -221,13 +221,6 @@ Metrics/PerceivedComplexity:
- 'app/models/spree/ability.rb'
- 'app/models/spree/order/checkout.rb'
# Offense count: 1
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
Naming/MethodParameterName:
Exclude:
- 'app/services/process_payment_intent.rb'
# Offense count: 26
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
# SupportedStyles: snake_case, normalcase, non_integer

View File

@@ -406,7 +406,7 @@ GEM
activesupport (>= 4.2)
jwt (2.8.1)
base64
knapsack_pro (7.4.0)
knapsack_pro (8.1.2)
rake
language_server-protocol (3.17.0.3)
launchy (3.0.0)

View File

@@ -48,7 +48,8 @@ module CheckoutCallbacks
end
def load_saved_addresses
finder = OpenFoodNetwork::AddressFinder.new(@order.email, @order.customer, spree_current_user)
finder = OpenFoodNetwork::AddressFinder.new(email: @order.email, customer: @order.customer,
user: spree_current_user)
@order.bill_address ||= finder.bill_address
@order.ship_address ||= finder.ship_address

View File

@@ -24,7 +24,7 @@ module PaymentGateways
result = ProcessPaymentIntent.new(params["payment_intent"], @order).call!
unless result.ok?
unless result.success?
flash.now[:error] = "#{I18n.t('payment_could_not_process')}. #{result.error}"
end

View File

@@ -5,7 +5,7 @@ class OrderCycleNotificationJob < ApplicationJob
def perform(order_cycle_id)
order_cycle = OrderCycle.find(order_cycle_id)
order_cycle.suppliers.each do |supplier|
ProducerMailer.order_cycle_report(supplier, order_cycle).deliver_now
ProducerMailer.order_cycle_report(supplier, order_cycle).deliver_later
end
order_cycle.update_columns mails_sent: true
end

View File

@@ -10,7 +10,7 @@ module Api
delegate :ship_address, to: :finder
def finder
@finder ||= OpenFoodNetwork::AddressFinder.new(object, object.email)
@finder ||= OpenFoodNetwork::AddressFinder.new(customer: object, email: object.email)
end
end
end

View File

@@ -11,11 +11,11 @@ module Api
has_one :bill_address, serializer: Api::AddressSerializer
def ship_address
OpenFoodNetwork::AddressFinder.new(object.email, object).ship_address
OpenFoodNetwork::AddressFinder.new(email: object.email, user: object).ship_address
end
def bill_address
OpenFoodNetwork::AddressFinder.new(object.email, object).bill_address
OpenFoodNetwork::AddressFinder.new(email: object.email, user: object).bill_address
end
def confirmed

View File

@@ -13,13 +13,13 @@ class ProcessPaymentIntent
class Result
attr_reader :error
def initialize(ok:, error: "")
@ok = ok
def initialize(success:, error: "")
@success = success
@error = error
end
def ok?
@ok
def success?
@success
end
end
@@ -30,8 +30,8 @@ class ProcessPaymentIntent
end
def call!
return Result.new(ok: false) unless payment.present? && ready_for_capture?
return Result.new(ok: true) if already_processed?
return Result.new(success: false) unless payment.present? && ready_for_capture?
return Result.new(success: true) if already_processed?
process_payment
@@ -39,16 +39,16 @@ class ProcessPaymentIntent
payment.complete_authorization
payment.clear_authorization_url
Result.new(ok: true)
Result.new(success: true)
else
payment.fail_authorization
payment.clear_authorization_url
Result.new(ok: false, error: I18n.t("payment_could_not_complete"))
Result.new(success: false, error: I18n.t("payment_could_not_complete"))
end
rescue Stripe::StripeError => e
payment.fail_authorization
payment.clear_authorization_url
Result.new(ok: false, error: e.message)
Result.new(success: false, error: e.message)
end
private

View File

@@ -10,13 +10,10 @@ module OpenFoodNetwork
class AddressFinder
attr_reader :email, :user, :customer
def initialize(*args)
args.each do |arg|
type = types[arg.class]
next unless type
public_send("#{type}=", arg)
end
def initialize(email: nil, user: nil, customer: nil)
@email = email
@user = user
@customer = customer
end
def bill_address
@@ -27,28 +24,8 @@ module OpenFoodNetwork
customer_preferred_ship_address || user_preferred_ship_address || fallback_ship_address
end
def email=(arg)
@email ||= arg
end
def customer=(arg)
@customer ||= arg
end
def user=(arg)
@user ||= arg
end
private
def types
{
String => "email",
Customer => "customer",
Spree::User => "user"
}
end
def customer_preferred_bill_address
customer&.bill_address
end

View File

@@ -10,7 +10,7 @@
"pretty-quick": "pretty-quick"
},
"dependencies": {
"@floating-ui/dom": "^1.6.13",
"@floating-ui/dom": "^1.7.0",
"@hotwired/stimulus": "^3.2",
"@hotwired/turbo": "^8.0.13",
"@rails/webpacker": "5.4.4",
@@ -37,7 +37,7 @@
"webpack": "~4"
},
"devDependencies": {
"jasmine-core": "~5.7.0",
"jasmine-core": "~5.7.1",
"jest": "^27.4.7",
"karma": "~6.4.4",
"karma-chrome-launcher": "~3.2.0",

View File

@@ -4,20 +4,18 @@ require 'spec_helper'
RSpec.describe OrderCycleNotificationJob do
let(:order_cycle) { create(:order_cycle) }
let(:mail) { double(:mail, deliver_now: true) }
before do
allow(ProducerMailer).to receive(:order_cycle_report).twice.and_return(mail)
end
it "sends a mail to each supplier" do
OrderCycleNotificationJob.perform_now order_cycle.id
expect(ProducerMailer).to have_received(:order_cycle_report).twice
expect {
OrderCycleNotificationJob.perform_now(order_cycle.id)
}.to enqueue_mail(ProducerMailer, :order_cycle_report).twice
end
it "records that mails have been sent for the order cycle" do
expect do
expect {
OrderCycleNotificationJob.perform_now(order_cycle.id)
end.to change{ order_cycle.reload.mails_sent? }.from(false).to(true)
}.to change {
order_cycle.reload.mails_sent?
}.from(false).to(true)
end
end

View File

@@ -12,39 +12,18 @@ module OpenFoodNetwork
let(:customer) { create(:customer) }
context "when passed any combination of instances of String, Customer or Spree::User" do
let(:finder1) { AddressFinder.new(email, customer, user) }
let(:finder2) { AddressFinder.new(customer, user, email) }
let(:finder1) { AddressFinder.new(email:, customer:, user:) }
it "stores arguments based on their class" do
it "stores arguments" do
expect(finder1.email).to eq email
expect(finder2.email).to eq email
expect(finder1.customer).to be customer
expect(finder2.customer).to be customer
expect(finder1.user).to be user
expect(finder2.user).to be user
end
end
context "when passed multiples instances of a class" do
let(:email2) { 'test2@example.com' }
let(:user2) { create(:user) }
let(:customer2) { create(:customer) }
let(:finder1) { AddressFinder.new(user2, email, email2, customer2, user, customer) }
let(:finder2) { AddressFinder.new(email2, customer, user, email, user2, customer2) }
it "only stores the first encountered instance of a given class" do
expect(finder1.email).to eq email
expect(finder2.email).to eq email2
expect(finder1.customer).to be customer2
expect(finder2.customer).to be customer
expect(finder1.user).to be user2
expect(finder2.user).to be user
end
end
end
describe "fallback_bill_address" do
let(:finder) { AddressFinder.new(email) }
let(:finder) { AddressFinder.new(email:) }
let(:address) { double(:address, clone: 'address_clone') }
context "when a last_used_bill_address is found" do
@@ -65,7 +44,7 @@ module OpenFoodNetwork
end
describe "fallback_ship_address" do
let(:finder) { AddressFinder.new(email) }
let(:finder) { AddressFinder.new(email:) }
let(:address) { double(:address, clone: 'address_clone') }
context "when a last_used_ship_address is found" do
@@ -92,7 +71,7 @@ module OpenFoodNetwork
create(:completed_order_with_totals, user: nil, email:, distributor:,
bill_address: nil)
}
let(:finder) { AddressFinder.new(email) }
let(:finder) { AddressFinder.new(email:) }
context "when searching by email is not allowed" do
before do
@@ -142,7 +121,7 @@ module OpenFoodNetwork
describe "last_used_ship_address" do
let(:address) { create(:address) }
let(:distributor) { create(:distributor_enterprise) }
let(:finder) { AddressFinder.new(email) }
let(:finder) { AddressFinder.new(email:) }
context "when searching by email is not allowed" do
before do

View File

@@ -39,7 +39,7 @@ RSpec.describe ProcessPaymentIntent do
it "returns false" do
result = service.call!
expect(result.ok?).to eq(false)
expect(result.success?).to eq(false)
expect(result.error).to eq("")
end
@@ -58,7 +58,7 @@ RSpec.describe ProcessPaymentIntent do
it "returns returns the error message" do
result = service.call!
expect(result.ok?).to eq(false)
expect(result.success?).to eq(false)
expect(result.error).to eq("error message")
end
@@ -150,7 +150,7 @@ RSpec.describe ProcessPaymentIntent do
it "does not return any error message" do
result = service.call!
expect(result.ok?).to eq(false)
expect(result.success?).to eq(false)
expect(result.error).to eq("")
end
@@ -173,7 +173,7 @@ RSpec.describe ProcessPaymentIntent do
it "returns a failed result" do
result = service.call!
expect(result.ok?).to eq(false)
expect(result.success?).to eq(false)
expect(result.error).to eq('The payment could not be completed')
end

View File

@@ -0,0 +1,677 @@
# frozen_string_literal: true
require "system_helper"
RSpec.describe '
As an administrator
I want to create and edit orders
' do
include WebHelper
include AuthenticationHelper
let(:user) { create(:user) }
let(:product) { create(:simple_product) }
let(:distributor) { create(:distributor_enterprise, owner: user, charges_sales_tax: true) }
let(:order_cycle) do
create(:simple_order_cycle, name: 'One', distributors: [distributor],
variants: [product.variants.first])
end
let(:order) do
create(:order_with_totals_and_distribution, user:, distributor:,
order_cycle:, state: 'complete',
payment_state: 'balance_due')
end
let(:customer) { order.customer }
before do
# ensure order has a payment to capture
order.finalize!
create :check_payment, order:, amount: order.total
end
def new_order_with_distribution(distributor, order_cycle)
visit spree.new_admin_order_path
expect(page).to have_selector('#s2id_order_distributor_id')
select2_select distributor.name, from: 'order_distributor_id'
select2_select order_cycle.name, from: 'order_order_cycle_id'
click_button 'Next'
end
context "as an enterprise manager" do
let(:coordinator1) { create(:distributor_enterprise) }
let(:coordinator2) { create(:distributor_enterprise) }
let!(:order_cycle1) { create(:order_cycle, coordinator: coordinator1) }
let!(:order_cycle2) { create(:simple_order_cycle, coordinator: coordinator2) }
let!(:supplier1) { order_cycle1.suppliers.first }
let!(:supplier2) { order_cycle1.suppliers.last }
let!(:distributor1) { order_cycle1.distributors.first }
let!(:distributor2) do
order_cycle1.distributors.reject{ |d| d == distributor1 }.last # ensure d1 != d2
end
let(:product) { order_cycle1.products.first }
before(:each) do
enterprise_user = create(:user)
enterprise_user.enterprise_roles.build(enterprise: supplier1).save
enterprise_user.enterprise_roles.build(enterprise: coordinator1).save
enterprise_user.enterprise_roles.build(enterprise: distributor1).save
login_as enterprise_user
end
describe "viewing the edit page" do
let!(:shipping_method_for_distributor1) do
create(:shipping_method_with, :flat_rate, name: "Normal", amount: 12,
distributors: [distributor1])
end
let!(:order) do
create(
:order_with_taxes,
distributor: distributor1,
order_cycle: order_cycle1,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.1,
included_in_price: true,
tax_rate_name: "Tax 1"
).tap do |order|
# Add a values to the fees
first_calculator = supplier_enterprise_fee1.calculator
first_calculator.preferred_amount = 2.5
first_calculator.save!
last_calculator = supplier_enterprise_fee2.calculator
last_calculator.preferred_amount = 7.5
last_calculator.save!
# Add all variant to the order cycle for a more realistic scenario
order.variants.each do |v|
first_exchange.variants << v
order_cycle1.cached_outgoing_exchanges.first.variants << v
end
variant1 = first_exchange.variants.first
variant2 = last_exchange.variants.first
order.contents.add(variant1)
order.contents.add(variant2)
# make sure all the fees are applied to the order
order.recreate_all_fees!
order.update_order!
end
end
let(:first_exchange) { order_cycle1.cached_incoming_exchanges.first }
let(:last_exchange) { order_cycle1.cached_incoming_exchanges.last }
let(:coordinator_fee) { order_cycle1.coordinator_fees.first }
let(:distributor_fee) { order_cycle1.cached_outgoing_exchanges.first.enterprise_fees.first }
let(:supplier_enterprise_fee1) { first_exchange.enterprise_fees.first }
let(:supplier_enterprise_fee2) { last_exchange.enterprise_fees.first }
before do
distributor1.update_attribute(:abn, '12345678')
visit spree.edit_admin_order_path(order)
end
it "verifying page contents" do
# shows a list of line_items
within('table.index tbody', match: :first) do
order.line_items.each do |item|
expect(page).to have_selector "td", match: :first, text: item.full_name
expect(page).to have_selector "td.item-price", text: item.single_display_amount
expect(page).to have_selector "input#quantity[value='#{item.quantity}']", visible: false
expect(page).to have_selector "td.item-total", text: item.display_amount
end
end
# shows the order non-tax adjustments
within "#order_adjustments" do
# supplier fees only apply to specific product
first_exchange.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{supplier_enterprise_fee1.name} fee \
by supplier #{supplier1.name}: $2.50".squish
)
expect(page).not_to have_content(
"#{variant.name} - #{supplier_enterprise_fee2.name} fee \
by supplier #{supplier2.name}: $7.50".squish
)
end
last_exchange.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{supplier_enterprise_fee2.name} fee \
by supplier #{supplier2.name}: $7.50".squish
)
expect(page).not_to have_content(
"#{variant.name} - #{supplier_enterprise_fee1.name} fee \
by supplier #{supplier1.name}: $2.50".squish
)
end
## Coordinator fee and Distributor fee apply to all product
order.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{coordinator_fee.name} fee \
by coordinator #{coordinator1.name}: $0.00".squish
)
expect(page).to have_content(
"#{variant.name} - #{distributor_fee.name} fee \
by distributor #{distributor1.name}: $0.00".squish
)
end
end
# shows the order total
expect(page).to have_selector "fieldset#order-total", text: order.display_total
# shows the order tax adjustments
within('fieldset', text: 'Line Item Adjustments') do
expect(page).to have_selector "td", match: :first, text: "Tax 1"
expect(page).to have_selector "td.total", text: Spree::Money.new(10)
end
# shows the dropdown menu" do
find("#links-dropdown .ofn-drop-down").click
within "#links-dropdown" do
expect(page).to have_link "Resend Confirmation",
href: spree.resend_admin_order_path(order)
end
end
context "Resending confirmation email" do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it "shows the link" do
expect(page).to have_link "Resend Confirmation",
href: spree.resend_admin_order_path(order)
end
it "resends the confirmation email" do
accept_alert "Are you sure you want to resend the order confirmation email?" do
click_link "Resend Confirmation"
end
expect(page).to have_content "Order email has been resent"
end
end
context "Canceling an order" do
shared_examples "canceling an order" do
it "shows the link" do
expect(page).to have_link "Cancel Order",
href: spree.fire_admin_order_path(order, e: 'cancel')
end
it 'cancels the order' do
within ".ofn-drop-down .menu" do
expect(page).to have_selector("span", text: "Cancel Order")
page.find("span", text: "Cancel Order").click
end
within '.modal-content' do
expect {
find_button("OK").click
}.to change { order.reload.state }.from('complete').to('canceled')
end
end
end
context "from order details page" do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
context "from order's payments" do
before do
visit spree.admin_order_payments_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
context "from order's adjustments" do
before do
visit spree.admin_order_adjustments_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
end
context "Check send/print invoice links" do
shared_examples_for 'can send/print invoices' do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it 'shows the right links' do
expect(page).to have_link "Send Invoice", href: spree.invoice_admin_order_path(order)
expect(page).to have_link "Print Invoice", href: spree.print_admin_order_path(order)
end
it 'can send invoices' do
accept_alert "An invoice for this order will be sent to the customer. " \
"Are you sure you want to continue?" do
click_link "Send Invoice"
end
expect(page).to have_content "Invoice email has been sent"
end
end
context "when abn number is not mandatory to send/print invoices" do
before do
Spree::Config[:enterprise_number_required_on_invoices?] = false
distributor1.update_attribute(:abn, "")
end
it_should_behave_like 'can send/print invoices'
end
context "when abn number is mandatory to send/print invoices" do
before do
Spree::Config[:enterprise_number_required_on_invoices?] = true
end
context "and a abn numer is set on the distributor" do
before do
distributor1.update_attribute(:abn, '12345678')
end
it_should_behave_like 'can send/print invoices'
end
context "and a abn number is not set on the distributor" do
before do
distributor1.update_attribute(:abn, "")
end
it "should not display links but a js alert" do
visit spree.edit_admin_order_path(order)
find("summary", text: "Actions").click
expect(page).to have_link "Send Invoice", href: "#"
expect(page).to have_link "Print Invoice", href: "#"
message = accept_prompt do
click_link "Print Invoice"
end
expect(message)
.to eq "#{distributor1.name} must have a valid ABN before invoices can be used."
find("summary", text: "Actions").click
message = accept_prompt do
click_link "Send Invoice"
end
expect(message)
.to eq "#{distributor1.name} must have a valid ABN before invoices can be used."
end
end
end
end
context "with different shipping methods" do
let!(:different_shipping_method_for_distributor1) do
create(:shipping_method_with, :flat_rate, name: "Different", amount: 15,
distributors: [distributor1])
end
let!(:shipping_method_for_distributor2) do
create(:shipping_method, name: "Other", distributors: [distributor2])
end
it "can edit shipping method" do
visit spree.edit_admin_order_path(order)
expect(page).not_to have_content different_shipping_method_for_distributor1.name
find('.edit-method').click
expect(page).to have_select2('selected_shipping_rate_id',
with_options: [
shipping_method_for_distributor1.name,
different_shipping_method_for_distributor1.name
], without_options: [shipping_method_for_distributor2.name])
select2_select(different_shipping_method_for_distributor1.name,
from: 'selected_shipping_rate_id')
find('.save-method').click
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name}"
)
within "#order-total" do
expect(page).to have_content "$239.98"
end
end
context "when the distributor unsupport a shipping method that's selected " \
"in an existing order " do
before do
distributor1.shipping_methods = [shipping_method_for_distributor1,
different_shipping_method_for_distributor1]
order.shipments.each(&:refresh_rates)
order.shipment.adjustments.first.open
order.select_shipping_method(different_shipping_method_for_distributor1)
order.shipment.adjustments.first.close
distributor1.shipping_methods = [shipping_method_for_distributor1]
end
context "shipment is shipped" do
before do
order.shipments.first.update_attribute(:state, 'shipped')
end
it "should not change the shipping method" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
context "when shipping rate is updated" do
before do
different_shipping_method_for_distributor1.shipping_rates.first.update!(cost: 16)
end
it "should not update the shipping cost" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
end
end
context "shipment is pending" do
before do
order.shipments.first.ensure_correct_adjustment
expect(order.shipments.first.state).to eq('pending')
end
it "should not replace the selected shipment method" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
context "when shipping rate is updated" do
before do
different_shipping_method_for_distributor1.shipping_rates.first.update!(cost: 16)
end
it "should not update the shipping cost" do
# Since the order is completed, the price is not supposed to be updated
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
end
end
end
end
it "can edit and delete tracking number" do
test_tracking_number = "ABCCBA"
expect(page).not_to have_content test_tracking_number
find('.edit-tracking').click
fill_in "tracking", with: test_tracking_number
find('.save-tracking').click
expect(page).to have_content test_tracking_number
find('.delete-tracking.icon-trash').click
# Cancel Deletion
# Check if the alert box shows and after clicking cancel
# the alert box vanishes and tracking num is still present
expect(page).to have_content 'Are you sure?'
find('.cancel').click
expect(page).not_to have_content 'Are you sure?'
expect(page).to have_content test_tracking_number
find('.delete-tracking.icon-trash').click
expect(page).to have_content 'Are you sure?'
find('.confirm').click
expect(page).not_to have_content test_tracking_number
end
it "can edit and delete note" do
test_note = "this is a note"
expect(page).not_to have_content test_note
find('.edit-note.icon-edit').click
fill_in "note", with: test_note
find('.save-note').click
expect(page).to have_content test_note
find('.delete-note.icon-trash').click
# Cancel Deletion
# Check if the alert box shows and after clicking cancel
# the alert box vanishes and note is still present
expect(page).to have_content 'Are you sure?'
find('.cancel').click
expect(page).not_to have_content 'Are you sure?'
expect(page).to have_content test_note
find('.delete-note.icon-trash').click
expect(page).to have_content 'Are you sure?'
find('.confirm').click
expect(page).not_to have_content test_note
end
it "viewing shipping fees" do
shipping_fee = order.shipment_adjustments.first
click_link "Adjustments"
expect(page).to have_selector "tr#spree_adjustment_#{shipping_fee.id}"
expect(page).to have_selector 'td.amount', text: shipping_fee.amount.to_s
expect(page).to have_selector 'td.tax', text: shipping_fee.included_tax_total.to_s
end
context "shipping orders" do
before do
order.finalize! # ensure order has a payment to capture
order.payments << create(:check_payment, order:, amount: order.total)
order.payments.first.capture!
visit spree.edit_admin_order_path(order)
end
it "ships the order and shipment email is sent" do
expect(page).to have_content "ready"
expect(page).not_to have_content "shipped"
expect(page).to have_select2 "add_variant_id"
click_button 'Ship'
expect {
within ".reveal-modal" do
expect(page).to have_checked_field(
'Send a shipment/pick up notification email to the customer.'
)
click_button "Confirm"
end
expect(page).to have_content "shipped"
expect(page).to have_content "Cannot add item to shipped order"
}.to enqueue_mail
.and change { order.reload.shipped? }.to true
end
it "ships the order without sending email" do
expect(page).to have_content "ready"
expect(page).not_to have_content "shipped"
click_button 'Ship'
expect {
within ".reveal-modal" do
uncheck 'Send a shipment/pick up notification email to the customer.'
click_button "Confirm"
end
expect(page).to have_content "shipped"
}.to enqueue_mail.exactly(0).times
.and change { order.reload.shipped? }.to true
end
shared_examples "ship order from dropdown" do |subpage|
context "in the #{subpage}", feature: :invoices do
it "ships the order and sends email" do
click_on subpage
expect(order.reload.shipped?).to be false
find('.ofn-drop-down').click
click_link 'Ship Order'
within ".reveal-modal" do
expect(page).to have_checked_field('Send a shipment/pick up ' \
'notification email to the customer.')
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
expect(page).to have_content "SHIPPED"
click_link('Order Details') unless subpage == 'Order Details'
expect(order.reload.shipped?).to be true
expect(ActionMailer::MailDeliveryJob).to have_been_enqueued
.exactly(:once)
.with("Spree::ShipmentMailer", "shipped_email", "deliver_now",
{ args: [order.shipment.id, { delivery: true }] })
end
it "ships the order without sending email" do
click_on subpage
expect(order.reload.shipped?).to be false
find('.ofn-drop-down').click
click_link 'Ship Order'
within ".reveal-modal" do
uncheck 'Send a shipment/pick up notification email to the customer.'
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
click_link('Order Details') unless subpage == 'Order Details'
expect(page).to have_content "SHIPPED"
expect(order.reload.shipped?).to be true
expect(ActionMailer::MailDeliveryJob).not_to have_been_enqueued
.with(array_including("Spree::ShipmentMailer"))
end
end
end
it_behaves_like "ship order from dropdown", "Order Details"
it_behaves_like "ship order from dropdown", "Customer Details"
it_behaves_like "ship order from dropdown", "Payments"
it_behaves_like "ship order from dropdown", "Adjustments"
it_behaves_like "ship order from dropdown", "Invoices"
it_behaves_like "ship order from dropdown", "Return Authorizations"
end
context "when an included variant has been deleted" do
let!(:deleted_variant) do
order.line_items.first.variant.tap(&:delete)
end
it "still lists the variant in the order page" do
within ".stock-contents" do
expect(page).to have_content deleted_variant.product_and_full_name
end
end
end
context "and the order has been canceled" do
it "does not allow modifying line items" do
order.cancel!
visit spree.edit_admin_order_path(order)
within("tr.stock-item", text: order.products.first.name) do
expect(page).not_to have_selector("a.edit-item")
end
end
end
context "when an incomplete order has some line items with insufficient stock" do
let(:incomplete_order) do
create(:order_with_line_items, user:, distributor:,
order_cycle:)
end
it "displays the out of stock line items and they can be deleted from the order" do
incomplete_order.line_items.first.variant.update!(on_demand: false, on_hand: 0)
visit spree.edit_admin_order_path(incomplete_order)
expect(page).to have_content "Out of Stock"
within ".insufficient-stock-items" do
expect(page).to have_content incomplete_order.products.first.name
accept_alert 'Are you sure?' do
find("a.delete-resource").click
end
expect(page).not_to have_content incomplete_order.products.first.name
end
# updates the order and verifies the warning disappears
click_button "Update And Recalculate Fees"
expect(page).not_to have_content "Out of Stock"
end
end
end
it "creating an order with distributor and order cycle" do
new_order_with_distribution(distributor1, order_cycle1)
expect(page).to have_selector 'h1', text: 'Customer Details'
click_link "Order Details"
expect(page).to have_content 'Add Product'
select2_select product.name, from: 'add_variant_id', search: true
find('button.add_variant').click
page.has_selector? "table.index tbody tr"
expect(page).to have_selector 'td', text: product.name
expect(page).to have_select2 'order_distributor_id', with_options: [distributor1.name]
expect(page).not_to have_select2 'order_distributor_id', with_options: [distributor2.name]
expect(page).to have_select2 'order_order_cycle_id',
with_options: ["#{order_cycle1.name} (open)"]
expect(page).not_to have_select2 'order_order_cycle_id',
with_options: ["#{order_cycle2.name} (open)"]
click_button 'Update'
o = Spree::Order.last
expect(o.distributor).to eq distributor1
expect(o.order_cycle).to eq order_cycle1
end
end
end

View File

@@ -555,6 +555,14 @@ RSpec.describe '
expect(page).to have_selector "tr.distributor-#{distributor_permitted.id}"
expect(page).to have_selector 'tr.distributor', count: 2
# Toggling all products displays the css section of the distributed products
click_link "Expand all"
expect(page).to have_css ".exchange-distributed-products", count: 2
# Colapsing all products hides the css section of the distributed products
click_link "Collapse all"
expect(page).not_to have_css ".exchange-distributed-products"
# Open the products list for managed_supplier's incoming exchange
within "tr.distributor-#{distributor_managed.id}" do
page.find("td.products").click

View File

@@ -555,643 +555,6 @@ RSpec.describe '
end
end
context "as an enterprise manager" do
let(:coordinator1) { create(:distributor_enterprise) }
let(:coordinator2) { create(:distributor_enterprise) }
let!(:order_cycle1) { create(:order_cycle, coordinator: coordinator1) }
let!(:order_cycle2) { create(:simple_order_cycle, coordinator: coordinator2) }
let!(:supplier1) { order_cycle1.suppliers.first }
let!(:supplier2) { order_cycle1.suppliers.last }
let!(:distributor1) { order_cycle1.distributors.first }
let!(:distributor2) do
order_cycle1.distributors.reject{ |d| d == distributor1 }.last # ensure d1 != d2
end
let(:product) { order_cycle1.products.first }
before(:each) do
enterprise_user = create(:user)
enterprise_user.enterprise_roles.build(enterprise: supplier1).save
enterprise_user.enterprise_roles.build(enterprise: coordinator1).save
enterprise_user.enterprise_roles.build(enterprise: distributor1).save
login_as enterprise_user
end
describe "viewing the edit page" do
let!(:shipping_method_for_distributor1) do
create(:shipping_method_with, :flat_rate, name: "Normal", amount: 12,
distributors: [distributor1])
end
let!(:order) do
create(
:order_with_taxes,
distributor: distributor1,
order_cycle: order_cycle1,
ship_address: create(:address),
product_price: 110,
tax_rate_amount: 0.1,
included_in_price: true,
tax_rate_name: "Tax 1"
).tap do |order|
# Add a values to the fees
first_calculator = supplier_enterprise_fee1.calculator
first_calculator.preferred_amount = 2.5
first_calculator.save!
last_calculator = supplier_enterprise_fee2.calculator
last_calculator.preferred_amount = 7.5
last_calculator.save!
# Add all variant to the order cycle for a more realistic scenario
order.variants.each do |v|
first_exchange.variants << v
order_cycle1.cached_outgoing_exchanges.first.variants << v
end
variant1 = first_exchange.variants.first
variant2 = last_exchange.variants.first
order.contents.add(variant1)
order.contents.add(variant2)
# make sure all the fees are applied to the order
order.recreate_all_fees!
order.update_order!
end
end
let(:first_exchange) { order_cycle1.cached_incoming_exchanges.first }
let(:last_exchange) { order_cycle1.cached_incoming_exchanges.last }
let(:coordinator_fee) { order_cycle1.coordinator_fees.first }
let(:distributor_fee) { order_cycle1.cached_outgoing_exchanges.first.enterprise_fees.first }
let(:supplier_enterprise_fee1) { first_exchange.enterprise_fees.first }
let(:supplier_enterprise_fee2) { last_exchange.enterprise_fees.first }
before do
distributor1.update_attribute(:abn, '12345678')
visit spree.edit_admin_order_path(order)
end
it "verifying page contents" do
# shows a list of line_items
within('table.index tbody', match: :first) do
order.line_items.each do |item|
expect(page).to have_selector "td", match: :first, text: item.full_name
expect(page).to have_selector "td.item-price", text: item.single_display_amount
expect(page).to have_selector "input#quantity[value='#{item.quantity}']", visible: false
expect(page).to have_selector "td.item-total", text: item.display_amount
end
end
# shows the order non-tax adjustments
within "#order_adjustments" do
# supplier fees only apply to specific product
first_exchange.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{supplier_enterprise_fee1.name} fee \
by supplier #{supplier1.name}: $2.50".squish
)
expect(page).not_to have_content(
"#{variant.name} - #{supplier_enterprise_fee2.name} fee \
by supplier #{supplier2.name}: $7.50".squish
)
end
last_exchange.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{supplier_enterprise_fee2.name} fee \
by supplier #{supplier2.name}: $7.50".squish
)
expect(page).not_to have_content(
"#{variant.name} - #{supplier_enterprise_fee1.name} fee \
by supplier #{supplier1.name}: $2.50".squish
)
end
## Coordinator fee and Distributor fee apply to all product
order.variants.each do |variant|
expect(page).to have_content(
"#{variant.name} - #{coordinator_fee.name} fee \
by coordinator #{coordinator1.name}: $0.00".squish
)
expect(page).to have_content(
"#{variant.name} - #{distributor_fee.name} fee \
by distributor #{distributor1.name}: $0.00".squish
)
end
end
# shows the order total
expect(page).to have_selector "fieldset#order-total", text: order.display_total
# shows the order tax adjustments
within('fieldset', text: 'Line Item Adjustments') do
expect(page).to have_selector "td", match: :first, text: "Tax 1"
expect(page).to have_selector "td.total", text: Spree::Money.new(10)
end
# shows the dropdown menu" do
find("#links-dropdown .ofn-drop-down").click
within "#links-dropdown" do
expect(page).to have_link "Resend Confirmation",
href: spree.resend_admin_order_path(order)
end
end
context "Resending confirmation email" do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it "shows the link" do
expect(page).to have_link "Resend Confirmation",
href: spree.resend_admin_order_path(order)
end
it "resends the confirmation email" do
accept_alert "Are you sure you want to resend the order confirmation email?" do
click_link "Resend Confirmation"
end
expect(page).to have_content "Order email has been resent"
end
end
context "Canceling an order" do
shared_examples "canceling an order" do
it "shows the link" do
expect(page).to have_link "Cancel Order",
href: spree.fire_admin_order_path(order, e: 'cancel')
end
it 'cancels the order' do
within ".ofn-drop-down .menu" do
expect(page).to have_selector("span", text: "Cancel Order")
page.find("span", text: "Cancel Order").click
end
within '.modal-content' do
expect {
find_button("OK").click
}.to change { order.reload.state }.from('complete').to('canceled')
end
end
end
context "from order details page" do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
context "from order's payments" do
before do
visit spree.admin_order_payments_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
context "from order's adjustments" do
before do
visit spree.admin_order_adjustments_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it_behaves_like "canceling an order"
end
end
context "Check send/print invoice links" do
shared_examples_for 'can send/print invoices' do
before do
visit spree.edit_admin_order_path(order)
find("#links-dropdown .ofn-drop-down").click
end
it 'shows the right links' do
expect(page).to have_link "Send Invoice", href: spree.invoice_admin_order_path(order)
expect(page).to have_link "Print Invoice", href: spree.print_admin_order_path(order)
end
it 'can send invoices' do
accept_alert "An invoice for this order will be sent to the customer. " \
"Are you sure you want to continue?" do
click_link "Send Invoice"
end
expect(page).to have_content "Invoice email has been sent"
end
end
context "when abn number is not mandatory to send/print invoices" do
before do
Spree::Config[:enterprise_number_required_on_invoices?] = false
distributor1.update_attribute(:abn, "")
end
it_should_behave_like 'can send/print invoices'
end
context "when abn number is mandatory to send/print invoices" do
before do
Spree::Config[:enterprise_number_required_on_invoices?] = true
end
context "and a abn numer is set on the distributor" do
before do
distributor1.update_attribute(:abn, '12345678')
end
it_should_behave_like 'can send/print invoices'
end
context "and a abn number is not set on the distributor" do
before do
distributor1.update_attribute(:abn, "")
end
it "should not display links but a js alert" do
visit spree.edit_admin_order_path(order)
find("summary", text: "Actions").click
expect(page).to have_link "Send Invoice", href: "#"
expect(page).to have_link "Print Invoice", href: "#"
message = accept_prompt do
click_link "Print Invoice"
end
expect(message)
.to eq "#{distributor1.name} must have a valid ABN before invoices can be used."
find("summary", text: "Actions").click
message = accept_prompt do
click_link "Send Invoice"
end
expect(message)
.to eq "#{distributor1.name} must have a valid ABN before invoices can be used."
end
end
end
end
context "with different shipping methods" do
let!(:different_shipping_method_for_distributor1) do
create(:shipping_method_with, :flat_rate, name: "Different", amount: 15,
distributors: [distributor1])
end
let!(:shipping_method_for_distributor2) do
create(:shipping_method, name: "Other", distributors: [distributor2])
end
it "can edit shipping method" do
visit spree.edit_admin_order_path(order)
expect(page).not_to have_content different_shipping_method_for_distributor1.name
find('.edit-method').click
expect(page).to have_select2('selected_shipping_rate_id',
with_options: [
shipping_method_for_distributor1.name,
different_shipping_method_for_distributor1.name
], without_options: [shipping_method_for_distributor2.name])
select2_select(different_shipping_method_for_distributor1.name,
from: 'selected_shipping_rate_id')
find('.save-method').click
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name}"
)
within "#order-total" do
expect(page).to have_content "$239.98"
end
end
context "when the distributor unsupport a shipping method that's selected " \
"in an existing order " do
before do
distributor1.shipping_methods = [shipping_method_for_distributor1,
different_shipping_method_for_distributor1]
order.shipments.each(&:refresh_rates)
order.shipment.adjustments.first.open
order.select_shipping_method(different_shipping_method_for_distributor1)
order.shipment.adjustments.first.close
distributor1.shipping_methods = [shipping_method_for_distributor1]
end
context "shipment is shipped" do
before do
order.shipments.first.update_attribute(:state, 'shipped')
end
it "should not change the shipping method" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
context "when shipping rate is updated" do
before do
different_shipping_method_for_distributor1.shipping_rates.first.update!(cost: 16)
end
it "should not update the shipping cost" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
end
end
context "shipment is pending" do
before do
order.shipments.first.ensure_correct_adjustment
expect(order.shipments.first.state).to eq('pending')
end
it "should not replace the selected shipment method" do
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
context "when shipping rate is updated" do
before do
different_shipping_method_for_distributor1.shipping_rates.first.update!(cost: 16)
end
it "should not update the shipping cost" do
# Since the order is completed, the price is not supposed to be updated
visit spree.edit_admin_order_path(order)
expect(page).to have_content(
"Shipping: #{different_shipping_method_for_distributor1.name} $15.00"
)
within "#order-total" do
expect(page).to have_content "$224.98"
end
end
end
end
end
end
it "can edit and delete tracking number" do
test_tracking_number = "ABCCBA"
expect(page).not_to have_content test_tracking_number
find('.edit-tracking').click
fill_in "tracking", with: test_tracking_number
find('.save-tracking').click
expect(page).to have_content test_tracking_number
find('.delete-tracking.icon-trash').click
# Cancel Deletion
# Check if the alert box shows and after clicking cancel
# the alert box vanishes and tracking num is still present
expect(page).to have_content 'Are you sure?'
find('.cancel').click
expect(page).not_to have_content 'Are you sure?'
expect(page).to have_content test_tracking_number
find('.delete-tracking.icon-trash').click
expect(page).to have_content 'Are you sure?'
find('.confirm').click
expect(page).not_to have_content test_tracking_number
end
it "can edit and delete note" do
test_note = "this is a note"
expect(page).not_to have_content test_note
find('.edit-note.icon-edit').click
fill_in "note", with: test_note
find('.save-note').click
expect(page).to have_content test_note
find('.delete-note.icon-trash').click
# Cancel Deletion
# Check if the alert box shows and after clicking cancel
# the alert box vanishes and note is still present
expect(page).to have_content 'Are you sure?'
find('.cancel').click
expect(page).not_to have_content 'Are you sure?'
expect(page).to have_content test_note
find('.delete-note.icon-trash').click
expect(page).to have_content 'Are you sure?'
find('.confirm').click
expect(page).not_to have_content test_note
end
it "viewing shipping fees" do
shipping_fee = order.shipment_adjustments.first
click_link "Adjustments"
expect(page).to have_selector "tr#spree_adjustment_#{shipping_fee.id}"
expect(page).to have_selector 'td.amount', text: shipping_fee.amount.to_s
expect(page).to have_selector 'td.tax', text: shipping_fee.included_tax_total.to_s
end
context "shipping orders" do
before do
order.finalize! # ensure order has a payment to capture
order.payments << create(:check_payment, order:, amount: order.total)
order.payments.first.capture!
visit spree.edit_admin_order_path(order)
end
it "ships the order and shipment email is sent" do
expect(page).to have_content "ready"
expect(page).not_to have_content "shipped"
expect(page).to have_select2 "add_variant_id"
click_button 'Ship'
expect {
within ".reveal-modal" do
expect(page).to have_checked_field(
'Send a shipment/pick up notification email to the customer.'
)
click_button "Confirm"
end
expect(page).to have_content "shipped"
expect(page).to have_content "Cannot add item to shipped order"
}.to enqueue_mail
.and change { order.reload.shipped? }.to true
end
it "ships the order without sending email" do
expect(page).to have_content "ready"
expect(page).not_to have_content "shipped"
click_button 'Ship'
expect {
within ".reveal-modal" do
uncheck 'Send a shipment/pick up notification email to the customer.'
click_button "Confirm"
end
expect(page).to have_content "shipped"
}.to enqueue_mail.exactly(0).times
.and change { order.reload.shipped? }.to true
end
shared_examples "ship order from dropdown" do |subpage|
context "in the #{subpage}", feature: :invoices do
it "ships the order and sends email" do
click_on subpage
expect(order.reload.shipped?).to be false
find('.ofn-drop-down').click
click_link 'Ship Order'
within ".reveal-modal" do
expect(page).to have_checked_field('Send a shipment/pick up ' \
'notification email to the customer.')
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
expect(page).to have_content "SHIPPED"
click_link('Order Details') unless subpage == 'Order Details'
expect(order.reload.shipped?).to be true
expect(ActionMailer::MailDeliveryJob).to have_been_enqueued
.exactly(:once)
.with("Spree::ShipmentMailer", "shipped_email", "deliver_now",
{ args: [order.shipment.id, { delivery: true }] })
end
it "ships the order without sending email" do
click_on subpage
expect(order.reload.shipped?).to be false
find('.ofn-drop-down').click
click_link 'Ship Order'
within ".reveal-modal" do
uncheck 'Send a shipment/pick up notification email to the customer.'
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
click_link('Order Details') unless subpage == 'Order Details'
expect(page).to have_content "SHIPPED"
expect(order.reload.shipped?).to be true
expect(ActionMailer::MailDeliveryJob).not_to have_been_enqueued
.with(array_including("Spree::ShipmentMailer"))
end
end
end
it_behaves_like "ship order from dropdown", "Order Details"
it_behaves_like "ship order from dropdown", "Customer Details"
it_behaves_like "ship order from dropdown", "Payments"
it_behaves_like "ship order from dropdown", "Adjustments"
it_behaves_like "ship order from dropdown", "Invoices"
it_behaves_like "ship order from dropdown", "Return Authorizations"
end
context "when an included variant has been deleted" do
let!(:deleted_variant) do
order.line_items.first.variant.tap(&:delete)
end
it "still lists the variant in the order page" do
within ".stock-contents" do
expect(page).to have_content deleted_variant.product_and_full_name
end
end
end
context "and the order has been canceled" do
it "does not allow modifying line items" do
order.cancel!
visit spree.edit_admin_order_path(order)
within("tr.stock-item", text: order.products.first.name) do
expect(page).not_to have_selector("a.edit-item")
end
end
end
context "when an incomplete order has some line items with insufficient stock" do
let(:incomplete_order) do
create(:order_with_line_items, user:, distributor:,
order_cycle:)
end
it "displays the out of stock line items and they can be deleted from the order" do
incomplete_order.line_items.first.variant.update!(on_demand: false, on_hand: 0)
visit spree.edit_admin_order_path(incomplete_order)
expect(page).to have_content "Out of Stock"
within ".insufficient-stock-items" do
expect(page).to have_content incomplete_order.products.first.name
accept_alert 'Are you sure?' do
find("a.delete-resource").click
end
expect(page).not_to have_content incomplete_order.products.first.name
end
# updates the order and verifies the warning disappears
click_button "Update And Recalculate Fees"
expect(page).not_to have_content "Out of Stock"
end
end
end
it "creating an order with distributor and order cycle" do
new_order_with_distribution(distributor1, order_cycle1)
expect(page).to have_selector 'h1', text: 'Customer Details'
click_link "Order Details"
expect(page).to have_content 'Add Product'
select2_select product.name, from: 'add_variant_id', search: true
find('button.add_variant').click
page.has_selector? "table.index tbody tr"
expect(page).to have_selector 'td', text: product.name
expect(page).to have_select2 'order_distributor_id', with_options: [distributor1.name]
expect(page).not_to have_select2 'order_distributor_id', with_options: [distributor2.name]
expect(page).to have_select2 'order_order_cycle_id',
with_options: ["#{order_cycle1.name} (open)"]
expect(page).not_to have_select2 'order_order_cycle_id',
with_options: ["#{order_cycle2.name} (open)"]
click_button 'Update'
o = Spree::Order.last
expect(o.distributor).to eq distributor1
expect(o.order_cycle).to eq order_cycle1
end
end
describe "searching customers" do
def searching_for_customers
# opens the customer dropdown

View File

@@ -0,0 +1,459 @@
# frozen_string_literal: true
require 'system_helper'
RSpec.describe "As a consumer I want to shop with a distributor" do
include AuthenticationHelper
include FileHelper
include WebHelper
include ShopWorkflow
include UIComponentHelper
describe "Viewing a distributor" do
let(:distributor) { create(:distributor_enterprise, with_payment_and_shipping: true) }
let(:supplier) { create(:supplier_enterprise, name: 'The small mammals company') }
let(:oc1) {
create(:simple_order_cycle, distributors: [distributor],
coordinator: create(:distributor_enterprise),
orders_close_at: 2.days.from_now)
}
let(:oc2) {
create(:simple_order_cycle, distributors: [distributor],
coordinator: create(:distributor_enterprise),
orders_close_at: 3.days.from_now)
}
let(:product) { create(:simple_product, supplier_id: supplier.id, meta_keywords: "Domestic") }
let(:variant) { product.variants.first }
let(:order) { create(:order, distributor:) }
before do
pick_order order
end
context "when no order cycles are available" do
it "tells us orders are closed" do
visit shop_path
expect(page).to have_content "Orders are closed"
end
it "shows the last order cycle" do
oc1 = create(:simple_order_cycle, distributors: [distributor],
orders_open_at: 17.days.ago,
orders_close_at: 10.days.ago)
visit shop_path
expect(page).to have_content "The last cycle closed 10 days ago"
end
it "shows the next order cycle" do
oc1 = create(:simple_order_cycle, distributors: [distributor],
orders_open_at: 10.days.from_now,
orders_close_at: 17.days.from_now)
visit shop_path
expect(page).to have_content "The next cycle opens in 10 days"
end
end
describe "selecting an order cycle" do
let(:exchange1) { oc1.exchanges.to_enterprises(distributor).outgoing.first }
describe "with only one open order cycle" do
before { exchange1.update_attribute :pickup_time, "turtles" }
it "selects an order cycle" do
visit shop_path
expect(page).to have_selector "p", text: 'turtles'
expect(page).not_to have_content "choose when you want your order"
expect(page).to have_content "Next order closing in 2 days"
end
describe "when order cycle closes in more than 3 months" do
before { oc1.update orders_close_at: 5.months.from_now }
it "shows alternative to 'closing in' message" do
visit shop_path
expect(page).to have_content "Orders are currently open"
end
end
end
describe "with multiple order cycles" do
let(:exchange2) { oc2.exchanges.to_enterprises(distributor).outgoing.first }
before do
exchange1.update_attribute :pickup_time, "frogs"
exchange2.update_attribute :pickup_time, "turtles"
distributor.update!(preferred_shopfront_message: "Hello!")
end
it "shows a select with all order cycles, but doesn't show the products by default" do
visit shop_path
expect(page).to have_selector "option", text: 'frogs'
expect(page).to have_selector "option", text: 'turtles'
expect(page).to have_content "Choose when you want your order:"
expect(page).not_to have_selector("input.button.right")
end
it "shows products after selecting an order cycle" do
variant.update_attribute(:display_name, "kitten")
variant.update_attribute(:display_as, "rabbit")
add_variant_to_order_cycle(exchange1, variant)
visit shop_path
expect(page).not_to have_content product.name
expect(Spree::Order.last.order_cycle).to be_nil
select "frogs", from: "order_cycle_id"
expect(page).to have_selector "products"
expect(page).to have_content "Next order closing in 2 days"
expect(Spree::Order.last.order_cycle).to eq(oc1)
expect(page).to have_content product.name
expect(page).to have_content variant.display_name
expect(page).to have_content variant.display_as
open_product_modal product
modal_should_be_open_for product
end
describe "changing order cycle" do
it "shows the correct fees after selecting and changing an order cycle" do
enterprise_fee = create(:enterprise_fee, amount: 1001)
exchange2.enterprise_fees << enterprise_fee
add_variant_to_order_cycle(exchange2, variant)
add_variant_to_order_cycle(exchange1, variant)
# -- Selecting an order cycle
visit shop_path
select "turtles", from: "order_cycle_id"
expect(page).to have_content with_currency(1020.99)
# -- Cart shows correct price
click_add_to_cart variant
expect(page).to have_in_cart with_currency(1020.99)
toggle_cart
# -- Changing order cycle
accept_alert do
select "frogs", from: "order_cycle_id"
end
expect(page).to have_content with_currency(19.99)
# -- Cart should be cleared
# 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)') { click_add_to_cart variant }
expect(page).to have_in_cart with_currency(19.99)
end
describe "declining to clear the cart" do
before do
add_variant_to_order_cycle(exchange2, variant)
add_variant_to_order_cycle(exchange1, variant)
visit shop_path
select "turtles", from: "order_cycle_id"
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"
expect(page).to have_in_cart "1"
expect(page).to have_selector "tr.product-cart"
# The order cycle choice should not have changed
expect(page).to have_select 'order_cycle_id', selected: 'turtles'
end
end
end
end
describe "two order cycles" do
before do
visit shop_path
end
context "one having 20 products" do
before do
20.times do
product = create(:simple_product, supplier_id: supplier.id)
add_variant_to_order_cycle(exchange1, product.variants.first)
end
end
it "displays 20 products, 10 per page" do
select "frogs", from: "order_cycle_id"
expect(page).to have_selector("product.animate-repeat", count: 10)
scroll_to(page.find(".product-listing"), align: :bottom)
expect(page).to have_selector("product.animate-repeat", count: 20)
end
end
context "another having 5 products" do
before do
5.times do
product = create(:simple_product, supplier_id: supplier.id)
add_variant_to_order_cycle(exchange2, product.variants.first)
end
end
it "displays 5 products, on one page" do
select "turtles", from: "order_cycle_id"
expect(page).to have_selector("product.animate-repeat", count: 5)
end
end
end
end
end
describe "after selecting an order cycle with products visible" do
let(:variant1) { create(:variant, product:, price: 20) }
let(:variant2) do
create(:variant, product:, price: 30, display_name: "Badgers",
display_as: 'displayedunderthename')
end
let(:product2) {
create(:simple_product, supplier_id: supplier.id, name: "Meercats",
meta_keywords: "Wild Fresh")
}
let(:variant3) {
create(:variant, product: product2, supplier:, price: 40, display_name: "Ferrets")
}
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
before do
exchange.update_attribute :pickup_time, "frogs"
add_variant_to_order_cycle(exchange, variant)
add_variant_to_order_cycle(exchange, variant1)
add_variant_to_order_cycle(exchange, variant2)
add_variant_to_order_cycle(exchange, variant3)
order.order_cycle = oc1
end
context "adjusting the price" do
before do
enterprise_fee1 = create(:enterprise_fee, amount: 20)
enterprise_fee2 = create(:enterprise_fee, amount: 3)
exchange.enterprise_fees = [enterprise_fee1, enterprise_fee2]
exchange.save
visit shop_path
end
it "displays the correct price" do
# Page should not have product.price (with or without fee)
expect(page).not_to have_price with_currency(10.00)
expect(page).not_to have_price with_currency(33.00)
# Page should have variant prices (with fee)
expect(page).to have_price with_currency(43.00)
expect(page).to have_price with_currency(53.00)
# Product price should be listed as the lesser of these
expect(page).to have_price with_currency(43.00)
end
end
context "filtering search results" do
it "returns results when successful" do
visit shop_path
# When we see the Add button, it means product are loaded on the page
expect(page).to have_content("Add", count: 4)
fill_in "search", with: "74576345634XXXXXX"
expect(page).to have_content "Sorry, no results found"
expect(page).not_to have_content 'Meercats'
click_on "Clear search" # clears search by clicking text
expect(page).to have_content("Add", count: 4)
fill_in "search", with: "Meer" # For product named "Meercats"
expect(page).to have_content 'Meercats'
expect(page).not_to have_content product.name
find("a.clear").click # clears search by clicking the X button
expect(page).to have_content("Add", count: 4)
end
it "returns results by looking at different columns in DB" do
visit shop_path
# When we see the Add button, it means product are loaded on the page
expect(page).to have_content("Add", count: 4)
# by keyword model: meta_keywords
fill_in "search", with: "Wild" # For product named "Meercats"
expect(page).to have_content 'Wild'
find("a.clear").click
# by variant display name model: variant display_name
fill_in "search", with: "Ferrets" # For variants named "Ferrets"
within('div.pad-top') do
expect(page).to have_content 'Ferrets'
expect(page).not_to have_content 'Badgers'
end
# model: variant display_as
fill_in "search", with: "displayedunder" # "Badgers"
within('div.pad-top') do
expect(page).not_to have_content 'Ferrets'
expect(page).to have_content 'Badgers'
end
# model: Enterprise name
fill_in "search", with: "Enterp" # Enterprise 1 sells nothing
within('p.no-results') do
expect(page).to have_content "Sorry, no results found for Enterp"
end
end
end
context "when supplier uses property" do
let(:product3) {
create(:simple_product, supplier_id: supplier.id, inherits_properties: false)
}
before do
add_variant_to_order_cycle(exchange, product3.variants.first)
property = create(:property, presentation: 'certified')
supplier.update!(properties: [property])
end
it "filters product by properties" do
visit shop_path
expect(page).to have_content product2.name
expect(page).to have_content product3.name
expect(page).to have_selector(
".sticky-shop-filters-container .property-selectors span", text: "certified"
)
find(".sticky-shop-filters-container .property-selectors span", text: 'certified').click
expect(page).to have_content "Results for certified"
expect(page).to have_content product2.name
expect(page).not_to have_content product3.name
end
end
it "returns search results for products where the search term matches one of the product's " \
"variant names" do
visit shop_path
fill_in "search", with: "Badg" # For variant with display_name "Badgers"
within('div.pad-top') do
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
context "when the distributor has no available payment/shipping methods" do
before do
distributor.update shipping_methods: [], payment_methods: []
end
# Display only shops are a very useful hack that is described in the user guide
it "still renders a display only shop" do
visit shop_path
expect(page).to have_content product.name
click_add_to_cart variant
expect(page).to have_in_cart product.name
# Try to go to cart
visit main_app.cart_path
expect(page).to have_content "The hub you have selected is temporarily closed for " \
"orders. Please try again later."
end
end
end
context "when shopping requires a customer" do
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
let(:product) { create(:simple_product) }
let(:variant) { create(:variant, product:) }
let(:unregistered_customer) { create(:customer, user: nil, enterprise: distributor) }
before do
add_variant_to_order_cycle(exchange, variant)
set_order_cycle(order, oc1)
distributor.require_login = true
distributor.save!
end
context "when not logged in" do
it "tells us to login" do
visit shop_path
expect(page).to have_content "Only approved customers can access this shop."
expect(page).to have_content "login to proceed"
expect(page).not_to have_content product.name
expect(page).not_to have_selector "ordercycle"
end
end
context "when logged in" do
let(:address) { create(:address, firstname: "Foo", lastname: "Bar") }
let(:user) { create(:user, bill_address: address, ship_address: address) }
before do
login_as user
end
context "as non-customer" do
it "tells us to contact enterprise" do
visit shop_path
expect(page).to have_content "Only approved customers can access this shop."
expect(page).to have_content "please contact #{distributor.name}"
expect(page).not_to have_content product.name
expect(page).not_to have_selector "ordercycle"
end
end
context "as customer" do
let!(:customer) { create(:customer, user:, enterprise: distributor) }
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
context "as a manager" do
let!(:role) { create(:enterprise_role, user:, enterprise: distributor) }
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
context "as the owner" do
before do
distributor.owner = user
distributor.save!
end
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
end
context "when previously unregistered customer registers" do
let!(:returning_user) { create(:user, email: unregistered_customer.email) }
before do
login_as returning_user
end
it "shows the products without customer only message" do
visit shop_path
shows_products_without_customer_warning
end
end
end
end
def shows_products_without_customer_warning
expect(page).not_to have_content "This shop is for customers only."
expect(page).to have_content product.name
end
end

View File

@@ -30,426 +30,6 @@ RSpec.describe "As a consumer I want to shop with a distributor" do
pick_order order
end
it "shows a distributor with images" do
# Given the distributor has a logo
distributor.update!(logo: white_logo_file)
# Then we should see the distributor and its logo
visit shop_path
expect(page).to have_text distributor.name
within ".tab-buttons" do
click_link "About"
end
expect(first("distributor img")['src']).to include "logo-white.png"
end
describe "shop tabs for a distributor" do
default_tabs = ["Shop", "About", "Producers", "Contact"].freeze
all_tabs = (default_tabs + ["Groups", "Home"]).freeze
before do
visit shop_path
end
shared_examples_for "reveal all right tabs" do |tabs, default|
tabs.each do |tab|
it "shows the #{tab} tab" do
within ".tab-buttons" do
expect(page).to have_content tab
end
end
end
(all_tabs - tabs).each do |tab|
it "does not show the #{tab} tab" do
within ".tab-buttons" do
expect(page).not_to have_content tab
end
end
end
it "shows the #{default} tab by default" do
within ".tab-buttons" do
expect(page).to have_selector ".selected", text: default
end
end
end
context "default" do
it_behaves_like "reveal all right tabs", default_tabs, "Shop"
end
context "when the distributor has a shopfront message" do
before do
distributor.update_attribute(:preferred_shopfront_message, "Hello")
visit shop_path
end
it_behaves_like "reveal all right tabs", default_tabs + ["Home"], "Home"
end
context "when the distributor has a custom tab" do
let(:custom_tab) { create(:custom_tab, title: "Custom") }
before do
distributor.update(custom_tab:)
visit shop_path
end
it_behaves_like "reveal all right tabs", default_tabs + ["Custom"], "Shop"
end
end
describe "producers tab" do
before do
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
add_variant_to_order_cycle(exchange, variant)
visit shop_path
within ".tab-buttons" do
click_link "Producers"
end
end
it "shows the producers for a distributor" do
expect(page).to have_content supplier.name
find("a", text: supplier.name).click
within ".reveal-modal" do
expect(page).to have_content supplier.name
end
end
context "when the producer visibility is set to 'hidden'" do
before do
supplier.visible = "hidden"
supplier.save
visit shop_path
within ".tab-buttons" do
click_link "Producers"
end
end
it "shows the producer name" do
expect(page).to have_content supplier.name
end
it "does not show the producer modal" do
expect(page).not_to have_link supplier.name
expect(page).not_to have_selector ".reveal-modal"
end
end
end
describe "selecting an order cycle" do
let(:exchange1) { oc1.exchanges.to_enterprises(distributor).outgoing.first }
describe "with only one open order cycle" do
before { exchange1.update_attribute :pickup_time, "turtles" }
it "selects an order cycle" do
visit shop_path
expect(page).to have_selector "p", text: 'turtles'
expect(page).not_to have_content "choose when you want your order"
expect(page).to have_content "Next order closing in 2 days"
end
describe "when order cycle closes in more than 3 months" do
before { oc1.update orders_close_at: 5.months.from_now }
it "shows alternative to 'closing in' message" do
visit shop_path
expect(page).to have_content "Orders are currently open"
end
end
end
describe "with multiple order cycles" do
let(:exchange2) { oc2.exchanges.to_enterprises(distributor).outgoing.first }
before do
exchange1.update_attribute :pickup_time, "frogs"
exchange2.update_attribute :pickup_time, "turtles"
distributor.update!(preferred_shopfront_message: "Hello!")
end
it "shows a select with all order cycles, but doesn't show the products by default" do
visit shop_path
expect(page).to have_selector "option", text: 'frogs'
expect(page).to have_selector "option", text: 'turtles'
expect(page).to have_content "Choose when you want your order:"
expect(page).not_to have_selector("input.button.right")
end
it "shows products after selecting an order cycle" do
variant.update_attribute(:display_name, "kitten")
variant.update_attribute(:display_as, "rabbit")
add_variant_to_order_cycle(exchange1, variant)
visit shop_path
expect(page).not_to have_content product.name
expect(Spree::Order.last.order_cycle).to be_nil
select "frogs", from: "order_cycle_id"
expect(page).to have_selector "products"
expect(page).to have_content "Next order closing in 2 days"
expect(Spree::Order.last.order_cycle).to eq(oc1)
expect(page).to have_content product.name
expect(page).to have_content variant.display_name
expect(page).to have_content variant.display_as
open_product_modal product
modal_should_be_open_for product
end
describe "changing order cycle" do
it "shows the correct fees after selecting and changing an order cycle" do
enterprise_fee = create(:enterprise_fee, amount: 1001)
exchange2.enterprise_fees << enterprise_fee
add_variant_to_order_cycle(exchange2, variant)
add_variant_to_order_cycle(exchange1, variant)
# -- Selecting an order cycle
visit shop_path
select "turtles", from: "order_cycle_id"
expect(page).to have_content with_currency(1020.99)
# -- Cart shows correct price
click_add_to_cart variant
expect(page).to have_in_cart with_currency(1020.99)
toggle_cart
# -- Changing order cycle
accept_alert do
select "frogs", from: "order_cycle_id"
end
expect(page).to have_content with_currency(19.99)
# -- Cart should be cleared
# 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)') { click_add_to_cart variant }
expect(page).to have_in_cart with_currency(19.99)
end
describe "declining to clear the cart" do
before do
add_variant_to_order_cycle(exchange2, variant)
add_variant_to_order_cycle(exchange1, variant)
visit shop_path
select "turtles", from: "order_cycle_id"
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"
expect(page).to have_in_cart "1"
expect(page).to have_selector "tr.product-cart"
# The order cycle choice should not have changed
expect(page).to have_select 'order_cycle_id', selected: 'turtles'
end
end
end
end
describe "two order cycles" do
before do
visit shop_path
end
context "one having 20 products" do
before do
20.times do
product = create(:simple_product, supplier_id: supplier.id)
add_variant_to_order_cycle(exchange1, product.variants.first)
end
end
it "displays 20 products, 10 per page" do
select "frogs", from: "order_cycle_id"
expect(page).to have_selector("product.animate-repeat", count: 10)
scroll_to(page.find(".product-listing"), align: :bottom)
expect(page).to have_selector("product.animate-repeat", count: 20)
end
end
context "another having 5 products" do
before do
5.times do
product = create(:simple_product, supplier_id: supplier.id)
add_variant_to_order_cycle(exchange2, product.variants.first)
end
end
it "displays 5 products, on one page" do
select "turtles", from: "order_cycle_id"
expect(page).to have_selector("product.animate-repeat", count: 5)
end
end
end
end
end
describe "after selecting an order cycle with products visible" do
let(:variant1) { create(:variant, product:, price: 20) }
let(:variant2) do
create(:variant, product:, price: 30, display_name: "Badgers",
display_as: 'displayedunderthename')
end
let(:product2) {
create(:simple_product, supplier_id: supplier.id, name: "Meercats",
meta_keywords: "Wild Fresh")
}
let(:variant3) {
create(:variant, product: product2, supplier:, price: 40, display_name: "Ferrets")
}
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
before do
exchange.update_attribute :pickup_time, "frogs"
add_variant_to_order_cycle(exchange, variant)
add_variant_to_order_cycle(exchange, variant1)
add_variant_to_order_cycle(exchange, variant2)
add_variant_to_order_cycle(exchange, variant3)
order.order_cycle = oc1
end
context "adjusting the price" do
before do
enterprise_fee1 = create(:enterprise_fee, amount: 20)
enterprise_fee2 = create(:enterprise_fee, amount: 3)
exchange.enterprise_fees = [enterprise_fee1, enterprise_fee2]
exchange.save
visit shop_path
end
it "displays the correct price" do
# Page should not have product.price (with or without fee)
expect(page).not_to have_price with_currency(10.00)
expect(page).not_to have_price with_currency(33.00)
# Page should have variant prices (with fee)
expect(page).to have_price with_currency(43.00)
expect(page).to have_price with_currency(53.00)
# Product price should be listed as the lesser of these
expect(page).to have_price with_currency(43.00)
end
end
context "filtering search results" do
it "returns results when successful" do
visit shop_path
# When we see the Add button, it means product are loaded on the page
expect(page).to have_content("Add", count: 4)
fill_in "search", with: "74576345634XXXXXX"
expect(page).to have_content "Sorry, no results found"
expect(page).not_to have_content 'Meercats'
click_on "Clear search" # clears search by clicking text
expect(page).to have_content("Add", count: 4)
fill_in "search", with: "Meer" # For product named "Meercats"
expect(page).to have_content 'Meercats'
expect(page).not_to have_content product.name
find("a.clear").click # clears search by clicking the X button
expect(page).to have_content("Add", count: 4)
end
it "returns results by looking at different columns in DB" do
visit shop_path
# When we see the Add button, it means product are loaded on the page
expect(page).to have_content("Add", count: 4)
# by keyword model: meta_keywords
fill_in "search", with: "Wild" # For product named "Meercats"
expect(page).to have_content 'Wild'
find("a.clear").click
# by variant display name model: variant display_name
fill_in "search", with: "Ferrets" # For variants named "Ferrets"
within('div.pad-top') do
expect(page).to have_content 'Ferrets'
expect(page).not_to have_content 'Badgers'
end
# model: variant display_as
fill_in "search", with: "displayedunder" # "Badgers"
within('div.pad-top') do
expect(page).not_to have_content 'Ferrets'
expect(page).to have_content 'Badgers'
end
# model: Enterprise name
fill_in "search", with: "Enterp" # Enterprise 1 sells nothing
within('p.no-results') do
expect(page).to have_content "Sorry, no results found for Enterp"
end
end
end
context "when supplier uses property" do
let(:product3) {
create(:simple_product, supplier_id: supplier.id, inherits_properties: false)
}
before do
add_variant_to_order_cycle(exchange, product3.variants.first)
property = create(:property, presentation: 'certified')
supplier.update!(properties: [property])
end
it "filters product by properties" do
visit shop_path
expect(page).to have_content product2.name
expect(page).to have_content product3.name
expect(page).to have_selector(
".sticky-shop-filters-container .property-selectors span", text: "certified"
)
find(".sticky-shop-filters-container .property-selectors span", text: 'certified').click
expect(page).to have_content "Results for certified"
expect(page).to have_content product2.name
expect(page).not_to have_content product3.name
end
end
it "returns search results for products where the search term matches one of the product's " \
"variant names" do
visit shop_path
fill_in "search", with: "Badg" # For variant with display_name "Badgers"
within('div.pad-top') do
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
context "when the distributor has no available payment/shipping methods" do
before do
distributor.update shipping_methods: [], payment_methods: []
end
# Display only shops are a very useful hack that is described in the user guide
it "still renders a display only shop" do
visit shop_path
expect(page).to have_content product.name
click_add_to_cart variant
expect(page).to have_in_cart product.name
# Try to go to cart
visit main_app.cart_path
expect(page).to have_content "The hub you have selected is temporarily closed for " \
"orders. Please try again later."
end
end
end
describe "group buy products" do
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
let(:product) { create(:simple_product, group_buy: true, on_hand: 15) }
@@ -702,121 +282,115 @@ RSpec.describe "As a consumer I want to shop with a distributor" do
end
end
context "when no order cycles are available" do
it "tells us orders are closed" do
visit shop_path
expect(page).to have_content "Orders are closed"
end
it "shows the last order cycle" do
oc1 = create(:simple_order_cycle, distributors: [distributor],
orders_open_at: 17.days.ago,
orders_close_at: 10.days.ago)
visit shop_path
expect(page).to have_content "The last cycle closed 10 days ago"
end
it "shows the next order cycle" do
oc1 = create(:simple_order_cycle, distributors: [distributor],
orders_open_at: 10.days.from_now,
orders_close_at: 17.days.from_now)
visit shop_path
expect(page).to have_content "The next cycle opens in 10 days"
it "shows a distributor with images" do
# Given the distributor has a logo
distributor.update!(logo: white_logo_file)
# Then we should see the distributor and its logo
visit shop_path
expect(page).to have_text distributor.name
within ".tab-buttons" do
click_link "About"
end
expect(first("distributor img")['src']).to include "logo-white.png"
end
context "when shopping requires a customer" do
let(:exchange) { Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id) }
let(:product) { create(:simple_product) }
let(:variant) { create(:variant, product:) }
let(:unregistered_customer) { create(:customer, user: nil, enterprise: distributor) }
describe "shop tabs for a distributor" do
default_tabs = ["Shop", "About", "Producers", "Contact"].freeze
all_tabs = (default_tabs + ["Groups", "Home"]).freeze
before do
visit shop_path
end
shared_examples_for "reveal all right tabs" do |tabs, default|
tabs.each do |tab|
it "shows the #{tab} tab" do
within ".tab-buttons" do
expect(page).to have_content tab
end
end
end
(all_tabs - tabs).each do |tab|
it "does not show the #{tab} tab" do
within ".tab-buttons" do
expect(page).not_to have_content tab
end
end
end
it "shows the #{default} tab by default" do
within ".tab-buttons" do
expect(page).to have_selector ".selected", text: default
end
end
end
context "default" do
it_behaves_like "reveal all right tabs", default_tabs, "Shop"
end
context "when the distributor has a shopfront message" do
before do
distributor.update_attribute(:preferred_shopfront_message, "Hello")
visit shop_path
end
it_behaves_like "reveal all right tabs", default_tabs + ["Home"], "Home"
end
context "when the distributor has a custom tab" do
let(:custom_tab) { create(:custom_tab, title: "Custom") }
before do
distributor.update(custom_tab:)
visit shop_path
end
it_behaves_like "reveal all right tabs", default_tabs + ["Custom"], "Shop"
end
end
describe "producers tab" do
before do
exchange = Exchange.find(oc1.exchanges.to_enterprises(distributor).outgoing.first.id)
add_variant_to_order_cycle(exchange, variant)
set_order_cycle(order, oc1)
distributor.require_login = true
distributor.save!
end
context "when not logged in" do
it "tells us to login" do
visit shop_path
expect(page).to have_content "Only approved customers can access this shop."
expect(page).to have_content "login to proceed"
expect(page).not_to have_content product.name
expect(page).not_to have_selector "ordercycle"
visit shop_path
within ".tab-buttons" do
click_link "Producers"
end
end
context "when logged in" do
let(:address) { create(:address, firstname: "Foo", lastname: "Bar") }
let(:user) { create(:user, bill_address: address, ship_address: address) }
it "shows the producers for a distributor" do
expect(page).to have_content supplier.name
find("a", text: supplier.name).click
within ".reveal-modal" do
expect(page).to have_content supplier.name
end
end
context "when the producer visibility is set to 'hidden'" do
before do
login_as user
end
context "as non-customer" do
it "tells us to contact enterprise" do
visit shop_path
expect(page).to have_content "Only approved customers can access this shop."
expect(page).to have_content "please contact #{distributor.name}"
expect(page).not_to have_content product.name
expect(page).not_to have_selector "ordercycle"
end
end
context "as customer" do
let!(:customer) { create(:customer, user:, enterprise: distributor) }
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
context "as a manager" do
let!(:role) { create(:enterprise_role, user:, enterprise: distributor) }
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
context "as the owner" do
before do
distributor.owner = user
distributor.save!
end
it "shows just products" do
visit shop_path
shows_products_without_customer_warning
end
end
end
context "when previously unregistered customer registers" do
let!(:returning_user) { create(:user, email: unregistered_customer.email) }
before do
login_as returning_user
end
it "shows the products without customer only message" do
supplier.visible = "hidden"
supplier.save
visit shop_path
shows_products_without_customer_warning
within ".tab-buttons" do
click_link "Producers"
end
end
it "shows the producer name" do
expect(page).to have_content supplier.name
end
it "does not show the producer modal" do
expect(page).not_to have_link supplier.name
expect(page).not_to have_selector ".reveal-modal"
end
end
end
end
def shows_products_without_customer_warning
expect(page).not_to have_content "This shop is for customers only."
expect(page).to have_content product.name
end
def expect_out_of_stock_behavior
# Shows an "out of stock" modal, with helpful user feedback
within(".out-of-stock-modal") do

View File

@@ -1127,22 +1127,22 @@
resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7"
integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==
"@floating-ui/core@^1.6.0":
version "1.6.4"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.4.tgz#0140cf5091c8dee602bff9da5ab330840ff91df6"
integrity sha512-a4IowK4QkXl4SCWTGUR0INAfEOX3wtsYw3rKK5InQEHMGObkR8Xk44qYQD9P4r6HHw0iIfK6GUKECmY8sTkqRA==
"@floating-ui/core@^1.7.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.7.0.tgz#1aff27a993ea1b254a586318c29c3b16ea0f4d0a"
integrity sha512-FRdBLykrPPA6P76GGGqlex/e7fbe0F1ykgxHYNXQsH/iTEtjMj/f9bpY5oQqbjt5VgZvgz/uKXbGuROijh3VLA==
dependencies:
"@floating-ui/utils" "^0.2.4"
"@floating-ui/dom@^1.6.13":
version "1.6.13"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.13.tgz#a8a938532aea27a95121ec16e667a7cbe8c59e34"
integrity sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==
dependencies:
"@floating-ui/core" "^1.6.0"
"@floating-ui/utils" "^0.2.9"
"@floating-ui/utils@^0.2.4", "@floating-ui/utils@^0.2.9":
"@floating-ui/dom@^1.7.0":
version "1.7.0"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.7.0.tgz#f9f83ee4fee78ac23ad9e65b128fc11a27857532"
integrity sha512-lGTor4VlXcesUMh1cupTUTDoCxMb0V6bm3CnxHzQcw8Eaf1jQbgQX4i02fYgT0vJ82tb5MZ4CZk1LRGkktJCzg==
dependencies:
"@floating-ui/core" "^1.7.0"
"@floating-ui/utils" "^0.2.9"
"@floating-ui/utils@^0.2.9":
version "0.2.9"
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.9.tgz#50dea3616bc8191fb8e112283b49eaff03e78429"
integrity sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==
@@ -5192,10 +5192,10 @@ istanbul-reports@^3.1.3:
html-escaper "^2.0.0"
istanbul-lib-report "^3.0.0"
jasmine-core@~5.7.0:
version "5.7.0"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-5.7.0.tgz#23476f408056a33674469005d87d57d873b4c525"
integrity sha512-EnUzZBHxS1Ofq+FPWs16rs2YC9o6Hb3buKJQDlkhJBDx+Bm5wNF+J1gUS06dWuW2ozaQ3oNIA1SESX9M5LopOQ==
jasmine-core@~5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-5.7.1.tgz#c347ede2dbf1b6b3b3c3362a5b6651414ada4745"
integrity sha512-QnurrtpKsPoixxG2R3d1xP0St/2kcX5oTZyDyQJMY+Vzi/HUlu1kGm+2V8Tz+9lV991leB1l0xcsyz40s9xOOw==
jest-changed-files@^27.5.1:
version "27.5.1"