shoppe 1.0.2 → 1.0.3
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/app/assets/images/shoppe/table-tear-off.png +0 -0
- data/app/assets/javascripts/shoppe/application.coffee +2 -2
- data/app/assets/stylesheets/shoppe/application.scss +80 -37
- data/app/assets/stylesheets/shoppe/elements.scss +1 -2
- data/app/controllers/shoppe/attachments_controller.rb +3 -3
- data/app/controllers/shoppe/countries_controller.rb +13 -13
- data/app/controllers/shoppe/delivery_service_prices_controller.rb +11 -11
- data/app/controllers/shoppe/delivery_services_controller.rb +13 -13
- data/app/controllers/shoppe/orders_controller.rb +20 -20
- data/app/controllers/shoppe/payments_controller.rb +8 -8
- data/app/controllers/shoppe/product_categories_controller.rb +13 -13
- data/app/controllers/shoppe/products_controller.rb +24 -13
- data/app/controllers/shoppe/sessions_controller.rb +7 -7
- data/app/controllers/shoppe/settings_controller.rb +6 -6
- data/app/controllers/shoppe/stock_level_adjustments_controller.rb +5 -5
- data/app/controllers/shoppe/tax_rates_controller.rb +13 -13
- data/app/controllers/shoppe/users_controller.rb +15 -15
- data/app/controllers/shoppe/variants_controller.rb +13 -13
- data/app/helpers/shoppe/application_helper.rb +12 -12
- data/app/models/shoppe/order/actions.rb +17 -3
- data/app/models/shoppe/order/billing.rb +18 -18
- data/app/models/shoppe/order/delivery.rb +30 -31
- data/app/models/shoppe/order_item.rb +33 -34
- data/app/models/shoppe/payment.rb +15 -15
- data/app/models/shoppe/product.rb +82 -21
- data/app/models/shoppe/product/variants.rb +10 -10
- data/app/models/shoppe/product_category.rb +7 -7
- data/app/models/shoppe/stock_level_adjustment.rb +6 -6
- data/app/validators/permalink_validator.rb +7 -0
- data/app/views/layouts/shoppe/application.html.haml +10 -20
- data/app/views/shoppe/countries/_form.html.haml +15 -11
- data/app/views/shoppe/countries/edit.html.haml +5 -4
- data/app/views/shoppe/countries/index.html.haml +9 -9
- data/app/views/shoppe/countries/new.html.haml +6 -4
- data/app/views/shoppe/delivery_service_prices/_form.html.haml +16 -16
- data/app/views/shoppe/delivery_service_prices/edit.html.haml +5 -4
- data/app/views/shoppe/delivery_service_prices/index.html.haml +8 -9
- data/app/views/shoppe/delivery_service_prices/new.html.haml +5 -4
- data/app/views/shoppe/delivery_services/_form.html.haml +15 -14
- data/app/views/shoppe/delivery_services/edit.html.haml +7 -5
- data/app/views/shoppe/delivery_services/index.html.haml +11 -12
- data/app/views/shoppe/delivery_services/new.html.haml +5 -4
- data/app/views/shoppe/orders/_form.html.haml +19 -19
- data/app/views/shoppe/orders/_order_details.html.haml +20 -15
- data/app/views/shoppe/orders/_order_items.html.haml +6 -6
- data/app/views/shoppe/orders/_order_items_form.html.haml +11 -11
- data/app/views/shoppe/orders/_payments_form.html.haml +4 -4
- data/app/views/shoppe/orders/_payments_table.html.haml +12 -12
- data/app/views/shoppe/orders/_search_form.html.haml +10 -10
- data/app/views/shoppe/orders/_status_bar.html.haml +17 -13
- data/app/views/shoppe/orders/despatch_note.html.haml +15 -15
- data/app/views/shoppe/orders/edit.html.haml +8 -8
- data/app/views/shoppe/orders/index.html.haml +12 -12
- data/app/views/shoppe/orders/new.html.haml +7 -7
- data/app/views/shoppe/orders/show.html.haml +9 -12
- data/app/views/shoppe/payments/refund.html.haml +6 -7
- data/app/views/shoppe/product_categories/_form.html.haml +9 -9
- data/app/views/shoppe/product_categories/edit.html.haml +4 -4
- data/app/views/shoppe/product_categories/index.html.haml +5 -5
- data/app/views/shoppe/product_categories/new.html.haml +4 -3
- data/app/views/shoppe/products/_form.html.haml +49 -50
- data/app/views/shoppe/products/_table.html.haml +10 -10
- data/app/views/shoppe/products/edit.html.haml +6 -6
- data/app/views/shoppe/products/import.html.haml +63 -0
- data/app/views/shoppe/products/index.html.haml +6 -4
- data/app/views/shoppe/products/new.html.haml +6 -4
- data/app/views/shoppe/sessions/new.html.haml +5 -5
- data/app/views/shoppe/sessions/reset.html.haml +6 -5
- data/app/views/shoppe/settings/edit.html.haml +5 -5
- data/app/views/shoppe/shared/error.html.haml +3 -3
- data/app/views/shoppe/stock_level_adjustments/index.html.haml +13 -12
- data/app/views/shoppe/tax_rates/form.html.haml +13 -13
- data/app/views/shoppe/tax_rates/index.html.haml +5 -5
- data/app/views/shoppe/users/_form.html.haml +10 -11
- data/app/views/shoppe/users/edit.html.haml +4 -4
- data/app/views/shoppe/users/index.html.haml +5 -5
- data/app/views/shoppe/users/new.html.haml +6 -4
- data/app/views/shoppe/variants/form.html.haml +27 -29
- data/app/views/shoppe/variants/index.html.haml +11 -11
- data/config/locales/en.yml +619 -14
- data/config/locales/es.yml +650 -0
- data/config/locales/pl.yml +650 -0
- data/config/locales/pt-BR.yml +643 -0
- data/config/routes.rb +16 -8
- data/db/migrate/20141026175622_add_indexes_to_shoppe_order_items.rb +6 -0
- data/db/migrate/20141026175943_add_indexes_to_shoppe_orders.rb +7 -0
- data/db/migrate/20141026180333_add_indexes_to_shoppe_payments.rb +6 -0
- data/db/migrate/20141026180835_add_indexes_to_shoppe_product_attributes.rb +7 -0
- data/db/migrate/20141026180952_add_indexes_to_shoppe_product_categories.rb +5 -0
- data/db/migrate/20141026181040_add_indexes_to_shoppe_products.rb +8 -0
- data/db/migrate/20141026181312_add_indexes_to_shoppe_settings.rb +5 -0
- data/db/migrate/20141026181354_add_indexes_to_shoppe_stock_level_adjustments.rb +6 -0
- data/db/migrate/20141026181559_add_indexes_to_shoppe_users.rb +5 -0
- data/db/migrate/20141026181716_add_indexes_to_shoppe_delivery_services.rb +9 -0
- data/db/schema.rb +36 -1
- data/lib/shoppe/engine.rb +6 -0
- data/lib/shoppe/navigation_manager.rb +1 -1
- data/lib/shoppe/version.rb +1 -1
- metadata +67 -5
|
@@ -1,53 +1,53 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
class UsersController < Shoppe::ApplicationController
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
before_filter { @active_nav = :users }
|
|
5
5
|
before_filter { params[:id] && @user = Shoppe::User.find(params[:id]) }
|
|
6
6
|
before_filter(:only => [:create, :update, :destroy]) do
|
|
7
7
|
if Shoppe.settings.demo_mode?
|
|
8
|
-
raise Shoppe::Error,
|
|
8
|
+
raise Shoppe::Error, t('shoppe.users.demo_mode_error')
|
|
9
9
|
end
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def index
|
|
13
13
|
@users = Shoppe::User.all
|
|
14
14
|
end
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
def new
|
|
17
17
|
@user = Shoppe::User.new
|
|
18
18
|
end
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
def create
|
|
21
21
|
@user = Shoppe::User.new(safe_params)
|
|
22
22
|
if @user.save
|
|
23
|
-
redirect_to :users, :flash => {:notice =>
|
|
23
|
+
redirect_to :users, :flash => {:notice => t('shoppe.users.create_notice') }
|
|
24
24
|
else
|
|
25
25
|
render :action => "new"
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
|
-
|
|
28
|
+
|
|
29
29
|
def edit
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
def update
|
|
33
33
|
if @user.update(safe_params)
|
|
34
|
-
redirect_to [:edit, @user], :flash => {:notice =>
|
|
34
|
+
redirect_to [:edit, @user], :flash => {:notice => t('shoppe.users.update_notice') }
|
|
35
35
|
else
|
|
36
36
|
render :action => "edit"
|
|
37
37
|
end
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
def destroy
|
|
41
|
-
raise Shoppe::Error,
|
|
41
|
+
raise Shoppe::Error, t('shoppe.users.self_remove_error') if @user == current_user
|
|
42
42
|
@user.destroy
|
|
43
|
-
redirect_to :users, :flash => {:notice =>
|
|
43
|
+
redirect_to :users, :flash => {:notice => t('shoppe.users.destroy_notice') }
|
|
44
44
|
end
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
private
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
def safe_params
|
|
49
49
|
params[:user].permit(:first_name, :last_name, :email_address, :password, :password_confirmation)
|
|
50
50
|
end
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
class VariantsController < ApplicationController
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
before_filter { @active_nav = :products }
|
|
5
5
|
before_filter { @product = Shoppe::Product.find(params[:product_id]) }
|
|
6
6
|
before_filter { params[:id] && @variant = @product.variants.find(params[:id]) }
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def index
|
|
9
9
|
@variants = @product.variants.ordered
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def new
|
|
13
13
|
@variant = @product.variants.build
|
|
14
14
|
render :action => "form"
|
|
15
15
|
end
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
def create
|
|
18
18
|
@variant = @product.variants.build(safe_params)
|
|
19
19
|
if @variant.save
|
|
20
|
-
redirect_to [@product, :variants], :notice =>
|
|
20
|
+
redirect_to [@product, :variants], :notice => t('shoppe.variants.create_notice')
|
|
21
21
|
else
|
|
22
22
|
render :action => "form"
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
def edit
|
|
27
27
|
render :action => "form"
|
|
28
28
|
end
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
def update
|
|
31
31
|
if @variant.update(safe_params)
|
|
32
|
-
redirect_to edit_product_variant_path(@product, @variant), :notice =>
|
|
32
|
+
redirect_to edit_product_variant_path(@product, @variant), :notice => t('shoppe.variants.update_notice')
|
|
33
33
|
else
|
|
34
34
|
render :action => "form"
|
|
35
35
|
end
|
|
36
36
|
end
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
def destroy
|
|
39
39
|
@variant.destroy
|
|
40
|
-
redirect_to [@product, :variants], :notice =>
|
|
40
|
+
redirect_to [@product, :variants], :notice => t('shoppe.variants.destroy_notice')
|
|
41
41
|
end
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
private
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
def safe_params
|
|
46
46
|
params[:product].permit(:name, :permalink, :sku, :default_image_file, :price, :cost_price, :tax_rate_id, :weight, :stock_control, :active, :default)
|
|
47
47
|
end
|
|
48
|
-
|
|
48
|
+
|
|
49
49
|
end
|
|
50
50
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
module ApplicationHelper
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
def navigation_manager_link(item)
|
|
5
5
|
link_to item.description, item.url(self), item.link_options.merge(:class => item.active?(self) ? 'active' : 'inactive')
|
|
6
6
|
end
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
def status_tag(status)
|
|
9
|
-
content_tag :span, status, :class => "status-tag #{status}"
|
|
9
|
+
content_tag :span, t("shoppe.orders.statuses.#{status}"), :class => "status-tag #{status}"
|
|
10
10
|
end
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
def attachment_preview(attachment, options = {})
|
|
13
13
|
if attachment
|
|
14
14
|
String.new.tap do |s|
|
|
@@ -22,24 +22,24 @@ module Shoppe
|
|
|
22
22
|
s << "<div class='desc'>"
|
|
23
23
|
s << "<span class='filename'><a href='#{attachment_path(attachment)}'>#{attachment.file_name}</a></span>"
|
|
24
24
|
s << "<span class='delete'>"
|
|
25
|
-
s << link_to(t('
|
|
25
|
+
s << link_to(t('helpers.attachment_preview.delete', :default => 'Delete this file?'), attachment_path(attachment), :method => :delete, :data => {:confirm => t('helpers.attachment_preview.delete_confirm', :default => "Are you sure you wish to remove this attachment?")})
|
|
26
26
|
s << "</span>"
|
|
27
27
|
s << "</div>"
|
|
28
28
|
s << "</div>"
|
|
29
29
|
end.html_safe
|
|
30
30
|
elsif !options[:hide_if_blank]
|
|
31
|
-
"<div class='attachmentPreview'><div class='imgContainer'><div class='img none'></div></div><div class='desc none'
|
|
31
|
+
"<div class='attachmentPreview'><div class='imgContainer'><div class='img none'></div></div><div class='desc none'>#{t('helpers.attachment_preview.no_attachment')},</div></div>".html_safe
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
def settings_label(field)
|
|
36
36
|
"<label for='settings_#{field}'>#{t("shoppe.settings.labels.#{field}")}</label>".html_safe
|
|
37
37
|
end
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
def settings_field(field, options = {})
|
|
40
|
-
default = t("shoppe.settings.defaults")[field.to_sym]
|
|
40
|
+
default = I18n.t("shoppe.settings.defaults")[field.to_sym]
|
|
41
41
|
value = (params[:settings] && params[:settings][field]) || Shoppe.settings[field.to_s]
|
|
42
|
-
type = t("shoppe.settings.types")[field.to_sym] || 'string'
|
|
42
|
+
type = I18n.t("shoppe.settings.types")[field.to_sym] || 'string'
|
|
43
43
|
case type
|
|
44
44
|
when 'boolean'
|
|
45
45
|
String.new.tap do |s|
|
|
@@ -55,6 +55,6 @@ module Shoppe
|
|
|
55
55
|
text_field_tag "settings[#{field}]", value, options.merge(:placeholder => default, :class => 'text')
|
|
56
56
|
end
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
end
|
|
60
|
-
end
|
|
60
|
+
end
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
class Order < ActiveRecord::Base
|
|
3
3
|
|
|
4
|
+
extend ActiveModel::Callbacks
|
|
5
|
+
|
|
4
6
|
# These additional callbacks allow for applications to hook into other
|
|
5
7
|
# parts of the order lifecycle.
|
|
6
8
|
define_model_callbacks :confirmation, :acceptance, :rejection
|
|
@@ -41,7 +43,7 @@ module Shoppe
|
|
|
41
43
|
self.order_items.each(&:confirm!)
|
|
42
44
|
|
|
43
45
|
# Send an email to the customer
|
|
44
|
-
|
|
46
|
+
deliver_received_order_email
|
|
45
47
|
end
|
|
46
48
|
|
|
47
49
|
# We're all good.
|
|
@@ -59,7 +61,7 @@ module Shoppe
|
|
|
59
61
|
self.status = 'accepted'
|
|
60
62
|
self.save!
|
|
61
63
|
self.order_items.each(&:accept!)
|
|
62
|
-
|
|
64
|
+
deliver_accepted_order_email
|
|
63
65
|
end
|
|
64
66
|
end
|
|
65
67
|
end
|
|
@@ -75,10 +77,22 @@ module Shoppe
|
|
|
75
77
|
self.status = 'rejected'
|
|
76
78
|
self.save!
|
|
77
79
|
self.order_items.each(&:reject!)
|
|
78
|
-
|
|
80
|
+
deliver_rejected_order_email
|
|
79
81
|
end
|
|
80
82
|
end
|
|
81
83
|
end
|
|
84
|
+
|
|
85
|
+
def deliver_accepted_order_email
|
|
86
|
+
Shoppe::OrderMailer.accepted(self).deliver
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def deliver_rejected_order_email
|
|
90
|
+
Shoppe::OrderMailer.rejected(self).deliver
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def deliver_received_order_email
|
|
94
|
+
Shoppe::OrderMailer.received(self).deliver
|
|
95
|
+
end
|
|
82
96
|
|
|
83
97
|
end
|
|
84
98
|
end
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
class Order < ActiveRecord::Base
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
# The country which this order should be billed to
|
|
5
5
|
#
|
|
6
6
|
# @return [Shoppe::Country]
|
|
7
7
|
belongs_to :billing_country, :class_name => 'Shoppe::Country', :foreign_key => 'billing_country_id'
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
# Payments which have been stored for the order
|
|
10
10
|
has_many :payments, :dependent => :destroy, :class_name => 'Shoppe::Payment'
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
# Validations
|
|
13
13
|
with_options :if => Proc.new { |o| !o.building? } do |order|
|
|
14
14
|
order.validates :first_name, :presence => true
|
|
@@ -19,43 +19,43 @@ module Shoppe
|
|
|
19
19
|
order.validates :billing_postcode, :presence => true
|
|
20
20
|
order.validates :billing_country, :presence => true
|
|
21
21
|
end
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
# The name for billing purposes
|
|
24
24
|
#
|
|
25
25
|
# @return [String]
|
|
26
26
|
def billing_name
|
|
27
27
|
company.blank? ? full_name : "#{full_name} (#{company})"
|
|
28
28
|
end
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
# The total cost of the order
|
|
31
31
|
#
|
|
32
32
|
# @return [BigDecimal]
|
|
33
33
|
def total_cost
|
|
34
|
-
self.delivery_cost_price +
|
|
34
|
+
self.delivery_cost_price +
|
|
35
35
|
order_items.inject(BigDecimal(0)) { |t, i| t + i.total_cost }
|
|
36
36
|
end
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
# Return the price for the order
|
|
39
39
|
#
|
|
40
40
|
# @return [BigDecimal]
|
|
41
41
|
def profit
|
|
42
42
|
total_before_tax - total_cost
|
|
43
43
|
end
|
|
44
|
-
|
|
44
|
+
|
|
45
45
|
# The total price of all items in the basket excluding delivery
|
|
46
46
|
#
|
|
47
47
|
# @return [BigDecimal]
|
|
48
48
|
def items_sub_total
|
|
49
49
|
order_items.inject(BigDecimal(0)) { |t, i| t + i.sub_total }
|
|
50
50
|
end
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
# The total price of the order before tax
|
|
53
53
|
#
|
|
54
54
|
# @return [BigDecimal]
|
|
55
55
|
def total_before_tax
|
|
56
56
|
self.delivery_price + self.items_sub_total
|
|
57
57
|
end
|
|
58
|
-
|
|
58
|
+
|
|
59
59
|
# The total amount of tax due on this order
|
|
60
60
|
#
|
|
61
61
|
# @return [BigDecimal]
|
|
@@ -63,43 +63,43 @@ module Shoppe
|
|
|
63
63
|
self.delivery_tax_amount +
|
|
64
64
|
order_items.inject(BigDecimal(0)) { |t, i| t + i.tax_amount }
|
|
65
65
|
end
|
|
66
|
-
|
|
66
|
+
|
|
67
67
|
# The total of the order including tax
|
|
68
68
|
#
|
|
69
69
|
# @return [BigDecimal]
|
|
70
70
|
def total
|
|
71
|
-
self.delivery_price +
|
|
72
|
-
self.delivery_tax_amount +
|
|
71
|
+
self.delivery_price +
|
|
72
|
+
self.delivery_tax_amount +
|
|
73
73
|
order_items.inject(BigDecimal(0)) { |t, i| t + i.total }
|
|
74
74
|
end
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
# The total amount due on the order
|
|
77
77
|
#
|
|
78
78
|
# @return [BigDecimal]
|
|
79
79
|
def balance
|
|
80
80
|
@balance ||= total - amount_paid
|
|
81
81
|
end
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
# Is there a payment still outstanding on this order?
|
|
84
84
|
#
|
|
85
85
|
# @return [Boolean]
|
|
86
86
|
def payment_outstanding?
|
|
87
87
|
balance > BigDecimal(0)
|
|
88
88
|
end
|
|
89
|
-
|
|
89
|
+
|
|
90
90
|
# Has this order been paid in full?
|
|
91
91
|
#
|
|
92
92
|
# @return [Boolean]
|
|
93
93
|
def paid_in_full?
|
|
94
94
|
!payment_outstanding?
|
|
95
95
|
end
|
|
96
|
-
|
|
96
|
+
|
|
97
97
|
# Is the order invoiced?
|
|
98
98
|
#
|
|
99
99
|
# @return [Boolean]
|
|
100
100
|
def invoiced?
|
|
101
101
|
!invoice_number.blank?
|
|
102
102
|
end
|
|
103
|
-
|
|
103
|
+
|
|
104
104
|
end
|
|
105
105
|
end
|
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
module Shoppe
|
|
2
2
|
class Order < ActiveRecord::Base
|
|
3
|
-
|
|
3
|
+
|
|
4
4
|
# The associated delivery service
|
|
5
5
|
#
|
|
6
6
|
# @return [Shoppe::DeliveryService]
|
|
7
7
|
belongs_to :delivery_service, :class_name => 'Shoppe::DeliveryService'
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
# The country where this order is being delivered to (if one has been provided)
|
|
10
10
|
#
|
|
11
11
|
# @return [Shoppe::Country]
|
|
12
12
|
belongs_to :delivery_country, :class_name => 'Shoppe::Country', :foreign_key => 'delivery_country_id'
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
# The user who marked the order has shipped
|
|
15
15
|
#
|
|
16
16
|
# @return [Shoppe::User]
|
|
17
17
|
belongs_to :shipper, :class_name => 'Shoppe::User', :foreign_key => 'shipped_by'
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
# Set up a callback for use when an order is shipped
|
|
20
20
|
define_model_callbacks :ship
|
|
21
|
-
|
|
21
|
+
|
|
22
22
|
# Validations
|
|
23
23
|
with_options :if => :separate_delivery_address? do |order|
|
|
24
24
|
order.validates :delivery_name, :presence => true
|
|
@@ -28,17 +28,17 @@ module Shoppe
|
|
|
28
28
|
order.validates :delivery_postcode, :presence => true
|
|
29
29
|
order.validates :delivery_country, :presence => true
|
|
30
30
|
end
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
validate do
|
|
33
33
|
if self.delivery_required?
|
|
34
34
|
if self.delivery_service.nil?
|
|
35
|
-
errors.add :delivery_service_id,
|
|
35
|
+
errors.add :delivery_service_id, :must_be_specified
|
|
36
36
|
elsif !self.valid_delivery_service?
|
|
37
|
-
errors.add :delivery_service_id,
|
|
37
|
+
errors.add :delivery_service_id, :not_suitable
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
|
-
|
|
41
|
+
|
|
42
42
|
before_confirmation do
|
|
43
43
|
# Ensure that before we confirm the order that the delivery service which has been selected
|
|
44
44
|
# is appropritae for the contents of the order.
|
|
@@ -47,7 +47,7 @@ module Shoppe
|
|
|
47
47
|
end
|
|
48
48
|
cache_delivery_pricing
|
|
49
49
|
end
|
|
50
|
-
|
|
50
|
+
|
|
51
51
|
# If an order has been received and something changes the delivery service or the delivery price
|
|
52
52
|
# is cleared, we will re-cache all the delivery pricing so that we have the latest.
|
|
53
53
|
before_save do
|
|
@@ -59,7 +59,7 @@ module Shoppe
|
|
|
59
59
|
cache_delivery_pricing
|
|
60
60
|
end
|
|
61
61
|
end
|
|
62
|
-
|
|
62
|
+
|
|
63
63
|
# If there isn't a seperate address needed, clear all the fields back to nil
|
|
64
64
|
before_validation do
|
|
65
65
|
unless separate_delivery_address?
|
|
@@ -72,7 +72,7 @@ module Shoppe
|
|
|
72
72
|
self.delivery_country = nil
|
|
73
73
|
end
|
|
74
74
|
end
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
# Create some delivery_ methods which will mimic the billing methods if the order does
|
|
77
77
|
# not need a seperate address.
|
|
78
78
|
[:delivery_name, :delivery_address1, :delivery_address2, :delivery_address3, :delivery_address4, :delivery_postcode, :delivery_country].each do |f|
|
|
@@ -80,7 +80,7 @@ module Shoppe
|
|
|
80
80
|
separate_delivery_address? ? super() : send(f.to_s.gsub('delivery_', 'billing_'))
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
|
-
|
|
83
|
+
|
|
84
84
|
# Cache delivery prices for the order
|
|
85
85
|
def cache_delivery_pricing
|
|
86
86
|
if self.delivery_service
|
|
@@ -96,34 +96,34 @@ module Shoppe
|
|
|
96
96
|
write_attribute :delivery_tax_amount, nil
|
|
97
97
|
end
|
|
98
98
|
end
|
|
99
|
-
|
|
99
|
+
|
|
100
100
|
# Cache prices and save the order
|
|
101
101
|
def cache_delivery_pricing!
|
|
102
102
|
cache_delivery_pricing
|
|
103
103
|
save!
|
|
104
104
|
end
|
|
105
|
-
|
|
105
|
+
|
|
106
106
|
# Has this order been shipped?
|
|
107
107
|
#
|
|
108
108
|
# @return [Boolean]
|
|
109
109
|
def shipped?
|
|
110
110
|
!!self.shipped_at?
|
|
111
111
|
end
|
|
112
|
-
|
|
112
|
+
|
|
113
113
|
# The total weight of the order
|
|
114
114
|
#
|
|
115
115
|
# @return [BigDecimal]
|
|
116
116
|
def total_weight
|
|
117
117
|
order_items.inject(BigDecimal(0)) { |t,i| t + i.total_weight}
|
|
118
118
|
end
|
|
119
|
-
|
|
119
|
+
|
|
120
120
|
# Is delivery required for this order?
|
|
121
121
|
#
|
|
122
122
|
# @return [Boolean]
|
|
123
123
|
def delivery_required?
|
|
124
124
|
total_weight > BigDecimal(0)
|
|
125
125
|
end
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
# An array of all the delivery services which are suitable for this order in it's
|
|
128
128
|
# current state (based on its current weight)
|
|
129
129
|
#
|
|
@@ -131,7 +131,7 @@ module Shoppe
|
|
|
131
131
|
def available_delivery_services
|
|
132
132
|
delivery_service_prices.map(&:delivery_service).uniq
|
|
133
133
|
end
|
|
134
|
-
|
|
134
|
+
|
|
135
135
|
# An array of all the delivery service prices which can be applied to this order.
|
|
136
136
|
#
|
|
137
137
|
# @return [Array] an array of Shoppe:DeliveryServicePrice objects
|
|
@@ -139,8 +139,7 @@ module Shoppe
|
|
|
139
139
|
if delivery_required?
|
|
140
140
|
prices = Shoppe::DeliveryServicePrice.joins(:delivery_service).where(:shoppe_delivery_services => {:active => true}).order(:price).for_weight(total_weight)
|
|
141
141
|
prices = prices.select { |p| p.countries.empty? || p.country?(self.delivery_country) }
|
|
142
|
-
prices
|
|
143
|
-
(prices[true] || []) | (prices[false] || [])
|
|
142
|
+
prices.sort{ |x,y| (y.delivery_service.default? ? 1 : 0) <=> (x.delivery_service.default? ? 1 : 0) } # Order by truthiness
|
|
144
143
|
else
|
|
145
144
|
[]
|
|
146
145
|
end
|
|
@@ -152,28 +151,28 @@ module Shoppe
|
|
|
152
151
|
def delivery_service
|
|
153
152
|
super || available_delivery_services.first
|
|
154
153
|
end
|
|
155
|
-
|
|
154
|
+
|
|
156
155
|
# Return the delivery price for this order in its current state
|
|
157
156
|
#
|
|
158
157
|
# @return [BigDecimal]
|
|
159
158
|
def delivery_service_price
|
|
160
159
|
self.delivery_service && self.delivery_service.delivery_service_prices.for_weight(self.total_weight).first
|
|
161
160
|
end
|
|
162
|
-
|
|
161
|
+
|
|
163
162
|
# The price for delivering this order in its current state
|
|
164
163
|
#
|
|
165
164
|
# @return [BigDecimal]
|
|
166
165
|
def delivery_price
|
|
167
166
|
read_attribute(:delivery_price) || delivery_service_price.try(:price) || BigDecimal(0)
|
|
168
167
|
end
|
|
169
|
-
|
|
168
|
+
|
|
170
169
|
# The cost of delivering this order in its current state
|
|
171
170
|
#
|
|
172
171
|
# @return [BigDecimal]
|
|
173
172
|
def delivery_cost_price
|
|
174
173
|
read_attribute(:delivery_cost_price) || delivery_service_price.try(:cost_price) || BigDecimal(0)
|
|
175
174
|
end
|
|
176
|
-
|
|
175
|
+
|
|
177
176
|
# The tax amount due for the delivery of this order in its current state
|
|
178
177
|
#
|
|
179
178
|
# @return [BigDecimal]
|
|
@@ -181,7 +180,7 @@ module Shoppe
|
|
|
181
180
|
read_attribute(:delivery_tax_amount) ||
|
|
182
181
|
delivery_price / BigDecimal(100) * delivery_tax_rate
|
|
183
182
|
end
|
|
184
|
-
|
|
183
|
+
|
|
185
184
|
# The tax rate for the delivery of this order in its current state
|
|
186
185
|
#
|
|
187
186
|
# @return [BigDecimal]
|
|
@@ -190,14 +189,14 @@ module Shoppe
|
|
|
190
189
|
delivery_service_price.try(:tax_rate).try(:rate_for, self) ||
|
|
191
190
|
BigDecimal(0)
|
|
192
191
|
end
|
|
193
|
-
|
|
192
|
+
|
|
194
193
|
# Is the currently assigned delivery service appropriate for this order?
|
|
195
194
|
#
|
|
196
195
|
# @return [Boolean]
|
|
197
196
|
def valid_delivery_service?
|
|
198
197
|
self.delivery_service ? self.available_delivery_services.include?(self.delivery_service) : !self.delivery_required?
|
|
199
198
|
end
|
|
200
|
-
|
|
199
|
+
|
|
201
200
|
# Remove the associated delivery service if it's invalid
|
|
202
201
|
def remove_delivery_service_if_invalid
|
|
203
202
|
unless self.valid_delivery_service?
|
|
@@ -205,7 +204,7 @@ module Shoppe
|
|
|
205
204
|
self.save
|
|
206
205
|
end
|
|
207
206
|
end
|
|
208
|
-
|
|
207
|
+
|
|
209
208
|
# The URL which can be used to track the delivery of this order
|
|
210
209
|
#
|
|
211
210
|
# @return [String]
|
|
@@ -213,7 +212,7 @@ module Shoppe
|
|
|
213
212
|
return nil if self.shipped_at.blank? || self.consignment_number.blank?
|
|
214
213
|
@courier_tracking_url ||= self.delivery_service.tracking_url_for(self)
|
|
215
214
|
end
|
|
216
|
-
|
|
215
|
+
|
|
217
216
|
# Mark this order as shipped
|
|
218
217
|
def ship!(consignment_number, user = nil)
|
|
219
218
|
run_callbacks :ship do
|
|
@@ -225,6 +224,6 @@ module Shoppe
|
|
|
225
224
|
Shoppe::OrderMailer.shipped(self).deliver
|
|
226
225
|
end
|
|
227
226
|
end
|
|
228
|
-
|
|
227
|
+
|
|
229
228
|
end
|
|
230
229
|
end
|