Merge pull request #5912 from luisramos0/tcs

Terms and Conditions - upload PDF in the Enterprise Business Details and read them on Checkout
This commit is contained in:
Luis Ramos
2020-09-17 12:01:45 +01:00
committed by GitHub
36 changed files with 765 additions and 521 deletions

View File

@@ -69,25 +69,24 @@ angular.module("admin.enterprises")
$scope.newUser = $scope.invite_errors = $scope.invite_success = null
$scope.removeLogo = ->
return unless confirm(t("admin.enterprises.remove_logo.immediate_removal_warning"))
Enterprises.removeLogo($scope.Enterprise).then (data) ->
$scope.Enterprise = angular.copy(data)
$scope.$emit("enterprise:updated", $scope.Enterprise)
StatusMessage.display("success", t("admin.enterprises.remove_logo.removed_successfully"))
, (response) ->
if response.data.error?
StatusMessage.display("failure", response.data.error)
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")
$scope.removePromoImage = ->
return unless confirm(t("admin.enterprises.remove_promo_image.immediate_removal_warning"))
$scope.performEnterpriseAction("removePromoImage", "immediate_promo_image_removal_warning", "removed_promo_image_successfully")
Enterprises.removePromoImage($scope.Enterprise).then (data) ->
$scope.removeTermsAndConditions = ->
$scope.performEnterpriseAction("removeTermsAndConditions", "immediate_terms_and_conditions_removal_warning", "removed_terms_and_conditions_successfully")
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
return unless confirm($scope.translation(warning_message_key))
Enterprises[enterpriseActionName]($scope.Enterprise).then (data) ->
$scope.Enterprise = angular.copy(data)
$scope.$emit("enterprise:updated", $scope.Enterprise)
StatusMessage.display("success", t("admin.enterprises.remove_promo_image.removed_successfully"))
StatusMessage.display("success", $scope.translation(success_message_key))
, (response) ->
if response.data.error?
StatusMessage.display("failure", response.data.error)
$scope.translation = (key) ->
t('js.admin.enterprises.form.images.' + key)

View File

@@ -14,4 +14,7 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
'removePromoImage':
url: '/api/enterprises/:id/promo_image.json'
method: 'DELETE'
'removeTermsAndConditions':
url: '/api/enterprises/:id/terms_and_conditions.json'
method: 'DELETE'
})

View File

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

View File

@@ -1,7 +1,9 @@
@import "variables";
@import "../variables";
span.unavailable, span.available {
span.unavailable,
span.available {
font-weight: bold;
i {
font-size: 150%;
}
@@ -13,4 +15,4 @@ span.available {
span.unavailable {
color: $warning-red;
}
}

View File

@@ -132,3 +132,25 @@ dl {
padding: 40px 0px;
color: lighten($color-body-text, 15);
}
.text-normal {
font-size: 1rem;
font-weight: 300;
}
.text-big {
font-size: 1.2rem;
font-weight: 300;
}
.text-red {
color: $warning-red;
}
input.text-big {
font-size: 1.1rem;
}
.pad-top {
padding-top: 1em;
}

View File

@@ -1,20 +0,0 @@
@import "variables";
.text-normal {
font-size: 1.0rem;
font-weight: 300;
}
.text-big {
font-size: 1.2rem;
font-weight: 300;
}
.text-red {
color: $warning-red;
}
input.text-big {
font-size: 1.1rem;
}

View File

@@ -0,0 +1,18 @@
# frozen_string_literal: true
module Api
class TermsAndConditionsController < Api::EnterpriseAttachmentController
private
def attachment_name
:terms_and_conditions
end
def enterprise_authorize_action
case action_name.to_sym
when :destroy
:remove_terms_and_conditions
end
end
end
end

View File

@@ -75,10 +75,16 @@ class Enterprise < ActiveRecord::Base
},
url: '/images/enterprises/promo_images/:id/:style/:basename.:extension',
path: 'public/images/enterprises/promo_images/:id/:style/:basename.:extension'
validates_attachment_content_type :logo, content_type: %r{\Aimage/.*\Z}
validates_attachment_content_type :promo_image, content_type: %r{\Aimage/.*\Z}
has_attached_file :terms_and_conditions,
url: '/files/enterprises/terms_and_conditions/:id/:basename.:extension',
path: 'public/files/enterprises/terms_and_conditions/:id/:basename.:extension'
validates_attachment_content_type :terms_and_conditions,
content_type: "application/pdf",
message: I18n.t(:enterprise_terms_and_conditions_type_error)
include Spree::Core::S3Support
supports_s3 :logo
supports_s3 :promo_image

View File

@@ -97,7 +97,9 @@ class AbilityDecorator
end
can [:admin, :index, :create], Enterprise
can [:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], Enterprise do |enterprise|
can [:read, :edit, :update,
:remove_logo, :remove_promo_image, :remove_terms_and_conditions,
:bulk_update, :resend_confirmation], Enterprise do |enterprise|
OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise
end
can [:welcome, :register], Enterprise do |enterprise|

View File

@@ -6,7 +6,7 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
:preferred_product_selection_from_inventory_only,
:preferred_show_customer_names_to_suppliers, :owner, :contact, :users, :tag_groups,
:default_tag_group, :require_login, :allow_guest_orders, :allow_order_changes,
:logo, :promo_image
:logo, :promo_image, :terms_and_conditions, :terms_and_conditions_file_name
has_one :owner, serializer: Api::Admin::UserSerializer
has_many :users, serializer: Api::Admin::UserSerializer
@@ -20,6 +20,12 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
attachment_urls(object.promo_image, [:thumb, :medium, :large])
end
def terms_and_conditions
return unless @object.terms_and_conditions.file?
@object.terms_and_conditions.url
end
def tag_groups
object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.

View File

@@ -25,7 +25,7 @@ module PermittedAttributes
[
:id, :name, :visible, :permalink, :owner_id, :contact_name, :email_address, :phone,
:is_primary_producer, :sells, :website, :facebook, :instagram, :linkedin, :twitter,
:description, :long_description, :logo, :promo_image,
:description, :long_description, :logo, :promo_image, :terms_and_conditions,
:allow_guest_orders, :allow_order_changes, :require_login, :enable_subscriptions,
:abn, :acn, :charges_sales_tax, :display_invoice_logo, :invoice_text,
:preferred_product_selection_from_inventory_only, :preferred_shopfront_message,

View File

@@ -31,3 +31,16 @@
= f.label :invoice_text, t('.invoice_text')
.omega.eight.columns
= f.text_area :invoice_text, style: "width: 100%; height: 100px;"
.row
.alpha.three.columns
= f.label :terms_and_conditions, t('.terms_and_conditions')
.omega.eight.columns
%a{ href: '{{ Enterprise.terms_and_conditions }}', ng: { if: 'Enterprise.terms_and_conditions' } }
= '{{ Enterprise.terms_and_conditions_file_name }}'
.pad-top
= f.file_field :terms_and_conditions
.pad-top
%a.button.red{ href: '', ng: {click: 'removeTermsAndConditions()', if: 'Enterprise.terms_and_conditions'} }
= t('.remove_terms_and_conditions')

View File

@@ -7,7 +7,7 @@
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.logo.medium }}', if: 'Enterprise.logo' } }
= f.file_field :logo
%a.button.red{ href: '', ng: {click: 'removeLogo()', if: 'Enterprise.logo'} }
= t('admin.enterprises.remove_logo.remove')
= t('.remove_logo')
.row.page-admin-enterprises-form__promo-image-field-group.image-field-group
.alpha.three.columns
@@ -23,4 +23,4 @@
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.promo_image.large }}', if: 'Enterprise.promo_image' } }
= f.file_field :promo_image
%a.button.red{ href: '', ng: {click: 'removePromoImage()', if: 'Enterprise.promo_image'} }
= t('admin.enterprises.remove_promo_image.remove')
= t('.remove_promo_image')

