solidus_address_book 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +23 -0
- data/README.md +49 -0
- data/Rakefile +23 -0
- data/app/assets/javascripts/spree/frontend/solidus_address_book.js.erb +59 -0
- data/app/assets/stylesheets/spree/frontend/solidus_address_book.scss +92 -0
- data/app/controllers/spree/addresses_controller.rb +84 -0
- data/app/controllers/spree/checkout_controller_decorator.rb +65 -0
- data/app/helpers/spree/addresses_helper.rb +39 -0
- data/app/models/concerns/solidus_address_book/address.rb +18 -0
- data/app/models/concerns/solidus_address_book/permitted_attributes_concern.rb +11 -0
- data/app/models/permitted_attributes_decorator.rb +1 -0
- data/app/models/spree/address_ability.rb +15 -0
- data/app/models/spree/address_decorator.rb +83 -0
- data/app/models/spree/order_decorator.rb +109 -0
- data/app/models/spree/user_decorator.rb +11 -0
- data/app/overrides/add_address_book_to_my_account.rb +9 -0
- data/app/views/spree/addresses/_form.html.erb +114 -0
- data/app/views/spree/addresses/destroy.js.erb +2 -0
- data/app/views/spree/addresses/edit.html.erb +29 -0
- data/app/views/spree/addresses/new.html.erb +29 -0
- data/app/views/spree/checkout/_address.html.erb +75 -0
- data/app/views/spree/users/_addresses.html.erb +36 -0
- data/config/locales/de.yml +15 -0
- data/config/locales/en.yml +28 -0
- data/config/locales/pt-BR.yml +3 -0
- data/config/locales/ru.yml +13 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20110302102208_add_user_id_and_deleted_at_to_addresses.rb +13 -0
- data/db/migrate/20190619191704_add_label_to_addresses.rb +7 -0
- data/lib/generators/solidus_address_book/install_generator.rb +30 -0
- data/lib/solidus_address_book.rb +6 -0
- data/lib/solidus_address_book/configuration.rb +8 -0
- data/lib/solidus_address_book/engine.rb +24 -0
- data/lib/solidus_address_book/version.rb +5 -0
- metadata +354 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'discard'
|
4
|
+
|
5
|
+
module SolidusAddressBook
|
6
|
+
module Address
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
belongs_to :user, class_name: Spree.user_class.to_s
|
11
|
+
|
12
|
+
include Discard::Model
|
13
|
+
self.discard_column = :deleted_at
|
14
|
+
|
15
|
+
scope :with_deleted, -> { where.not(deleted_at: nil) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Spree::PermittedAttributes.singleton_class.prepend SolidusAddressBook::PermittedAttributesConcern
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Spree::AddressAbility
|
4
|
+
include CanCan::Ability
|
5
|
+
|
6
|
+
def initialize(user)
|
7
|
+
can :manage, Spree::Address do |address|
|
8
|
+
address.user == user
|
9
|
+
end
|
10
|
+
|
11
|
+
can :create, Spree::Address do |_address|
|
12
|
+
user.id.present?
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'discard'
|
4
|
+
|
5
|
+
module AddressDecorator
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
prepend(InstanceMethods)
|
10
|
+
|
11
|
+
include Discard::Model
|
12
|
+
self.discard_column = :deleted_at
|
13
|
+
|
14
|
+
def self.required_fields
|
15
|
+
Spree::Address.validators.map do |v|
|
16
|
+
v.kind_of?(ActiveModel::Validations::PresenceValidator) ? v.attributes : []
|
17
|
+
end.flatten
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.default(user = nil, kind = 'bill')
|
21
|
+
if user && user_address = user.public_send(:"#{kind}_address")
|
22
|
+
user_address.clone
|
23
|
+
else
|
24
|
+
build_default
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module InstanceMethods
|
30
|
+
# TODO: look into if this is actually needed. I don't want to override methods unless it is really needed
|
31
|
+
# can modify an address if it's not been used in an order
|
32
|
+
def same_as?(other)
|
33
|
+
return false if other.nil?
|
34
|
+
|
35
|
+
attributes.except('id', 'updated_at', 'created_at', 'user_id') == other.attributes.except('id', 'updated_at', 'created_at', 'user_id')
|
36
|
+
end
|
37
|
+
|
38
|
+
# can modify an address if it's not been used in an completed order
|
39
|
+
def editable?
|
40
|
+
new_record? || (Spree::Order.complete.where("bill_address_id = ? OR
|
41
|
+
ship_address_id = ? AND
|
42
|
+
state != 'complete' AND
|
43
|
+
shipment_state != 'shipped'", id, id).count == 0)
|
44
|
+
end
|
45
|
+
|
46
|
+
def can_be_deleted?
|
47
|
+
Spree::Order.where("bill_address_id = ? OR
|
48
|
+
ship_address_id = ? AND
|
49
|
+
state != 'complete' AND
|
50
|
+
shipment_state != 'shipped'", id, id).count == 0
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
[
|
55
|
+
full_name,
|
56
|
+
company.to_s,
|
57
|
+
address1.to_s,
|
58
|
+
address2.to_s,
|
59
|
+
"#{city}, #{state ? state.abbr : state_name} #{zipcode}",
|
60
|
+
country.to_s
|
61
|
+
].reject(&:empty?).join("<br/>").html_safe
|
62
|
+
end
|
63
|
+
|
64
|
+
# Remove readonly validation to be able to modify addresses over the flow
|
65
|
+
def readonly?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
# Use discard ability to not affect order created previously
|
70
|
+
def destroy
|
71
|
+
can_be_deleted? ? delete : discard
|
72
|
+
end
|
73
|
+
|
74
|
+
def check
|
75
|
+
attrs = attributes.except('id', 'updated_at', 'created_at')
|
76
|
+
the_same_address = user.addresses.where(attrs).first
|
77
|
+
the_same_address || self
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
Spree::Address.include(SolidusAddressBook::Address)
|
83
|
+
Spree::Address.include(AddressDecorator)
|
@@ -0,0 +1,109 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module OrderDecorator
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
prepend(InstanceMethods)
|
8
|
+
before_validation :clone_shipping_address
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceMethods
|
12
|
+
def clone_shipping_address
|
13
|
+
return unless SolidusAddressBook::Config[:disable_bill_address]
|
14
|
+
|
15
|
+
bill_address = ship_address if ship_address
|
16
|
+
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def clone_billing_address
|
21
|
+
if bill_address
|
22
|
+
ship_address = bill_address
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
def bill_address_id=(id)
|
28
|
+
address = Spree::Address.where(id: id).first
|
29
|
+
|
30
|
+
if address && address.user_id == user_id
|
31
|
+
self["bill_address_id"] = address.id
|
32
|
+
user.update_attribute(:bill_address_id, address.id)
|
33
|
+
bill_address.reload
|
34
|
+
else
|
35
|
+
self["bill_address_id"] = nil
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def bill_address_attributes=(attributes)
|
40
|
+
bill_address = update_or_create_address(attributes)
|
41
|
+
user.bill_address = bill_address if user
|
42
|
+
end
|
43
|
+
|
44
|
+
def ship_address_id=(id)
|
45
|
+
address = Spree::Address.where(id: id).first
|
46
|
+
|
47
|
+
if address && address.user_id == user_id
|
48
|
+
self["ship_address_id"] = address.id
|
49
|
+
user.update_attribute(:ship_address_id, address.id)
|
50
|
+
ship_address.reload
|
51
|
+
else
|
52
|
+
self["ship_address_id"] = nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def ship_address_attributes=(attributes)
|
57
|
+
ship_address = update_or_create_address(attributes)
|
58
|
+
user.ship_address = ship_address if user
|
59
|
+
end
|
60
|
+
|
61
|
+
def assign_default_addresses!
|
62
|
+
if user
|
63
|
+
bill_address = user.bill_address if !bill_address_id && user.bill_address.try(:valid?)
|
64
|
+
# Skip setting ship address if order doesn't have a delivery checkout step
|
65
|
+
# to avoid triggering validations on shipping address
|
66
|
+
ship_address = user.ship_address if !ship_address_id && user.ship_address.try(:valid?) && checkout_steps.include?("delivery")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def update_addresses_params
|
73
|
+
bill_address_attributes = @updating_params["order"].delete("bill_address_attributes")
|
74
|
+
bill_address_id = @updating_params["order"].delete("bill_address_id")
|
75
|
+
ship_address_attributes = @updating_params["order"].delete("ship_address_attributes")
|
76
|
+
ship_address_id = @updating_params["order"].delete("ship_address_id")
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_or_create_address(attributes = {})
|
80
|
+
return if attributes.blank?
|
81
|
+
|
82
|
+
if user
|
83
|
+
address = user.addresses.build(attributes.except(:id)).check
|
84
|
+
return address if address.id
|
85
|
+
end
|
86
|
+
|
87
|
+
if attributes[:id]
|
88
|
+
address = Spree::Address.find(attributes[:id])
|
89
|
+
attributes.delete(:id)
|
90
|
+
|
91
|
+
if address&.editable?
|
92
|
+
address.update_attributes(attributes)
|
93
|
+
return address
|
94
|
+
else
|
95
|
+
attributes.delete(:id)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if !attributes[:id]
|
100
|
+
address = Spree::Address.new(attributes)
|
101
|
+
address.save
|
102
|
+
end
|
103
|
+
|
104
|
+
address
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
Spree::Order.include(OrderDecorator)
|
@@ -0,0 +1,114 @@
|
|
1
|
+
<% address_id = address_type.chars.first %>
|
2
|
+
|
3
|
+
<div class="inner" data-hook=<%="#{address_type}_inner" %>>
|
4
|
+
<div class="field" id=<%="#{address_id}label" %>>
|
5
|
+
<%= address_form.label :label, t('spree.label') %>
|
6
|
+
<%= address_form.text_field :label, class: 'required', autocomplete: address_type + ' label', autofocus: true, placeholder: t('spree.placeholder.address.label') %>
|
7
|
+
</div>
|
8
|
+
|
9
|
+
<div class="field field-required" id=<%="#{address_id}firstname" %>>
|
10
|
+
<%= address_form.label :firstname, t('spree.first_name') %>
|
11
|
+
<%= address_form.text_field :firstname, class: 'required', autocomplete: address_type + ' given-name', required: true %>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div class="field" id=<%="#{address_id}lastname" %>>
|
15
|
+
<%= address_form.label :lastname, t('spree.last_name') %>
|
16
|
+
<%= address_form.text_field :lastname, autocomplete: address_type + ' family-name' %>
|
17
|
+
</div>
|
18
|
+
|
19
|
+
<% if Spree::Config[:company] %>
|
20
|
+
<div class="field" id=<%="#{address_id}company" %>>
|
21
|
+
<%= address_form.label :company, t('spree.company') %>
|
22
|
+
<%= address_form.text_field :company, autocomplete: address_type + ' organization' %>
|
23
|
+
</div>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<div class="field field-required" id=<%="#{address_id}address1" %>>
|
27
|
+
<%= address_form.label :address1, t('spree.street_address') %>
|
28
|
+
<%= address_form.text_field :address1, class: 'required', autocomplete: address_type + ' address-line1', required: true %>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<div class="field" id=<%="#{address_id}address2" %>>
|
32
|
+
<%= address_form.label :address2, I18n.t('spree.street_address_2') %>
|
33
|
+
<%= address_form.text_field :address2, autocomplete: address_type + ' address-line2' %>
|
34
|
+
</div>
|
35
|
+
|
36
|
+
<div class="field field-required" id=<%="#{address_id}city" %>>
|
37
|
+
<%= address_form.label :city, t('spree.city') %>
|
38
|
+
<%= address_form.text_field :city, class: 'required', autocomplete: address_type + ' address-level2', required: true %>
|
39
|
+
</div>
|
40
|
+
|
41
|
+
<div class="field field-required" id=<%="#{address_id}country" %>>
|
42
|
+
<%= address_form.label :country_id, t('spree.country') %>
|
43
|
+
<span id=<%="#{address_id}country-selection" %>>
|
44
|
+
<%= address_form.collection_select :country_id, available_countries, :id, :name, {},
|
45
|
+
class: 'required',
|
46
|
+
autocomplete: address_type + ' country-name',
|
47
|
+
required: true
|
48
|
+
%>
|
49
|
+
</span>
|
50
|
+
</div>
|
51
|
+
|
52
|
+
<% if Spree::Config[:address_requires_state] %>
|
53
|
+
<div class="field field-required" id=<%="#{address_id}state" %>>
|
54
|
+
<% have_states = !address.country.states.empty? %>
|
55
|
+
<%= address_form.label :state, t('spree.state') %>
|
56
|
+
|
57
|
+
<span class="js-address-fields" style="display: none;">
|
58
|
+
<%=
|
59
|
+
address_form.collection_select(
|
60
|
+
:state_id, address.country.states, :id, :name,
|
61
|
+
{include_blank: true},
|
62
|
+
{
|
63
|
+
class: have_states ? 'required' : '',
|
64
|
+
style: have_states ? '' : 'display: none;',
|
65
|
+
disabled: !have_states,
|
66
|
+
autocomplete: address_type + ' address-level1',
|
67
|
+
})
|
68
|
+
%>
|
69
|
+
<%=
|
70
|
+
address_form.text_field(
|
71
|
+
:state_name,
|
72
|
+
class: !have_states ? 'required' : '',
|
73
|
+
style: have_states ? 'display: none;' : '',
|
74
|
+
disabled: have_states,
|
75
|
+
autocomplete: address_type + ' address-level1',
|
76
|
+
)
|
77
|
+
%>
|
78
|
+
</span>
|
79
|
+
|
80
|
+
<noscript>
|
81
|
+
<%= address_form.text_field :state_name, class: 'required', autocomplete: address_type + ' address-level1', required: true %>
|
82
|
+
</noscript>
|
83
|
+
</div>
|
84
|
+
<% end %>
|
85
|
+
|
86
|
+
<div class="field <%= 'field-required' if address.require_zipcode? %>" id=<%="#{address_id}zipcode" %>>
|
87
|
+
<%= address_form.label :zipcode, t('spree.zip') %>
|
88
|
+
<%= address_form.text_field :zipcode, class: "#{'required' if address.require_zipcode?}", autocomplete: address_type + ' postal-code', required: true %>
|
89
|
+
</div>
|
90
|
+
|
91
|
+
<div class="field <%= 'field-required' if address.require_phone? %>" id=<%="#{address_id}phone" %>>
|
92
|
+
<%= address_form.label :phone, t('spree.phone') %>
|
93
|
+
<% phone_hash = address.require_phone? ? { class: 'required', required: true } : {} %>
|
94
|
+
<%= address_form.phone_field :phone, phone_hash.merge({ autocomplete: address_type + ' home tel' }) %>
|
95
|
+
</div>
|
96
|
+
|
97
|
+
<% if Spree::Config[:alternative_shipping_phone] %>
|
98
|
+
<div class="field" id=<%="#{address_id}altphone" %>>
|
99
|
+
<%= address_form.label :alternative_phone, t('spree.alternative_phone') %>
|
100
|
+
<%= address_form.phone_field :alternative_phone, autocomplete: address_type + ' tel'%>
|
101
|
+
</div>
|
102
|
+
<% end %>
|
103
|
+
|
104
|
+
<% if params[:controller] == 'spree/checkout' %>
|
105
|
+
<div class="field" id=<%="#{address_id}save" %>>
|
106
|
+
<p class="field checkbox" data-hook="save_user_address">
|
107
|
+
<%= label_tag :save_user_address, id: 'save_user_address' do %>
|
108
|
+
<%= check_box_tag 'save_user_address', '1' %>
|
109
|
+
<%= t('spree.save_address') %>
|
110
|
+
<% end %>
|
111
|
+
</p>
|
112
|
+
</div>
|
113
|
+
<% end %>
|
114
|
+
</div>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="col-md-6 col-md-offset-3">
|
2
|
+
<div class="panel panel-default">
|
3
|
+
<div class="panel-heading">
|
4
|
+
<h3 class="panel-title"><%= t(:edit_shipping_address, scope: :spree) %></h3>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<div class="panel-body">
|
8
|
+
<%= render 'spree/shared/error_messages', target: @address %>
|
9
|
+
|
10
|
+
<%= form_for @address, html: { id: 'checkout_form_address' } do |f| %>
|
11
|
+
<fieldset>
|
12
|
+
<div class="inner">
|
13
|
+
<%= render 'spree/addresses/form',
|
14
|
+
address_name: 'address',
|
15
|
+
address_form: f,
|
16
|
+
address_type: 'shipping',
|
17
|
+
address: @address
|
18
|
+
%>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<%= f.submit t('spree.update'), class: 'btn btn-primary' %>
|
22
|
+
<% if try_spree_current_user && respond_to?(:account_path) %>
|
23
|
+
<%= link_to t('spree.back_to_my_account'), spree.account_path, class: 'btn btn-primary' %>
|
24
|
+
<% end %>
|
25
|
+
</fieldset>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</div>
|
@@ -0,0 +1,29 @@
|
|
1
|
+
<div class="col-md-6 col-md-offset-3">
|
2
|
+
<div class="panel panel-default">
|
3
|
+
<div class="panel-heading">
|
4
|
+
<h3 class="panel-title"><%= t(:new_shipping_address, scope: :spree) %></h3>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<div class="panel-body">
|
8
|
+
<%= render 'spree/shared/error_messages', target: @address %>
|
9
|
+
|
10
|
+
<%= form_for @address, html: { id: 'checkout_form_address' } do |f| %>
|
11
|
+
<fieldset>
|
12
|
+
<div class="inner">
|
13
|
+
<%= render 'spree/addresses/form',
|
14
|
+
address_name: 'address',
|
15
|
+
address_form: f,
|
16
|
+
address_type: 'shipping',
|
17
|
+
address: @address
|
18
|
+
%>
|
19
|
+
</div>
|
20
|
+
|
21
|
+
<%= f.submit t('spree.save'), class: 'btn btn-primary' %>
|
22
|
+
<% if try_spree_current_user && respond_to?(:account_path) %>
|
23
|
+
<%= link_to t('spree.back_to_my_account'), spree.account_path, class: 'btn btn-primary' %>
|
24
|
+
<% end %>
|
25
|
+
</fieldset>
|
26
|
+
<% end %>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
</div>
|