shoppe 0.0.16 → 0.0.17

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/Rakefile +5 -6
  3. data/app/assets/javascripts/shoppe/application.coffee +19 -0
  4. data/app/assets/stylesheets/shoppe/application.scss +62 -20
  5. data/app/assets/stylesheets/shoppe/{chosen.css → chosen.scss} +18 -24
  6. data/app/assets/stylesheets/shoppe/dialog.scss +17 -2
  7. data/app/controllers/shoppe/orders_controller.rb +9 -7
  8. data/app/controllers/shoppe/payments_controller.rb +33 -0
  9. data/app/controllers/shoppe/settings_controller.rb +4 -0
  10. data/app/controllers/shoppe/tax_rates_controller.rb +1 -1
  11. data/app/controllers/shoppe/users_controller.rb +1 -1
  12. data/app/helpers/shoppe/application_helper.rb +0 -9
  13. data/app/models/shoppe/country.rb +17 -20
  14. data/app/models/shoppe/delivery_service.rb +16 -22
  15. data/app/models/shoppe/delivery_service_price.rb +10 -21
  16. data/app/models/shoppe/order/actions.rb +80 -0
  17. data/app/models/shoppe/order/billing.rb +99 -0
  18. data/app/models/shoppe/order/delivery.rb +196 -0
  19. data/app/models/shoppe/order/states.rb +69 -0
  20. data/app/models/shoppe/order.rb +29 -365
  21. data/app/models/shoppe/order_item.rb +52 -39
  22. data/app/models/shoppe/payment.rb +80 -0
  23. data/app/models/shoppe/product/product_attributes.rb +6 -4
  24. data/app/models/shoppe/product/variants.rb +20 -7
  25. data/app/models/shoppe/product.rb +37 -37
  26. data/app/models/shoppe/product_attribute.rb +13 -20
  27. data/app/models/shoppe/product_category.rb +6 -19
  28. data/app/models/shoppe/setting.rb +9 -0
  29. data/app/models/shoppe/stock_level_adjustment.rb +5 -18
  30. data/app/models/shoppe/tax_rate.rb +18 -21
  31. data/app/models/shoppe/user.rb +8 -15
  32. data/app/views/shoppe/delivery_service_prices/_form.html.haml +9 -3
  33. data/app/views/shoppe/delivery_service_prices/index.html.haml +6 -4
  34. data/app/views/shoppe/delivery_services/_form.html.haml +1 -1
  35. data/app/views/shoppe/orders/edit.html.haml +62 -0
  36. data/app/views/shoppe/orders/index.html.haml +2 -3
  37. data/app/views/shoppe/orders/show.html.haml +100 -63
  38. data/app/views/shoppe/payments/refund.html.haml +14 -0
  39. data/app/views/shoppe/product_categories/_form.html.haml +1 -1
  40. data/app/views/shoppe/products/_form.html.haml +8 -2
  41. data/app/views/shoppe/settings/edit.html.haml +1 -1
  42. data/app/views/shoppe/tax_rates/form.html.haml +5 -4
  43. data/app/views/shoppe/users/_form.html.haml +1 -1
  44. data/app/views/shoppe/variants/form.html.haml +2 -2
  45. data/config/routes.rb +3 -1
  46. data/db/migrate/20130926094549_create_shoppe_initial_schema.rb +1 -1
  47. data/db/migrate/20131024201501_add_address_type_to_shoppe_tax_rates.rb +5 -0
  48. data/db/migrate/20131024204815_create_shoppe_payments.rb +32 -0
  49. data/db/schema.rb +218 -0
  50. data/db/seeds.rb +15 -15
  51. data/lib/shoppe/engine.rb +7 -2
  52. data/lib/shoppe/errors/refund_failed.rb +15 -0
  53. data/lib/shoppe/settings.rb +0 -2
  54. data/lib/shoppe/version.rb +1 -1
  55. data/lib/shoppe/view_helpers.rb +16 -0
  56. data/lib/shoppe.rb +23 -6
  57. data/test/app/db/schema.rb +21 -6
  58. data/test/app/log/development.log +12782 -0
  59. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/application.scssc +0 -0
  60. data/test/app/tmp/cache/assets/development/sass/edac894564dae62b78e653a08d1c41f10ade93f9/chosen.scssc +0 -0
  61. data/test/app/tmp/cache/assets/development/sprockets/01d6eb5fc12044a487be4b93584690f2 +0 -0
  62. data/test/app/tmp/cache/assets/development/sprockets/02d3923383f72b56dd7919e301d22d24 +0 -0
  63. data/test/app/tmp/cache/assets/development/sprockets/0a6bca3e510625f255083bd154cc470b +0 -0
  64. data/test/app/tmp/cache/assets/development/sprockets/2f80004fb2e2ce07283a83ac15cf920a +0 -0
  65. data/test/app/tmp/cache/assets/development/sprockets/322295abdd8625fcce4da08f9565cc63 +0 -0
  66. data/test/app/tmp/cache/assets/development/sprockets/4c8cb5cfd87990ebddbaa5b5fd594be5 +0 -0
  67. data/test/app/tmp/cache/assets/development/sprockets/53c0f5159a54836310b1a3f5357bc4c6 +0 -0
  68. data/test/app/tmp/cache/assets/development/sprockets/7938636d16e11b754d4dd046b89863c4 +0 -0
  69. data/test/app/tmp/cache/assets/development/sprockets/7a90d9251a7c5506f33a3c72a224e571 +0 -0
  70. data/test/app/tmp/cache/assets/development/sprockets/9da17bb4868a0b762f8884db45c76ffd +0 -0
  71. data/test/app/tmp/cache/assets/development/sprockets/a692ba7ed6cff183bb840c2622233c87 +0 -0
  72. data/test/app/tmp/cache/assets/development/sprockets/a9befe910d55141b8ba02d8198b8f966 +0 -0
  73. data/test/app/tmp/cache/assets/development/sprockets/accc4dc17ef18d0b510917a005340da5 +0 -0
  74. data/test/app/tmp/cache/assets/development/sprockets/b9ad7ea18b7e55c3626a15d1dae142ed +0 -0
  75. data/test/app/tmp/cache/assets/development/sprockets/c733f1a2fe9d05a3a634ff64a394f64b +0 -0
  76. data/test/app/tmp/cache/assets/development/sprockets/da76586dcb6d9a408b2cf33307790d66 +0 -0
  77. metadata +62 -63
  78. data/README.rdoc +0 -1
