comable-core 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +97 -0
- data/app/assets/javascripts/comable/application.js +13 -0
- data/app/assets/stylesheets/comable/application.css +13 -0
- data/app/controllers/concerns/comable/permitted_attributes.rb +15 -0
- data/app/helpers/comable/application_helper.rb +84 -0
- data/app/helpers/comable/products_helper.rb +82 -0
- data/app/mailers/comable/order_mailer.rb +18 -0
- data/app/models/comable/ability.rb +18 -0
- data/app/models/comable/address.rb +39 -0
- data/app/models/comable/category.rb +72 -0
- data/app/models/comable/image.rb +15 -0
- data/app/models/comable/order.rb +121 -0
- data/app/models/comable/order/associations.rb +22 -0
- data/app/models/comable/order/callbacks.rb +43 -0
- data/app/models/comable/order/morrisable.rb +20 -0
- data/app/models/comable/order/scopes.rb +17 -0
- data/app/models/comable/order/validations.rb +39 -0
- data/app/models/comable/order_item.rb +98 -0
- data/app/models/comable/order_item/csvable.rb +32 -0
- data/app/models/comable/page.rb +30 -0
- data/app/models/comable/payment.rb +87 -0
- data/app/models/comable/payment_method.rb +27 -0
- data/app/models/comable/product.rb +55 -0
- data/app/models/comable/product/csvable.rb +20 -0
- data/app/models/comable/shipment.rb +85 -0
- data/app/models/comable/shipment_method.rb +9 -0
- data/app/models/comable/stock.rb +71 -0
- data/app/models/comable/stock/csvable.rb +26 -0
- data/app/models/comable/store.rb +30 -0
- data/app/models/comable/theme.rb +25 -0
- data/app/models/comable/tracker.rb +17 -0
- data/app/models/comable/user.rb +130 -0
- data/app/models/concerns/comable/cart_owner.rb +94 -0
- data/app/models/concerns/comable/checkout.rb +85 -0
- data/app/models/concerns/comable/importable.rb +67 -0
- data/app/models/concerns/comable/liquidable.rb +12 -0
- data/app/models/concerns/comable/product/search.rb +41 -0
- data/app/models/concerns/comable/ransackable.rb +38 -0
- data/app/models/concerns/comable/role_owner.rb +15 -0
- data/app/models/concerns/comable/sku_choice.rb +19 -0
- data/app/models/concerns/comable/sku_item.rb +17 -0
- data/app/uploaders/image_uploader.rb +7 -0
- data/app/views/comable/order_mailer/complete.text.erb +42 -0
- data/config/initializers/comma.rb +8 -0
- data/config/locales/en.yml +424 -0
- data/config/locales/ja.yml +425 -0
- data/db/migrate/20131214194807_create_comable_products.rb +15 -0
- data/db/migrate/20140120032559_create_comable_users.rb +46 -0
- data/db/migrate/20140502060116_create_comable_stocks.rb +14 -0
- data/db/migrate/20140723175431_create_comable_orders.rb +20 -0
- data/db/migrate/20140723175810_create_comable_order_items.rb +19 -0
- data/db/migrate/20140817194104_create_comable_payment_methods.rb +13 -0
- data/db/migrate/20140921191416_create_comable_shipment_methods.rb +11 -0
- data/db/migrate/20140926063541_create_comable_stores.rb +11 -0
- data/db/migrate/20141024025526_create_comable_addresses.rb +17 -0
- data/db/migrate/20150111031228_create_comable_categories.rb +10 -0
- data/db/migrate/20150111031229_create_comable_products_categories.rb +8 -0
- data/db/migrate/20150112173706_create_comable_images.rb +9 -0
- data/db/migrate/20150423095210_create_comable_shipments.rb +13 -0
- data/db/migrate/20150511171940_create_comable_payments.rb +12 -0
- data/db/migrate/20150513185230_create_comable_trackers.rb +12 -0
- data/db/migrate/20150519080729_create_comable_pages.rb +17 -0
- data/db/migrate/20150612143226_create_comable_themes.rb +15 -0
- data/db/migrate/20150612143445_add_theme_id_to_comable_stores.rb +7 -0
- data/db/seeds.rb +5 -0
- data/db/seeds/comable/users.rb +51 -0
- data/lib/comable/core.rb +48 -0
- data/lib/comable/core/configuration.rb +22 -0
- data/lib/comable/core/engine.rb +50 -0
- data/lib/comable/deprecator.rb +26 -0
- data/lib/comable/payment_provider.rb +14 -0
- data/lib/comable/payment_provider/base.rb +42 -0
- data/lib/comable/payment_provider/general.rb +15 -0
- data/lib/comable/state_machine_patch.rb +32 -0
- data/lib/comma_extractor_extentions.rb +31 -0
- data/lib/generators/comable/install/install_generator.rb +133 -0
- data/lib/generators/comable/install/templates/config/initializers/comable.rb +31 -0
- data/lib/tasks/comable_tasks.rake +4 -0
- 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
|