View File

@@ -14,6 +14,7 @@
= render "checkout/shipping", f: f
= render "checkout/payment", f: f
= render "checkout/already_ordered", f: f if show_bought_items?
= render "checkout/terms_and_conditions", f: f
%p
%button.button.primary{type: :submit}
= t :checkout_send

View File

@@ -0,0 +1,2 @@
%p.small
= t('.message_html', terms_and_conditions_link: link_to( t( '.link_text' ), current_order.distributor.terms_and_conditions.url, target: '_blank')) if current_order.distributor.terms_and_conditions.file?

View File

@@ -694,6 +694,8 @@ en:
acn_placeholder: eg. 123 456 789
display_invoice_logo: Display logo in invoices
invoice_text: Add customized text at the end of invoices
terms_and_conditions: "Terms and Conditions"
remove_terms_and_conditions: "Remove File"
contact:
name: Name
name_placeholder: eg. Gustav Plum
@@ -716,6 +718,8 @@ en:
promo_image_note1: 'PLEASE NOTE:'
promo_image_note2: Any promo image uploaded here will be cropped to 1200 x 260.
promo_image_note3: The promo image is displayed at the top of an enterprise's profile page and pop-ups.
remove_logo: "Remove Image"
remove_promo_image: "Remove Image"
inventory_settings:
text1: You may opt to manage stock levels and prices in via your
inventory: inventory
@@ -900,14 +904,6 @@ en:
new:
title: New Enterprise
back_link: Back to enterprises list
remove_logo:
remove: "Remove Image"
removed_successfully: "Logo removed successfully"
immediate_removal_warning: "The logo will be removed immediately after you confirm."
remove_promo_image:
remove: "Remove Image"
removed_successfully: "Promo image removed successfully"
immediate_removal_warning: "The promo image will be removed immediately after you confirm."
welcome:
welcome_title: Welcome to the Open Food Network!
welcome_text: You have successfully created a
@@ -1215,6 +1211,8 @@ en:
destroy_attachment_does_not_exist: "Logo does not exist"
enterprise_promo_image:
destroy_attachment_does_not_exist: "Promo image does not exist"
enterprise_terms_and_conditions:
destroy_attachment_does_not_exist: "Terms and Conditions file does not exist"
orders:
failed_to_update: "Failed to update order"
@@ -1227,6 +1225,9 @@ en:
already_ordered:
cart: "cart"
message_html: "You have an order for this order cycle already. Check the %{cart} to see the items you ordered before. You can also cancel items as long as the order cycle is open."
terms_and_conditions:
message_html: "By placing this order you agree to the %{terms_and_conditions_link}."
link_text: "Terms of Service"
failed: "The checkout failed. Please let us know so that we can process your order."
shops:
hubs:
@@ -2437,6 +2438,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using
enterprise_name_error: "has already been taken. If this is your enterprise and you would like to claim ownership, or if you would like to trade with this enterprise please contact the current manager of this profile at %{email}."
enterprise_owner_error: "^%{email} is not permitted to own any more enterprises (limit is %{enterprise_limit})."
enterprise_role_uniqueness_error: "^That role is already present."
enterprise_terms_and_conditions_type_error: "Only PDFs are allowed"
inventory_item_visibility_error: must be true or false
product_importer_file_error: "error: no file uploaded"
product_importer_spreadsheet_error: "could not process file: invalid filetype"
@@ -2702,6 +2704,15 @@ See the %{link} to find out more about %{sitename}'s features and to start using
error_saving: "Error saving subscription"
new:
please_select_a_shop: "Please select a shop"
enterprises:
form:
images:
removed_logo_successfully: "Logo removed successfully"
immediate_logo_removal_warning: "The logo will be removed immediately after you confirm."
removed_promo_image_successfully: "Promo image removed successfully"
immediate_promo_image_removal_warning: "The promo image will be removed immediately after you confirm."
immediate_terms_and_conditions_removal_warning: "The Terms and Conditions file will be removed immediately after you confirm."
removed_terms_and_conditions_successfully: "Terms and Conditions file removed successfully"
insufficient_stock: "Insufficient stock available, only %{on_hand} remaining"
out_of_stock:
reduced_stock_available: Reduced stock available

View File

@@ -33,6 +33,7 @@ Openfoodnetwork::Application.routes.draw do
resource :logo, only: [:destroy]
resource :promo_image, only: [:destroy]
resource :terms_and_conditions, only: [:destroy]
end
resources :shops, only: [:show] do

View File