@@ -0,0 +1,80 @@
1
+ module Shoppe
2
+ class Payment < ActiveRecord::Base
3
+
4
+ # The associated order
5
+ #
6
+ # @return [Shoppe::Order]
7
+ belongs_to :order, :class_name => 'Shoppe::Order'
8
+
9
+ # An associated payment (only applies to refunds)
10
+ #
11
+ # @return [Shoppe::Payment]
12
+ belongs_to :parent, :class_name => "Shoppe::Payment", :foreign_key => "parent_payment_id"
13
+
14
+ # Validatiosn
15
+ validates :amount, :numericality => true
16
+ validates :reference, :presence => true
17
+ validates :method, :presence => true
18
+
19
+ # Payments can have associated properties
20
+ key_value_store :properties
21
+
22
+ # Callbacks
23
+ after_create :cache_amount_paid
24
+ after_destroy :cache_amount_paid
25
+ before_destroy { self.parent.update_attribute(:amount_refunded, self.parent.amount_refunded + amount) if self.parent }
26
+
27
+ # Is this payment a refund?
28
+ #
29
+ # @return [Boolean]
30
+ def refund?
31
+ self.amount < BigDecimal(0)
32
+ end
33
+
34
+ # Has this payment had any refunds taken from it?
35
+ #
36
+ # @return [Boolean]
37
+ def refunded?
38
+ self.amount_refunded > BigDecimal(0)
39
+ end
40
+
41
+ # How much of the payment can be refunded
42
+ #
43
+ # @return [BigDecimal]
44
+ def refundable_amount
45
+ refundable? ? (self.amount - self.amount_refunded) : BigDecimal(0.0)
46
+ end
47
+
48
+ # Process a refund from this payment.
49
+ #
50
+ # @param amount [String] the amount which should be refunded
51
+ # @return [Boolean]
52
+ def refund!(amount)
53
+ amount = BigDecimal(amount)
54
+ if refundable_amount >= amount
55
+ transaction do
56
+ self.class.create(:parent => self, :order_id => self.order_id, :amount => 0-amount, :method => self.method, :reference => reference)
57
+ self.update_attribute(:amount_refunded, self.amount_refunded + amount)
58
+ true
59
+ end
60
+ else
61
+ raise Shoppe::Errors::RefundFailed, :message => "Refunds must be less than the payment (#{refundable_amount})"
62
+ end
63
+ end
64
+
65
+ # Return a transaction URL for viewing further information about this
66
+ # payment.
67
+ #
68
+ # @return [String]
69
+ def transaction_url
70
+ nil
71
+ end
72
+
73
+ private
74
+
75
+ def cache_amount_paid
76
+ self.order.update_attribute(:amount_paid, self.order.payments.sum(:amount))
77
+ end
78
+
79
+ end
80
+ end
@@ -1,13 +1,15 @@
1
1
  module Shoppe
