Merge pull request #5976 from luisramos0/address_form

Fix address state selector and "use billing address" checkbox in order customer details page
This commit is contained in:
Luis Ramos
2020-09-23 12:42:37 +01:00
committed by GitHub
10 changed files with 202 additions and 97 deletions

View File

@@ -1,27 +1,17 @@
var update_state = function(region) {
var country = $('span#' + region + 'country .select2').select2('val');
var state_select = $('span#' + region + 'state select.select2');
var state_input = $('span#' + region + 'state input.state_name');
$.get(Spree.routes.states_search + "?country_id=" + country, function(data) {
var states = data["states"]
if (states.length > 0) {
state_select.html('');
var states_with_blank = [{name: '', id: ''}].concat(states);
$.each(states_with_blank, function(pos,state) {
var opt = $(document.createElement('option'))
.attr('value', state.id)
.html(state.name);
state_select.append(opt);
});
state_select.prop("disabled", false).show();
state_select.select2();
state_input.hide().prop("disabled", true);
} else {
state_input.prop("disabled", false).show();
state_select.select2('destroy').hide();
}
$.get(Spree.routes.states_search + "?country_id=" + country, function(states) {
state_select.html('');
var states_with_blank = [{name: '', id: ''}].concat(states);
$.each(states_with_blank, function(pos,state) {
var opt = $(document.createElement('option'))
.attr('value', state.id)
.html(state.name);
state_select.append(opt);
});
state_select.prop("disabled", false).show();
state_select.select2();
})
};

View File

@@ -0,0 +1,17 @@
$(document).ready(function() {
var order_use_billing_input = $('input#order_use_billing');
var order_use_billing = function () {
if (!order_use_billing_input.is(':checked')) {
$('#shipping').show();
} else {
$('#shipping').hide();
}
};
order_use_billing_input.click(function() {
order_use_billing();
});
order_use_billing();
});

View File

@@ -0,0 +1,44 @@
# frozen_string_literal: true
module Api
class StatesController < Api::BaseController
respond_to :json
skip_authorization_check
def index
render json: states, each_serializer: Api::StateSerializer, status: :ok
end
def show
@state = scope.find(params[:id])
render json: @state, serializer: Api::StateSerializer, status: :ok
end
private
def scope
if params[:country_id]
@country = Spree::Country.find(params[:country_id])
@country.states
else
Spree::State.all
end
end
def states
states = scope.ransack(params[:q]).result.
includes(:country).order('name ASC')
if pagination?
states = states.page(params[:page]).per(params[:per_page])
end
states
end
def pagination?
params[:page] || params[:per_page]
end
end
end

View File

@@ -1,3 +1,3 @@
class Api::StateSerializer < ActiveModel::Serializer
attributes :id, :name, :abbr
attributes :id, :name, :abbr, :country_id
end

View File

@@ -0,0 +1,45 @@
- if use_billing
.field{style: "position: absolute;margin-top: -15px;right: 0;"}
%span
= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address))
= label_tag 'order[use_billing]', Spree.t(:use_billing_address)
- is_shipping_address = name == Spree.t(:shipping_address)
- s_or_b = is_shipping_address ? 's' : 'b'
- display_style = (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address == @order.ship_address)) ? 'none' : 'block'
%div{id: "#{is_shipping_address ? 'shipping' : 'billing'}", style: "display: #{display_style}"}
%div{class: "field"}
= f.label :firstname, Spree.t(:first_name) + ':'
= f.text_field :firstname, class: 'fullwidth'
%div{class: "field"}
= f.label :lastname, Spree.t(:last_name) + ':'
= f.text_field :lastname, class: 'fullwidth'
- if Spree::Config[:company]
%div{class: "field"}
= f.label :company, Spree.t(:company) + ':'
= f.text_field :company, class: 'fullwidth'
%div{class: "field"}
= f.label :address1, Spree.t(:street_address) + ':'
= f.text_field :address1, class: 'fullwidth'
%div{class: "field"}
= f.label :address2, Spree.t(:street_address_2) + ':'
= f.text_field :address2, class: 'fullwidth'
%div{class: "field"}
= f.label :city, Spree.t(:city) + ':'
= f.text_field :city, class: 'fullwidth'
%div{class: "field"}
= f.label :zipcode, Spree.t(:zip) + ':'
= f.text_field :zipcode, class: 'fullwidth'
%div{class: "field"}
= f.label :country_id, Spree.t(:country) + ':'
%span{id: "#{s_or_b}country"}
= f.collection_select :country_id, available_countries, :id, :name, {}, {class: 'select2 fullwidth', onchange: "update_state('#{s_or_b}')"}
%div{class: "field"}
= f.label :state_id, Spree.t(:state) + ':'
%span{id: "#{s_or_b}state"}
= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {include_blank: true}, {class: 'select2 fullwidth', disabled: f.object.country.states.empty?}
%div{class: "field"}
= f.label :phone, Spree.t(:phone) + ':'
= f.phone_field :phone, class: 'fullwidth'

View File

@@ -11,13 +11,13 @@
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:billing_address)
= f.fields_for :bill_address do |ba_form|
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
= render :partial => 'address_form', :locals => { :f => ba_form, :name => Spree.t(:billing_address), :use_billing => false }
.omega.six.columns{"data-hook" => "ship_address_wrapper"}
%fieldset.no-border-bottom
%legend{:align => "center"}= Spree.t(:shipping_address)
= f.fields_for :ship_address do |sa_form|
= render :partial => 'spree/admin/shared/address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
= render :partial => 'address_form', :locals => { :f => sa_form, :name => Spree.t(:shipping_address), :use_billing => true }
.clear
@@ -26,3 +26,4 @@
- content_for :head do
= javascript_include_tag 'admin/spree/orders/address_states.js'
= javascript_include_tag 'admin/spree/orders/use_billing.js'

