Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
</div>
<% end %>
<% end %>
<%= render component('ui/panel').new(title: t('.address')) do |panel| %>
<% panel.with_section do %>
<%= render component('ui/forms/address').new(
addressable: address,
form_field_name: "store[address_attributes]",
excludes: address_excludes
) %>
<% end %>
<% end %>
<%= render component('ui/panel').new(title: t('.localization')) do |panel| %>
<% panel.with_section(class: "flex flex-col gap-4") do %>
<div class="flex flex-col gap-4 w-full">
Expand Down
10 changes: 10 additions & 0 deletions admin/app/components/solidus_admin/stores/form/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ def initialize(store:, id:, url:)
@url = url
end

def address
@store.address || Spree::Address.new(country: Spree::Country.find_by(iso: Spree::Config.default_country_iso))
end

def address_excludes
excludes = [:email, :street_contd]
excludes << :phone unless Spree::Config.address_requires_phone
excludes
end

def available_locales
Spree.i18n_available_locales.map do |locale|
[I18n.t("spree.i18n.this_file_language", locale: locale, default: locale.to_s, fallback: false), locale]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
en:
address: Address
localization: Localization
plugins:
install: Install
Expand Down
8 changes: 6 additions & 2 deletions admin/app/controllers/solidus_admin/stores_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,12 @@ def permitted_resource_params
:mail_from_address,
:default_currency,
:cart_tax_country_iso,
available_locales: []
)
available_locales: [],
address_attributes: Spree::PermittedAttributes.address_attributes
).tap do |store_params|
without_address_parameter = store_params[:address_attributes]&.except(:country_id, :state_id, :reverse_charge_status)&.compact_blank&.empty?
store_params.delete(:address_attributes) if without_address_parameter
end
end
end
end
23 changes: 23 additions & 0 deletions admin/spec/features/stores_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
available_locales: %w[en])

create(:country, iso: "US")
create(:country, iso: "DE", states_required: false)
visit "/admin/stores"
click_on "B2C Store"
expect(page).to be_axe_clean
Expand Down Expand Up @@ -111,6 +112,28 @@
expect(solidus_select_control("Default Currency")).to have_content("USD")
expect(solidus_select_control("Tax Country")).to have_content("United States")
end

it "updates store address" do
expect(page).not_to have_field("Email", exact: true)

fill_in "Name", with: "B2C Store Inc."
fill_in "Street Address", with: "1 Store Street"
fill_in "City", with: "Storetown"
fill_in "Zip Code", with: "12345"
fill_in "Phone", with: "555-555-0199"
solidus_select("Germany", from: "Country")

within("header") { click_on "Save" }

expect(page).to have_content("Store was successfully updated")
expect(Spree::Store.find_by(name: "B2C Store").address).to have_attributes(
name: "B2C Store Inc.",
address1: "1 Store Street",
city: "Storetown",
phone: "555-555-0199",
country: Spree::Country.find_by(iso: "DE")
)
end
end

describe "clicking Discard" do
Expand Down
49 changes: 49 additions & 0 deletions admin/spec/requests/solidus_admin/stores_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,53 @@
let(:valid_attributes) { {name: "Store", code: "store", url: "store.com", mail_from_address: "store@example.com"} }
let(:invalid_attributes) { {name: ""} }
end

describe "address" do
let(:admin_user) { create(:admin_user) }
let(:store) { create(:store, default: false) }
let(:country) { create(:country, states_required: false) }
let(:address_attributes) do
{name: "Store Inc.", address1: "1 Store Street", city: "Storetown", zipcode: "12345", phone: "555-555-0199", vat_id: "DE123456789", country_id: country.id}
end

before { allow_any_instance_of(SolidusAdmin::BaseController).to receive(:spree_current_user).and_return(admin_user) }

it "renders the address fields without email, address2 and VAT-ID" do
get solidus_admin.edit_store_path(store)
expect(response.body).to include('name="store[address_attributes][address1]"')
expect(response.body).to include('name="store[address_attributes][phone]"')
expect(response.body).not_to include('name="store[address_attributes][email]"')
expect(response.body).not_to include('name="store[address_attributes][address2]"')
expect(response.body).not_to include('name="store[address_attributes][vat_id]"')
end

it "does not render the phone field if phone is not required" do
allow(Spree::Config).to receive(:address_requires_phone).and_return(false)
get solidus_admin.edit_store_path(store)
expect(response.body).not_to include('name="store[address_attributes][phone]"')
end

it "renders the VAT-ID once if reverse charge fields are shown" do
allow(Spree::Backend::Config).to receive(:show_reverse_charge_fields).and_return(true)
get solidus_admin.edit_store_path(store)
expect(response.body.scan('name="store[address_attributes][vat_id]"').size).to eq(1)
end

