Skip to content

Commit bb18ebd

Browse files
committed
Added country/state validations and test cases for the store.
1 parent 0ad8199 commit bb18ebd

File tree

7 files changed

+170
-76
lines changed

7 files changed

+170
-76
lines changed

api/lib/spree/api_configuration.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def promotion_attributes=(value)
127127
preference :store_attributes, :array, default: [
128128
:id, :name, :legal_name, :url, :meta_description, :meta_keywords, :seo_title,
129129
:mail_from_address, :default_currency, :code, :default,
130-
:bcc_email, :contact_phone, :contact_email, :tax_id, :vat_id, :description,
131-
:address1, :address2, :city, :postal_code, :country_id, :state_id, :state_name, :available_locales
130+
:bcc_email, :phone, :contact_email, :tax_id, :vat_id, :description,
131+
:address1, :address2, :city, :zipcode, :country_id, :state_id, :state_name, :available_locales
132132
]
133133

134134
preference :store_credit_history_attributes, :array, default: [

api/spec/requests/spree/api/stores_spec.rb

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
module Spree::Api
66
describe 'Stores', type: :request do
7+
let(:country) { create :country, states_required: true }
8+
let(:state) { create :state, name: 'maryland', abbr: 'md', country: }
9+
let!(:base_attributes) { Spree::Api::Config.store_attributes }
10+
711
let!(:store) do
812
create(:store, name: "My Spree Store", url: "spreestore.example.com")
913
end
@@ -22,6 +26,60 @@ module Spree::Api
2226
default: false)
2327
end
2428