@@ -0,0 +1,5 @@
class AddTermsAndConditionsToEnterprises < ActiveRecord::Migration
def change
add_attachment :enterprises, :terms_and_conditions
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20200721135726) do
ActiveRecord::Schema.define(version: 20200817150002) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -190,8 +190,8 @@ ActiveRecord::Schema.define(version: 20200721135726) do
t.integer "address_id"
t.text "pickup_times"
t.string "next_collection_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
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"
@@ -201,22 +201,26 @@ ActiveRecord::Schema.define(version: 20200721135726) do
t.string "promo_image_content_type"
t.integer "promo_image_file_size"
t.datetime "promo_image_updated_at"
t.boolean "visible", default: true
t.boolean "visible", default: true
t.string "facebook"
t.string "instagram"
t.string "linkedin"
t.integer "owner_id", null: false
t.string "sells", default: "none", null: false
t.boolean "producer_profile_only", default: false
t.string "permalink", null: false
t.boolean "charges_sales_tax", default: false, null: false
t.integer "owner_id", null: false
t.string "sells", default: "none", null: false
t.boolean "producer_profile_only", default: false
t.string "permalink", null: false
t.boolean "charges_sales_tax", default: false, null: false
t.string "email_address"
t.boolean "require_login", default: false, null: false
t.boolean "allow_guest_orders", default: true, null: false
t.boolean "require_login", default: false, null: false
t.boolean "allow_guest_orders", default: true, null: false
t.text "invoice_text"
t.boolean "display_invoice_logo", default: false
t.boolean "allow_order_changes", default: false, null: false
t.boolean "enable_subscriptions", default: false, null: false
t.boolean "display_invoice_logo", default: false
t.boolean "allow_order_changes", default: false, null: false
t.boolean "enable_subscriptions", default: false, null: false
t.string "terms_and_conditions_file_name"
t.string "terms_and_conditions_content_type"
t.integer "terms_and_conditions_file_size"
t.datetime "terms_and_conditions_updated_at"
end
add_index "enterprises", ["address_id"], name: "index_enterprises_on_address_id", using: :btree

View File

@@ -77,6 +77,12 @@ describe Admin::StripeAccountsController, type: :controller do
describe "#status" do
let(:params) { { format: :json, enterprise_id: enterprise.id } }
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
end
before do
allow(Stripe).to receive(:api_key) { "sk_test_12345" }
Spree::Config.set(stripe_connect_enabled: false)

View File

@@ -4,8 +4,10 @@ describe Admin::StripeConnectSettingsController, type: :controller do
let(:user) { create(:user) }
let(:admin) { create(:admin_user) }
before do
Spree::Config.set(stripe_connect_enabled: true)
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config[:stripe_connect_enabled] = original_stripe_connect_enabled
end
describe "edit" do
@@ -19,7 +21,10 @@ describe Admin::StripeConnectSettingsController, type: :controller do
end
context "as super admin" do
before { allow(controller).to receive(:spree_current_user) { admin } }
before do
Spree::Config.set(stripe_connect_enabled: true)
allow(controller).to receive(:spree_current_user) { admin }
end
context "when a Stripe API key is not set" do
before do
@@ -81,7 +86,10 @@ describe Admin::StripeConnectSettingsController, type: :controller do
end
context "as super admin" do
before { allow(controller).to receive(:spree_current_user) { admin } }
before do
allow(controller).to receive(:spree_current_user) { admin }
Spree::Config.set(stripe_connect_enabled: true)
end
it "sets global config to the specified values" do
expect(Spree::Config.stripe_connect_enabled).to be true

View File

@@ -0,0 +1,50 @@
require "spec_helper"
module Api
describe TermsAndConditionsController, type: :controller do
include AuthenticationHelper
let(:enterprise_owner) { create(:user) }
let(:enterprise) { create(:enterprise, owner: enterprise_owner ) }
let(:enterprise_manager) { create(:user, enterprises: [enterprise]) }
describe "removing terms and conditions file" do
fake_terms_file_path = File.open(Rails.root.join("app", "assets", "images", "logo-black.png"))
let(:terms_and_conditions_file) { Rack::Test::UploadedFile.new(fake_terms_file_path, "application/pdf") }
let(:enterprise) { create(:enterprise, owner: enterprise_owner) }
before do
allow(controller).to receive(:spree_current_user) { current_user }
enterprise.update terms_and_conditions: terms_and_conditions_file
end
context "as manager" do
let(:current_user) { enterprise_manager }
it "removes terms and conditions file" do
spree_delete :destroy, enterprise_id: enterprise
expect(response).to be_success
expect(json_response["id"]).to eq enterprise.id
enterprise.reload
expect(enterprise.terms_and_conditions?).to be false
end
context "when terms and conditions file does not exist" do
let(:enterprise) { create(:enterprise, owner: enterprise_owner) }
before do
enterprise.update terms_and_conditions: nil
end
it "responds with error" do
spree_delete :destroy, enterprise_id: enterprise
expect(response.status).to eq(409)
expect(json_response["error"]).to eq I18n.t("api.enterprise_terms_and_conditions.destroy_attachment_does_not_exist")
end
end
end
end
end
end

View File

@@ -1,3 +1,5 @@
# frozen_string_literal: true
require "spec_helper"
feature "Managing enterprise images" do
@@ -15,7 +17,7 @@ feature "Managing enterprise images" do
visit edit_admin_enterprise_path(distributor)
end
describe "images for an enterprise", js: true do
describe "images for an enterprise" do
def go_to_images
within(".side_menu") do
click_link "Images"

View File

@@ -0,0 +1,64 @@
# frozen_string_literal: true
require "spec_helper"
feature "Uploading Terms and Conditions PDF" do
include AuthenticationHelper
context "as an Enterprise user", js: true do
let(:enterprise_user) { create(:user, enterprise_limit: 1) }
let(:distributor) { create(:distributor_enterprise, name: "First Distributor") }
before do
enterprise_user.enterprise_roles.build(enterprise: distributor).save!
login_as enterprise_user
visit edit_admin_enterprise_path(distributor)
end
describe "images for an enterprise" do
def go_to_business_details
within(".side_menu") do
click_link "Business Details"
end
end
let(:white_pdf_file_name) { Rails.root.join("app/assets/images/logo-white.pdf") }
let(:black_pdf_file_name) { Rails.root.join("app/assets/images/logo-black.pdf") }
around do |example|
# Create fake PDFs from PNG images
FileUtils.cp(Rails.root.join("app/assets/images/logo-white.png"), white_pdf_file_name)
FileUtils.cp(Rails.root.join("app/assets/images/logo-black.png"), black_pdf_file_name)
example.run
# Delete fake PDFs
FileUtils.rm_f(white_pdf_file_name)
FileUtils.rm_f(black_pdf_file_name)
end
scenario "uploading terms and conditions" do
go_to_business_details
# Add PDF
attach_file "enterprise[terms_and_conditions]", white_pdf_file_name
click_button "Update"
expect(page).
to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!")
go_to_business_details
expect(page).to have_selector("a[href*='logo-white.pdf']")
# Replace PDF
attach_file "enterprise[terms_and_conditions]", black_pdf_file_name
click_button "Update"
expect(page).
to have_content("Enterprise \"#{distributor.name}\" has been successfully updated!")
go_to_business_details
expect(page).to have_selector("a[href*='logo-black.pdf']")
end
end
end
end

