shoppe 1.0.7 → 1.0.8

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/shoppe/application.coffee +4 -0
  3. data/app/assets/stylesheets/shoppe/application.scss +3 -3
  4. data/app/controllers/shoppe/addresses_controller.rb +47 -0
  5. data/app/controllers/shoppe/customers_controller.rb +55 -0
  6. data/app/controllers/shoppe/orders_controller.rb +29 -0
  7. data/app/controllers/shoppe/product_category_localisations_controller.rb +58 -0
  8. data/app/controllers/shoppe/product_localisations_controller.rb +58 -0
  9. data/app/controllers/shoppe/products_controller.rb +1 -1
  10. data/app/models/shoppe/address.rb +44 -0
  11. data/app/models/shoppe/customer.rb +41 -0
  12. data/app/models/shoppe/order.rb +7 -0
  13. data/app/models/shoppe/product.rb +6 -3
  14. data/app/models/shoppe/product/variants.rb +1 -1
  15. data/app/models/shoppe/product_category.rb +3 -3
  16. data/app/views/shoppe/addresses/_form.html.haml +33 -0
  17. data/app/views/shoppe/addresses/edit.html.haml +5 -0
  18. data/app/views/shoppe/addresses/new.html.haml +5 -0
  19. data/app/views/shoppe/customers/_addresses.html.haml +20 -0
  20. data/app/views/shoppe/customers/_form.html.haml +30 -0
  21. data/app/views/shoppe/customers/_search_form.html.haml +13 -0
  22. data/app/views/shoppe/customers/edit.html.haml +5 -0
  23. data/app/views/shoppe/customers/index.html.haml +32 -0
  24. data/app/views/shoppe/customers/new.html.haml +5 -0
  25. data/app/views/shoppe/customers/show.html.haml +53 -0
  26. data/app/views/shoppe/orders/_form.html.haml +3 -0
  27. data/app/views/shoppe/product_categories/_form.html.haml +1 -2
  28. data/app/views/shoppe/product_categories/edit.html.haml +3 -1
  29. data/app/views/shoppe/product_categories/index.html.haml +7 -0
  30. data/app/views/shoppe/product_category_localisations/form.html.haml +29 -0
  31. data/app/views/shoppe/product_category_localisations/index.html.haml +26 -0
  32. data/app/views/shoppe/product_localisations/form.html.haml +32 -0
  33. data/app/views/shoppe/product_localisations/index.html.haml +26 -0
  34. data/app/views/shoppe/products/edit.html.haml +1 -0
  35. data/app/views/shoppe/variants/form.html.haml +3 -1
  36. data/config/locales/en.yml +82 -1
  37. data/config/routes.rb +10 -1
  38. data/db/migrate/20141013192427_create_shoppe_customers.rb +14 -0
  39. data/db/migrate/20141027215005_create_shoppe_addresses.rb +17 -0
  40. data/db/migrate/20150315215633_add_customer_to_shoppe_orders.rb +5 -0
  41. data/db/migrate/20150513171350_create_shoppe_product_category_translation_table.rb +17 -0
  42. data/db/migrate/20150519173350_create_shoppe_product_translation_table.rb +18 -0
  43. data/db/schema.rb +42 -1
  44. data/lib/shoppe.rb +1 -0
  45. data/lib/shoppe/default_navigation.rb +1 -0
  46. data/lib/shoppe/version.rb +1 -1
  47. metadata +41 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fa73eb9e87ef1d27482822773c0ca8d61f7baea1
4
- data.tar.gz: e94359654bfb0ad01f39eaf0ac0638e14c2bac4e
3
+ metadata.gz: bf9a0256bc9ea841945749f08d51e47c307c574d
4
+ data.tar.gz: 538c996c91a1a34081fbfe945b7afa450fed2443
5
5
  SHA512:
