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,15 @@
1
+ module Comable
2
+ class Image < ActiveRecord::Base
3
+ include Comable::Liquidable
4
+
5
+ mount_uploader :file, ImageUploader
6
+
7
+ belongs_to :product, class_name: Comable::Product.name
8
+
9
+ liquid_methods :url
10
+
11
+ delegate :url, to: :file, allow_nil: true
12
+ delegate :current_path, to: :file, allow_nil: true
13
+ delegate :identifier, to: :file, allow_nil: true
14
+ end
15
+ end
@@ -0,0 +1,121 @@
1
+ require_dependency 'comable/order/associations'
2
+ require_dependency 'comable/order/callbacks'
3
+ require_dependency 'comable/order/scopes'
4
+ require_dependency 'comable/order/validations'
5
+ require_dependency 'comable/order/morrisable'
6
+
7
+ module Comable
8
+ class Order < ActiveRecord::Base
9
+ include Comable::Checkout
10
+ include Comable::Ransackable
11
+ include Comable::Liquidable
12
+ include Comable::Order::Associations
13
+ include Comable::Order::Callbacks
14
+ include Comable::Order::Scopes
15
+ include Comable::Order::Validations
16
+ include Comable::Order::Morrisable
17
+
18
+ ransack_options attribute_select: { associations: [:payment, :shipment] }, ransackable_attributes: { except: [:bill_address_id, :ship_address_id] }
19
+
20
+ liquid_methods :code, :payment_fee, :shipment_fee, :item_total_price, :total_price, :order_items
21
+
22
+ delegate :full_name, to: :bill_address, allow_nil: true, prefix: :bill
23
+ delegate :full_name, to: :ship_address, allow_nil: true, prefix: :ship
24
+ delegate :state, :human_state_name, to: :payment, allow_nil: true, prefix: true
25
+ delegate :state, :human_state_name, to: :shipment, allow_nil: true, prefix: true
26
+
27
+ def complete!
28
+ ActiveRecord::Base.transaction do
29
+ run_callbacks :complete do
30
+ self.attributes = current_attributes
31
+
32
+ order_items.each(&:complete)
33
+ save!
34
+
35
+ payment.next_state! if payment
36
+ shipment.next_state! if shipment
37
+
38
+ touch(:completed_at)
39
+ end
40
+ end
41
+ end
42
+
43
+ alias_method :complete, :complete!
44
+ deprecate :complete, deprecator: Comable::Deprecator.instance
45
+
46
+ def restock!
47
+ order_items.each(&:restock)
48
+ save!
49
+ end
50
+
51
+ def unstock!
52
+ order_items.each(&:unstock)
53
+ save!
54
+ end
55
+
56
+ def stocked_items
57
+ order_items.to_a.select(&:unstocked?)
58
+ end
59
+
60
+ # 時価商品合計を取得
61
+ def current_item_total_price
62
+ order_items.to_a.sum(&:current_subtotal_price)
63
+ end
64
+
65
+ # 売価商品合計を取得
66
+ def item_total_price
67
+ order_items.to_a.sum(&:subtotal_price)
68
+ end
69
+
70
+ # 時価送料を取得
71
+ def current_shipment_fee
72
+ shipment.try(:fee) || 0
73
+ end
74
+
75
+ # Get the current payment fee
76
+ def current_payment_fee
77
+ payment.try(:fee) || 0
78
+ end
79
+
80
+ # 時価合計を取得
81
+ def current_total_price
82
+ current_item_total_price + current_payment_fee + current_shipment_fee
83
+ end
84
+
85
+ # Inherit from other Order
86
+ def inherit!(order)
87
+ self.bill_address ||= order.bill_address
88
+ self.ship_address ||= order.ship_address
89
+ self.payment ||= order.payment
90
+ self.shipment ||= order.shipment
91
+
92
+ stated?(order.state) ? save! : next_state!
93
+ end
94
+
95
+ def completed?
96
+ completed_at?
97
+ end
98
+
99
+ def paid?
100
+ payment ? payment.completed? : true
101
+ end
102
+
103
+ def shipped?
104
+ shipment ? shipment.completed? : true
105
+ end
106
+
107
+ def can_ship?
108
+ shipment && shipment.ready? && paid? && completed?
109
+ end
110
+
111
+ private
112
+
113
+ def current_attributes
114
+ {
115
+ payment_fee: current_payment_fee,
116
+ shipment_fee: current_shipment_fee,
117
+ total_price: current_total_price
118
+ }
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,22 @@
1
+ module Comable
2
+ class Order < ActiveRecord::Base
3
+ module Associations
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ belongs_to :user, class_name: Comable::User.name, autosave: false
8
+ belongs_to :bill_address, class_name: Comable::Address.name, autosave: true, dependent: :destroy
9
+ belongs_to :ship_address, class_name: Comable::Address.name, autosave: true, dependent: :destroy
10
+ has_many :order_items, dependent: :destroy, class_name: Comable::OrderItem.name, inverse_of: :order
11
+ has_one :payment, dependent: :destroy, class_name: Comable::Payment.name, inverse_of: :order
12
+ has_one :shipment, dependent: :destroy, class_name: Comable::Shipment.name, inverse_of: :order
13
+
14
+ accepts_nested_attributes_for :bill_address
15
+ accepts_nested_attributes_for :ship_address
16
+ accepts_nested_attributes_for :order_items
17
+ accepts_nested_attributes_for :payment
18
+ accepts_nested_attributes_for :shipment
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,43 @@
1
+ module Comable
2
+ class Order < ActiveRecord::Base
3
+ module Callbacks
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ define_model_callbacks :complete
8
+
9
+ before_validation :generate_guest_token, on: :create
10
+ before_validation :clone_addresses_from_user, on: :create
11
+ before_complete :generate_code
12
+ after_complete :clone_addresses_to_user
13
+ end
14
+
15
+ def generate_code
16
+ self.code = loop do
17
+ random_token = "C#{Array.new(11) { rand(9) }.join}"
18
+ break random_token unless self.class.exists?(code: random_token)
19
+ end
20
+ end
21
+
22
+ def generate_guest_token
23
+ return if user
24
+ self.guest_token ||= loop do
25
+ random_token = SecureRandom.urlsafe_base64(nil, false)
26
+ break random_token unless self.class.exists?(guest_token: random_token)
27
+ end
28
+ end
29
+
30
+ def clone_addresses_from_user
31
+ return unless user
32
+ self.bill_address ||= user.bill_address.try(:clone)
33
+ self.ship_address ||= user.ship_address.try(:clone)
34
+ end
35
+
36
+ def clone_addresses_to_user
37
+ return unless user
38
+ user.update_bill_address_by bill_address
39
+ user.update_ship_address_by ship_address
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,20 @@
1
+ module Comable
2
+ class Order < ActiveRecord::Base
3
+ module Morrisable
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def morris_keys
8
+ %w( count price )
9
+ end
10
+
11
+ def to_morris
12
+ this = (Rails::VERSION::MAJOR == 3) ? scoped : all
13
+ this.group_by { |order| order.completed_at.to_date }.map do |date, orders|
14
+ { date: date, count: orders.count, price: orders.sum(&:total_price) }
15
+ end.to_json
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ module Comable
2
+ class Order < ActiveRecord::Base
3
+ module Scopes
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ scope :complete, -> { where.not(completed_at: nil) }
8
+ scope :incomplete, -> { where(completed_at: nil) }
9
+ scope :by_user, -> (user) { where(user_id: user) }
10
+ scope :this_month, -> { where(completed_at: Time.now.beginning_of_month..Time.now.end_of_month) }
11
+ scope :this_week, -> { where(completed_at: Time.now.beginning_of_week..Time.now.end_of_week) }
12
+ scope :last_week, -> { where(completed_at: 1.week.ago.beginning_of_week..1.week.ago.end_of_week) }
13
+ scope :recent, -> { order('completed_at DESC, id DESC') }
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,39 @@
1
+ module Comable
2
+ class Order < ActiveRecord::Base
3
+ module Validations
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ validates :user_id, uniqueness: { scope: :completed_at }, if: :user
8
+ validates :guest_token, presence: true, uniqueness: { scope: :completed_at }, unless: :user
9
+
10
+ with_options if: -> { stated?(:cart) } do |context|
11
+ context.validates :email, presence: true, length: { maximum: 255 }
12
+ end
13
+
14
+ with_options if: -> { stated?(:orderer) } do |context|
15
+ context.validates :bill_address, presence: true
16
+ end
17
+
18
+ with_options if: -> { stated?(:delivery) } do |context|
19
+ context.validates :ship_address, presence: true
20
+ end
21
+
22
+ with_options if: -> { stated?(:shipment) && shipment_required? } do |context|
23
+ context.validates :shipment, presence: true
24
+ end
25
+
26
+ with_options if: -> { stated?(:payment) && payment_required? } do |context|
27
+ context.validates :payment, presence: true
28
+ end
29
+
30
+ with_options if: -> { stated?(:confirm) } do |context|
31
+ context.validates :code, presence: true
32
+ context.validates :payment_fee, presence: true
33
+ context.validates :shipment_fee, presence: true
34
+ context.validates :total_price, presence: true
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,98 @@
1
+ module Comable
2
+ class OrderItem < ActiveRecord::Base
3
+ include Comable::SkuItem
4
+ include Comable::SkuChoice
5
+ include Comable::Liquidable
6
+ include Comable::OrderItem::Csvable
7
+
8
+ belongs_to :stock, class_name: Comable::Stock.name, autosave: true
9
+ belongs_to :order, class_name: Comable::Order.name, inverse_of: :order_items
10
+
11
+ validates :quantity, numericality: { greater_than: 0 }
12
+ validate :valid_stock_quantity
13
+
14
+ liquid_methods :name, :name_with_sku, :code, :quantity, :price, :subtotal_price
15
+
16
+ delegate :product, to: :stock
17
+ delegate :image_url, to: :product
18
+ delegate :guest_token, to: :order
19
+ delegate :completed?, to: :order, allow_nil: true
20
+
21
+ before_validation :copy_attributes, unless: :completed?
22
+
23
+ def complete
24
+ unstock
25
+ end
26
+
27
+ def unstock
28
+ decrement_stock
29
+ end
30
+
31
+ def restock
32
+ increment_stock
33
+ end
34
+
35
+ # TODO: カート投入時との差額表示
36
+ def copy_attributes
37
+ self.attributes = current_attributes
38
+ end
39
+
40
+ # 時価を取得
41
+ def current_price
42
+ stock.price
43
+ end
44
+
45
+ # 時価小計を取得
46
+ def current_subtotal_price
47
+ current_price * quantity
48
+ end
49
+
50
+ # 売価小計を取得
51
+ def subtotal_price
52
+ price * quantity
53
+ end
54
+
55
+ def unstocked?
56
+ stock_with_clean_quantity do |stock|
57
+ stock.unstocked?(quantity: quantity)
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def valid_stock_quantity
64
+ return unless unstocked?
65
+ errors.add :quantity, Comable.t('errors.messages.out_of_stock', name: stock.name_with_sku)
66
+ end
67
+
68
+ def stock_with_clean_quantity
69
+ quantity_will = stock.quantity
70
+ stock.quantity = stock.quantity_was if stock.quantity_was
71
+ yield stock
72
+ ensure
73
+ stock.quantity = quantity_will
74
+ end
75
+
76
+ def decrement_stock
77
+ stock.lock!
78
+ stock.quantity -= quantity
79
+ end
80
+
81
+ def increment_stock
82
+ stock.lock!
83
+ stock.quantity += quantity
84
+ end
85
+
86
+ def current_attributes
87
+ {
88
+ name: product.name,
89
+ code: stock.code,
90
+ price: stock.price,
91
+ sku_h_item_name: product.sku_h_item_name,
92
+ sku_v_item_name: product.sku_v_item_name,
93
+ sku_h_choice_name: stock.sku_h_choice_name,
94
+ sku_v_choice_name: stock.sku_v_choice_name
95
+ }
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,32 @@
1
+ module Comable
2
+ class OrderItem < ActiveRecord::Base
3
+ module Csvable
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ comma do
8
+ __association__ order: :code
9
+ __association__ order: :email
10
+ __association__ order: :payment_fee
11
+ __association__ order: :shipment_fee
12
+ __association__ order: :total_price
13
+ __association__ order: { bill_address: :family_name }
14
+ __association__ order: { bill_address: :first_name }
15
+ __association__ order: { bill_address: :zip_code }
16
+ __association__ order: { bill_address: :state_name }
17
+ __association__ order: { bill_address: :city }
18
+ __association__ order: { bill_address: :detail }
19
+ __association__ order: { bill_address: :phone_number }
20
+ name
21
+ code
22
+ price
23
+ sku_h_item_name
24
+ sku_v_item_name
25
+ sku_h_choice_name
26
+ sku_v_choice_name
27
+ quantity
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,30 @@
1
+ module Comable
2
+ class Page < ActiveRecord::Base
3
+ include Comable::Ransackable
4
+
5
+ extend FriendlyId
6
+ friendly_id :title, use: :slugged
7
+
8
+ validates :title, length: { maximum: 255 }, presence: true
9
+ validates :content, presence: true
10
+ validates :page_title, length: { maximum: 255 }
11
+ validates :meta_description, length: { maximum: 255 }
12
+ validates :meta_keywords, length: { maximum: 255 }
13
+ validates :slug, length: { maximum: 255 }, presence: true, uniqueness: true
14
+
15
+ PREVIEW_SESSION_KEY = :preview_page
16
+
17
+ def published?
18
+ published_at.present? && published_at <= Time.now
19
+ end
20
+
21
+ def default_slug
22
+ id ||= self.class.maximum(:id).next
23
+ "pages_#{id}"
24
+ end
25
+
26
+ def normalize_slug(string)
27
+ normalize_friendly_id(string).presence || default_slug
28
+ end
29
+ end
30
+ end