comable-core 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +97 -0
  4. data/app/assets/javascripts/comable/application.js +13 -0
  5. data/app/assets/stylesheets/comable/application.css +13 -0
  6. data/app/controllers/concerns/comable/permitted_attributes.rb +15 -0
  7. data/app/helpers/comable/application_helper.rb +84 -0
  8. data/app/helpers/comable/products_helper.rb +82 -0
  9. data/app/mailers/comable/order_mailer.rb +18 -0
  10. data/app/models/comable/ability.rb +18 -0
  11. data/app/models/comable/address.rb +39 -0
  12. data/app/models/comable/category.rb +72 -0
  13. data/app/models/comable/image.rb +15 -0
  14. data/app/models/comable/order.rb +121 -0
  15. data/app/models/comable/order/associations.rb +22 -0
  16. data/app/models/comable/order/callbacks.rb +43 -0
  17. data/app/models/comable/order/morrisable.rb +20 -0
  18. data/app/models/comable/order/scopes.rb +17 -0
  19. data/app/models/comable/order/validations.rb +39 -0
  20. data/app/models/comable/order_item.rb +98 -0
  21. data/app/models/comable/order_item/csvable.rb +32 -0
  22. data/app/models/comable/page.rb +30 -0
  23. data/app/models/comable/payment.rb +87 -0
  24. data/app/models/comable/payment_method.rb +27 -0
  25. data/app/models/comable/product.rb +55 -0
  26. data/app/models/comable/product/csvable.rb +20 -0
  27. data/app/models/comable/shipment.rb +85 -0
  28. data/app/models/comable/shipment_method.rb +9 -0
  29. data/app/models/comable/stock.rb +71 -0
  30. data/app/models/comable/stock/csvable.rb +26 -0
  31. data/app/models/comable/store.rb +30 -0
  32. data/app/models/comable/theme.rb +25 -0
  33. data/app/models/comable/tracker.rb +17 -0
  34. data/app/models/comable/user.rb +130 -0
  35. data/app/models/concerns/comable/cart_owner.rb +94 -0
  36. data/app/models/concerns/comable/checkout.rb +85 -0
  37. data/app/models/concerns/comable/importable.rb +67 -0
  38. data/app/models/concerns/comable/liquidable.rb +12 -0
  39. data/app/models/concerns/comable/product/search.rb +41 -0
  40. data/app/models/concerns/comable/ransackable.rb +38 -0
  41. data/app/models/concerns/comable/role_owner.rb +15 -0
  42. data/app/models/concerns/comable/sku_choice.rb +19 -0
  43. data/app/models/concerns/comable/sku_item.rb +17 -0
  44. data/app/uploaders/image_uploader.rb +7 -0
  45. data/app/views/comable/order_mailer/complete.text.erb +42 -0
  46. data/config/initializers/comma.rb +8 -0
  47. data/config/locales/en.yml +424 -0
  48. data/config/locales/ja.yml +425 -0
  49. data/db/migrate/20131214194807_create_comable_products.rb +15 -0
  50. data/db/migrate/20140120032559_create_comable_users.rb +46 -0
  51. data/db/migrate/20140502060116_create_comable_stocks.rb +14 -0
  52. data/db/migrate/20140723175431_create_comable_orders.rb +20 -0
  53. data/db/migrate/20140723175810_create_comable_order_items.rb +19 -0
  54. data/db/migrate/20140817194104_create_comable_payment_methods.rb +13 -0
  55. data/db/migrate/20140921191416_create_comable_shipment_methods.rb +11 -0
  56. data/db/migrate/20140926063541_create_comable_stores.rb +11 -0
  57. data/db/migrate/20141024025526_create_comable_addresses.rb +17 -0
  58. data/db/migrate/20150111031228_create_comable_categories.rb +10 -0
  59. data/db/migrate/20150111031229_create_comable_products_categories.rb +8 -0
  60. data/db/migrate/20150112173706_create_comable_images.rb +9 -0
  61. data/db/migrate/20150423095210_create_comable_shipments.rb +13 -0
  62. data/db/migrate/20150511171940_create_comable_payments.rb +12 -0
  63. data/db/migrate/20150513185230_create_comable_trackers.rb +12 -0
  64. data/db/migrate/20150519080729_create_comable_pages.rb +17 -0
  65. data/db/migrate/20150612143226_create_comable_themes.rb +15 -0
  66. data/db/migrate/20150612143445_add_theme_id_to_comable_stores.rb +7 -0
  67. data/db/seeds.rb +5 -0
  68. data/db/seeds/comable/users.rb +51 -0
  69. data/lib/comable/core.rb +48 -0
  70. data/lib/comable/core/configuration.rb +22 -0
  71. data/lib/comable/core/engine.rb +50 -0
  72. data/lib/comable/deprecator.rb +26 -0
  73. data/lib/comable/payment_provider.rb +14 -0
  74. data/lib/comable/payment_provider/base.rb +42 -0
  75. data/lib/comable/payment_provider/general.rb +15 -0
  76. data/lib/comable/state_machine_patch.rb +32 -0
  77. data/lib/comma_extractor_extentions.rb +31 -0
  78. data/lib/generators/comable/install/install_generator.rb +133 -0
  79. data/lib/generators/comable/install/templates/config/initializers/comable.rb +31 -0
  80. data/lib/tasks/comable_tasks.rake +4 -0
  81. metadata +346 -0
