shoppe 1.1.1 → 1.1.2
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 +4 -4
- data/README.md +6 -0
- data/app/assets/stylesheets/shoppe/application.scss +15 -4
- data/app/controllers/shoppe/application_controller.rb +2 -2
- data/app/controllers/shoppe/customers_controller.rb +10 -12
- data/app/models/shoppe/address.rb +14 -14
- data/app/models/shoppe/attachment.rb +9 -9
- data/app/models/shoppe/country.rb +14 -14
- data/app/models/shoppe/customer.rb +11 -8
- data/app/models/shoppe/delivery_service.rb +10 -10
- data/app/models/shoppe/delivery_service_price.rb +15 -15
- data/app/models/shoppe/order.rb +12 -9
- data/app/models/shoppe/order/actions.rb +15 -15
- data/app/models/shoppe/order/billing.rb +10 -10
- data/app/models/shoppe/order/delivery.rb +13 -13
- data/app/models/shoppe/order/states.rb +20 -20
- data/app/models/shoppe/order_item.rb +10 -10
- data/app/models/shoppe/payment.rb +7 -7
- data/app/models/shoppe/product.rb +24 -24
- data/app/models/shoppe/product/product_attributes.rb +5 -5
- data/app/models/shoppe/product/variants.rb +3 -3
- data/app/models/shoppe/product_attribute.rb +20 -20
- data/app/models/shoppe/product_category.rb +6 -6
- data/app/models/shoppe/setting.rb +13 -13
- data/app/models/shoppe/stock_level_adjustment.rb +5 -5
- data/app/models/shoppe/tax_rate.rb +16 -16
- data/app/models/shoppe/user.rb +13 -13
- data/app/uploaders/shoppe/attachment_uploader.rb +0 -1
- data/app/views/shoppe/customers/_addresses.html.haml +5 -5
- data/app/views/shoppe/customers/_form.html.haml +17 -10
- data/app/views/shoppe/customers/_search_form.html.haml +5 -5
- data/app/views/shoppe/customers/edit.html.haml +4 -4
- data/app/views/shoppe/customers/index.html.haml +11 -11
- data/app/views/shoppe/customers/new.html.haml +3 -3
- data/app/views/shoppe/customers/show.html.haml +11 -12
- data/app/views/shoppe/product_categories/index.html.haml +3 -2
- data/app/views/shoppe/variants/form.html.haml +0 -1
- data/config/locales/de.yml +58 -7
- data/config/locales/en.yml +38 -4
- data/config/locales/es-US.yml +656 -0
- data/config/locales/es.yml +372 -281
- data/config/locales/ru.yml +781 -0
- data/db/seeds.rb +113 -98
- data/lib/shoppe.rb +10 -10
- data/lib/shoppe/version.rb +1 -1
- metadata +22 -6
@@ -13,25 +13,25 @@ module Shoppe
|
|
13
13
|
self.table_name = 'shoppe_product_categories'
|
14
14
|
|
15
15
|
# Attachments for this product category
|
16
|
-
has_many :attachments, :
|
16
|
+
has_many :attachments, as: :parent, dependent: :destroy, class_name: "Shoppe::Attachment"
|
17
17
|
|
18
18
|
# All products within this category
|
19
19
|
has_many :product_categorizations, dependent: :restrict_with_exception, class_name: 'Shoppe::ProductCategorization', inverse_of: :product_category
|
20
20
|
has_many :products, class_name: 'Shoppe::Product', through: :product_categorizations
|
21
21
|
|
22
22
|
# Validations
|
23
|
-
validates :name, :
|
24
|
-
validates :permalink, :
|
23
|
+
validates :name, presence: true
|
24
|
+
validates :permalink, presence: true, uniqueness: { scope: :parent_id }, permalink: true
|
25
25
|
|
26
26
|
# Root (no parent) product categories only
|
27
27
|
scope :without_parent, -> { where(parent_id: nil) }
|
28
28
|
|
29
|
-
# No
|
29
|
+
# No descendants
|
30
30
|
scope :except_descendants, ->(record) { where.not(id: (Array.new(record.descendants) << record).flatten) }
|
31
31
|
|
32
32
|
translates :name, :permalink, :description
|
33
33
|
scope :ordered, -> { includes(:translations).order(:name) }
|
34
|
-
|
34
|
+
|
35
35
|
# Set the permalink on callback
|
36
36
|
before_validation :set_permalink, :set_ancestral_permalink
|
37
37
|
after_save :set_child_permalinks
|
@@ -56,7 +56,7 @@ module Shoppe
|
|
56
56
|
end
|
57
57
|
|
58
58
|
# Attachment with the role image
|
59
|
-
#
|
59
|
+
#
|
60
60
|
# @return [String]
|
61
61
|
def image
|
62
62
|
self.attachments.for("image")
|
@@ -2,17 +2,17 @@ require 'ostruct'
|
|
2
2
|
|
3
3
|
module Shoppe
|
4
4
|
class Setting < ActiveRecord::Base
|
5
|
-
|
5
|
+
|
6
6
|
# Validations
|
7
|
-
validates :key, :
|
8
|
-
validates :value, :
|
9
|
-
validates :value_type, :
|
10
|
-
|
7
|
+
validates :key, presence: true, uniqueness: true
|
8
|
+
validates :value, presence: true
|
9
|
+
validates :value_type, presence: true
|
10
|
+
|
11
11
|
before_validation do
|
12
12
|
self.value_type = I18n.t("shoppe.settings.types")[self.key.to_sym].try(:capitalize) || self.value.class.to_s
|
13
13
|
self.value = encoded_value
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
# The encoded value for saving in the backend (as a string)
|
17
17
|
#
|
18
18
|
# @return [String]
|
@@ -23,7 +23,7 @@ module Shoppe
|
|
23
23
|
else value.to_s
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# The decoded value for the setting attribute (in it's native type)
|
28
28
|
#
|
29
29
|
# @return [Object]
|
@@ -36,7 +36,7 @@ module Shoppe
|
|
36
36
|
else value.to_s
|
37
37
|
end
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
# A full hash of all settings available in the current scope
|
41
41
|
#
|
42
42
|
# @return [Hash]
|
@@ -46,8 +46,8 @@ module Shoppe
|
|
46
46
|
h
|
47
47
|
end
|
48
48
|
end
|
49
|
-
|
50
|
-
# Update settings from a given hash and persist them. Accepts a
|
49
|
+
|
50
|
+
# Update settings from a given hash and persist them. Accepts a
|
51
51
|
# hash of keys (which should be strings).
|
52
52
|
#
|
53
53
|
# @return [Hash]
|
@@ -56,13 +56,13 @@ module Shoppe
|
|
56
56
|
hash.each do |key, value|
|
57
57
|
existing = existing_settings.select { |s| s.key.to_s == key.to_s }.first
|
58
58
|
if existing
|
59
|
-
value.blank? ? existing.destroy! : existing.update!(:
|
59
|
+
value.blank? ? existing.destroy! : existing.update!(value: value)
|
60
60
|
else
|
61
|
-
value.blank? ? nil : self.create!(:
|
61
|
+
value.blank? ? nil : self.create!(key: key, value: value)
|
62
62
|
end
|
63
63
|
end
|
64
64
|
hash
|
65
65
|
end
|
66
|
-
|
66
|
+
|
67
67
|
end
|
68
68
|
end
|
@@ -2,18 +2,18 @@ module Shoppe
|
|
2
2
|
class StockLevelAdjustment < ActiveRecord::Base
|
3
3
|
|
4
4
|
# The orderable item which the stock level adjustment belongs to
|
5
|
-
belongs_to :item, :
|
5
|
+
belongs_to :item, polymorphic: true
|
6
6
|
|
7
7
|
# The parent (OrderItem) which the stock level adjustment belongs to
|
8
|
-
belongs_to :parent, :
|
8
|
+
belongs_to :parent, polymorphic: true
|
9
9
|
|
10
10
|
# Validations
|
11
|
-
validates :description, :
|
12
|
-
validates :adjustment, :
|
11
|
+
validates :description, presence: true
|
12
|
+
validates :adjustment, numericality: true
|
13
13
|
validate { errors.add(:adjustment, I18n.t('shoppe.activerecord.attributes.stock_level_adjustment.must_be_greater_or_equal_zero')) if adjustment == 0 }
|
14
14
|
|
15
15
|
# All stock level adjustments ordered by their created date desending
|
16
|
-
scope :ordered, -> { order(:
|
16
|
+
scope :ordered, -> { order(id: :desc) }
|
17
17
|
|
18
18
|
end
|
19
19
|
end
|
@@ -1,37 +1,37 @@
|
|
1
1
|
module Shoppe
|
2
2
|
class TaxRate < ActiveRecord::Base
|
3
|
-
|
3
|
+
|
4
4
|
self.table_name = 'shoppe_tax_rates'
|
5
|
-
|
5
|
+
|
6
6
|
include Shoppe::AssociatedCountries
|
7
|
-
|
7
|
+
|
8
8
|
# The order address types which may be used when choosing how to apply the tax rate
|
9
9
|
ADDRESS_TYPES = ['billing', 'delivery']
|
10
|
-
|
10
|
+
|
11
11
|
# Validations
|
12
|
-
validates :name, :
|
13
|
-
validates :address_type, :
|
14
|
-
validates :rate, :
|
15
|
-
|
12
|
+
validates :name, presence: true
|
13
|
+
validates :address_type, inclusion: {in: ADDRESS_TYPES}
|
14
|
+
validates :rate, numericality: true
|
15
|
+
|
16
16
|
# All products which are assigned to this tax rate
|
17
|
-
has_many :products, :
|
18
|
-
|
17
|
+
has_many :products, dependent: :restrict_with_exception, class_name: 'Shoppe::Product'
|
18
|
+
|
19
19
|
# All delivery service prices which are assigned to this tax rate
|
20
|
-
has_many :delivery_service_prices, :
|
21
|
-
|
20
|
+
has_many :delivery_service_prices, dependent: :restrict_with_exception, class_name: 'Shoppe::DeliveryServicePrice'
|
21
|
+
|
22
22
|
# All tax rates ordered by their ID
|
23
23
|
scope :ordered, -> { order(:id)}
|
24
|
-
|
24
|
+
|
25
25
|
# Set the address type if appropriate
|
26
26
|
before_validation { self.address_type = ADDRESS_TYPES.first if self.address_type.blank? }
|
27
|
-
|
27
|
+
|
28
28
|
# A description of the tax rate including its name & percentage
|
29
29
|
#
|
30
30
|
# @return [String]
|
31
31
|
def description
|
32
32
|
"#{name} (#{rate}%)"
|
33
33
|
end
|
34
|
-
|
34
|
+
|
35
35
|
# The rate for a given order based on the rules on the tax rate
|
36
36
|
#
|
37
37
|
# @return [BigDecimal]
|
@@ -41,6 +41,6 @@ module Shoppe
|
|
41
41
|
return rate if address_type == 'delivery' && (order.delivery_country.nil? || country?(order.delivery_country))
|
42
42
|
BigDecimal(0)
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
end
|
46
46
|
end
|
data/app/models/shoppe/user.rb
CHANGED
@@ -2,48 +2,48 @@ module Shoppe
|
|
2
2
|
class User < ActiveRecord::Base
|
3
3
|
|
4
4
|
self.table_name = 'shoppe_users'
|
5
|
-
|
5
|
+
|
6
6
|
has_secure_password
|
7
|
-
|
7
|
+
|
8
8
|
# Validations
|
9
|
-
validates :first_name, :
|
10
|
-
validates :last_name, :
|
11
|
-
validates :email_address, :
|
12
|
-
|
9
|
+
validates :first_name, presence: true
|
10
|
+
validates :last_name, presence: true
|
11
|
+
validates :email_address, presence: true
|
12
|
+
|
13
13
|
# The user's first name & last name concatenated
|
14
14
|
#
|
15
15
|
# @return [String]
|
16
16
|
def full_name
|
17
17
|
"#{first_name} #{last_name}"
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# The user's first name & initial of last name concatenated
|
21
21
|
#
|
22
22
|
# @return [String]
|
23
23
|
def short_name
|
24
24
|
"#{first_name} #{last_name[0,1]}"
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
# Reset the user's password to something random and e-mail it to them
|
28
28
|
def reset_password!
|
29
29
|
self.password = SecureRandom.hex(8)
|
30
30
|
self.password_confirmation = self.password
|
31
31
|
self.save!
|
32
|
-
Shoppe::UserMailer.new_password(self).
|
32
|
+
Shoppe::UserMailer.new_password(self).deliver
|
33
33
|
end
|
34
|
-
|
35
|
-
# Attempt to authenticate a user based on email & password. Returns the
|
34
|
+
|
35
|
+
# Attempt to authenticate a user based on email & password. Returns the
|
36
36
|
# user if successful otherwise returns false.
|
37
37
|
#
|
38
38
|
# @param email_address [String]
|
39
39
|
# @param paassword [String]
|
40
40
|
# @return [Shoppe::User]
|
41
41
|
def self.authenticate(email_address, password)
|
42
|
-
user = self.where(:
|
42
|
+
user = self.where(email_address: email_address).first
|
43
43
|
return false if user.nil?
|
44
44
|
return false unless user.authenticate(password)
|
45
45
|
user
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
end
|
49
49
|
end
|
@@ -3,18 +3,18 @@
|
|
3
3
|
%table.data
|
4
4
|
%thead
|
5
5
|
%tr
|
6
|
-
%th
|
7
|
-
%th
|
8
|
-
%th
|
6
|
+
%th= t('shoppe.customers.type')
|
7
|
+
%th= t('shoppe.customers.default')
|
8
|
+
%th= t('shoppe.custoemrs.address')
|
9
9
|
%th
|
10
10
|
%tbody
|
11
11
|
- if @addresses.empty?
|
12
12
|
%tr.empty
|
13
|
-
%td{:colspan => 4}
|
13
|
+
%td{:colspan => 4}= t('shoppe.customers.no_addresses')
|
14
14
|
- else
|
15
15
|
- for address in @addresses
|
16
16
|
%tr
|
17
17
|
%td= address.address_type.capitalize
|
18
18
|
%td= boolean_tag address.default
|
19
19
|
%td= address.full_address
|
20
|
-
%td= link_to
|
20
|
+
%td= link_to t('shoppe.customers.edit'), edit_customer_address_path(@customer, address)
|
@@ -1,30 +1,37 @@
|
|
1
1
|
= form_for @customer do |f|
|
2
2
|
= f.error_messages
|
3
3
|
|
4
|
-
= field_set_tag
|
4
|
+
= field_set_tag t('shoppe.customers.customer_information') do
|
5
5
|
.splitContainer
|
6
6
|
%dl.third
|
7
|
-
%dt= f.label :first_name
|
7
|
+
%dt= f.label :first_name, t('shoppe.customers.first_name')
|
8
8
|
%dd= f.text_field :first_name, :class => "text focus"
|
9
9
|
%dl.third
|
10
|
-
%dt= f.label :last_name
|
10
|
+
%dt= f.label :last_name, t('shoppe.customers.last_name')
|
11
11
|
%dd= f.text_field :last_name, :class => "text"
|
12
12
|
%dl.third
|
13
|
-
%dt= f.label :company
|
13
|
+
%dt= f.label :company, t('shoppe.customers.company')
|
14
14
|
%dd= f.text_field :company, :class => "text"
|
15
15
|
.splitContainer
|
16
16
|
%dl.third
|
17
|
-
%dt= f.label :email
|
17
|
+
%dt= f.label :email, t('shoppe.customers.email')
|
18
18
|
%dd= f.text_field :email, :class => "text"
|
19
19
|
%dl.third
|
20
|
-
%dt= f.label :phone
|
20
|
+
%dt= f.label :phone, t('shoppe.customers.phone')
|
21
21
|
%dd= f.text_field :phone, :class => "text"
|
22
22
|
%dl.third
|
23
|
-
%dt= f.label :mobile
|
23
|
+
%dt= f.label :mobile, t('shoppe.customers.mobile_phone')
|
24
24
|
%dd= f.text_field :mobile, :class => "text"
|
25
25
|
|
26
26
|
%p.submit
|
27
27
|
- unless @customer.new_record?
|
28
|
-
%span.right
|
29
|
-
|
30
|
-
|
28
|
+
%span.right
|
29
|
+
= link_to t('shoppe.customers.delete'),
|
30
|
+
@customer,
|
31
|
+
class: 'button purple',
|
32
|
+
method: :delete,
|
33
|
+
data: {confirm: t('shoppe.customers.delete_confirmation')}
|
34
|
+
= f.submit t('shoppe.customers.save'),
|
35
|
+
class: 'button green',
|
36
|
+
data: {disable_with: (@customer.new_record? ? t('shoppe.customers.creating_customer') : t('shoppe.customers.updating_customer'))}
|
37
|
+
= link_to t('shoppe.customers.cancel'), :customers, :class => 'button'
|
@@ -1,13 +1,13 @@
|
|
1
1
|
.customerSearch{:style => action_name == 'search' ? "display:block" : ''}
|
2
2
|
= search_form_for @query, :url => search_customers_path, :html => { :method => :post } do |f|
|
3
3
|
%dl.left
|
4
|
-
%dt= f.label :first_name_or_last_name_or_company_cont,
|
4
|
+
%dt= f.label :first_name_or_last_name_or_company_cont, t('shoppe.customers.first_or_last_name')
|
5
5
|
%dd= f.text_field :first_name_or_last_name_or_company_cont
|
6
|
-
%dt= f.label :company_cont,
|
6
|
+
%dt= f.label :company_cont, t('shoppe.customers.company')
|
7
7
|
%dd= f.text_field :company_cont
|
8
8
|
%dl.right
|
9
|
-
%dt= f.label :email_cont,
|
9
|
+
%dt= f.label :email_cont, t('shoppe.customers.email')
|
10
10
|
%dd= f.text_field :email_cont
|
11
|
-
%dt= f.label :phone_cont,
|
11
|
+
%dt= f.label :phone_cont, t('shoppe.customers.phone')
|
12
12
|
%dd= f.text_field :phone_cont
|
13
|
-
%dd= f.submit
|
13
|
+
%dd= f.submit t('shoppe.customers.search'), :class => 'button green button'
|
@@ -1,5 +1,5 @@
|
|
1
|
-
- @page_title =
|
1
|
+
- @page_title = t('shoppe.customers.customers')
|
2
2
|
= content_for :header do
|
3
|
-
%p.buttons= link_to
|
4
|
-
%h2.users
|
5
|
-
= render "form"
|
3
|
+
%p.buttons= link_to t('shoppe.customers.back_to_customers_list'), :customers, :class => 'button'
|
4
|
+
%h2.users= t('shoppe.customers.customers')
|
5
|
+
= render "form"
|
@@ -1,10 +1,10 @@
|
|
1
|
-
- @page_title =
|
1
|
+
- @page_title = t('shoppe.customers.customers')
|
2
2
|
|
3
3
|
= content_for :header do
|
4
4
|
%p.buttons
|
5
|
-
= link_to
|
6
|
-
= link_to
|
7
|
-
%h2.users
|
5
|
+
= link_to t('shoppe.customers.new_customer'), :new_customer, class: "button green"
|
6
|
+
= link_to t('shoppe.customers.search_customer'), '#', class: 'button', rel: "searchCustomers"
|
7
|
+
%h2.users= t('shoppe.customers.customers')
|
8
8
|
|
9
9
|
= render "search_form"
|
10
10
|
|
@@ -12,15 +12,15 @@
|
|
12
12
|
%table.data
|
13
13
|
%thead
|
14
14
|
%tr
|
15
|
-
%th
|
16
|
-
%th
|
17
|
-
%th
|
18
|
-
%th
|
19
|
-
%th
|
15
|
+
%th= t('shoppe.customers.name')
|
16
|
+
%th= t('shoppe.customers.company')
|
17
|
+
%th= t('shoppe.customers.email')
|
18
|
+
%th= t('shoppe.customers.phone')
|
19
|
+
%th= t('shoppe.customers.mobile_phone')
|
20
20
|
%tbody
|
21
21
|
- if @customers.empty?
|
22
22
|
%tr.empty
|
23
|
-
%td{colspan: 5}
|
23
|
+
%td{colspan: 5}= t('shoppe.customers.no_customers')
|
24
24
|
- else
|
25
25
|
- for customer in @customers
|
26
26
|
%tr
|
@@ -29,4 +29,4 @@
|
|
29
29
|
%td= customer.email
|
30
30
|
%td= customer.phone
|
31
31
|
%td= customer.mobile
|
32
|
-
= paginate @customers
|
32
|
+
= paginate @customers
|
@@ -1,5 +1,5 @@
|
|
1
|
-
- @page_title =
|
1
|
+
- @page_title = t('shoppe.customers.customers')
|
2
2
|
= content_for :header do
|
3
|
-
%p.buttons= link_to
|
3
|
+
%p.buttons= link_to t('shoppe.customers.back_to_customers_list'), :customers, :class => 'button'
|
4
4
|
%h2.users Customers
|
5
|
-
= render "form"
|
5
|
+
= render "form"
|
@@ -1,29 +1,28 @@
|
|
1
|
-
- @page_title = "
|
1
|
+
- @page_title = t('shoppe.customers.customers') + " - #{@customer.name}"
|
2
2
|
= content_for :header do
|
3
3
|
%p.buttons
|
4
|
-
= link_to
|
5
|
-
= link_to
|
6
|
-
%h2.users
|
7
|
-
Customer - #{@customer.name}
|
4
|
+
= link_to t('shoppe.customers.new_address'), [:new, @customer, :address], class: "button"
|
5
|
+
= link_to t('shoppe.customers.edit'), [:edit, @customer], class: "button"
|
6
|
+
%h2.users= t('shoppe.customers.customers') + "- #{@customer.name}"
|
8
7
|
|
9
8
|
#customer
|
10
9
|
.details
|
11
10
|
.left
|
12
11
|
%dl
|
13
|
-
%dt
|
12
|
+
%dt= t('shoppe.customers.name')
|
14
13
|
%dd= @customer.full_name
|
15
|
-
%dt
|
14
|
+
%dt= t('shoppe.customers.company')
|
16
15
|
%dd= @customer.company.blank? ? '-' : @customer.company
|
17
16
|
.right
|
18
17
|
%dl
|
19
|
-
%dt
|
18
|
+
%dt= t('shoppe.customers.email')
|
20
19
|
%dd= mail_to @customer.email
|
21
|
-
%dt
|
20
|
+
%dt= t('shoppe.customers.phone')
|
22
21
|
%dd= @customer.phone
|
23
|
-
%dt
|
22
|
+
%dt= t('shoppe.customers.mobile_phone')
|
24
23
|
%dd= @customer.mobile
|
25
24
|
|
26
|
-
= field_set_tag
|
25
|
+
= field_set_tag t('shoppe.customers.addresses'), :class => 'padded' do
|
27
26
|
= render "addresses"
|
28
27
|
|
29
28
|
= field_set_tag t('shoppe.orders.orders'), :class => 'padded' do
|
@@ -50,4 +49,4 @@
|
|
50
49
|
- for item in order.order_items
|
51
50
|
%li #{item.quantity} x #{item.ordered_item.full_name}
|
52
51
|
%td= number_to_currency order.total
|
53
|
-
%td= boolean_tag order.paid_in_full?, nil, :true_text => number_to_currency(order.amount_paid), :false_text => number_to_currency(order.amount_paid)
|
52
|
+
%td= boolean_tag order.paid_in_full?, nil, :true_text => number_to_currency(order.amount_paid), :false_text => number_to_currency(order.amount_paid)
|