2
2
  class Product < ActiveRecord::Base
3
3
 
4
- # Relationships
4
+ # Product attributes for this product
5
5
  has_many :product_attributes, -> { order(:position) }, :class_name => 'Shoppe::ProductAttribute'
6
6
 
7
- # Attribute for providing the hash
7
+ # Used for setting an array of product attributes which will be updated. Usually
8
+ # received from a web browser.
8
9
  attr_accessor :product_attributes_array
9
-
10
- # Save the attributes after saving the record
10
+
11
+ # After saving automatically try to update the product attributes based on the
12
+ # the contents of the product_attributes_array array.
11
13
  after_save do
12
14
  return unless product_attributes_array.is_a?(Array)
13
15
  self.product_attributes.update_from_array(product_attributes_array)
@@ -1,26 +1,39 @@
1
1
  module Shoppe
2
2
  class Product < ActiveRecord::Base
3
3
 
4
- # Relationships
4
+ # Validations
5
+ validate { errors.add :base, "can only belong to a root product" if self.parent && self.parent.parent }
6
+
7
+ # Variants of the product
5
8
  has_many :variants, -> { order("`default` desc, name asc")}, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id', :dependent => :destroy
6
- belongs_to :parent, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id'
7
9
 
8
- # Validations
9
- validate do
10
- errors.add :base, "can only belong to a root product" if self.parent && self.parent.parent
11
- end
10
+ # The parent product (only applies to variants)
11
+ belongs_to :parent, :class_name => 'Shoppe::Product', :foreign_key => 'parent_id'
12
12
 
13
- # Scopes
13
+ # All products which are not variants
14
14
  scope :root, -> { where(:parent_id => nil) }
15
15
 
16
+ # Does this product have any variants?
17
+ #
18
+ # @return [Boolean]
16
19
  def has_variants?
17
20
  !variants.empty?
18
21
  end
19
22
 
23
+ # Returns the default variant for the product or nil if none exists.
24
+ #
25
+ # @return [Shoppe::Product]
20
26
  def default_variant
21
27
  return nil if self.parent
22
28
  @default_variant ||= self.variants.select { |v| v.default? }.first
23
29
  end
24
30
 
31
+ # Is this product a variant of another?
32
+ #
33
+ # @return [Boolean]
34
+ def variant?
35
+ !self.parent_id.blank?
36
+ end
37
+
25
38
  end
26
39
  end
@@ -1,47 +1,33 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_products
4
- #
5
- # id :integer not null, primary key
6
- # parent_id :integer
7
- # product_category_id :integer
8
- # name :string(255)
9
- # sku :string(255)
10
- # permalink :string(255)
11
- # description :text
12
- # short_description :text
13
- # active :boolean default(TRUE)
14
- # weight :decimal(8, 3) default(0.0)
15
- # price :decimal(8, 2) default(0.0)
16
- # cost_price :decimal(8, 2) default(0.0)
17
- # tax_rate_id :integer
18
- # created_at :datetime
19
- # updated_at :datetime
20
- # featured :boolean default(FALSE)
21
- # in_the_box :text
22
- # stock_control :boolean default(TRUE)
23
- # default :boolean default(FALSE)
24
- #
25
-
26
1
  module Shoppe
27
2
  class Product < ActiveRecord::Base
28
3
 
29
- # Set the table name
30
4
  self.table_name = 'shoppe_products'