6
- metadata.gz: abffb88a987ab3a8aa34e0ff5da824f89cec0fc7905a1a250cc01b80e95b24eb4735b1fe27aa218845efb03002ab16b540b380734955f5b909f781f4b6c69655
7
- data.tar.gz: 9b830ff1d41ff811b183b0aabd62be74b625ccedea233d1034ccb52f0ae2f459e04afe247b9965bd581e301bb29cd788d728c4252c82ddf43b20b7d6242a6c97
6
+ metadata.gz: e75007e5bccf210a4954380863cadd7061396f758dd59ecfc7a28dd368068f56521c64ab2a501febf51eca1b5530122c7599f2590a740a5547903e78104056b6
7
+ data.tar.gz: 7f896f5bf90086972c0119d604ad1390262d6ef7d21ee8c382da5a8c7025d3eb72c1745cf9aa69f0db73908bad0fa38b09ddc426e08eb8e570521c8e5623dab9
@@ -13,6 +13,10 @@ $ ->
13
13
  # When clicking the order search button, toggle the form
14
14
  $('a[rel=searchOrders]').on 'click', ->
15
15
  $('div.orderSearch').toggle()
16
+
17
+ # When clicking the customer search button, toggle the form
18
+ $('a[rel=searchCustomers]').on 'click', ->
19
+ $('div.customerSearch').toggle()
16
20
 
17
21
  # Add a new attribute to a table
18
22
  $('a[data-behavior=addAttributeToAttributesTable]').on 'click', ->
@@ -321,9 +321,9 @@ header.main {
321
321
  }
322
322
 
323
323
  //
324
- // order summary page
324
+ // order & customer summary pages
325
325
  //