@@ -0,0 +1,87 @@
1
+ module Comable
2
+ class Payment < ActiveRecord::Base
3
+ include Comable::Ransackable
4
+
5
+ belongs_to :order, class_name: Comable::Order.name, inverse_of: :payment
6
+ belongs_to :payment_method, class_name: Comable::PaymentMethod.name
7
+
8
+ before_validation :copy_attributes_from_payment_method, unless: :order_completed?
9
+
10
+ validates :order, presence: true
11
+ validates :payment_method, presence: true
12
+ validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
13
+
14
+ delegate :name, to: :payment_method
15
+ delegate :payment_provider, to: :payment_method
16
+ delegate :authorize!, :complete!, :cancel!, :resume!, to: :payment_provider, prefix: :provider
17
+
18
+ ransack_options ransackable_attributes: { except: [:order_id, :payment_method_id] }
19
+
20
+ # The #state attribute assigns the following values:
21
+ #
22
+ # pending when Order is not able to pay (default)
23
+ # ready when Order is able to pay
24
+ # completed when Order is already paid
25
+ # canceled when Order is canceled
26
+ # resumed when Order is resumed from the "canceled" state
27
+ state_machine initial: :pending do
28
+ state :pending
29
+ state :ready
30
+ state :completed
31
+ state :canceled
32
+ state :resumed
33
+
34
+ event :next_state do
35
+ transition :pending => :ready
36
+ transition :ready => :completed
37
+ end
38
+
39
+ event :cancel do
40
+ transition [:completed, :resumed] => :canceled
41
+ end
42
+
43
+ event :resume do
44
+ transition :canceled => :resumed
45
+ end
46
+
47
+ after_transition to: :ready, do: :next_state!
48
+ before_transition to: :ready, do: -> (s) { s.provider_authorize! }
49
+ before_transition to: :completed, do: -> (s) { s.complete! }
50
+ before_transition to: :canceled, do: -> (s) { s.provider_cancel! }
51
+ before_transition to: :canceled, do: -> (s) { s.provider_resume! }
52
+ end
53
+
54
+ class << self
55
+ def state_names
56
+ state_machine.states.keys
57
+ end
58
+ end
59
+
60
+ def stated?(target_state)
61
+ target_state_index = self.class.state_names.index(target_state.to_sym)
62
+ current_state_index = self.class.state_names.index(state_name)
63
+ target_state_index < current_state_index
64
+ end
65
+
66
+ def completed?
67
+ completed_at?
68
+ end
69
+
70
+ def complete!
71
+ provider_complete!
72
+ touch :completed_at
73
+ end
74
+
75
+ private
76
+
77
+ def order_completed?
78
+ order.completed?
79
+ end
80
+
81
+ def copy_attributes_from_payment_method
82
+ self.attributes = {
83
+ fee: payment_method.fee
84
+ }
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,27 @@
1
+ module Comable
2
+ class PaymentMethod < ActiveRecord::Base
3
+ validates :name, presence: true, length: { maximum: 255 }
4
+ validates :payment_provider_type, presence: true, length: { maximum: 255 }
5
+ validates :payment_provider_kind, presence: true, numericality: { greater_than_or_equal_to: 0 }
6
+ validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
7
+ validates :enable_price_from, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
8
+ validates :enable_price_to, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
9
+
10
+ def payment_provider
11
+ return unless Object.const_defined?(payment_provider_type)
12
+ Object.const_get(payment_provider_type)
13
+ end
14
+
15
+ def payment_provider_name
16
+ payment_provider.display_name
17
+ end
18
+
19
+ def payment_provider_kind_key
20
+ payment_provider.kind.keys.slice(payment_provider_kind)
21
+ end
22
+
23
+ def payment_provider_kind_name
24
+ payment_provider.kind.slice(payment_provider_kind_key).values.first
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,55 @@
1
+ module Comable
2
+ class Product < ActiveRecord::Base
3
+ include Comable::SkuItem
4
+ include Comable::Ransackable
5
+ include Comable::Liquidable
6
+ include Comable::Product::Search
7
+ include Comable::Product::Csvable
8
+
9
+ has_many :stocks, class_name: Comable::Stock.name, dependent: :destroy
10
+ has_many :images, class_name: Comable::Image.name, dependent: :destroy
11
+ has_and_belongs_to_many :categories, class_name: Comable::Category.name, join_table: :comable_products_categories
12
+
13
+ accepts_nested_attributes_for :images, allow_destroy: true
14
+
15
+ validates :name, presence: true, length: { maximum: 255 }
16
+ validates :code, presence: true, length: { maximum: 255 }
17
+ validates :price, presence: true, numericality: { greater_than_or_equal_to: 0, allow_blank: true }
18
+ validates :sku_h_item_name, length: { maximum: 255 }
19
+ validates :sku_v_item_name, length: { maximum: 255 }
20
+
21
+ liquid_methods :id, :code, :name, :price, :images, :image_url
22
+
23
+ ransack_options attribute_select: { associations: :stocks }
24
+
25
+ # Add conditions for the images association.
26
+ # Override method of the images association to support Rails 3.x.
27
+ def images
28
+ super.order(:id)
29
+ end
30
+
31
+ def image_url
32
+ image = images.first
33
+ return image.url if image
34
+ 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9InllcyI/PjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMTcxIiBoZWlnaHQ9IjE4MCIgdmlld0JveD0iMCAwIDE3MSAxODAiIHByZXNlcnZlQXNwZWN0UmF0aW89Im5vbmUiPjxkZWZzLz48cmVjdCB3aWR0aD0iMTcxIiBoZWlnaHQ9IjE4MCIgZmlsbD0iI0VFRUVFRSIvPjxnPjx0ZXh0IHg9IjU4IiB5PSI5MCIgc3R5bGU9ImZpbGw6I0FBQUFBQTtmb250LXdlaWdodDpib2xkO2ZvbnQtZmFtaWx5OkFyaWFsLCBIZWx2ZXRpY2EsIE9wZW4gU2Fucywgc2Fucy1zZXJpZiwgbW9ub3NwYWNlO2ZvbnQtc2l6ZToxMHB0O2RvbWluYW50LWJhc2VsaW5lOmNlbnRyYWwiPjE3MXgxODA8L3RleHQ+PC9nPjwvc3ZnPg=='
35
+ end
36
+
37
+ def stocked?
38
+ stocks.stocked.exists?
39
+ end
40
+
41
+ def unstocked?
42
+ !stocked?
43
+ end
44
+
45
+ def category_path_names=(category_path_names, delimiter: Comable::Category::DEFAULT_PATH_NAME_DELIMITER)
46
+ self.categories = Comable::Category.find_by_path_names(category_path_names, delimiter: delimiter)
47
+ end
48
+
49
+ private
50
+
51
+ def create_stock
52
+ stocks.create(code: code) unless stocks.exists?
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,20 @@
1
+ module Comable
2
+ class Product < ActiveRecord::Base
3
+ module Csvable
4
+ extend ActiveSupport::Concern
5
+
6
+ include Comable::Importable
7
+
8
+ included do
9
+ comma do
10
+ name
11
+ code
12
+ price
13
+ caption
14
+ sku_h_item_name
15
+ sku_v_item_name
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,85 @@
1
+ module Comable
2
+ class Shipment < ActiveRecord::Base
3
+ include Comable::Ransackable
4
+
5
+ belongs_to :order, class_name: Comable::Order.name, inverse_of: :shipment
6
+ belongs_to :shipment_method, class_name: Comable::ShipmentMethod.name
7
+
8
+ before_validation :copy_attributes_from_shipment_method, unless: :order_completed?
9
+
10
+ validates :order, presence: true
11
+ validates :shipment_method, presence: true
12
+ validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
13
+ validates :tracking_number, length: { maximum: 255 }
14
+
15
+ delegate :name, to: :shipment_method
16
+
17
+ ransack_options ransackable_attributes: { except: [:order_id, :shipment_method_id] }
18
+
19
+ # The #state attribute assigns the following values:
20
+ #
21
+ # pending when Order is not able to ship (default)
22
+ # ready when Order is able to ship
23
+ # completed when Order is already shipped
24
+ # canceled when Order is canceled
25
+ # resumed when Order is resumed from the "canceled" state
26
+ state_machine initial: :pending do
27
+ state :pending
28
+ state :ready
29
+ state :completed
30
+ state :canceled
31
+ state :resumed
32
+
33
+ event :next_state do
34
+ transition :pending => :ready
35
+ transition :ready => :completed
36
+ end
37
+
38
+ event :ship do
39
+ transition :ready => :completed
40
+ end
41
+
42
+ event :cancel do
43
+ transition [:completed, :resumed] => :canceled
44
+ end
45
+
46
+ event :resume do
47
+ transition :canceled => :resumed
48
+ end
49
+
50
+ before_transition to: :completed, do: -> (s) { s.complete! }
51
+ end
52
+
53
+ class << self
54
+ def state_names
55
+ state_machine.states.keys
56
+ end
57
+ end
58
+
59
+ def stated?(target_state)
60
+ target_state_index = self.class.state_names.index(target_state.to_sym)
61
+ current_state_index = self.class.state_names.index(state_name)
62
+ target_state_index < current_state_index
63
+ end
64
+
65
+ def completed?
66
+ completed_at?
67
+ end
68
+
69
+ def complete!
70
+ touch :completed_at
71
+ end
72
+
73
+ private
74
+
75
+ def order_completed?
76
+ order.completed?
77
+ end
78
+
79
+ def copy_attributes_from_shipment_method
80
+ self.attributes = {
81
+ fee: shipment_method.fee
82
+ }
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,9 @@
1
+ module Comable
2
+ class ShipmentMethod < ActiveRecord::Base
3
+ validates :name, presence: true, length: { maximum: 255 }
4
+ validates :fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
5
+ validates :traking_url, length: { maximum: 255 }
6
+
7
+ scope :activated, -> { where(activated_flag: true) }
8
+ end
9
+ end
@@ -0,0 +1,71 @@
1
+ module Comable
2
+ #
3
+ # 在庫モデル。
4
+ # 商品に複数紐付き、品数やSKU(Stock Keeping Unit)情報を保持する。
5
+ #
6
+ class Stock < ActiveRecord::Base
7
+ include Comable::SkuItem
8
+ include Comable::SkuChoice
9
+ include Comable::Ransackable
10
+ include Comable::Liquidable
11
+ include Comable::Stock::Csvable
12
+
13
+ belongs_to :product, class_name: Comable::Product.name
14
+
15
+ #
16
+ # @!group Scope
17
+ #
18
+
19
+ # @!scope class
20
+ # 品切れでない在庫インスタンスを返す
21
+ scope :stocked, -> { where('quantity > ?', 0) }
22
+
23
+ # @!scope class
24
+ # 品切れの在庫インスタンスを返す
25
+ scope :unstocked, -> { where('quantity <= ?', 0) }
26
+
27
+ #
28
+ # @!endgroup
29
+ #
30
+
31
+ validates :product, presence: { message: Comable.t('admin.is_not_exists') }
32
+ validates :code, presence: true, length: { maximum: 255 }
33
+ validates :sku_h_choice_name, length: { maximum: 255 }
34
+ validates :sku_v_choice_name, length: { maximum: 255 }
35
+ # TODO: add conditions (by limitless flag, backoder flag and etc..)
36
+ validates :quantity, numericality: { greater_than_or_equal_to: 0 }
37
+
38
+ delegate :name, to: :product
39
+ delegate :price, to: :product
40
+ delegate :sku_h_item_name, to: :product
41
+ delegate :sku_v_item_name, to: :product
42
+
43
+ ransack_options attribute_select: { associations: :product }, ransackable_attributes: { except: :product_id }
44
+
45
+ # 在庫の有無を取得する
46
+ #
47
+ # @example
48
+ # stock.quanaity = 1
49
+ # stock.stocked? #=> true
50
+ #
51
+ # @param quantity [Fixnum] 減算する在庫数を指定する
52
+ # @return [Boolean] 在庫があれば true を返す
53
+ # @see #unstocked?
54
+ def stocked?(quantity: 1)
55
+ (self.quantity - quantity) >= 0
56
+ end
57
+
58
+ # 在庫の有無を取得する
59
+ #
60
+ # @example
61
+ # stock.quanaity = 1
62
+ # stock.unstocked? #=> false
63
+ #
64
+ # @param quantity [Fixnum] 減算する在庫数を指定する
65
+ # @return [Boolean] {#stocked?} の逆。在庫がなければ true を返す
66
+ # @see #stocked?
67
+ def unstocked?(quantity: 1)
68
+ !stocked?(quantity: quantity)
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,26 @@
1
+ module Comable
2
+ class Stock < ActiveRecord::Base
3
+ module Csvable
4
+ extend ActiveSupport::Concern
5
+
6
+ include Comable::Importable
7
+
8
+ included do
9
+ comma do
10
+ product_code
11
+ code
12
+ quantity
13
+ sku_h_choice_name
14
+ sku_v_choice_name
15
+ end
16
+ end
17
+
18
+ delegate :code, to: :product, prefix: true, allow_nil: true
19
+
20
+ def product_code=(code)
21
+ return if product_code == code
22
+ self.product = Comable::Product.find_by(code: code)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ module Comable
2
+ class Store < ActiveRecord::Base
3
+ include Comable::Liquidable
4
+
5
+ belongs_to :theme, class_name: Comable::Theme.name
6
+
7
+ validates :name, length: { maximum: 255 }
8
+ validates :meta_keywords, length: { maximum: 255 }
9
+ validates :meta_description, length: { maximum: 255 }
10
+ validates :email, length: { maximum: 255 }
11
+
12
+ liquid_methods :name, :meta_keywords, :meta_description, :email
13
+
14
+ delegate :name, to: :theme, prefix: true, allow_nil: true
15
+
16
+ class << self
17
+ def instance
18
+ first || new(name: default_name)
19
+ end
20
+
21
+ def default_name
22
+ Comable.t('default_store_name')
23
+ end
24
+ end
25
+
26
+ def can_send_mail?
27
+ email.present?
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,25 @@
1
+ module Comable
2
+ class Theme < ActiveRecord::Base
3
+ has_one :store, class_name: Comable::Store.name
4
+
5
+ validates :name, uniqueness: { scope: :version }
6
+ validates :name, presence: true, length: { maximum: 255 }
7
+ validates :version, presence: true, length: { maximum: 255 }
8
+ validates :display, length: { maximum: 255 }
9
+ validates :description, length: { maximum: 255 }
10
+ validates :homepage, length: { maximum: 255 }
11
+ validates :author, length: { maximum: 255 }
12
+
13
+ def default_version
14
+ '0.1.0'
15
+ end
16
+
17
+ def to_param
18
+ name
19
+ end
20
+
21
+ def display_name
22
+ display.presence || name
23
+ end
24
+ end
25
+ end