31
5
 
32
- # Require some concerns
6
+ # Add dependencies for products
33
7
  require_dependency 'shoppe/product/product_attributes'
34
8
  require_dependency 'shoppe/product/variants'
35
-
36
- # Attachments
9
+
10
+ # Products have a default_image and a data_sheet
37
11
  attachment :default_image
38
12
  attachment :data_sheet
39
13
 
40
- # Relationships
14
+ # The product's category
15
+ #
16
+ # @return [Shoppe::ProductCategory]
41
17
  belongs_to :product_category, :class_name => 'Shoppe::ProductCategory'
18
+
19
+ # The product's tax rate
20
+ #
21
+ # @return [Shoppe::TaxRate]
42
22
  belongs_to :tax_rate, :class_name => "Shoppe::TaxRate"
23
+
24
+ # Ordered items which are associated with this product
43
25
  has_many :order_items, :dependent => :restrict_with_exception, :class_name => 'Shoppe::OrderItem', :as => :ordered_item
26
+
27
+ # Orders which have ordered this product
44
28
  has_many :orders, :through => :order_items, :class_name => 'Shoppe::Order'
29
+
30
+ # Stock level adjustments for this product
45
31
  has_many :stock_level_adjustments, :dependent => :destroy, :class_name => 'Shoppe::StockLevelAdjustment', :as => :item
46
32
 
47
33
  # Validations
@@ -56,47 +42,59 @@ module Shoppe
56
42
  validates :weight, :numericality => true
57
43
  validates :price, :numericality => true
58
44
  validates :cost_price, :numericality => true, :allow_blank => true
59
-
60
- # Set the permalink
45
+
46
+ # Before validation, set the permalink if we don't already have one
61
47
  before_validation { self.permalink = self.name.parameterize if self.permalink.blank? && self.name.is_a?(String) }
62
48
 
63
- # Scopes
49
+ # All active products
64
50
  scope :active, -> { where(:active => true) }
51
+
52
+ # All featured products
65
53
  scope :featured, -> {where(:featured => true)}
54
+
55
+ # All products ordered with default items first followed by name ascending
66
56
  scope :ordered, -> {order('`default` desc, name asc')}
67
57
 
68
58
  # Return the name of the product
59
+ #
60
+ # @return [String]
69
61
  def full_name
70
62
  self.parent ? "#{self.parent.name} (#{name})" : name
71
63
  end
72
64
 
73
- # Is this product actually orderable?
65
+ # Is this product orderable?
66
+ #
67
+ # @return [Boolean]
74
68
  def orderable?
75
69
  return false if self.has_variants?
76
70
  true
77
71
  end
78
72
 
79
- # Return the price for the product
73
+ # The price for the product
74
+ #
75
+ # @return [BigDecimal]
80
76
  def price
81
77
  self.default_variant ? self.default_variant.price : read_attribute(:price)
82
78
  end
83
79
 
84
80
  # Is this product currently in stock?
81
+ #
82
+ # @return [Boolean]
85
83
  def in_stock?
86
84
  self.default_variant ? self.default_variant.in_stock? : stock > 0
87
85
  end
88
86
 
89
87
  # Return the total number of items currently in stock
88
+ #
89
+ # @return [Fixnum]
90
90
  def stock
91
91
  @stock ||= self.stock_level_adjustments.sum(:adjustment)
92
92
  end
93
93
 
94
- # Specify which attributes can be searched
95
94
  def self.ransackable_attributes(auth_object = nil)
96
95
  ["id", "name", "sku"] + _ransackers.keys
97
96
  end
98
97
 
99
- # Specify which associations can be searched
100
98
  def self.ransackable_associations(auth_object = nil)
101
99
  []
102
100
  end
@@ -106,6 +104,8 @@ module Shoppe
106
104
  # For example:
107
105
  #
108
106
  # Shoppe::Product.active.with_attribute('Manufacturer', 'Apple').with_attribute('Model', ['Macbook', 'iPhone'])
107
+ #
108
+ # @return [Enumerable]
109
109
  def self.with_attributes(key, values)
110
110
  product_ids = Shoppe::ProductAttribute.searchable.where(:key => key, :value => values).pluck(:product_id).uniq
111
111
  where(:id => product_ids)