View File

@@ -37,6 +37,12 @@ feature '
let!(:disconnected_stripe_account) { create(:stripe_account, enterprise: revoked_account_enterprise, stripe_user_id: "acc_revoked123") }
let!(:stripe_account_mock) { { id: "acc_connected123", business_name: "My Org", charges_enabled: true } }
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
end
before do
Spree::Config.set(stripe_connect_enabled: true)
allow(Stripe).to receive(:api_key) { "sk_test_12345" }

View File

@@ -8,6 +8,12 @@ feature "Credit Cards", js: true do
let!(:default_card) { create(:credit_card, user_id: user.id, gateway_customer_profile_id: 'cus_AZNMJ', is_default: true) }
let!(:non_default_card) { create(:credit_card, user_id: user.id, gateway_customer_profile_id: 'cus_FDTG') }
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
end
before do
login_as user

View File

@@ -4,7 +4,7 @@ feature "As a consumer I want to check out my cart", js: true do
include AuthenticationHelper
include WebHelper
include ShopWorkflow
include CheckoutWorkflow
include CheckoutHelper
include UIComponentHelper
describe "using the checkout" do

View File

@@ -1,8 +1,8 @@
require "spec_helper"
feature "Checking out with Paypal", js: true do
feature "Check out with Paypal", js: true do
include ShopWorkflow
include CheckoutWorkflow
include CheckoutHelper
let(:distributor) { create(:distributor_enterprise) }
let(:supplier) { create(:supplier_enterprise) }
@@ -44,7 +44,8 @@ feature "Checking out with Paypal", js: true do
describe "as a guest" do
it "fails with an error message" do
visit checkout_path
complete_the_form
checkout_as_guest
fill_out_form(free_shipping.name, paypal.name, save_default_addresses: false)
paypal_response = double(:response, success?: false, errors: [])
paypal_provider = double(
@@ -59,30 +60,4 @@ feature "Checking out with Paypal", js: true do
expect(page).to have_content "PayPal failed."
end
end
def complete_the_form
checkout_as_guest
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Email", with: "test@test.com"
fill_in "Phone", with: "0468363090"
end
within "#billing" do
fill_in "City", with: "Melbourne"
fill_in "Postcode", with: "3066"
fill_in "Address", with: "123 Your Head"
select "Australia", from: "Country"
select "Victoria", from: "State"
end
within "#shipping" do
choose free_shipping.name
end
within "#payment" do
choose paypal.name
end
end
end

View File

@@ -3,7 +3,7 @@ require 'spec_helper'
feature "As a consumer I want to check out my cart", js: true do
include AuthenticationHelper
include ShopWorkflow
include CheckoutWorkflow
include CheckoutHelper
include WebHelper
include UIComponentHelper
@@ -16,6 +16,19 @@ feature "As a consumer I want to check out my cart", js: true do
let(:variant) { product.variants.first }
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor, bill_address_id: nil, ship_address_id: nil) }
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: 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'
pm.preferred_password = '1406163716'
pm.preferred_signature = 'AFcWxV21C7fd0v3bYYYRCpSSRl31AaTntNJ-AjvUJkWf4dgJIvcLsf1V'
end
end
before do
Spree::Config.shipment_inc_vat = true
Spree::Config.shipping_tax_rate = 0.25
@@ -23,61 +36,70 @@ feature "As a consumer I want to check out my cart", js: true do
add_enterprise_fee enterprise_fee
set_order order
add_product_to_cart order, product
distributor.shipping_methods << free_shipping
distributor.shipping_methods << shipping_with_fee
distributor.shipping_methods << tagged_shipping
end
describe "with shipping and payment methods" do
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: 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'
pm.preferred_password = '1406163716'
pm.preferred_signature = 'AFcWxV21C7fd0v3bYYYRCpSSRl31AaTntNJ-AjvUJkWf4dgJIvcLsf1V'
end
describe "when I have an out of stock product in my cart" do
before do
variant.on_demand = false
variant.on_hand = 0
variant.save!
end
it "returns me to the cart with an error message" do
visit checkout_path
expect(page).not_to have_selector 'closing', text: "Checkout now"
expect(page).to have_selector 'closing', text: "Your shopping cart"
expect(page).to have_content "An item in your cart has become unavailable"
end
end
context 'login in as user' do
let(:user) { create(:user) }
before do
distributor.shipping_methods << free_shipping
distributor.shipping_methods << shipping_with_fee
distributor.shipping_methods << tagged_shipping
login_as(user)
end
describe "when I have an out of stock product in my cart" do
context "with details filled out" do
before do
variant.on_demand = false
variant.on_hand = 0
variant.save!
end
it "returns me to the cart with an error message" do
visit checkout_path
expect(page).not_to have_selector 'closing', text: "Checkout now"
expect(page).to have_selector 'closing', text: "Your shopping cart"
expect(page).to have_content "An item in your cart has become unavailable"
end
end
context 'login in as user' do
let(:user) { create(:user) }
before do
login_as(user)
fill_out_form(free_shipping.name, check_without_fee.name)
end
context "with details filled out" 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
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
context "when the user and customer have existing default addresses" do
let(:existing_address) { create(:address) }
before do
visit checkout_path
fill_out_form
user.bill_address = existing_address
user.ship_address = existing_address
end
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
it "updates billing address and shipping address" do
expect(order.bill_address).to be_nil
expect(order.ship_address).to be_nil
@@ -93,365 +115,304 @@ feature "As a consumer I want to check out my cart", js: true do
expect(user.reload.bill_address.address1).to eq '123 Your Head'
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
it "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
end
context "with previous orders" do
let!(:prev_order) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor, user: order.user) }
before do
order.distributor.allow_order_changes = true
order.distributor.save
visit checkout_path
end
it "informs about previous orders" do
expect(page).to have_content("You have an order for this order cycle already.")
end
it "doesn't tell about previous orders" do
expect(page).to have_no_content("You have an order for this order cycle already.")
end
context "when the user has a preset shipping and billing address" do
before do
user.bill_address = build(:address)
user.ship_address = build(:address)
user.save!
end
it "doesn't show link to terms and conditions" do
expect(page).to have_no_link("Terms of Service")
end
end
it "checks out successfully" do
visit checkout_path
context "when distributor has terms and conditions" do
let(:fake_terms_and_conditions_path) { Rails.root.join("app/assets/images/logo-white.png") }
let(:terms_and_conditions_file) { Rack::Test::UploadedFile.new(fake_terms_and_conditions_path, "application/pdf") }
before do
order.distributor.terms_and_conditions = terms_and_conditions_file
order.distributor.save
end
it "shows a link to the terms and conditions" do
visit checkout_path
expect(page).to have_link("Terms of Service", href: order.distributor.terms_and_conditions.url)
end
end
context "with previous orders" do
let!(:prev_order) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor, user: order.user) }
before do
order.distributor.allow_order_changes = true
order.distributor.save
visit checkout_path
end
it "informs about previous orders" do
expect(page).to have_content("You have an order for this order cycle already.")
end
end
context "when the user has a preset shipping and billing address" do
before do
user.bill_address = build(:address)
user.ship_address = build(:address)
user.save!
end
it "checks out successfully" do
visit checkout_path
choose shipping_with_fee.name
choose check_without_fee.name
expect do
place_order
expect(page).to have_content "Your order has been processed successfully"
end.to enqueue_job ConfirmOrderJob
end
end
end
context "guest checkout" do
before do
visit checkout_path
checkout_as_guest
end
it "shows the current distributor" do
visit checkout_path
expect(page).to have_content distributor.name
end
it 'does not show the save as default address checkbox' do
expect(page).not_to have_content "Save as default billing address"
expect(page).not_to have_content "Save as default shipping address"
end
it "shows a breakdown of the order price" do
choose shipping_with_fee.name
expect(page).to have_selector 'orderdetails .cart-total', text: with_currency(11.23)
expect(page).to have_selector 'orderdetails .shipping', text: with_currency(4.56)
expect(page).to have_selector 'orderdetails .total', text: with_currency(15.79)
# Tax should not be displayed in checkout, as the customer's choice of shipping method
# affects the tax and we haven't written code to live-update the tax amount when they
# make a change.
expect(page).not_to have_content product.tax_category.name
end
it "shows all shipping methods in order by name" do
within '#shipping' do
expect(page).to have_selector "label", count: 4 # Three shipping methods + instructions label
labels = page.all('label').map(&:text)
expect(labels[0]).to start_with("Donkeys") # shipping_with_fee
expect(labels[1]).to start_with("Frogs") # free_shipping
expect(labels[2]).to start_with("Local") # tagged_shipping
end
end
context "when shipping method requires an address" do
before do
choose free_shipping.name
end
it "shows ship address forms when 'same as billing address' is unchecked" do
uncheck "Shipping address same as billing address?"
expect(find("#ship_address > div.visible").visible?).to be true
end
end
it "filters out 'Back office only' shipping methods" do
expect(page).to have_content shipping_with_fee.name
shipping_with_fee.update_attribute :display_on, 'back_end' # Back office only
visit checkout_path
checkout_as_guest
expect(page).not_to have_content shipping_with_fee.name
end
context "using FilterShippingMethods" do
let(:user) { create(:user) }
let(:customer) { create(:customer, user: user, enterprise: distributor) }
it "shows shipping methods allowed by the rule" do
# No rules in effect
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).to have_content "Local"
create(:filter_shipping_methods_tag_rule,
enterprise: distributor,
preferred_customer_tags: "local",
preferred_shipping_method_tags: "local",
preferred_matched_shipping_methods_visibility: 'visible')
create(:filter_shipping_methods_tag_rule,
enterprise: distributor,
is_default: true,
preferred_shipping_method_tags: "local",
preferred_matched_shipping_methods_visibility: 'hidden')
visit checkout_path
checkout_as_guest
# Default rule in effect, disallows access to 'Local'
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).not_to have_content "Local"
login_as(user)
visit checkout_path
# Default rule in still effect, disallows access to 'Local'
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).not_to have_content "Local"
customer.update_attribute(:tag_list, "local")
visit checkout_path
# #local Customer can access 'Local' shipping method
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).to have_content "Local"
end
end
it "shows all available payment methods" do
expect(page).to have_content check_without_fee.name
expect(page).to have_content check_with_fee.name
expect(page).to have_content paypal.name
end
describe "purchasing" do
it "takes us to the order confirmation page when we submit a complete form" do
fill_out_details
fill_out_billing_address
within "#shipping" do
choose shipping_with_fee.name
choose check_without_fee.name
expect do
place_order
expect(page).to have_content "Your order has been processed successfully"
end.to enqueue_job ConfirmOrderJob
fill_in 'Any comments or special instructions?', with: "SpEcIaL NoTeS"
end
within "#payment" do
choose check_without_fee.name
end
expect do
place_order
expect(page).to have_content "Your order has been processed successfully"
end.to enqueue_job ConfirmOrderJob
# And the order's special instructions should be set
order = Spree::Order.complete.first
expect(order.special_instructions).to eq "SpEcIaL NoTeS"
# And the Spree tax summary should not be displayed
expect(page).not_to have_content product.tax_category.name
# And the total tax for the order, including shipping and fee tax, should be displayed
# product tax ($10.00 @ 10% = $0.91)
# + fee tax ($ 1.23 @ 10% = $0.11)
# + shipping tax ($ 4.56 @ 25% = $0.91)
# = $1.93
expect(page).to have_content '(includes tax)'
expect(page).to have_content with_currency(1.93)
expect(page).to have_content 'Back To Store'
end
context "with Stripe" do
let!(:stripe_pm) do
create(:stripe_payment_method, distributors: [distributor])
end
let!(:saved_card) do
create(:credit_card,
user_id: user.id,
month: "01",
year: "2025",
cc_type: "visa",
number: "1111111111111111",
payment_method_id: stripe_pm.id,
gateway_customer_profile_id: "i_am_saved")
end
let!(:stripe_account) { create(:stripe_account, enterprise_id: distributor.id, stripe_user_id: 'some_id') }
let(:response_mock) { { id: "ch_1234", object: "charge", amount: 2000 } }
context "with basic details filled" do
before do
allow(Stripe).to receive(:api_key) { "sk_test_12345" }
allow(Stripe).to receive(:publishable_key) { "some_key" }
Spree::Config.set(stripe_connect_enabled: true)
stub_request(:post, "https://api.stripe.com/v1/charges")
.with(basic_auth: ["sk_test_12345", ""])
.to_return(status: 200, body: JSON.generate(response_mock))
visit checkout_path
fill_out_form
choose stripe_pm.name
choose free_shipping.name
choose check_without_fee.name
fill_out_details
fill_out_billing_address
check "Shipping address same as billing address?"
end
it "allows use of a saved card" do
# shows the saved credit card dropdown
expect(page).to have_content I18n.t("spree.checkout.payment.stripe.used_saved_card")
# default card is selected, form element is not shown
expect(page).to have_no_selector "#card-element.StripeElement"
expect(page).to have_select 'selected_card', selected: "Visa x-1111 Exp:01/2025"
# allows checkout
it "takes us to the order confirmation page when submitted with 'same as billing address' checked" do
place_order
expect(page).to have_content "Your order has been processed successfully"
end
end
end
context "on the checkout page" do
before do
visit checkout_path
checkout_as_guest
end
it "takes us to the cart page with an error when a product becomes out of stock just before we purchase", js: true do
variant.on_demand = false
variant.on_hand = 0
variant.save!
it "shows the current distributor" do
visit checkout_path
expect(page).to have_content distributor.name
end
place_order
it 'does not show the save as default address checkbox' do
expect(page).not_to have_content "Save as default billing address"
expect(page).not_to have_content "Save as default shipping address"
end
it "shows a breakdown of the order price" do
choose shipping_with_fee.name
expect(page).to have_selector 'orderdetails .cart-total', text: with_currency(11.23)
expect(page).to have_selector 'orderdetails .shipping', text: with_currency(4.56)
expect(page).to have_selector 'orderdetails .total', text: with_currency(15.79)
# Tax should not be displayed in checkout, as the customer's choice of shipping method
# affects the tax and we haven't written code to live-update the tax amount when they
# make a change.
expect(page).not_to have_content product.tax_category.name
end
it "shows all shipping methods in order by name" do
within '#shipping' do
expect(page).to have_selector "label", count: 4 # Three shipping methods + instructions label
labels = page.all('label').map(&:text)
expect(labels[0]).to start_with("Donkeys") # shipping_with_fee
expect(labels[1]).to start_with("Frogs") # free_shipping
expect(labels[2]).to start_with("Local") # tagged_shipping
expect(page).not_to have_content "Your order has been processed successfully"
expect(page).to have_selector 'closing', text: "Your shopping cart"
expect(page).to have_content "An item in your cart has become unavailable."
end
end
context "when shipping method requires an address" do
before do
choose free_shipping.name
end
it "shows ship address forms when 'same as billing address' is unchecked" do
uncheck "Shipping address same as billing address?"
expect(find("#ship_address > div.visible").visible?).to be true
end
end
context "when we are charged a shipping fee" do
before { choose shipping_with_fee.name }
it "filters out 'Back office only' shipping methods" do
expect(page).to have_content shipping_with_fee.name
shipping_with_fee.update_attribute :display_on, 'back_end' # Back office only
visit checkout_path
checkout_as_guest
expect(page).not_to have_content shipping_with_fee.name
end
context "using FilterShippingMethods" do
let(:user) { create(:user) }
let(:customer) { create(:customer, user: user, enterprise: distributor) }
it "shows shipping methods allowed by the rule" do
# No rules in effect
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).to have_content "Local"
create(:filter_shipping_methods_tag_rule,
enterprise: distributor,
preferred_customer_tags: "local",
preferred_shipping_method_tags: "local",
preferred_matched_shipping_methods_visibility: 'visible')
create(:filter_shipping_methods_tag_rule,
enterprise: distributor,
is_default: true,
preferred_shipping_method_tags: "local",
preferred_matched_shipping_methods_visibility: 'hidden')
visit checkout_path
checkout_as_guest
# Default rule in effect, disallows access to 'Local'
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).not_to have_content "Local"
login_as(user)
visit checkout_path
# Default rule in still effect, disallows access to 'Local'
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).not_to have_content "Local"
customer.update_attribute(:tag_list, "local")
visit checkout_path
# #local Customer can access 'Local' shipping method
expect(page).to have_content "Frogs"
expect(page).to have_content "Donkeys"
expect(page).to have_content "Local"
end
end
end
context "on the checkout page with payments open" do
before do
visit checkout_path
checkout_as_guest
end
it "shows all available payment methods" do
expect(page).to have_content check_without_fee.name
expect(page).to have_content check_with_fee.name
expect(page).to have_content paypal.name
end
describe "purchasing" do
it "takes us to the order confirmation page when we submit a complete form" do
fill_out_details
fill_out_billing_address
within "#shipping" do
choose shipping_with_fee.name
fill_in 'Any comments or special instructions?', with: "SpEcIaL NoTeS"
end
within "#payment" do
choose check_without_fee.name
end
expect do
it "creates a payment for the full amount inclusive of shipping" do
place_order
expect(page).to have_content "Your order has been processed successfully"
end.to enqueue_job ConfirmOrderJob
# And the order's special instructions should be set
order = Spree::Order.complete.first
expect(order.special_instructions).to eq "SpEcIaL NoTeS"
# And the Spree tax summary should not be displayed
expect(page).not_to have_content product.tax_category.name
# And the total tax for the order, including shipping and fee tax, should be displayed
# product tax ($10.00 @ 10% = $0.91)
# + fee tax ($ 1.23 @ 10% = $0.11)
# + shipping tax ($ 4.56 @ 25% = $0.91)
# = $1.93
expect(page).to have_content '(includes tax)'
expect(page).to have_content with_currency(1.93)
expect(page).to have_content 'Back To Store'
# There are two orders - our order and our new cart
o = Spree::Order.complete.first
expect(o.adjustments.shipping.first.amount).to eq(4.56)
expect(o.payments.first.amount).to eq(10 + 1.23 + 4.56) # items + fees + shipping
end
end
context "with basic details filled" do
before do
choose free_shipping.name
choose check_without_fee.name
fill_out_details
fill_out_billing_address
check "Shipping address same as billing address?"
end
context "when we are charged a payment method fee (transaction fee)" do
it "creates a payment including the transaction fee" do
# Selecting the transaction fee, it is displayed
expect(page).to have_selector ".transaction-fee td", text: with_currency(0.00)
expect(page).to have_selector ".total", text: with_currency(11.23)
choose "#{check_with_fee.name} (#{with_currency(5.67)})"
expect(page).to have_selector ".transaction-fee td", text: with_currency(5.67)
expect(page).to have_selector ".total", text: with_currency(16.90)
it "takes us to the order confirmation page when submitted with 'same as billing address' checked" do
place_order
expect(page).to have_content "Your order has been processed successfully"
# There are two orders - our order and our new cart
o = Spree::Order.complete.first
expect(o.adjustments.payment_fee.first.amount).to eq 5.67
expect(o.payments.first.amount).to eq(10 + 1.23 + 5.67) # items + fees + transaction
end
end
it "takes us to the cart page with an error when a product becomes out of stock just before we purchase", js: true do
variant.on_demand = false
variant.on_hand = 0
variant.save!
describe "credit card payments" do
["Spree::Gateway::Bogus", "Spree::Gateway::BogusSimple"].each do |gateway_type|
context "with a credit card payment method using #{gateway_type}" do
let!(:check_without_fee) { create(:payment_method, distributors: [distributor], name: "Roger rabbit", type: gateway_type) }
place_order
it "takes us to the order confirmation page when submitted with a valid credit card" do
fill_in 'Card Number', with: "4111111111111111"
select 'February', from: 'secrets.card_month'
select (Date.current.year + 1).to_s, from: 'secrets.card_year'
fill_in 'Security Code', with: '123'
expect(page).not_to have_content "Your order has been processed successfully"
expect(page).to have_selector 'closing', text: "Your shopping cart"
expect(page).to have_content "An item in your cart has become unavailable."
end
place_order
expect(page).to have_content "Your order has been processed successfully"
context "when we are charged a shipping fee" do
before { choose shipping_with_fee.name }
# Order should have a payment with the correct amount
o = Spree::Order.complete.first
expect(o.payments.first.amount).to eq(11.23)
end
it "creates a payment for the full amount inclusive of shipping" do
place_order
expect(page).to have_content "Your order has been processed successfully"
it "shows the payment processing failed message when submitted with an invalid credit card" do
fill_in 'Card Number', with: "9999999988887777"
select 'February', from: 'secrets.card_month'
select (Date.current.year + 1).to_s, from: 'secrets.card_year'
fill_in 'Security Code', with: '123'
# There are two orders - our order and our new cart
o = Spree::Order.complete.first
expect(o.adjustments.shipping.first.amount).to eq(4.56)
expect(o.payments.first.amount).to eq(10 + 1.23 + 4.56) # items + fees + shipping
end
end
place_order
expect(page).to have_content 'Bogus Gateway: Forced failure'
context "when we are charged a payment method fee (transaction fee)" do
it "creates a payment including the transaction fee" do
# Selecting the transaction fee, it is displayed
expect(page).to have_selector ".transaction-fee td", text: with_currency(0.00)
expect(page).to have_selector ".total", text: with_currency(11.23)
choose "#{check_with_fee.name} (#{with_currency(5.67)})"
expect(page).to have_selector ".transaction-fee td", text: with_currency(5.67)
expect(page).to have_selector ".total", text: with_currency(16.90)
place_order
expect(page).to have_content "Your order has been processed successfully"
# There are two orders - our order and our new cart
o = Spree::Order.complete.first
expect(o.adjustments.payment_fee.first.amount).to eq 5.67
expect(o.payments.first.amount).to eq(10 + 1.23 + 5.67) # items + fees + transaction
end
end
describe "credit card payments" do
["Spree::Gateway::Bogus", "Spree::Gateway::BogusSimple"].each do |gateway_type|
context "with a credit card payment method using #{gateway_type}" do
let!(:check_without_fee) { create(:payment_method, distributors: [distributor], name: "Roger rabbit", type: gateway_type) }
it "takes us to the order confirmation page when submitted with a valid credit card" do
fill_in 'Card Number', with: "4111111111111111"
select 'February', from: 'secrets.card_month'
select (Date.current.year + 1).to_s, from: 'secrets.card_year'
fill_in 'Security Code', with: '123'
place_order
expect(page).to have_content "Your order has been processed successfully"
# Order should have a payment with the correct amount
o = Spree::Order.complete.first
expect(o.payments.first.amount).to eq(11.23)
end
it "shows the payment processing failed message when submitted with an invalid credit card" do
fill_in 'Card Number', with: "9999999988887777"
select 'February', from: 'secrets.card_month'
select (Date.current.year + 1).to_s, from: 'secrets.card_year'
fill_in 'Security Code', with: '123'
place_order
expect(page).to have_content 'Bogus Gateway: Forced failure'
# Does not show duplicate shipping fee
visit checkout_path
expect(page).to have_selector "th", text: "Shipping", count: 1
end
# Does not show duplicate shipping fee
visit checkout_path
expect(page).to have_selector "th", text: "Shipping", count: 1
end
end
end
@@ -459,36 +420,4 @@ feature "As a consumer I want to check out my cart", js: true do
end
end
end
def fill_out_details
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Email", with: "test@test.com"
fill_in "Phone", with: "0468363090"
end
end
def fill_out_billing_address
within "#billing" do
fill_in "City", with: "Melbourne"
fill_in "Postcode", with: "3066"
fill_in "Address", with: "123 Your Head"
select "Australia", from: "Country"
select "Victoria", from: "State"
end
end
def fill_out_form
choose free_shipping.name
choose check_without_fee.name
fill_out_details
check "Save as default billing address"
fill_out_billing_address
check "Shipping address same as billing address?"
check "Save as default shipping address"
end
end