it "saves the address" do
patch solidus_admin.store_path(store), params: {store: {address_attributes:}}
expect(store.reload.address).to have_attributes(address_attributes)
end

it "does not create an address from blank fields" do
patch solidus_admin.store_path(store), params: {store: {address_attributes: {name: "", address1: "", country_id: country.id, reverse_charge_status: "disabled"}}}
expect(response).to have_http_status(:see_other)
expect(store.reload.address).to be_nil
end

it "creates a store without address from blank fields" do
post solidus_admin.stores_path, params: {store: {name: "New Store", code: "new-store", url: "new-store.com", mail_from_address: "store@example.com", address_attributes: {name: "", address1: "", country_id: country.id}}}
expect(response).to have_http_status(:see_other)
expect(Spree::Store.find_by!(code: "new-store").address).to be_nil
end
end
end
10 changes: 10 additions & 0 deletions api/app/views/spree/api/stores/_store.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

json.call(store, *store_attributes)
json.address do
if store.address
json.partial!("spree/api/addresses/address", address: store.address)
else
json.nil!
end
end
2 changes: 1 addition & 1 deletion api/app/views/spree/api/stores/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# frozen_string_literal: true

json.stores(@stores) { |store| json.call(store, *store_attributes) }
json.stores(@stores) { |store| json.partial!("spree/api/stores/store", store:) }
2 changes: 1 addition & 1 deletion api/app/views/spree/api/stores/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# frozen_string_literal: true

json.call(@store, *store_attributes)
json.partial!("spree/api/stores/store", store: @store)
4 changes: 4 additions & 0 deletions api/openapi/solidus-api.oas.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6474,6 +6474,8 @@ components:
type: string
url:
type: string
address:
$ref: '#/components/schemas/address'
taxonomy:
type: object
properties:
Expand Down Expand Up @@ -6955,6 +6957,8 @@ components:
type: string
cart_tax_country_iso:
type: string
address_attributes:
$ref: '#/components/schemas/address-input'
taxonomy-input:
type: object
title: Taxonomy input
Expand Down
53 changes: 50 additions & 3 deletions api/spec/requests/spree/api/stores_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ module Spree::Api
"default_currency" => nil,
"code" => store.code,
"default" => true,
"available_locales" => ["en"]
"available_locales" => ["en"],
"address" => nil
},
{
"id" => non_default_store.id,
Expand All @@ -53,7 +54,8 @@ module Spree::Api
"default_currency" => nil,
"code" => non_default_store.code,
"default" => false,
"available_locales" => ["en"]
"available_locales" => ["en"],
"address" => nil
}
])
end
Expand All @@ -73,7 +75,8 @@ module Spree::Api
"default_currency" => nil,
"code" => store.code,
"default" => true,
"available_locales" => ["en"]
"available_locales" => ["en"],
"address" => nil
)
end

Expand Down Expand Up @@ -101,6 +104,50 @@ module Spree::Api
expect(store.reload.bcc_email).to eql "bcc@example.net"
end

context "address" do
let(:country) { create(:country, states_required: false) }
let(:address_params) do
attributes_for(:address).slice(:name, :address1, :city, :zipcode, :phone).merge(country_id: country.id)
end

it "includes the address in the store details" do
store.update!(address: create(:address))
get spree.api_store_path(store)
expect(json_response["address"]).to include(
"id" => store.address.id,
"address1" => store.address.address1,
"city" => store.address.city
)
expect(json_response["address"]["country"]).to include("iso" => store.address.country.iso)
end

it "can create a new store with an address" do
store_hash = {
code: "spree123",
name: "Hack0rz",
url: "spree123.example.com",
mail_from_address: "me@example.com",
address_attributes: address_params
}
post spree.api_stores_path, params: {store: store_hash}
expect(response.status).to eq(201)
expect(json_response["address"]).to include("address1" => address_params[:address1])
end

it "can update the address of an existing store" do
put spree.api_store_path(store), params: {store: {address_attributes: address_params}}
expect(response.status).to eq(200)
expect(store.reload.address.address1).to eq(address_params[:address1])
expect(store.address.country).to eq(country)
end

it "responds with an error for an invalid address" do
put spree.api_store_path(store), params: {store: {address_attributes: address_params.merge(city: "")}}
expect(response.status).to eq(422)
expect(json_response["errors"]).to include("address")
end
end

context "deleting a store" do
it "will fail if it's the default Store" do
delete spree.api_store_path(store)
Expand Down
7 changes: 7 additions & 0 deletions backend/app/controllers/spree/admin/stores_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ def index

private