@@ -1,35 +1,25 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_product_attributes
4
- #
5
- # id :integer not null, primary key
6
- # product_id :integer
7
- # key :string(255)
8
- # value :string(255)
9
- # position :integer default(1)
10
- # searchable :boolean default(TRUE)
11
- # created_at :datetime
12
- # updated_at :datetime
13
- # public :boolean default(TRUE)
14
- #
15
-
16
1
  module Shoppe
17
2
  class ProductAttribute < ActiveRecord::Base
18
3
 
19
- # Set the table name
20
4
  self.table_name = 'shoppe_product_attributes'
21
-
5
+
22
6
  # Validations
23
7
  validates :key, :presence => true
24
8
 
25
- # Relationships
9
+ # The associated product
10
+ #
11
+ # @return [Shoppe::Product]
26
12
  belongs_to :product, :class_name => 'Shoppe::Product'
27
13
 
28
- # Scopes
14
+ # All attributes which are searchable
29
15
  scope :searchable, -> { where(:searchable => true) }
16
+
17
+ # All attributes which are public
30
18
  scope :public, -> { where(:public => true) }
31
19
 
32
20
  # Return the the available options as a hash
21
+ #
22
+ # @return [Hash]
33
23
  def self.grouped_hash
34
24
  all.group_by(&:key).inject(Hash.new) do |h, (key, attributes)|
35
25
  h[key] = attributes.map(&:value).uniq
@@ -38,7 +28,9 @@ module Shoppe
38
28
  end
39
29
 
40
30
  # Create/update attributes for a product based on the provided hash of
41
- # keys & values
31
+ # keys & values.
32
+ #
33
+ # @param array [Array]
42
34
  def self.update_from_array(array)
43
35
  existing_keys = self.pluck(:key)
44
36
  index = 0
@@ -62,6 +54,7 @@ module Shoppe
62
54
  end
63
55
  end
64
56
  self.where(:key => existing_keys - array.map { |h| h['key']}).delete_all
57
+ true
65
58
  end
66
59
 
67
60
  end
@@ -1,35 +1,22 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_product_categories
4
- #
5
- # id :integer not null, primary key
6
- # name :string(255)
7
- # permalink :string(255)
8
- # description :text
9
- # created_at :datetime
10
- # updated_at :datetime
11
- #
12
-
13
1
  module Shoppe
14
2
  class ProductCategory < ActiveRecord::Base
15
3
 
16
- # Set the table name
17
4
  self.table_name = 'shoppe_product_categories'
18
5
 
19
- # Attachments
6
+ # Categories have an image attachment
20
7
  attachment :image
21
8
 
22
- # Relationships
9
+ # All products within this category
23
10
  has_many :products, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Product'
24
-
11
+
25
12
  # Validations
26
13
  validates :name, :presence => true
27
14
  validates :permalink, :presence => true, :uniqueness => true
28
15
 
29
- # Scopes
16
+ # All categories ordered by their name ascending
30
17
  scope :ordered, -> { order(:name) }
31
-
32
- # Set the permalink
18
+
19
+ # Set the permalink on callback
33
20
  before_validation { self.permalink = self.name.parameterize if self.permalink.blank? && self.name.is_a?(String) }
34
21
 
35
22
  end
@@ -3,6 +3,7 @@ require 'ostruct'
3
3
  module Shoppe
4
4
  class Setting < ActiveRecord::Base
5
5
 
6
+ # Validations
6
7
  validates :key, :presence => true, :uniqueness => true
7
8
  validates :value, :presence => true
8
9
  validates :value_type, :presence => true
@@ -13,6 +14,8 @@ module Shoppe
13
14
  end
14
15
 
15
16
  # The encoded value for saving in the backend (as a string)
17
+ #
18
+ # @return [String]
16
19
  def encoded_value
17
20
  case value_type
18
21
  when 'Array', 'Hash' then value.to_json
@@ -22,6 +25,8 @@ module Shoppe
22
25
  end
23
26
 
24
27
  # The decoded value for the setting attribute (in it's native type)
28
+ #
29
+ # @return [Object]
25
30
  def decoded_value
26
31
  case value_type
27
32
  when 'Fixnum' then value.to_i
@@ -33,6 +38,8 @@ module Shoppe
33
38
  end