View File

@@ -1,72 +0,0 @@
<% if use_billing %>
<div class="field" style="position: absolute;margin-top: -15px;right: 0;">
<span data-hook="use_billing">
<%= check_box_tag 'order[use_billing]', '1', (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.same_as?(@order.ship_address)) %>
<%= label_tag 'order[use_billing]', Spree.t(:use_billing_address) %>
</span>
</div>
<% end %>
<% is_shipping_address = name == Spree.t(:shipping_address) %>
<% shipping_or_billing = is_shipping_address ? 'shipping' : 'billing' %>
<% s_or_b = is_shipping_address ? 's' : 'b' %>
<div id="<%= is_shipping_address ? 'shipping' : 'billing' %>" style="display: <%= (use_billing && (!(@order.bill_address.empty? && @order.ship_address.empty?) && @order.bill_address.eql?(@order.ship_address))) ? 'none' : 'block' %>" data-hook="address_fields">
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :firstname, Spree.t(:first_name) + ':' %>
<%= f.text_field :firstname, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :lastname, Spree.t(:last_name) + ':' %>
<%= f.text_field :lastname, :class => 'fullwidth' %>
</div>
<% if Spree::Config[:company] %>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :company, Spree.t(:company) + ':' %>
<%= f.text_field :company, :class => 'fullwidth' %>
</div>
<% end %>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :address1, Spree.t(:street_address) + ':' %>
<%= f.text_field :address1, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :address2, Spree.t(:street_address_2) + ':' %>
<%= f.text_field :address2, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :city, Spree.t(:city) + ':' %>
<%= f.text_field :city, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :zipcode, Spree.t(:zip) + ':' %>
<%= f.text_field :zipcode, :class => 'fullwidth' %>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :country_id, Spree.t(:country) + ':' %>
<span id="<%= s_or_b %>country">
<%= f.collection_select :country_id, available_countries, :id, :name, {}, {:class => 'select2 fullwidth'} %>
</span>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :state_id, Spree.t(:state) + ':' %>
<span id="<%= s_or_b %>state">
<%= f.text_field :state_name,
:style => "display: #{f.object.country.states.empty? ? 'block' : 'none' };",
:disabled => !f.object.country.states.empty?, :class => 'fullwidth state_name' %>
<%= f.collection_select :state_id, f.object.country.states.sort, :id, :name, {:include_blank => true}, {:class => 'select2 fullwidth', :style => "display: #{f.object.country.states.empty? ? 'none' : 'block' };", :disabled => f.object.country.states.empty?} %>
</span>
</div>
<div class="field <%= "#{shipping_or_billing}-row" %>">
<%= f.label :phone, Spree.t(:phone) + ':' %>
<%= f.phone_field :phone, :class => 'fullwidth' %>
</div>
</div>
<% content_for :head do %>
<%= javascript_tag do -%>
$(document).ready(function(){
$('span#<%= s_or_b %>country .select2').on('change', function() { update_state('<%= s_or_b %>'); });
});
<% end -%>
<% end %>

View File

@@ -2,6 +2,7 @@
Spree.routes = <%== {
:variants_search => spree.admin_search_variants_path(:format => 'json'),
:taxons_search => main_app.api_taxons_path(:format => 'json'),
:orders_api => main_app.api_orders_path
:orders_api => main_app.api_orders_path,
:states_search => main_app.api_states_path(:format => 'json')
}.to_json %>;
</script>

View File

@@ -62,6 +62,8 @@ Openfoodnetwork::Application.routes.draw do
post '/product_images/:product_id', to: 'product_images#update_product_image'
resources :states, :only => [:index, :show]
resources :taxons, :only => [:index]
resources :taxonomies do

View File

@@ -0,0 +1,77 @@
# frozen_string_literal: true
require 'spec_helper'
module Api
describe StatesController do
render_views
let!(:state) { create(:state, name: "Victoria") }
let(:attributes) { [:id, :name, :abbr, :country_id] }
let(:current_user) { create(:user) }
before do
allow(controller).to receive(:spree_current_user) { current_user }
end
it "gets all states" do
api_get :index
expect(json_response.first.symbolize_keys.keys).to include(*attributes)
expect(json_response.map { |state| state[:name] }).to include(state.name)
end
context "pagination" do
before do
expect(Spree::State).to receive(:all).and_return(@scope = double)
allow(@scope).to receive_message_chain(:ransack, :result, :includes, :order).and_return(@scope)
end
it "does not paginate states results when asked not to do so" do
expect(@scope).not_to receive(:page)
expect(@scope).not_to receive(:per)
api_get :index
end
it "paginates when page parameter is passed through" do
expect(@scope).to receive(:page).with(1).and_return(@scope)
expect(@scope).to receive(:per).with(nil)
api_get :index, page: 1
end
it "paginates when per_page parameter is passed through" do
expect(@scope).to receive(:page).with(nil).and_return(@scope)
expect(@scope).to receive(:per).with(25)
api_get :index, per_page: 25
end
end
context "with two states" do
before { create(:state, name: "New South Wales") }
it "gets all states for a country" do
country = create(:country, states_required: true)
state.country = country
state.save
api_get :index, country_id: country.id
expect(json_response.first.symbolize_keys.keys).to include(*attributes)
expect(json_response.count).to eq 1
end
it "can view all states" do
api_get :index
expect(json_response.first.symbolize_keys.keys).to include(*attributes)
end
it 'can query the results through a paramter' do
api_get :index, q: { name_cont: 'Vic' }
expect(json_response.first['name']).to eq("Victoria")
end
end
it "can view a state" do
api_get :show, id: state.id
expect(json_response.symbolize_keys.keys).to include(*attributes)
end
end
end