29+
let(:country_with_states) { create(:country, states: [create(:state)]) }
30+
let(:country_without_states) { create(:country) }
31+
32+
describe "Validations" do
33+
context "when the country has states" do
34+
it "is invalid without a state" do
35+
store = Spree::Store.new(name: "Test Store", country: country_with_states, state: nil, url: "spreestore.example.com",
36+
mail_from_address: "spreestore.example.com", code: "test-store",)
37+
expect(store).not_to be_valid
38+
expect(store.errors[:state]).to include("can't be blank")
39+
end
40+
41+
it "is valid with a state" do
42+
store = Spree::Store.new(name: "Test Store", country: country_with_states, state: state, url: "spreestore.example.com",
43+
mail_from_address: "spreestore.example.com", code: "test-store",)
44+
expect(store).to be_valid
45+
end
46+
end
47+
48+
context "when the country has no states" do
49+
it "is valid without a state" do
50+
store = Spree::Store.new(name: "Test Store", country: country_without_states, state: nil, url: "spreestore.example.com",
51+
mail_from_address: "spreestore.example.com", code: "test-store",)
52+
expect(store).to be_valid
53+
end
54+
end
55+
56+
it "is valid without an address and without country/state" do
57+
expect(store).to be_valid
58+
end
59+
60+
it "is valid with only correct country and state" do
61+
store = Spree::Store.create!(
62+
name: "Test Store",
63+
url: "spreestore.example.com",
64+
mail_from_address: "spreestore.example.com",
65+
code: "test-store",
66+
address1: "123 Main St",
67+
city: "New York",
68+
zipcode: "10001",
69+
country: country,
70+
)
71+
expect(store).to be_valid
72+
end
73+
end
74+
75+
describe "#index" do
76+
it "ensures the API store attributes match the expected attributes" do
77+
get spree.api_stores_path
78+
first_store = json_response["stores"].first
79+
expect(first_store.keys).to include(*base_attributes.map(&:to_s))
80+
end
81+
end
82+
2583
it "can list the available stores" do
2684
get spree.api_stores_path
2785
expect(json_response["stores"]).to match_array([
@@ -39,15 +97,15 @@ module Spree::Api
3997
"default" => true,
4098
"available_locales" => ["en"],
4199
"legal_name" => nil,
42-
"contact_phone" => nil,
43100
"contact_email" => nil,
44101
"description" => nil,
102+
"phone" => nil,
45103
"tax_id" => nil,
46104
"vat_id" => nil,
47105
"address1" => nil,
48106
"address2" => nil,
49107
"city" => nil,
50-
"postal_code" => nil,
108+
"zipcode" => nil,
51109
"country_id" => nil,
52110
"state_id" => nil,
53111
"state_name" => nil
@@ -66,15 +124,15 @@ module Spree::Api
66124
"default" => false,
67125
"available_locales" => ["en"],
68126
"legal_name" => nil,
69-
"contact_phone" => nil,
70127
"contact_email" => nil,
71128
"description" => nil,
129+
"phone" => nil,
72130
"tax_id" => nil,
73131
"vat_id" => nil,
74132
"address1" => nil,
75133
"address2" => nil,
76134
"city" => nil,
77-
"postal_code" => nil,
135+
"zipcode" => nil,
78136
"country_id" => nil,
79137
"state_id" => nil,
80138
"state_name" => nil
@@ -98,15 +156,15 @@ module Spree::Api
98156
"default" => true,
99157
"available_locales" => ["en"],
100158
"legal_name" => nil,
101-
"contact_phone" => nil,
102159
"contact_email" => nil,
103160
"description" => nil,
161+
"phone" => nil,
104162
"tax_id" => nil,
105163
"vat_id" => nil,
106164
"address1" => nil,
107165
"address2" => nil,
108166
"city" => nil,
109-
"postal_code" => nil,
167+
"zipcode" => nil,
110168
"country_id" => nil,
111169
"state_id" => nil,
112170
"state_name" => nil
@@ -118,7 +176,14 @@ module Spree::Api
118176
code: "spree123",
119177
name: "Hack0rz",
120178
url: "spree123.example.com",
121-
mail_from_address: "[email protected]"
179+
mail_from_address: "[email protected]",
180+
legal_name: 'ABC Corp',
181+
address1: "123 Main St",
182+
city: 'San Francisco',
183+
country_id: country.id,
184+
state_id: state.id,
185+
phone: "123-456-7890",
186+
zipcode: "12345"
122187
}
123188
post spree.api_stores_path, params: { store: store_hash }
124189
expect(response.status).to eq(201)
@@ -128,13 +193,34 @@ module Spree::Api
128193
store_hash = {
129194
url: "spree123.example.com",
130195
mail_from_address: "[email protected]",
131-
bcc_email: "[email protected]"
196+
bcc_email: "[email protected]",
197+
legal_name: 'XYZ Corp',
198+
description: "Leading provider of high-quality tech accessories, offering the latest gadgets, peripherals, and electronics to enhance your digital lifestyle.",
199+
tax_id: "TX-987654321",
200+
vat_id: "VAT-123456789",
201+
address1: "123 Innovation Drive",
202+
address2: "Suite 456",
203+
city: "New York",
204+
country_id: country.id,
205+
state_id: state.id,
206+
phone: "123-456-7888",
207+
zipcode: "10001"
132208
}
133209
put spree.api_store_path(store), params: { store: store_hash }
134210
expect(response.status).to eq(200)
135211
expect(store.reload.url).to eql "spree123.example.com"
136212
expect(store.reload.mail_from_address).to eql "[email protected]"
137213
expect(store.reload.bcc_email).to eql "[email protected]"
214+
expect(store.reload.legal_name).to eql "XYZ Corp"
215+
expect(store.reload.tax_id).to eql "TX-987654321"
216+
expect(store.reload.vat_id).to eql "VAT-123456789"
217+
expect(store.reload.address1).to eql "123 Innovation Drive"
218+
expect(store.reload.address2).to eql "Suite 456"
219+
expect(store.reload.city).to eql "New York"
220+
expect(store.reload.country_id).to eql country.id
221+
expect(store.reload.state_id).to eql state.id
222+
expect(store.reload.phone).to eql "123-456-7888"
223+
expect(store.reload.zipcode).to eql "10001"
138224
end
139225

140226
context "deleting a store" do
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
2+
<% s_or_b = type.chars.first %>
3+
<hr>
4+
5+
<div class="row" id="<%= type %>" data-hook="address_fields">
6+
<div class="col-12 col-md-6">
7+
<div class="field <%= "#{type}-row" %>">
8+
<%= f.label :legal_name %>
9+
<%= f.text_field :legal_name, class: 'fullwidth' %>
10+
</div>
11+
12+
<div class="field <%= "#{type}-row" %>">
13+
<%= f.label :address1 %>
14+
<%= f.text_field :address1, class: 'fullwidth' %>
15+
</div>
16+
17+
<div class="field <%= "#{type}-row" %>">
18+
<%= f.label :address2 %>
19+
<%= f.text_field :address2, class: 'fullwidth' %>
20+
</div>
21+
22+
<div class="field <%= "#{type}-row" %>">
23+
<%= f.label :phone %>
24+
<%= f.phone_field :phone, class: 'fullwidth' %>
25+
</div>
26+
</div>
27+
28+
<div class="col-12 col-md-6">
29+
<div class="field <%= "#{type}-row" %>">
30+
<%= f.label :city %>
31+
<%= f.text_field :city, class: 'fullwidth' %>
32+
</div>
33+
34+
<div class="field <%= "#{type}-row" %>">
35+
<%= f.label :zipcode %>
36+
<%= f.text_field :zipcode, class: 'fullwidth' %>
37+
</div>
38+
39+
<div class="field <%= "#{type}-row" %>">
40+
<%= f.label :country_id, Spree::Country.model_name.human %>
41+
<span id="<%= s_or_b %>country">
42+
<%= f.collection_select :country_id, available_countries, :id, :name, { include_blank: true }, {class: 'custom-select fullwidth js-country_id'} %>
43+
</span>
44+
</div>
45+
46+
<div class="field <%= "#{type}-row" %>">
47+
<%= f.label :state_id, Spree::State.model_name.human %>
48+
<span id="<%= s_or_b %>state">
49+
<%= f.hidden_field :state_name, value: nil %>
50+
<% states = f.object.country.try(:states).nil? ? [] : f.object.country.states %>
51+
<%= f.text_field :state_name,
52+
style: "display: #{states.empty? ? 'block' : 'none' };",
53+
disabled: !states.empty?, class: 'fullwidth state_name js-state_name' %>
54+
<%= f.hidden_field :state_id, value: nil %>
55+
<%= f.collection_select :state_id,
56+
states.sort,
57+
:id, :name,
58+
{ include_blank: true },
59+
{ class: 'custom-select fullwidth js-state_id',
60+
style: "display: #{states.empty? ? 'none' : 'block' };",
61+
disabled: states.empty? } %>
62+
</span>
63+
</div>
64+
</div>
65+
</div>

backend/app/views/spree/admin/stores/_form.html.erb

Lines changed: 4 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<div class="row js-addresses-form">
1+
<div class="row">
22
<div class="col-12 col-md-6">
33
<%= f.field_container :name do %>
44
<%= f.label :name, class: 'required' %>
@@ -31,18 +31,6 @@
3131
<%= f.error_message_on :meta_description %>
3232
<% end %>
3333

34-
<%= f.field_container :legal_name do %>
35-
<%= f.label :legal_name %>
36-
<%= f.text_field :legal_name, class: 'fullwidth' %>
37-
<%= f.error_message_on :legal_name %>
38-
<% end %>
39-
40-
<%= f.field_container :contact_phone do %>
41-
<%= f.label :contact_phone %>
42-
<%= f.phone_field :contact_phone, class: 'fullwidth' %>
43-
<%= f.error_message_on :contact_phone %>
44-
<% end %>
45-
4634
<%= f.field_container :tax_id do %>
4735
<%= f.label :tax_id %>
4836
<%= f.text_field :tax_id, class: 'fullwidth' %>
@@ -108,62 +96,16 @@
10896
<%= f.error_message_on :default_currency %>
10997
<% end %>
11098

111-
<%= f.field_container :contact_email do %>
112-
<%= f.label :contact_email %>
113-
<%= f.email_field :contact_email, class: 'fullwidth' %>
114-
<%= f.error_message_on :contact_email %>
115-
<% end %>
116-
11799
<%= f.field_container :description do %>
118100
<%= f.label :description %>
119-
<%= f.text_area :description, class: 'fullwidth', rows: 6 %>
101+
<%= f.text_area :description, class: 'fullwidth' %>
120102
<%= f.error_message_on :description %>
121103
<% end %>
122104
</div>
123105

124106
<div class="col-12">
125-
<%= f.label :address %>
126-
<div class="row border mx-1 py-3 border-secondary rounded">
127-
<div class="col-md-6 mb-3">
128-
<%= f.field_container :address1 do %>
129-
<%= f.label :address1 %>
130-
<%= f.text_field :address1, class: 'fullwidth' %>
131-
<% end %>
132-
</div>
133-
<div class="col-md-6 mb-3">
134-
<%= f.field_container :address2 do %>
135-
<%= f.label :address2 %>
136-
<%= f.text_field :address2, class: 'fullwidth' %>
137-
<% end %>
138-
</div>
139-
<div class="col-md-6 mb-3">
140-
<%= f.field_container :city do %>
141-
<%= f.label :city %>
142-
<%= f.text_field :city, class: 'fullwidth' %>
143-
<% end %>
144-
</div>
145-
<div class="col-md-6 mb-3">
146-
<%= f.field_container :postal_code do %>
147-
<%= f.label :postal_code %>
148-
<%= f.text_field :postal_code, class: 'fullwidth' %>
149-
<% end %>
150-
</div>
151-
<div class="col-md-6 mb-3">
152-
<%= f.field_container :country_id do %>
153-
<%= f.label :country_id %>
154-
<span id="country"><%= f.collection_select :country_id, available_countries(restrict_to_zone: nil), :id, :name, { include_blank: true }, { class: 'custom-select js-country_id fullwidth' } %></span>
155-
<% end %>
156-
</div>
157-
<div class="col-md-6 mb-3">
158-
<%= f.field_container :state do %>
159-
<% country = f.object.country %>
160-
<%= f.label :state_id %>
161-
<span id="state" class="region">
162-
<%= f.text_field :state_name, style: "display: none", class: 'fullwidth state_name js-state_name' %>
163-
<%= f.collection_select :state_id, country ? country.states.sort : [], :id, :name, { include_blank: true }, {class: 'custom-select fullwidth js-state_id', style: "display: none" } %>
164-
</span>
165-
<% end %>
166-
</div>
107+
<div class="js-addresses-form">
108+
<%= render partial: 'address_form', locals: { f: f, type: 'store' } %>
167109
</div>
168110
</div>
169111
</div>

core/app/models/spree/store.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Store < Spree::Base
2424
validates :name, presence: true
2525
validates :url, presence: true
2626
validates :mail_from_address, presence: true
27+
validates :state, presence: true, if: -> { country&.states&.exists? }
2728

2829
self.allowed_ransackable_attributes = %w[name url code]
2930

core/db/migrate/20250202173007_add_store_attributes_to_spree_stores.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
class AddStoreAttributesToSpreeStores < ActiveRecord::Migration[7.2]
22
def change
33
add_column :spree_stores, :legal_name, :string
4-
add_column :spree_stores, :contact_phone, :string
54
add_column :spree_stores, :contact_email, :string
65
add_column :spree_stores, :description, :text
76
add_column :spree_stores, :vat_id, :string
87
add_column :spree_stores, :tax_id, :string
98
add_column :spree_stores, :address1, :string
109
add_column :spree_stores, :address2, :string
1110
add_column :spree_stores, :city, :string
12-
add_column :spree_stores, :postal_code, :string
11+
add_column :spree_stores, :zipcode, :string
1312
add_column :spree_stores, :state_name, :string
13+
add_column :spree_stores, :phone, :string
1414
add_reference :spree_stores, :country, foreign_key: { to_table: :spree_countries }, index: true
1515
add_reference :spree_stores, :state, foreign_key: { to_table: :spree_states }, index: true
1616
end

core/lib/spree/permitted_attributes.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ module PermittedAttributes
113113
@@store_attributes = [:name, :legal_name, :url, :seo_title, :meta_keywords,
114114
:meta_description, :default_currency,
115115
:mail_from_address, :cart_tax_country_iso,
116-
:bcc_email, :contact_email, :contact_phone, :code,
116+
:bcc_email, :contact_email, :phone, :code,
117117
:tax_id, :vat_id, :description, :address1, :address2,
118-
:city, :postal_code, :country_id, :state_id, :state_name]
118+
:city, :zipcode, :country_id, :state_id, :state_name]
119119

120120
@@taxonomy_attributes = [:name]
121121

0 commit comments

Comments
 (0)