34
39
 
35
40
  # A full hash of all settings available in the current scope
41
+ #
42
+ # @return [Hash]
36
43
  def self.to_hash
37
44
  all.inject({}) do |h, setting|
38
45
  h[setting.key.to_s] = setting.decoded_value
@@ -42,6 +49,8 @@ module Shoppe
42
49
 
43
50
  # Update settings from a given hash and persist them. Accepts a
44
51
  # hash of keys (which should be strings).
52
+ #
53
+ # @return [Hash]
45
54
  def self.update_from_hash(hash)
46
55
  existing_settings = self.all.to_a
47
56
  hash.each do |key, value|
@@ -1,23 +1,10 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_stock_level_adjustments
4
- #
5
- # id :integer not null, primary key
6
- # item_id :integer
7
- # item_type :string(255)
8
- # description :string(255)
9
- # adjustment :integer default(0)
10
- # parent_type :string(255)
11
- # parent_id :integer
12
- # created_at :datetime
13
- # updated_at :datetime
14
- #
15
-
16
1
  module Shoppe
17
2
  class StockLevelAdjustment < ActiveRecord::Base
18
3
 
19
- # Relationships
4
+ # The orderable item which the stock level adjustment belongs to
20
5
  belongs_to :item, :polymorphic => true
6
+
7
+ # The parent (OrderItem) which the stock level adjustment belongs to
21
8
  belongs_to :parent, :polymorphic => true
22
9
 
23
10
  # Validations
@@ -25,8 +12,8 @@ module Shoppe
25
12
  validates :adjustment, :numericality => true
26
13
  validate { errors.add(:adjustment, "must be greater or less than zero") if adjustment == 0 }
27
14
 
28
- # Scopes
29
- scope :ordered, -> { order('created_at desc') }
15
+ # All stock level adjustments ordered by their created date desending
16
+ scope :ordered, -> { order('id desc') }
30
17
 
31
18
  end
32
19
  end
@@ -1,45 +1,42 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_tax_rates
4
- #
5
- # id :integer not null, primary key
6
- # name :string(255)
7
- # rate :decimal(8, 2)
8
- # created_at :datetime
9
- # updated_at :datetime
10
- # country_ids :text
11
- #
12
-
13
1
  module Shoppe
14
2
  class TaxRate < ActiveRecord::Base
15
3
 
16
- # Set the table name
17
4
  self.table_name = 'shoppe_tax_rates'
18
5
 
19
- # Tax rates are associated with countries
20
6
  include Shoppe::AssociatedCountries
21
7
 
8
+ # The order address types which may be used when choosing how to apply the tax rate
9
+ ADDRESS_TYPES = ['billing', 'delivery']
10
+
22
11
  # Validations
23
12
  validates :name, :presence => true
13
+ validates :address_type, :inclusion => {:in => ADDRESS_TYPES}
24
14
  validates :rate, :numericality => true
25
15
 
26
- # Relationships
16
+ # All products which are assigned to this tax rate
27
17
  has_many :products, :dependent => :restrict_with_exception, :class_name => 'Shoppe::Product'
18
+
19
+ # All delivery service prices which are assigned to this tax rate
28
20
  has_many :delivery_service_prices, :dependent => :restrict_with_exception, :class_name => 'Shoppe::DeliveryServicePrice'
29
21
 
30
- # Scopes
22
+ # All tax rates ordered by their ID
31
23
  scope :ordered, -> { order("shoppe_tax_rates.id")}
32
24
 
25
+ # A description of the tax rate including its name & percentage
26
+ #
27
+ # @return [String]
33
28
  def description
34
29
  "#{name} (#{rate}%)"
35
30
  end
36
31
 
32
+ # The rate for a given order based on the rules on the tax rate
33
+ #
34
+ # @return [BigDecimal]
37
35
  def rate_for(order)
38
- if countries.empty? || order.billing_country.nil? || country?(order.billing_country)
39
- self.rate
40
- else
41
- 0.0
42
- end
36
+ return rate if countries.empty?
37
+ return rate if address_type == 'billing' && (order.billing_country.nil? || country?(order.billing_country))
38
+ return rate if address_type == 'delivery' && (order.delivery_country.nil? || country?(order.delivery_country))
39
+ BigDecimal(0)
43
40
  end