def permitted_resource_params
super.tap do |store_params|
without_address_parameters = store_params[:address_attributes]&.except(:country_id, :state_id, :reverse_charge_status)&.compact_blank&.empty?
store_params.delete(:address_attributes) if without_address_parameters
end
end

def store_params
params.require(:store).permit(permitted_params)
end
Expand Down
30 changes: 18 additions & 12 deletions backend/app/views/spree/admin/shared/_address_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
<%= f.text_field :address1, class: 'fullwidth' %>
</div>

<div class="field <%= "#{type}-row" %>">
<%= f.label :address2 %>
<%= f.text_field :address2, class: 'fullwidth' %>
</div>
<% unless local_assigns.fetch(:excludes, []).include?(:address2) %>
<div class="field <%= "#{type}-row" %>">
<%= f.label :address2 %>
<%= f.text_field :address2, class: 'fullwidth' %>
</div>
<% end %>

<div class="field <%= "#{type}-row" %>">
<%= f.label :city %>
Expand Down Expand Up @@ -59,15 +61,19 @@
</span>
</div>

<div class="field <%= "#{type}-row" %>">
<%= f.label :phone %>
<%= f.phone_field :phone, class: 'fullwidth' %>
</div>
<% unless local_assigns.fetch(:excludes, []).include?(:phone) %>
<div class="field <%= "#{type}-row" %>">
<%= f.label :phone %>
<%= f.phone_field :phone, class: 'fullwidth' %>
</div>
<% end %>

<div class="field <%= "#{type}-row" %>">
<%= f.label :email %>
<%= f.email_field :email, class: 'fullwidth' %>
</div>
<% unless local_assigns.fetch(:excludes, []).include?(:email) %>
<div class="field <%= "#{type}-row" %>">
<%= f.label :email %>
<%= f.email_field :email, class: 'fullwidth' %>
</div>
<% end %>

<% if Spree::Backend::Config.show_reverse_charge_fields %>
<div class="field <%= "#{type}-row" %>">
Expand Down
7 changes: 7 additions & 0 deletions backend/app/views/spree/admin/stores/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
<%= f.error_message_on :reverse_charge_status %>
<% end %>
<% end %>

<fieldset class="no-border-bottom js-addresses-form" data-hook="store_address_wrapper">
<legend align="center"><%= Spree::Address.model_name.human %></legend>
<%= f.fields_for :address, f.object.address || Spree::Address.new(country: Spree::Country.find_by(iso: Spree::Config.default_country_iso)) do |address_form| %>
<%= render partial: 'spree/admin/shared/address_form', locals: { f: address_form, type: "store", excludes: Spree::Config.address_requires_phone ? [:address2, :email] : [:address2, :email, :phone] } %>
<% end %>
</fieldset>
</div>
<div class="col-12 col-md-6">
<%= f.field_container :url do %>
Expand Down
50 changes: 50 additions & 0 deletions backend/spec/controllers/spree/admin/stores_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

require "spec_helper"

describe Spree::Admin::StoresController, type: :controller do
stub_authorization!

let(:store) { create(:store) }
let(:country) { create(:country, states_required: false) }
let(:address_attributes) do
{name: "Store Inc.", address1: "1 Store Street", city: "Storetown", zipcode: "12345", phone: "555-555-0199", country_id: country.id}
end

describe "#edit" do
render_views

it "renders the address fields without email and address2" do
get :edit, params: {id: store.id}
expect(response.body).to include('name="store[address_attributes][address1]"')
expect(response.body).to include('name="store[address_attributes][phone]"')
expect(response.body).not_to include('name="store[address_attributes][email]"')
expect(response.body).not_to include('name="store[address_attributes][address2]"')
end

it "does not render the phone field if phone is not required" do
stub_spree_preferences(address_requires_phone: false)
get :edit, params: {id: store.id}
expect(response.body).not_to include('name="store[address_attributes][phone]"')
end
end

describe "#update" do
it "saves the address" do
put :update, params: {id: store.id, store: {address_attributes:}}
expect(store.reload.address).to have_attributes(address_attributes)
end

it "does not create an address from blank fields" do
put :update, params: {id: store.id, store: {name: "New Name", address_attributes: {name: "", address1: "", country_id: country.id, reverse_charge_status: "disabled"}}}
expect(store.reload).to have_attributes(name: "New Name", address: nil)
end
end

describe "#create" do
it "creates a store without address from blank fields" do
post :create, params: {store: {name: "New Store", code: "new-store", url: "new-store.com", mail_from_address: "store@example.com", address_attributes: {name: "", address1: "", country_id: country.id}}}
expect(Spree::Store.find_by!(code: "new-store").address).to be_nil
end
end
end
Loading
Loading