diff --git a/api/lib/spree/api_configuration.rb b/api/lib/spree/api_configuration.rb index 87736c59c2..974a2c3a31 100644 --- a/api/lib/spree/api_configuration.rb +++ b/api/lib/spree/api_configuration.rb @@ -127,8 +127,8 @@ def promotion_attributes=(value) preference :store_attributes, :array, default: [ :id, :name, :legal_name, :url, :meta_description, :meta_keywords, :seo_title, :mail_from_address, :default_currency, :code, :default, - :bcc_email, :contact_phone, :contact_email, :tax_id, :vat_id, :description, - :address1, :address2, :city, :postal_code, :country_id, :state_id, :state_name, :available_locales + :bcc_email, :phone, :contact_email, :tax_id, :vat_id, :description, + :address1, :address2, :city, :zipcode, :country_id, :state_id, :state_name, :available_locales ] preference :store_credit_history_attributes, :array, default: [ diff --git a/api/spec/requests/spree/api/stores_spec.rb b/api/spec/requests/spree/api/stores_spec.rb index da2d2924e6..3d87a17f3e 100644 --- a/api/spec/requests/spree/api/stores_spec.rb +++ b/api/spec/requests/spree/api/stores_spec.rb @@ -4,6 +4,10 @@ module Spree::Api describe 'Stores', type: :request do + let(:country) { create :country, states_required: true } + let(:state) { create :state, name: 'maryland', abbr: 'md', country: } + let!(:base_attributes) { Spree::Api::Config.store_attributes } + let!(:store) do create(:store, name: "My Spree Store", url: "spreestore.example.com") end @@ -22,6 +26,60 @@ module Spree::Api default: false) end + let(:country_with_states) { create(:country, states: [create(:state)]) } + let(:country_without_states) { create(:country) } + + describe "Validations" do + context "when the country has states" do + it "is invalid without a state" do + store = Spree::Store.new(name: "Test Store", country: country_with_states, state: nil, url: "spreestore.example.com", + mail_from_address: "spreestore.example.com", code: "test-store",) + expect(store).not_to be_valid + expect(store.errors[:state]).to include("can't be blank") + end + + it "is valid with a state" do + store = Spree::Store.new(name: "Test Store", country: country_with_states, state: state, url: "spreestore.example.com", + mail_from_address: "spreestore.example.com", code: "test-store",) + expect(store).to be_valid + end + end + + context "when the country has no states" do + it "is valid without a state" do + store = Spree::Store.new(name: "Test Store", country: country_without_states, state: nil, url: "spreestore.example.com", + mail_from_address: "spreestore.example.com", code: "test-store",) + expect(store).to be_valid + end + end + + it "is valid without an address and without country/state" do + expect(store).to be_valid + end + + it "is valid with only correct country and state" do + store = Spree::Store.create!( + name: "Test Store", + url: "spreestore.example.com", + mail_from_address: "spreestore.example.com", + code: "test-store", + address1: "123 Main St", + city: "New York", + zipcode: "10001", + country: country, + ) + expect(store).to be_valid + end + end + + describe "#index" do + it "ensures the API store attributes match the expected attributes" do + get spree.api_stores_path + first_store = json_response["stores"].first + expect(first_store.keys).to include(*base_attributes.map(&:to_s)) + end + end + it "can list the available stores" do get spree.api_stores_path expect(json_response["stores"]).to match_array([ @@ -39,15 +97,15 @@ module Spree::Api "default" => true, "available_locales" => ["en"], "legal_name" => nil, - "contact_phone" => nil, "contact_email" => nil, "description" => nil, + "phone" => nil, "tax_id" => nil, "vat_id" => nil, "address1" => nil, "address2" => nil, "city" => nil, - "postal_code" => nil, + "zipcode" => nil, "country_id" => nil, "state_id" => nil, "state_name" => nil @@ -66,15 +124,15 @@ module Spree::Api "default" => false, "available_locales" => ["en"], "legal_name" => nil, - "contact_phone" => nil, "contact_email" => nil, "description" => nil, + "phone" => nil, "tax_id" => nil, "vat_id" => nil, "address1" => nil, "address2" => nil, "city" => nil, - "postal_code" => nil, + "zipcode" => nil, "country_id" => nil, "state_id" => nil, "state_name" => nil @@ -98,15 +156,15 @@ module Spree::Api "default" => true, "available_locales" => ["en"], "legal_name" => nil, - "contact_phone" => nil, "contact_email" => nil, "description" => nil, + "phone" => nil, "tax_id" => nil, "vat_id" => nil, "address1" => nil, "address2" => nil, "city" => nil, - "postal_code" => nil, + "zipcode" => nil, "country_id" => nil, "state_id" => nil, "state_name" => nil @@ -118,7 +176,14 @@ module Spree::Api code: "spree123", name: "Hack0rz", url: "spree123.example.com", - mail_from_address: "me@example.com" + mail_from_address: "me@example.com", + legal_name: 'ABC Corp', + address1: "123 Main St", + city: 'San Francisco', + country_id: country.id, + state_id: state.id, + phone: "123-456-7890", + zipcode: "12345" } post spree.api_stores_path, params: { store: store_hash } expect(response.status).to eq(201) @@ -128,13 +193,34 @@ module Spree::Api store_hash = { url: "spree123.example.com", mail_from_address: "me@example.com", - bcc_email: "bcc@example.net" + bcc_email: "bcc@example.net", + legal_name: 'XYZ Corp', + description: "Leading provider of high-quality tech accessories, offering the latest gadgets, peripherals, and electronics to enhance your digital lifestyle.", + tax_id: "TX-987654321", + vat_id: "VAT-123456789", + address1: "123 Innovation Drive", + address2: "Suite 456", + city: "New York", + country_id: country.id, + state_id: state.id, + phone: "123-456-7888", + zipcode: "10001" } put spree.api_store_path(store), params: { store: store_hash } expect(response.status).to eq(200) expect(store.reload.url).to eql "spree123.example.com" expect(store.reload.mail_from_address).to eql "me@example.com" expect(store.reload.bcc_email).to eql "bcc@example.net" + expect(store.reload.legal_name).to eql "XYZ Corp" + expect(store.reload.tax_id).to eql "TX-987654321" + expect(store.reload.vat_id).to eql "VAT-123456789" + expect(store.reload.address1).to eql "123 Innovation Drive" + expect(store.reload.address2).to eql "Suite 456" + expect(store.reload.city).to eql "New York" + expect(store.reload.country_id).to eql country.id + expect(store.reload.state_id).to eql state.id + expect(store.reload.phone).to eql "123-456-7888" + expect(store.reload.zipcode).to eql "10001" end context "deleting a store" do diff --git a/backend/app/views/spree/admin/stores/_address_form.html.erb b/backend/app/views/spree/admin/stores/_address_form.html.erb new file mode 100644 index 0000000000..99bff9af55 --- /dev/null +++ b/backend/app/views/spree/admin/stores/_address_form.html.erb @@ -0,0 +1,65 @@ + +<% s_or_b = type.chars.first %> +
+ +
+
+
"> + <%= f.label :legal_name %> + <%= f.text_field :legal_name, class: 'fullwidth' %> +
+ +
"> + <%= f.label :address1 %> + <%= f.text_field :address1, class: 'fullwidth' %> +
+ +
"> + <%= f.label :address2 %> + <%= f.text_field :address2, class: 'fullwidth' %> +
+ +
"> + <%= f.label :phone %> + <%= f.phone_field :phone, class: 'fullwidth' %> +
+
+ +
+
"> + <%= f.label :city %> + <%= f.text_field :city, class: 'fullwidth' %> +
+ +
"> + <%= f.label :zipcode %> + <%= f.text_field :zipcode, class: 'fullwidth' %> +
+ +
"> + <%= f.label :country_id, Spree::Country.model_name.human %> + + <%= f.collection_select :country_id, available_countries, :id, :name, { include_blank: true }, {class: 'custom-select fullwidth js-country_id'} %> + +
+ +
"> + <%= f.label :state_id, Spree::State.model_name.human %> + + <%= f.hidden_field :state_name, value: nil %> + <% states = f.object.country.try(:states).nil? ? [] : f.object.country.states %> + <%= f.text_field :state_name, + style: "display: #{states.empty? ? 'block' : 'none' };", + disabled: !states.empty?, class: 'fullwidth state_name js-state_name' %> + <%= f.hidden_field :state_id, value: nil %> + <%= f.collection_select :state_id, + states.sort, + :id, :name, + { include_blank: true }, + { class: 'custom-select fullwidth js-state_id', + style: "display: #{states.empty? ? 'none' : 'block' };", + disabled: states.empty? } %> + +
+
+
diff --git a/backend/app/views/spree/admin/stores/_form.html.erb b/backend/app/views/spree/admin/stores/_form.html.erb index 98a52a079d..9cb0fbf105 100644 --- a/backend/app/views/spree/admin/stores/_form.html.erb +++ b/backend/app/views/spree/admin/stores/_form.html.erb @@ -1,4 +1,4 @@ -
+
<%= f.field_container :name do %> <%= f.label :name, class: 'required' %> @@ -31,18 +31,6 @@ <%= f.error_message_on :meta_description %> <% end %> - <%= f.field_container :legal_name do %> - <%= f.label :legal_name %> - <%= f.text_field :legal_name, class: 'fullwidth' %> - <%= f.error_message_on :legal_name %> - <% end %> - - <%= f.field_container :contact_phone do %> - <%= f.label :contact_phone %> - <%= f.phone_field :contact_phone, class: 'fullwidth' %> - <%= f.error_message_on :contact_phone %> - <% end %> - <%= f.field_container :tax_id do %> <%= f.label :tax_id %> <%= f.text_field :tax_id, class: 'fullwidth' %> @@ -108,62 +96,16 @@ <%= f.error_message_on :default_currency %> <% end %> - <%= f.field_container :contact_email do %> - <%= f.label :contact_email %> - <%= f.email_field :contact_email, class: 'fullwidth' %> - <%= f.error_message_on :contact_email %> - <% end %> - <%= f.field_container :description do %> <%= f.label :description %> - <%= f.text_area :description, class: 'fullwidth', rows: 6 %> + <%= f.text_area :description, class: 'fullwidth' %> <%= f.error_message_on :description %> <% end %>
- <%= f.label :address %> -
-
- <%= f.field_container :address1 do %> - <%= f.label :address1 %> - <%= f.text_field :address1, class: 'fullwidth' %> - <% end %> -
-
- <%= f.field_container :address2 do %> - <%= f.label :address2 %> - <%= f.text_field :address2, class: 'fullwidth' %> - <% end %> -
-
- <%= f.field_container :city do %> - <%= f.label :city %> - <%= f.text_field :city, class: 'fullwidth' %> - <% end %> -
-
- <%= f.field_container :postal_code do %> - <%= f.label :postal_code %> - <%= f.text_field :postal_code, class: 'fullwidth' %> - <% end %> -
-
- <%= f.field_container :country_id do %> - <%= f.label :country_id %> - <%= f.collection_select :country_id, available_countries(restrict_to_zone: nil), :id, :name, { include_blank: true }, { class: 'custom-select js-country_id fullwidth' } %> - <% end %> -
-
- <%= f.field_container :state do %> - <% country = f.object.country %> - <%= f.label :state_id %> - - <%= f.text_field :state_name, style: "display: none", class: 'fullwidth state_name js-state_name' %> - <%= f.collection_select :state_id, country ? country.states.sort : [], :id, :name, { include_blank: true }, {class: 'custom-select fullwidth js-state_id', style: "display: none" } %> - - <% end %> -
+
+ <%= render partial: 'address_form', locals: { f: f, type: 'store' } %>
diff --git a/core/app/models/spree/store.rb b/core/app/models/spree/store.rb index 4ca3d4df93..d4c04a9ddb 100644 --- a/core/app/models/spree/store.rb +++ b/core/app/models/spree/store.rb @@ -24,6 +24,7 @@ class Store < Spree::Base validates :name, presence: true validates :url, presence: true validates :mail_from_address, presence: true + validates :state, presence: true, if: -> { country&.states&.exists? } self.allowed_ransackable_attributes = %w[name url code] diff --git a/core/db/migrate/20250202173007_add_store_attributes_to_spree_stores.rb b/core/db/migrate/20250202173007_add_store_attributes_to_spree_stores.rb index bea37b9329..48c75da67b 100644 --- a/core/db/migrate/20250202173007_add_store_attributes_to_spree_stores.rb +++ b/core/db/migrate/20250202173007_add_store_attributes_to_spree_stores.rb @@ -1,7 +1,6 @@ class AddStoreAttributesToSpreeStores < ActiveRecord::Migration[7.2] def change add_column :spree_stores, :legal_name, :string - add_column :spree_stores, :contact_phone, :string add_column :spree_stores, :contact_email, :string add_column :spree_stores, :description, :text add_column :spree_stores, :vat_id, :string @@ -9,8 +8,9 @@ def change add_column :spree_stores, :address1, :string add_column :spree_stores, :address2, :string add_column :spree_stores, :city, :string - add_column :spree_stores, :postal_code, :string + add_column :spree_stores, :zipcode, :string add_column :spree_stores, :state_name, :string + add_column :spree_stores, :phone, :string add_reference :spree_stores, :country, foreign_key: { to_table: :spree_countries }, index: true add_reference :spree_stores, :state, foreign_key: { to_table: :spree_states }, index: true end diff --git a/core/lib/spree/permitted_attributes.rb b/core/lib/spree/permitted_attributes.rb index 4ba54749a2..6047c62d16 100644 --- a/core/lib/spree/permitted_attributes.rb +++ b/core/lib/spree/permitted_attributes.rb @@ -113,9 +113,9 @@ module PermittedAttributes @@store_attributes = [:name, :legal_name, :url, :seo_title, :meta_keywords, :meta_description, :default_currency, :mail_from_address, :cart_tax_country_iso, - :bcc_email, :contact_email, :contact_phone, :code, + :bcc_email, :contact_email, :phone, :code, :tax_id, :vat_id, :description, :address1, :address2, - :city, :postal_code, :country_id, :state_id, :state_name] + :city, :zipcode, :country_id, :state_id, :state_name] @@taxonomy_attributes = [:name]