44
41
 
45
42
  end
@@ -1,23 +1,8 @@
1
- # == Schema Information
2
- #
3
- # Table name: shoppe_users
4
- #
5
- # id :integer not null, primary key
6
- # first_name :string(255)
7
- # last_name :string(255)
8
- # email_address :string(255)
9
- # password_digest :string(255)
10
- # created_at :datetime
11
- # updated_at :datetime
12
- #
13
-
14
1
  module Shoppe
15
2
  class User < ActiveRecord::Base
16
3
 
17
- # Set the table name
18
4
  self.table_name = 'shoppe_users'
19
5
 
20
- # Self explanatory I think!
21
6
  has_secure_password
22
7
 
23
8
  # Validations
@@ -26,11 +11,15 @@ module Shoppe
26
11
  validates :email_address, :presence => true
27
12
 
28
13
  # The user's first name & last name concatenated
14
+ #
15
+ # @return [String]
29
16
  def full_name
30
17
  "#{first_name} #{last_name}"
31
18
  end
32
19
 
33
20
  # The user's first name & initial of last name concatenated
21
+ #
22
+ # @return [String]
34
23
  def short_name
35
24
  "#{first_name} #{last_name[0,1]}"
36
25
  end
@@ -45,6 +34,10 @@ module Shoppe
45
34
 
46
35
  # Attempt to authenticate a user based on email & password. Returns the
47
36
  # user if successful otherwise returns false.
37
+ #
38
+ # @param email_address [String]
39
+ # @param paassword [String]
40
+ # @return [Shoppe::User]
48
41
  def self.authenticate(email_address, password)
49
42
  user = self.where(:email_address => email_address).first
50
43
  return false if user.nil?
@@ -4,7 +4,7 @@
4
4
  .splitContainer
5
5
  %dl.third
6
6
  %dt= f.label :code
7
- %dd= f.text_field :code, :class => 'text'
7
+ %dd= f.text_field :code, :class => 'focus text'
8
8
 
9
9
  %dl.third
10
10
  %dt= f.label :min_weight
@@ -17,10 +17,16 @@
17
17
  .splitContainer
18
18
  %dl.third
19
19
  %dt= f.label :price
20
- %dd= f.text_field :price, :class => 'text'
20
+ %dd
21
+ .moneyInput
22
+ .currency= Shoppe.settings.currency_unit.html_safe
23
+ = f.text_field :price, :class => 'text'
21
24
  %dl.third
22
25
  %dt= f.label :cost_price
23
- %dd= f.text_field :cost_price, :class => 'text'
26
+ %dd
27
+ .moneyInput
28
+ .currency= Shoppe.settings.currency_unit.html_safe
29
+ = f.text_field :cost_price, :class => 'text'
24
30
  %dl.third
25
31
  %dt= f.label :tax_rate_id
26
32
  %dd= f.collection_select :tax_rate_id, Shoppe::TaxRate.ordered, :id, :description, {:include_blank => true}, {:class => 'chosen-with-deselect', :data => {:placeholder => "No tax"}}
@@ -10,13 +10,15 @@
10
10
  %table.data
11
11
  %thead
12
12
  %tr
13
- %th Price
14
- %th Weight Allowance
15
13
  %th Code
14
+ %th Weight Allowance
15
+ %th Price
16
+ %th Cost
16
17
  %tbody
17
18
  - for price in @delivery_service_prices
18
19
  %tr
19
- %td= link_to number_to_currency(price.price), [:edit, @delivery_service, price]
20
+ %td= link_to price.code, [:edit, @delivery_service, price]
20
21
  %td #{number_to_weight price.min_weight} &rarr; #{number_to_weight price.max_weight}
21
- %td= price.code
22
+ %td= number_to_currency(price.price)
23
+ %td= number_to_currency price.cost_price
22
24
 
@@ -4,7 +4,7 @@
4
4
  .splitContainer
5
5
  %dl.half
6
6
  %dt= f.label :name
7
- %dd= f.text_field :name, :class => 'text'
7
+ %dd= f.text_field :name, :class => 'focus text'
8
8
  %dl.half
9
9
  %dt= f.label :code
10
10
  %dd= f.text_field :code, :class => 'text'