View File

@@ -0,0 +1,82 @@
require 'spec_helper'
feature "Check out with Stripe", js: true do
include AuthenticationHelper
include ShopWorkflow
include CheckoutHelper
let(:distributor) { create(:distributor_enterprise) }
let!(:order_cycle) { create(:simple_order_cycle, distributors: [distributor], variants: [variant]) }
let(:product) { create(:product, price: 10) }
let(:variant) { product.variants.first }
let(:order) { create(:order, order_cycle: order_cycle, distributor: distributor, bill_address_id: nil, ship_address_id: nil) }
let(:shipping_with_fee) { create(:shipping_method, require_ship_address: false, name: "Donkeys", calculator: Calculator::FlatRate.new(preferred_amount: 4.56)) }
let!(:check_with_fee) { create(:payment_method, distributors: [distributor], calculator: Calculator::FlatRate.new(preferred_amount: 5.67)) }
before do
set_order order
add_product_to_cart order, product
distributor.shipping_methods << shipping_with_fee
end
context 'login in as user' do
let(:user) { create(:user) }
before do
login_as(user)
end
context "with Stripe" do
let!(:stripe_pm) do
create(:stripe_payment_method, distributors: [distributor])
end
let!(:saved_card) do
create(:credit_card,
user_id: user.id,
month: "01",
year: "2025",
cc_type: "visa",
number: "1111111111111111",
payment_method_id: stripe_pm.id,
gateway_customer_profile_id: "i_am_saved")
end
let!(:stripe_account) { create(:stripe_account, enterprise_id: distributor.id, stripe_user_id: 'some_id') }
let(:response_mock) { { id: "ch_1234", object: "charge", amount: 2000 } }
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
end
before do
allow(Stripe).to receive(:api_key) { "sk_test_12345" }
allow(Stripe).to receive(:publishable_key) { "some_key" }
Spree::Config.set(stripe_connect_enabled: true)
stub_request(:post, "https://api.stripe.com/v1/charges")
.with(basic_auth: ["sk_test_12345", ""])
.to_return(status: 200, body: JSON.generate(response_mock))
visit checkout_path
fill_out_form(shipping_with_fee.name, stripe_pm.name, save_default_addresses: false)
end
it "allows use of a saved card" do
# shows the saved credit card dropdown
expect(page).to have_content I18n.t("spree.checkout.payment.stripe.used_saved_card")
# default card is selected, form element is not shown
expect(page).to have_no_selector "#card-element.StripeElement"
expect(page).to have_select 'selected_card', selected: "Visa x-1111 Exp:01/2025"
# allows checkout
place_order
expect(page).to have_content "Your order has been processed successfully"
end
end
end
end