326
- #order {
326
+ #order, #customer {
327
327
  .details {
328
328
  overflow:hidden;
329
329
  .left {
@@ -433,7 +433,7 @@ header.main {
433
433
  //
434
434
  // order search
435
435
  //
436
- div.orderSearch {
436
+ div.orderSearch, div.customerSearch {
437
437
  overflow:hidden;
438
438
  display:none;
439
439
  dl.left, dl.right {
@@ -0,0 +1,47 @@
1
+ module Shoppe
2
+ class AddressesController < Shoppe::ApplicationController
3
+
4
+ before_filter { @active_nav = :customers }
5
+ before_filter { params[:customer_id] && @customer = Shoppe::Customer.find(params[:customer_id])}
6
+ before_filter { params[:id] && @address = @customer.addresses.find(params[:id])}
7
+
8
+ def new
9
+ @address = Shoppe::Address.new
10
+ end
11
+
12
+ def edit
13
+ end
14
+
15
+ def create
16
+ @address = @customer.addresses.build(safe_params)
17
+ if @customer.addresses.count == 0
18
+ @address.default = true
19
+ end
20
+ if @customer.save
21
+ redirect_to @customer, :flash => {:notice => "Address has been created successfully"}
22
+ else
23
+ render action: "new"
24
+ end
25
+ end
26
+
27
+ def update
28
+ if @address.update(safe_params)
29
+ redirect_to @customer, :flash => {:notice => "Address has been updated successfully"}
30
+ else
31
+ render action: "edit"
32
+ end
33
+ end
34
+
35
+ def destroy
36
+ @address.destroy
37
+ redirect_to @customer, :flash => {:notice => "Address has been deleted successfully"}
38
+ end
39
+
40
+ private
41
+
42
+ def safe_params
43
+ params[:address].permit(:address_type, :address1, :address2, :address3, :address4, :postcode, :country_id)
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,55 @@
1
+ module Shoppe
2
+ class CustomersController < Shoppe::ApplicationController
3
+
4
+ before_filter { @active_nav = :customers }
5
+ before_filter { params[:id] && @customer = Shoppe::Customer.find(params[:id])}
6
+
7
+ def index
8
+ @query = Shoppe::Customer.ordered.page(params[:page]).search(params[:q])
9
+ @customers = @query.result
10
+ end
11
+
12
+ def new
13
+ @customer = Shoppe::Customer.new
14
+ end
15
+
16
+ def show
17
+ @addresses = @customer.addresses.ordered.load
18
+ @orders = @customer.orders.ordered.load
19
+ end
20
+
21
+ def create
22
+ @customer = Shoppe::Customer.new(safe_params)
23
+ if @customer.save
24
+ redirect_to @customer, :flash => {:notice => "Customer has been created successfully"}
25
+ else
26
+ render :action => "new"
27
+ end
28
+ end
29
+
30
+ def update
31
+ if @customer.update(safe_params)
32
+ redirect_to @customer, :flash => {:notice => "Customer has been updated successfully"}
33
+ else
34
+ render :action => "edit"
35
+ end
36
+ end
37
+
38
+ def destroy
39
+ @customer.destroy
40
+ redirect_to customers_path, :flash => {:notice => "Customer has been deleted successfully"}
41
+ end
42
+
43
+ def search
44
+ index
45
+ render :action => "index"
46
+ end
47
+
48
+ private
49
+
50
+ def safe_params
51
+ params[:customer].permit(:first_name, :last_name, :company, :email, :phone, :mobile)
52
+ end
53
+
54
+ end
55
+ end
@@ -18,6 +18,34 @@ module Shoppe
18
18
  Shoppe::Order.transaction do
19
19
  @order = Shoppe::Order.new(safe_params)
20
20
  @order.status = 'confirming'
21
+
22
+ if safe_params[:customer_id]
23
+ @customer = Shoppe::Customer.find safe_params[:customer_id]
24
+ @order.first_name = @customer.first_name
25
+ @order.last_name = @customer.last_name
26
+ @order.company = @customer.company
27
+ @order.email_address = @customer.email
28
+ @order.phone_number = @customer.phone
29
+ if @customer.addresses.billing.present?
30
+ billing = @customer.addresses.billing.first
31
+ @order.billing_address1 = billing.address1
32
+ @order.billing_address2 = billing.address2
33
+ @order.billing_address3 = billing.address3
34
+ @order.billing_address4 = billing.address4
35
+ @order.billing_postcode = billing.postcode
36
+ @order.billing_country_id = billing.country_id
37
+ end
38
+ if @customer.addresses.delivery.present?
39
+ delivery = @customer.addresses.delivery.first
40
+ @order.delivery_address1 = delivery.address1
41
+ @order.delivery_address2 = delivery.address2
42
+ @order.delivery_address3 = delivery.address3
43
+ @order.delivery_address4 = delivery.address4
44
+ @order.delivery_postcode = delivery.postcode
45
+ @order.delivery_country_id = delivery.country_id
46
+ end
47
+ end
48
+
21
49
  if !request.xhr? && @order.save
22
50
  @order.confirm!
23
51
  redirect_to @order, :notice => t('shoppe.orders.create_notice')
@@ -76,6 +104,7 @@ module Shoppe
76
104
 
77
105
  def safe_params
78
106
  params[:order].permit(
107
+ :customer_id,
79
108
  :first_name, :last_name, :company,
80
109
  :billing_address1, :billing_address2, :billing_address3, :billing_address4, :billing_postcode, :billing_country_id,
81
110
  :separate_delivery_address,
@@ -0,0 +1,58 @@
1
+ require "globalize"
2
+
3
+ module Shoppe
4
+ class ProductCategoryLocalisationsController < ApplicationController
5
+
6
+ before_filter { @active_nav = :product_categories }
7
+ before_filter { @product_category = Shoppe::ProductCategory.find(params[:product_category_id]) }
8
+ before_filter { params[:id] && @localisation = @product_category.translations.find(params[:id]) }
9
+
10
+ def index
11
+ @localisations = @product_category.translations
12
+ end
13
+
14
+ def new
15
+ @localisation = @product_category.translations.new
16
+ render :action => "form"
17
+ end
18
+
19
+ def create
20
+ if I18n.available_locales.include? safe_params[:locale].to_sym
21
+ I18n.locale = safe_params[:locale].to_sym
22
+
23
+ if @product_category.update(safe_params)
24
+ I18n.locale = I18n.default_locale
25
+ redirect_to [@product_category, :localisations], :flash => { :notice => t("shoppe.localisations.localisation_created") }
26
+ else
27
+ render :action => "edit"
28
+ end
29
+ else
30
+ redirect_to [@product_category, :localisations]
31
+ end
32
+ end
33
+
34
+ def edit
35
+ render :action => "form"
36
+ end
37
+
38
+ def update
39
+ if @localisation.update(safe_params)
40
+ redirect_to [@product_category, :localisations], :notice => t('shoppe.localisations.localisation_updated')
41
+ else
42
+ render :action => "form"
43
+ end
44
+ end
45
+
46
+ def destroy
47
+ @localisation.destroy
48
+ redirect_to [@product_category, :localisations], :notice => t('shoppe.localisations.localisation_destroyed')
49
+ end
50
+
51
+ private
52
+
53
+ def safe_params
54
+ params[:product_category_translation].permit(:name, :locale, :permalink, :description)
55
+ end
56
+
57
+ end
58
+ end
@@ -0,0 +1,58 @@
1
+ require "globalize"
2
+
3
+ module Shoppe
4
+ class ProductLocalisationsController < ApplicationController
5
+
6
+ before_filter { @active_nav = :products }
7
+ before_filter { @product = Shoppe::Product.find(params[:product_id]) }
8
+ before_filter { params[:id] && @localisation = @product.translations.find(params[:id]) }
9
+
10
+ def index
11
+ @localisations = @product.translations
12
+ end
13
+
14
+ def new
15
+ @localisation = @product.translations.new
16
+ render :action => "form"
17
+ end
18
+
19
+ def create
20
+ if I18n.available_locales.include? safe_params[:locale].to_sym
21
+ I18n.locale = safe_params[:locale].to_sym
22
+
23
+ if @product.update(safe_params)
24
+ I18n.locale = I18n.default_locale
25
+ redirect_to [@product, :localisations], :flash => { :notice => t("shoppe.localisations.localisation_created") }
26
+ else
27
+ render :action => "form"
28
+ end
29
+ else
30
+ redirect_to [@product, :localisations]
31
+ end
32
+ end
33
+
34
+ def edit
35
+ render :action => "form"
36
+ end
37
+
38
+ def update
39
+ if @localisation.update(safe_params)
40
+ redirect_to [@product, :localisations], :notice => t('shoppe.localisations.localisation_updated')
41
+ else
42
+ render :action => "form"
43
+ end
44
+ end
45
+
46
+ def destroy
47
+ @localisation.destroy
48
+ redirect_to [@product, :localisations], :notice => t('shoppe.localisations.localisation_destroyed')
49
+ end
50
+
51
+ private
52
+
53
+ def safe_params
54
+ params[:product_translation].permit(:name, :locale, :permalink, :description, :short_description)
55
+ end
56
+
57
+ end
58
+ end
@@ -5,7 +5,7 @@ module Shoppe
5
5
  before_filter { params[:id] && @product = Shoppe::Product.root.find(params[:id]) }
6
6
 
7
7
  def index
8
- @products = Shoppe::Product.root.includes(:stock_level_adjustments, :default_image, :product_categories, :variants).order(:name).group_by(&:product_category).sort_by { |cat,pro| cat.name }
8
+ @products = Shoppe::Product.root.includes(:translations, :stock_level_adjustments, :default_image, :product_categories, :variants).order(:name).group_by(&:product_category).sort_by { |cat,pro| cat.name }
9
9
  end
10
10
 
11
11
  def new
@@ -0,0 +1,44 @@
1
+ module Shoppe
2
+ class Address < ActiveRecord::Base
3
+
4
+ # An array of all the available types for an address
5
+ TYPES = ["billing", "delivery"]
6
+
7
+ # Set the table name
8
+ self.table_name = "shoppe_addresses"
9
+
10
+ # The customer which this address should be linked to
11
+ #
12
+ # @return [Shoppe::Customer]
13
+ belongs_to :customer, :class_name => "Shoppe::Customer"
14
+
15
+ # The order which this address should be linked to
16
+ #
17
+ # @return [Shoppe::Order]
18
+ belongs_to :order, :class_name => "Shoppe::Order"
19
+
20
+ # The country which this address should be linked to
21
+ #
22
+ # @return [Shoppe::Country]
23
+ belongs_to :country, :class_name => "Shoppe::Country"
24
+
25
+ # Validations
26
+ validates :address_type, :presence => true, :inclusion => {:in => TYPES}
27
+ validates :address1, :presence => true
28
+ validates :address3, :presence => true
29
+ validates :address4, :presence => true
30
+ validates :postcode, :presence => true
31
+ validates :country, :presence => true
32
+
33
+ # All addresses ordered by their id asending
34
+ scope :ordered, -> { order(:id => :desc)}
35
+ scope :default, -> { where(default: true)}
36
+ scope :billing, -> { where(address_type: "billing")}
37
+ scope :delivery, -> { where(address_type: "delivery")}
38
+
39
+ def full_address
40
+ [address1, address2, address3, address4, postcode, country.try(:name)].join(", ")
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,41 @@
1
+ module Shoppe
2
+ class Customer < ActiveRecord::Base
3
+
4
+ self.table_name = "shoppe_customers"
5
+
6
+ has_many :addresses, :dependent => :restrict_with_exception, :class_name => "Shoppe::Address"
7
+
8
+ has_many :orders, :dependent => :restrict_with_exception, :class_name => "Shoppe::Order"
9
+
10
+ # Validations
11
+ validates :email, :presence => true, :uniqueness => true, :format => {:with => /\A\b[A-Z0-9\.\_\%\-\+]+@(?:[A-Z0-9\-]+\.)+[A-Z]{2,6}\b\z/i}
12
+ validates :phone, :presence => true, :format => {:with => /\A[\d\ \-x\(\)]{7,}\z/}
13
+
14
+ # All customers ordered by their ID desending
15
+ scope :ordered, -> { order(:id => :desc)}
16
+
17
+ # The name of the customer in the format of "Company (First Last)" or if they don't have
18
+ # company specified, just "First Last".
19
+ #
20
+ # @return [String]
21
+ def name
22
+ company.blank? ? full_name : "#{company} (#{full_name})"
23
+ end
24
+
25
+ # The full name of the customer created by concatinting the first & last name
26
+ #
27
+ # @return [String]
28
+ def full_name
29
+ "#{first_name} #{last_name}"
30
+ end
31
+
32
+ def self.ransackable_attributes(auth_object = nil)
33
+ ["id", "first_name", "last_name", "company", "email", "phone", "mobile"] + _ransackers.keys
34
+ end
35
+
36
+ def self.ransackable_associations(auth_object = nil)
37
+ []
38
+ end
39
+
40
+ end
41
+ end
@@ -19,6 +19,10 @@ module Shoppe
19
19
  # All products which are part of this order (accessed through the items)
20
20
  has_many :products, :through => :order_items, :class_name => 'Shoppe::Product', :source => :ordered_item, :source_type => 'Shoppe::Product'
21
21
 
22
+ # The order can belong to a customer
23
+ belongs_to :customer, :class_name => 'Shoppe::Customer'
24
+ has_many :addresses, :through => :customers, :class_name => "Shoppe::Address"
25
+
22
26
  # Validations
23
27
  validates :token, :presence => true
24
28
  with_options :if => Proc.new { |o| !o.building? } do |order|
@@ -29,6 +33,9 @@ module Shoppe
29
33
  # Set some defaults
30
34
  before_validation { self.token = SecureRandom.uuid if self.token.blank? }
31
35
 
36
+ # Some methods for setting the billing & delivery addresses
37
+ attr_accessor :save_addresses, :billing_address_id, :delivery_address_id
38
+
32
39
  # The order number
33
40
  #
34
41
  # @return [String] - the order number padded with at least 5 zeros
@@ -1,4 +1,5 @@
1
- require 'roo'
1
+ require "roo"
2
+ require "globalize"
2
3
 
3
4
  module Shoppe
4
5
  class Product < ActiveRecord::Base
@@ -58,8 +59,9 @@ module Shoppe
58
59
  # All featured products
59
60
  scope :featured, -> {where(:featured => true)}
60
61
 
61
- # All products ordered with default items first followed by name ascending
62
- scope :ordered, -> {order(:default => :desc, :name => :asc)}
62
+ # Localisations
63
+ translates :name, :permalink, :description, :short_description
64
+ scope :ordered, -> { includes(:translations).order(:name) }
63
65
 
64
66
  # Return the name of the product
65
67
  #
@@ -81,6 +83,7 @@ module Shoppe
81
83
  #
82
84
  # @return [BigDecimal]
83
85
  def price
86
+ # self.default_variant ? self.default_variant.price : read_attribute(:price)
84
87
  self.default_variant ? self.default_variant.price : read_attribute(:price)
85
88
  end
86
89