View File

@@ -5,7 +5,7 @@ feature "Using embedded shopfront functionality", js: true do
include AuthenticationHelper
include WebHelper
include ShopWorkflow
include CheckoutWorkflow
include CheckoutHelper
include UIComponentHelper
describe "using iframes" do

View File

@@ -4,7 +4,7 @@ feature "shopping with variant overrides defined", js: true do
include AuthenticationHelper
include WebHelper
include ShopWorkflow
include CheckoutWorkflow
include CheckoutHelper
include UIComponentHelper
let(:hub) { create(:distributor_enterprise, with_payment_and_shipping: true) }

View File

@@ -241,6 +241,12 @@ describe EnterprisesHelper, type: :helper do
let!(:pm4) { create(:stripe_payment_method, distributors: [distributor], preferred_enterprise_id: some_other_distributor.id) }
let(:available_payment_methods) { helper.available_payment_methods }
around do |example|
original_stripe_connect_enabled = Spree::Config[:stripe_connect_enabled]
example.run
Spree::Config.set(stripe_connect_enabled: original_stripe_connect_enabled)
end
before do
allow(helper).to receive(:current_distributor) { distributor }
end

View File

@@ -300,11 +300,11 @@ module Spree
let!(:er_pd) { create(:enterprise_relationship, parent: d_related, child: d1, permissions_list: [:edit_profile]) }
it "should be able to edit enterprises it manages" do
is_expected.to have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], for: d1)
is_expected.to have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :remove_terms_and_conditions, :bulk_update, :resend_confirmation], for: d1)
end
it "should be able to edit enterprises it has permission to" do
is_expected.to have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :bulk_update, :resend_confirmation], for: d_related)
is_expected.to have_ability([:read, :edit, :update, :remove_logo, :remove_promo_image, :remove_terms_and_conditions, :bulk_update, :resend_confirmation], for: d_related)
end
it "should be able to manage shipping methods, payment methods and enterprise fees for enterprises it manages" do

View File

@@ -0,0 +1,55 @@
module CheckoutHelper
def have_checkout_details
have_content "Your details"
end
def checkout_as_guest
click_button "Checkout as guest"
end
def place_order
find("button", text: "Place order now").click
end
def toggle_accordion(id)
find("##{id} dd a").click
end
def toggle_details
toggle_accordion :details
end
def fill_out_details
within "#details" do
fill_in "First Name", with: "Will"
fill_in "Last Name", with: "Marshall"
fill_in "Email", with: "test@test.com"
fill_in "Phone", with: "0468363090"
end
end
def fill_out_billing_address
within "#billing" do
fill_in "City", with: "Melbourne"
fill_in "Postcode", with: "3066"
fill_in "Address", with: "123 Your Head"
select "Australia", from: "Country"
select "Victoria", from: "State"
end
end
def fill_out_form(shipping_method_name, payment_method_name, save_default_addresses: true)
choose shipping_method_name
choose payment_method_name
fill_out_details
check "Save as default billing address" if save_default_addresses
fill_out_billing_address
if save_default_addresses
check "Shipping address same as billing address?"
check "Save as default shipping address"
end
end
end

View File

@@ -1,21 +0,0 @@
module CheckoutWorkflow
def have_checkout_details
have_content "Your details"
end
def checkout_as_guest
click_button "Checkout as guest"
end
def place_order
find("button", text: "Place order now").click
end
def toggle_accordion(id)
find("##{id} dd a").click
end
def toggle_details
toggle_accordion :details
end
end