comable 0.0.2 → 0.0.3
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.
- checksums.yaml +4 -4
- data/app/controllers/comable/orders_controller.rb +35 -28
- data/app/models/comable/customer.rb +41 -71
- data/app/models/comable/order.rb +70 -6
- data/app/models/comable/order_delivery.rb +6 -2
- data/app/models/comable/order_detail.rb +31 -2
- data/app/models/comable/payment.rb +26 -0
- data/app/models/comable/stock.rb +53 -2
- data/app/views/comable/carts/show.slim +1 -6
- data/app/views/comable/orders/confirm.slim +2 -2
- data/app/views/comable/orders/delivery.slim +1 -1
- data/app/views/comable/orders/orderer.slim +1 -1
- data/app/views/comable/orders/payment.slim +12 -0
- data/config/routes.rb +4 -2
- data/db/migrate/20140723175431_create_comable_orders.rb +6 -4
- data/db/migrate/20140723175624_create_comable_order_deliveries.rb +2 -2
- data/db/migrate/20140723175810_create_comable_order_details.rb +3 -1
- data/db/migrate/20140817194104_create_comable_payments.rb +11 -0
- data/lib/comable.rb +3 -2
- data/lib/comable/cart_owner.rb +79 -0
- data/lib/comable/errors.rb +4 -0
- data/lib/comable/payment_method.rb +14 -0
- data/lib/comable/payment_method/base.rb +26 -0
- data/lib/comable/payment_method/general.rb +15 -0
- data/lib/comable/version.rb +1 -1
- data/lib/tasks/comable_yardoc.task +14 -0
- metadata +40 -5
- data/app/models/comable/cart_item.rb +0 -34
- data/db/migrate/20140120024159_create_comable_cart_items.rb +0 -12
- data/lib/comable/cash_register.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa8570f259479b4b4a76b6c53c7b0619f43268e0
|
4
|
+
data.tar.gz: 20638bda91ba247e08fb561a27168f8ec67423af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbb7f75de40ca35dfc593a5a78bcc7808e0d183667a40c78cb36e2d097485125c9425bbee8d8d9207cf7fb01a3263c7fc6b01e3dab0b141f0b94905985d95e66
|
7
|
+
data.tar.gz: 3f2ccc2dd66370b11f1dfa8651b3e1a7052a18b5e953ecc6ad3cc4ec0db03c7ed878f64cc2cd246591a780d0a90e49ffe6f8cfdf47e26ff47c6b2620b160a427
|
@@ -5,6 +5,11 @@ module Comable
|
|
5
5
|
before_filter :redirect_for_logged_in_customer, only: [:new, :orderer]
|
6
6
|
after_filter :save_order, except: :create
|
7
7
|
|
8
|
+
rescue_from ActiveRecord::RecordInvalid, with: :record_invalid
|
9
|
+
rescue_from Comable::InvalidOrder, with: :order_invalid
|
10
|
+
|
11
|
+
include Decoratable
|
12
|
+
|
8
13
|
def new
|
9
14
|
end
|
10
15
|
|
@@ -16,23 +21,26 @@ module Comable
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def delivery
|
24
|
+
case request.method_symbol
|
25
|
+
when :post
|
26
|
+
redirect_to comable.payment_order_path
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def payment
|
19
31
|
case request.method_symbol
|
20
32
|
when :post
|
21
33
|
redirect_to comable.confirm_order_path
|
22
|
-
when :get
|
23
|
-
@order.order_deliveries.build if @order.order_deliveries.empty?
|
24
34
|
end
|
25
35
|
end
|
26
36
|
|
27
37
|
def confirm
|
28
|
-
@order = current_customer.preorder(build_order_nested_attributes)
|
29
38
|
end
|
30
39
|
|
31
40
|
def create
|
32
|
-
|
33
|
-
if
|
41
|
+
order = current_customer.order
|
42
|
+
if order.complete?
|
34
43
|
flash[:notice] = I18n.t('comable.orders.success')
|
35
|
-
reset_session
|
36
44
|
else
|
37
45
|
flash[:alert] = I18n.t('comable.orders.failure')
|
38
46
|
redirect_to comable.confirm_order_path
|
@@ -41,10 +49,6 @@ module Comable
|
|
41
49
|
|
42
50
|
private
|
43
51
|
|
44
|
-
def reset_session
|
45
|
-
session.delete('comable.order')
|
46
|
-
end
|
47
|
-
|
48
52
|
def verify
|
49
53
|
return if current_customer.cart.any?
|
50
54
|
flash[:alert] = I18n.t('comable.carts.empty')
|
@@ -52,27 +56,11 @@ module Comable
|
|
52
56
|
end
|
53
57
|
|
54
58
|
def load_order
|
55
|
-
|
56
|
-
order_attributes.update(order_params) if order_params
|
57
|
-
@order = Comable::Order.new(order_attributes)
|
59
|
+
@order = current_customer.preorder(order_params || {})
|
58
60
|
end
|
59
61
|
|
60
62
|
def save_order
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
def build_order_nested_attributes
|
65
|
-
@order.attributes.merge(
|
66
|
-
order_deliveries_attributes: build_order_delivery_nested_attributes
|
67
|
-
)
|
68
|
-
end
|
69
|
-
|
70
|
-
def build_order_delivery_nested_attributes
|
71
|
-
@order.order_deliveries.map do |order_delivery|
|
72
|
-
order_delivery.attributes.merge(
|
73
|
-
order_details_attributes: order_delivery.order_details.map(&:attributes)
|
74
|
-
)
|
75
|
-
end
|
63
|
+
@order.save
|
76
64
|
end
|
77
65
|
|
78
66
|
def order_params
|
@@ -82,6 +70,8 @@ module Comable
|
|
82
70
|
order_params_for_orderer
|
83
71
|
when :delivery
|
84
72
|
order_params_for_delivery
|
73
|
+
when :payment
|
74
|
+
order_params_for_payment
|
85
75
|
end
|
86
76
|
end
|
87
77
|
|
@@ -95,14 +85,31 @@ module Comable
|
|
95
85
|
def order_params_for_delivery
|
96
86
|
params.require(:order).permit(
|
97
87
|
order_deliveries_attributes: [
|
88
|
+
:id,
|
98
89
|
:family_name,
|
99
90
|
:first_name
|
100
91
|
]
|
101
92
|
)
|
102
93
|
end
|
103
94
|
|
95
|
+
def order_params_for_payment
|
96
|
+
params.require(:order).permit(
|
97
|
+
Comable::Payment.table_name.singularize.foreign_key.to_sym
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
104
101
|
def redirect_for_logged_in_customer
|
105
102
|
return redirect_to delivery_order_path if current_customer.logged_in?
|
106
103
|
end
|
104
|
+
|
105
|
+
def record_invalid
|
106
|
+
flash[:alert] = I18n.t('comable.orders.failure')
|
107
|
+
redirect_to comable.cart_path
|
108
|
+
end
|
109
|
+
|
110
|
+
def order_invalid(exception)
|
111
|
+
flash[:alert] = exception.message
|
112
|
+
redirect_to comable.cart_path
|
113
|
+
end
|
107
114
|
end
|
108
115
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Comable
|
2
2
|
class Customer < ActiveRecord::Base
|
3
3
|
include Decoratable
|
4
|
+
include CartOwner
|
4
5
|
|
5
6
|
has_many :comable_orders, class_name: Comable::Order.name, foreign_key: table_name.singularize.foreign_key
|
6
7
|
alias_method :orders, :comable_orders
|
@@ -24,52 +25,33 @@ module Comable
|
|
24
25
|
!logged_in?
|
25
26
|
end
|
26
27
|
|
27
|
-
def add_cart_item(obj, quantity: 1)
|
28
|
-
process_cart_item(obj) do |stock|
|
29
|
-
add_stock_to_cart(stock, quantity)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def remove_cart_item(obj, quantity: -1)
|
34
|
-
process_cart_item(obj) do |stock|
|
35
|
-
add_stock_to_cart(stock, quantity)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def reset_cart_item(obj, quantity: 0)
|
40
|
-
process_cart_item(obj) do |stock|
|
41
|
-
reset_stock_from_cart(stock, quantity)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
28
|
def reset_cart
|
46
|
-
|
29
|
+
return unless @incomplete_order
|
30
|
+
if @incomplete_order.complete?
|
31
|
+
@incomplete_order = nil
|
32
|
+
else
|
33
|
+
# TODO: テストケースの作成
|
34
|
+
@incomplete_order.destroy
|
35
|
+
@incomplete_order = nil
|
36
|
+
end
|
47
37
|
end
|
48
38
|
|
49
39
|
def cart_items
|
50
|
-
|
51
|
-
Comable::Customer.table_name.singularize.foreign_key => id,
|
52
|
-
:guest_token => current_guest_token
|
53
|
-
)
|
40
|
+
incomplete_order.order_deliveries.first.order_details
|
54
41
|
end
|
55
42
|
|
56
|
-
def
|
57
|
-
|
58
|
-
end
|
59
|
-
|
60
|
-
class Cart < Array
|
61
|
-
def price
|
62
|
-
cart_item_ids = map(&:id)
|
63
|
-
Comable::CartItem.includes(stock: :product).where(id: cart_item_ids).to_a.sum(&:price)
|
64
|
-
end
|
43
|
+
def incomplete_order
|
44
|
+
@incomplete_order ||= initialize_incomplete_order
|
65
45
|
end
|
66
46
|
|
67
47
|
def preorder(order_params = {})
|
68
|
-
|
48
|
+
incomplete_order.attributes = order_params
|
49
|
+
incomplete_order.precomplete
|
69
50
|
end
|
70
51
|
|
71
52
|
def order(order_params = {})
|
72
|
-
|
53
|
+
incomplete_order.attributes = order_params
|
54
|
+
incomplete_order.complete.tap { |completed_flag| reset_cart if completed_flag }
|
73
55
|
end
|
74
56
|
|
75
57
|
private
|
@@ -79,49 +61,37 @@ module Comable
|
|
79
61
|
@cookies.signed[:guest_token]
|
80
62
|
end
|
81
63
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
when Array
|
89
|
-
obj.map { |item| yield item }
|
90
|
-
else
|
91
|
-
fail
|
92
|
-
end
|
64
|
+
def initialize_incomplete_order
|
65
|
+
orders = find_incomplete_orders
|
66
|
+
return orders.first if orders.any?
|
67
|
+
order = orders.create(family_name: family_name, first_name: first_name, order_deliveries_attributes: [{ family_name: family_name, first_name: first_name }])
|
68
|
+
@cookies.permanent.signed[:guest_token] = order.guest_token if not_logged_in?
|
69
|
+
order
|
93
70
|
end
|
94
71
|
|
95
|
-
def
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
cart_item = cart_items.create(quantity: quantity)
|
105
|
-
@cookies.permanent.signed[:guest_token] = cart_item.guest_token if not_logged_in?
|
106
|
-
end
|
72
|
+
def find_incomplete_orders
|
73
|
+
Comable::Order
|
74
|
+
.incomplete
|
75
|
+
.includes(order_deliveries: :order_details)
|
76
|
+
.where(
|
77
|
+
Comable::Customer.table_name.singularize.foreign_key => self,
|
78
|
+
:guest_token => current_guest_token
|
79
|
+
)
|
80
|
+
.limit(1)
|
107
81
|
end
|
108
82
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
cart_item.quantity = quantity
|
115
|
-
cart_item.save
|
116
|
-
else
|
117
|
-
return false if cart_items.empty?
|
118
|
-
cart_item.destroy
|
83
|
+
# Rails 3.x だと has_many 先のインスタンスが追加されても
|
84
|
+
# 親インスタンスが感知できないので、いちいちリロードするように変更
|
85
|
+
if Rails::VERSION::MAJOR == 3
|
86
|
+
def add_stock_to_cart_with_reload(*args)
|
87
|
+
add_stock_to_cart_without_reload(*args).tap { @incomplete_order = nil }
|
119
88
|
end
|
120
|
-
|
89
|
+
alias_method_chain :add_stock_to_cart, :reload
|
121
90
|
|
122
|
-
|
123
|
-
|
124
|
-
|
91
|
+
def reset_stock_from_cart_with_reload(*args)
|
92
|
+
reset_stock_from_cart_without_reload(*args).tap { @incomplete_order = nil }
|
93
|
+
end
|
94
|
+
alias_method_chain :reset_stock_from_cart, :reload
|
125
95
|
end
|
126
96
|
end
|
127
97
|
end
|
data/app/models/comable/order.rb
CHANGED
@@ -3,18 +3,78 @@ module Comable
|
|
3
3
|
include Decoratable
|
4
4
|
|
5
5
|
belongs_to :customer, class_name: Comable::Customer.name, foreign_key: Comable::Customer.table_name.singularize.foreign_key, autosave: false
|
6
|
+
belongs_to :payment, class_name: Comable::Payment.name, foreign_key: Comable::Payment.table_name.singularize.foreign_key, autosave: false
|
6
7
|
has_many :order_deliveries, dependent: :destroy, class_name: Comable::OrderDelivery.name, foreign_key: table_name.singularize.foreign_key
|
7
8
|
|
8
9
|
accepts_nested_attributes_for :order_deliveries
|
9
10
|
|
10
|
-
|
11
|
-
|
11
|
+
with_options if: :complete? do |complete_order|
|
12
|
+
complete_order.validates :code, presence: true
|
13
|
+
complete_order.validates :first_name, presence: true
|
14
|
+
complete_order.validates :family_name, presence: true
|
15
|
+
complete_order.validates Comable::Payment.table_name.singularize.foreign_key, presence: true
|
16
|
+
end
|
17
|
+
|
18
|
+
with_options if: :incomplete? do |incomplete_order|
|
19
|
+
incomplete_order.validates Comable::Customer.table_name.singularize.foreign_key, uniqueness: { scope: [Comable::Customer.table_name.singularize.foreign_key, :completed_at] }, if: :customer
|
20
|
+
incomplete_order.validates :guest_token, uniqueness: { scope: [:guest_token, :completed_at] }, if: :guest_token
|
21
|
+
end
|
22
|
+
|
23
|
+
before_create :generate_guest_token
|
24
|
+
|
25
|
+
scope :complete, -> { where.not(completed_at: nil) }
|
26
|
+
scope :incomplete, -> { where(completed_at: nil) }
|
27
|
+
|
28
|
+
def precomplete
|
29
|
+
valid_stock
|
30
|
+
fail Comable::InvalidOrder, errors.full_messages.join("\n") if errors.any?
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def complete
|
35
|
+
# TODO: トランザクションの追加
|
36
|
+
precomplete
|
37
|
+
# TODO: コールバック化
|
38
|
+
# define_model_callbacks :complete
|
39
|
+
before_complete
|
40
|
+
save!
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def complete?
|
45
|
+
!incomplete?
|
46
|
+
end
|
12
47
|
|
13
|
-
|
14
|
-
|
48
|
+
def incomplete?
|
49
|
+
completed_at.nil?
|
50
|
+
end
|
51
|
+
|
52
|
+
# 時価合計を取得
|
53
|
+
def current_total_price
|
54
|
+
order_deliveries.map(&:order_details).flatten.each(&:current_subtotal_price)
|
55
|
+
end
|
56
|
+
|
57
|
+
# 売価合計を取得
|
58
|
+
def total_price
|
59
|
+
order_deliveries.map(&:order_details).flatten.each(&:subtotal_price)
|
60
|
+
end
|
15
61
|
|
16
62
|
private
|
17
63
|
|
64
|
+
def before_complete
|
65
|
+
self.completed_at = Time.now
|
66
|
+
generate_code
|
67
|
+
order_deliveries.each(&:before_complete)
|
68
|
+
end
|
69
|
+
|
70
|
+
def valid_stock
|
71
|
+
order_deliveries.map(&:order_details).flatten.each do |order_detail|
|
72
|
+
return errors.add :base, "「#{order_detail.stock.name}」の注文数が不正です。" if order_detail.quantity <= 0
|
73
|
+
quantity = order_detail.stock.quantity - order_detail.quantity
|
74
|
+
return errors.add :base, "「#{order_detail.stock.name}」の在庫が不足しています。" if quantity < 0
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
18
78
|
def generate_code
|
19
79
|
self.code = loop do
|
20
80
|
random_token = "C#{Array.new(11) { rand(9) }.join}"
|
@@ -22,8 +82,12 @@ module Comable
|
|
22
82
|
end
|
23
83
|
end
|
24
84
|
|
25
|
-
def
|
26
|
-
|
85
|
+
def generate_guest_token
|
86
|
+
return if send(Comable::Customer.table_name.singularize.foreign_key)
|
87
|
+
self.guest_token ||= loop do
|
88
|
+
random_token = SecureRandom.urlsafe_base64(nil, false)
|
89
|
+
break random_token unless self.class.exists?(guest_token: random_token)
|
90
|
+
end
|
27
91
|
end
|
28
92
|
end
|
29
93
|
end
|
@@ -5,8 +5,12 @@ module Comable
|
|
5
5
|
belongs_to :order, class_name: Comable::Order.name, foreign_key: Comable::Order.table_name.singularize.foreign_key
|
6
6
|
has_many :order_details, dependent: :destroy, class_name: Comable::OrderDetail.name, foreign_key: table_name.singularize.foreign_key
|
7
7
|
|
8
|
-
accepts_nested_attributes_for :order_details
|
9
|
-
|
10
8
|
delegate :customer, to: :order
|
9
|
+
delegate :guest_token, to: :order
|
10
|
+
delegate :complete?, to: :order
|
11
|
+
|
12
|
+
def before_complete
|
13
|
+
order_details.each(&:before_complete)
|
14
|
+
end
|
11
15
|
end
|
12
16
|
end
|
@@ -5,9 +5,38 @@ module Comable
|
|
5
5
|
belongs_to :stock, class_name: Comable::Stock.name, foreign_key: Comable::Stock.table_name.singularize.foreign_key
|
6
6
|
belongs_to :order_delivery, class_name: Comable::OrderDelivery.name, foreign_key: Comable::OrderDelivery.table_name.singularize.foreign_key
|
7
7
|
|
8
|
-
|
9
|
-
delegate :decrement_quantity!, to: :stock
|
8
|
+
# TODO: バリデーションの追加
|
10
9
|
|
11
10
|
delegate :product, to: :stock
|
11
|
+
delegate :guest_token, to: :order_delivery
|
12
|
+
delegate :complete?, to: :order_delivery
|
13
|
+
|
14
|
+
def before_complete
|
15
|
+
save_price
|
16
|
+
decrement_stock
|
17
|
+
end
|
18
|
+
|
19
|
+
# 時価を取得
|
20
|
+
def current_price
|
21
|
+
stock.price
|
22
|
+
end
|
23
|
+
|
24
|
+
# 時価小計を取得
|
25
|
+
def current_subtotal_price
|
26
|
+
current_price * quantity
|
27
|
+
end
|
28
|
+
|
29
|
+
# 売価小計を取得
|
30
|
+
def subtotal_price
|
31
|
+
price * quantity
|
32
|
+
end
|
33
|
+
|
34
|
+
def decrement_stock
|
35
|
+
stock.decrement!(quantity: quantity)
|
36
|
+
end
|
37
|
+
|
38
|
+
def save_price
|
39
|
+
self.price = stock.price
|
40
|
+
end
|
12
41
|
end
|
13
42
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Comable
|
2
|
+
class Payment < ActiveRecord::Base
|
3
|
+
include Decoratable
|
4
|
+
|
5
|
+
validates :name, presence: true
|
6
|
+
validates :payment_method_type, presence: true
|
7
|
+
validates :payment_method_kind, presence: true
|
8
|
+
|
9
|
+
def payment_method
|
10
|
+
return unless Object.const_defined?(payment_method_type)
|
11
|
+
Object.const_get(payment_method_type)
|
12
|
+
end
|
13
|
+
|
14
|
+
def payment_method_name
|
15
|
+
payment_method.display_name
|
16
|
+
end
|
17
|
+
|
18
|
+
def payment_method_kind_key
|
19
|
+
payment_method.kind.keys.slice(payment_method_kind)
|
20
|
+
end
|
21
|
+
|
22
|
+
def payment_method_kind_name
|
23
|
+
payment_method.kind.slice(payment_method_kind_key).values.first
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/app/models/comable/stock.rb
CHANGED
@@ -1,30 +1,81 @@
|
|
1
1
|
module Comable
|
2
|
+
#
|
3
|
+
# 在庫モデル。
|
4
|
+
# 商品に複数紐付き、品数やSKU(Stock Keeping Unit)情報を保持する。
|
5
|
+
#
|
2
6
|
class Stock < ActiveRecord::Base
|
3
7
|
include Decoratable
|
4
8
|
|
5
9
|
belongs_to :product, class_name: Comable::Product.name, foreign_key: Comable::Product.table_name.singularize.foreign_key
|
6
10
|
|
11
|
+
#
|
12
|
+
# @!group Scope
|
13
|
+
#
|
14
|
+
|
15
|
+
# @!scope class
|
16
|
+
# 有効な在庫インスタンスを返す
|
7
17
|
scope :activated, -> { where.not(product_id_num: nil) }
|
18
|
+
|
19
|
+
# @!scope class
|
20
|
+
# 品切れでない在庫インスタンスを返す
|
8
21
|
scope :unsold, -> { where('quantity > ?', 0) }
|
22
|
+
|
23
|
+
# @!scope class
|
24
|
+
# 品切れの在庫インスタンスを返す
|
9
25
|
scope :soldout, -> { where('quantity <= ?', 0) }
|
10
26
|
|
27
|
+
#
|
28
|
+
# @!endgroup
|
29
|
+
#
|
30
|
+
|
11
31
|
delegate :price, to: :product
|
12
32
|
delegate :sku?, to: :product
|
13
33
|
|
34
|
+
def name
|
35
|
+
return product.name unless product.sku?
|
36
|
+
sku_name = sku_h_choice_name
|
37
|
+
sku_name += '/' + sku_v_choice_name if sku_v_choice_name.present?
|
38
|
+
product.name + "(#{sku_name})"
|
39
|
+
end
|
40
|
+
|
41
|
+
# 在庫の有無を取得する
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# stock.unsold? #=> true
|
45
|
+
#
|
46
|
+
# @return [Boolean] 在庫があれば true を返す
|
47
|
+
# @see #soldout?
|
14
48
|
def unsold?
|
15
49
|
return false if product_id_num.nil?
|
16
50
|
return false if quantity.nil?
|
17
51
|
quantity > 0
|
18
52
|
end
|
19
53
|
|
54
|
+
# 在庫の有無を取得する
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
# stock.soldout? #=> false
|
58
|
+
#
|
59
|
+
# @return [Boolean] {#unsold?} の逆。在庫がなければ true を返す
|
60
|
+
# @see #unsold?
|
20
61
|
def soldout?
|
21
62
|
!unsold?
|
22
63
|
end
|
23
64
|
|
24
|
-
|
65
|
+
# 在庫減算を行う
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# stock.quantity #=> 10
|
69
|
+
# stock.decrement!(quantity: 1) #=> true
|
70
|
+
# stock.quantity #=> 9
|
71
|
+
#
|
72
|
+
# @param quantity [Fixnum] 減算する在庫数を指定する
|
73
|
+
# @return [Boolean] レコードの保存に成功すると true を返す
|
74
|
+
def decrement!(quantity: 1)
|
25
75
|
with_lock do
|
26
76
|
# TODO: カラムマッピングのdecrementメソッドへの対応
|
27
|
-
|
77
|
+
self.quantity -= quantity
|
78
|
+
save!
|
28
79
|
end
|
29
80
|
end
|
30
81
|
end
|
@@ -7,12 +7,7 @@ ul.cart
|
|
7
7
|
- product = stock.product
|
8
8
|
li.product
|
9
9
|
h2.name
|
10
|
-
|
11
|
-
- sku_name = stock.sku_h_choice_name
|
12
|
-
- sku_name += '/' + stock.sku_v_choice_name if stock.sku_v_choice_name.present?
|
13
|
-
= link_to product.name + "(#{sku_name})", comable.product_path(product)
|
14
|
-
- else
|
15
|
-
= link_to product.name, comable.product_path(product)
|
10
|
+
= link_to stock.name, comable.product_path(product)
|
16
11
|
.caption
|
17
12
|
= product.caption
|
18
13
|
.price
|
@@ -16,10 +16,10 @@ h1 注文情報確認
|
|
16
16
|
- order_delivery.order_details.each do |order_detail|
|
17
17
|
.name
|
18
18
|
= order_detail.product.name
|
19
|
-
.
|
19
|
+
.price
|
20
20
|
= order_detail.price
|
21
21
|
.quantity
|
22
22
|
= order_detail.quantity
|
23
23
|
|
24
|
-
= form_for @order, as: :order, url: comable.order_path do |f|
|
24
|
+
= form_for @order, as: :order, url: comable.order_path, method: :post do |f|
|
25
25
|
= f.submit
|
@@ -1,7 +1,7 @@
|
|
1
1
|
h1 配送先情報入力
|
2
2
|
|
3
3
|
.orderer
|
4
|
-
= form_for @order, as: :order, url: comable.delivery_order_path do |f|
|
4
|
+
= form_for @order, as: :order, url: comable.delivery_order_path, method: :put do |f|
|
5
5
|
= f.fields_for :order_deliveries do |order_delivery|
|
6
6
|
= order_delivery.text_field :family_name, placeholder: '姓'
|
7
7
|
= order_delivery.text_field :first_name, placeholder: '名'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
h1 注文者情報入力
|
2
2
|
|
3
3
|
.orderer
|
4
|
-
= form_for @order, as: :order, url: comable.orderer_order_path do |f|
|
4
|
+
= form_for @order, as: :order, url: comable.orderer_order_path, method: :put do |f|
|
5
5
|
= f.text_field :family_name, placeholder: '姓'
|
6
6
|
= f.text_field :first_name, placeholder: '名'
|
7
7
|
= f.submit
|
@@ -0,0 +1,12 @@
|
|
1
|
+
h1 決済方法
|
2
|
+
|
3
|
+
.order.payment
|
4
|
+
= form_for @order, as: :order, url: comable.payment_order_path, method: :put do |f|
|
5
|
+
ul
|
6
|
+
- Comable::Payment.all.each.with_index do |payment, index|
|
7
|
+
li
|
8
|
+
- payment_foreign_key = Comable::Payment.table_name.singularize.foreign_key.to_sym
|
9
|
+
- checked_flag = @order.payment ? (@order.payment.id == payment.id) : index.zero?
|
10
|
+
= f.radio_button payment_foreign_key, payment.id, checked: checked_flag
|
11
|
+
= f.label payment_foreign_key, payment.name, value: payment.id
|
12
|
+
= f.submit
|
data/config/routes.rb
CHANGED
@@ -2,10 +2,12 @@ class CreateComableOrders < Comable::Migration
|
|
2
2
|
def change
|
3
3
|
create_table :comable_orders do |t|
|
4
4
|
t.integer :comable_customer_id
|
5
|
-
t.
|
6
|
-
t.string :
|
7
|
-
t.string :
|
8
|
-
t.
|
5
|
+
t.integer :comable_payment_id
|
6
|
+
t.string :guest_token
|
7
|
+
t.string :code
|
8
|
+
t.string :family_name
|
9
|
+
t.string :first_name
|
10
|
+
t.datetime :completed_at
|
9
11
|
end
|
10
12
|
|
11
13
|
add_index :comable_orders, :code, unique: true, name: :comable_orders_idx_01
|
@@ -2,8 +2,8 @@ class CreateComableOrderDeliveries < Comable::Migration
|
|
2
2
|
def change
|
3
3
|
create_table :comable_order_deliveries do |t|
|
4
4
|
t.integer :comable_order_id, null: false
|
5
|
-
t.string :family_name
|
6
|
-
t.string :first_name
|
5
|
+
t.string :family_name
|
6
|
+
t.string :first_name
|
7
7
|
end
|
8
8
|
end
|
9
9
|
end
|
@@ -3,8 +3,10 @@ class CreateComableOrderDetails < Comable::Migration
|
|
3
3
|
create_table :comable_order_details do |t|
|
4
4
|
t.integer :comable_order_delivery_id, null: false
|
5
5
|
t.integer :comable_stock_id, null: false
|
6
|
-
t.integer :price
|
6
|
+
t.integer :price
|
7
7
|
t.integer :quantity, default: 1, null: false
|
8
8
|
end
|
9
|
+
|
10
|
+
add_index :comable_order_details, [:comable_order_delivery_id, :comable_stock_id], unique: true, name: :comable_order_details_idx_01
|
9
11
|
end
|
10
12
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateComablePayments < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :comable_payments do |t|
|
4
|
+
t.string :name, null: false
|
5
|
+
t.string :payment_method_type, null: false
|
6
|
+
t.integer :payment_method_kind, null: false
|
7
|
+
t.integer :enable_price_from
|
8
|
+
t.integer :enable_price_to
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
data/lib/comable.rb
CHANGED
@@ -0,0 +1,79 @@
|
|
1
|
+
module Comable
|
2
|
+
module CartOwner
|
3
|
+
def add_cart_item(obj, quantity: 1)
|
4
|
+
process_cart_item(obj) do |stock|
|
5
|
+
add_stock_to_cart(stock, quantity)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def remove_cart_item(obj, quantity: -1)
|
10
|
+
add_cart_item(obj, quantity: quantity)
|
11
|
+
end
|
12
|
+
|
13
|
+
def reset_cart_item(obj, quantity: 0)
|
14
|
+
process_cart_item(obj) do |stock|
|
15
|
+
reset_stock_from_cart(stock, quantity)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def cart_items
|
20
|
+
fail 'You should implement cart_items method.'
|
21
|
+
end
|
22
|
+
|
23
|
+
def cart
|
24
|
+
Cart.new(cart_items)
|
25
|
+
end
|
26
|
+
|
27
|
+
class Cart < Array
|
28
|
+
def price
|
29
|
+
sum(&:current_subtotal_price)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def process_cart_item(obj)
|
36
|
+
case obj
|
37
|
+
when Comable::Product
|
38
|
+
yield obj.stocks.first
|
39
|
+
when Comable::Stock
|
40
|
+
yield obj
|
41
|
+
when Array
|
42
|
+
obj.map { |item| yield item }
|
43
|
+
else
|
44
|
+
fail
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_stock_to_cart(stock, quantity)
|
49
|
+
fail I18n.t('comable.carts.product_not_stocked') if stock.soldout?
|
50
|
+
|
51
|
+
cart_items = find_cart_items_by(stock)
|
52
|
+
if cart_items.any?
|
53
|
+
cart_item = cart_items.first
|
54
|
+
cart_item.quantity += quantity
|
55
|
+
(cart_item.quantity > 0) ? cart_item.save : cart_item.destroy
|
56
|
+
else
|
57
|
+
cart_items.create(quantity: quantity)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def reset_stock_from_cart(stock, quantity)
|
62
|
+
cart_items = find_cart_items_by(stock)
|
63
|
+
if quantity > 0
|
64
|
+
return add_stock_to_cart(stock, quantity) if cart_items.empty?
|
65
|
+
cart_item = cart_items.first
|
66
|
+
cart_item.quantity = quantity
|
67
|
+
cart_item.save
|
68
|
+
else
|
69
|
+
return false if cart_items.empty?
|
70
|
+
cart_item.destroy
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def find_cart_items_by(stock)
|
75
|
+
fail I18n.t('comable.carts.product_not_found') unless stock.is_a?(Comable::Stock)
|
76
|
+
cart_items.where(Comable::Stock.table_name.singularize.foreign_key => stock.id)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'comable/payment_method/base'
|
2
|
+
require 'comable/payment_method/general'
|
3
|
+
|
4
|
+
module Comable
|
5
|
+
module PaymentMethod
|
6
|
+
class << self
|
7
|
+
def all
|
8
|
+
(constants - [:Base]).map do |constant_name|
|
9
|
+
const_get(constant_name)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Comable
|
2
|
+
module PaymentMethod
|
3
|
+
class Base
|
4
|
+
class << self
|
5
|
+
def name_symbol
|
6
|
+
name.demodulize.underscore.to_sym
|
7
|
+
end
|
8
|
+
|
9
|
+
def display_name
|
10
|
+
please_implement_method
|
11
|
+
end
|
12
|
+
|
13
|
+
def kind
|
14
|
+
please_implement_method
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def please_implement_method
|
20
|
+
calling_method_name = caller_locations(1, 1).first.label
|
21
|
+
fail "You should implement '#{calling_method_name}' method in #{name}."
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/comable/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'yard'
|
2
|
+
require 'yard/rake/yardoc_task'
|
3
|
+
|
4
|
+
YARD::Rake::YardocTask.new do |t|
|
5
|
+
t.files = %w(
|
6
|
+
app/models/**/*.rb
|
7
|
+
app/controllers/**/*.rb
|
8
|
+
app/helpers/**/*.rb
|
9
|
+
app/mailers/**/*.rb
|
10
|
+
lib/**/*.rb
|
11
|
+
)
|
12
|
+
t.options = []
|
13
|
+
t.options = %w(--debug --verbose) if $trace
|
14
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: comable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YOSHIDA Hiroki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -206,6 +206,34 @@ dependencies:
|
|
206
206
|
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: 0.0.6
|
209
|
+
- !ruby/object:Gem::Dependency
|
210
|
+
name: yard
|
211
|
+
requirement: !ruby/object:Gem::Requirement
|
212
|
+
requirements:
|
213
|
+
- - ">="
|
214
|
+
- !ruby/object:Gem::Version
|
215
|
+
version: '0'
|
216
|
+
type: :development
|
217
|
+
prerelease: false
|
218
|
+
version_requirements: !ruby/object:Gem::Requirement
|
219
|
+
requirements:
|
220
|
+
- - ">="
|
221
|
+
- !ruby/object:Gem::Version
|
222
|
+
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: inch
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :development
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
209
237
|
description: Comable provides a simple way to add e-commerce features to your Ruby
|
210
238
|
on Rails application.
|
211
239
|
email:
|
@@ -225,11 +253,11 @@ files:
|
|
225
253
|
- app/controllers/comable/products_controller.rb
|
226
254
|
- app/helpers/comable/application_helper.rb
|
227
255
|
- app/helpers/comable/products_helper.rb
|
228
|
-
- app/models/comable/cart_item.rb
|
229
256
|
- app/models/comable/customer.rb
|
230
257
|
- app/models/comable/order.rb
|
231
258
|
- app/models/comable/order_delivery.rb
|
232
259
|
- app/models/comable/order_detail.rb
|
260
|
+
- app/models/comable/payment.rb
|
233
261
|
- app/models/comable/product.rb
|
234
262
|
- app/models/comable/stock.rb
|
235
263
|
- app/views/comable/carts/show.slim
|
@@ -238,25 +266,31 @@ files:
|
|
238
266
|
- app/views/comable/orders/delivery.slim
|
239
267
|
- app/views/comable/orders/new.slim
|
240
268
|
- app/views/comable/orders/orderer.slim
|
269
|
+
- app/views/comable/orders/payment.slim
|
241
270
|
- app/views/comable/products/index.slim
|
242
271
|
- app/views/comable/products/show.slim
|
243
272
|
- app/views/layouts/comable/application.slim
|
244
273
|
- config/locales/ja.yml
|
245
274
|
- config/routes.rb
|
246
275
|
- db/migrate/20131214194807_create_comable_products.rb
|
247
|
-
- db/migrate/20140120024159_create_comable_cart_items.rb
|
248
276
|
- db/migrate/20140120032559_create_comable_customers.rb
|
249
277
|
- db/migrate/20140502060116_create_comable_stocks.rb
|
250
278
|
- db/migrate/20140723175431_create_comable_orders.rb
|
251
279
|
- db/migrate/20140723175624_create_comable_order_deliveries.rb
|
252
280
|
- db/migrate/20140723175810_create_comable_order_details.rb
|
281
|
+
- db/migrate/20140817194104_create_comable_payments.rb
|
253
282
|
- lib/comable.rb
|
254
|
-
- lib/comable/
|
283
|
+
- lib/comable/cart_owner.rb
|
255
284
|
- lib/comable/decoratable.rb
|
256
285
|
- lib/comable/engine.rb
|
286
|
+
- lib/comable/errors.rb
|
257
287
|
- lib/comable/migration.rb
|
288
|
+
- lib/comable/payment_method.rb
|
289
|
+
- lib/comable/payment_method/base.rb
|
290
|
+
- lib/comable/payment_method/general.rb
|
258
291
|
- lib/comable/version.rb
|
259
292
|
- lib/tasks/comable_tasks.rake
|
293
|
+
- lib/tasks/comable_yardoc.task
|
260
294
|
homepage: https://github.com/hyoshida/comable#comable
|
261
295
|
licenses: []
|
262
296
|
metadata: {}
|
@@ -282,3 +316,4 @@ specification_version: 4
|
|
282
316
|
summary: Comable provides a simple way to add e-commerce features to your Ruby on
|
283
317
|
Rails application.
|
284
318
|
test_files: []
|
319
|
+
has_rdoc:
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Comable
|
2
|
-
class CartItem < ActiveRecord::Base
|
3
|
-
belongs_to :customer, class_name: Comable::Customer.name, foreign_key: Comable::Customer.table_name.singularize.foreign_key
|
4
|
-
belongs_to :stock, class_name: Comable::Stock.name, foreign_key: Comable::Stock.table_name.singularize.foreign_key
|
5
|
-
|
6
|
-
with_options if: :customer do |customer|
|
7
|
-
customer.validates Comable::Customer.table_name.singularize.foreign_key, uniqueness: { scope: [Comable::Customer.table_name.singularize.foreign_key, Comable::Stock.table_name.singularize.foreign_key] }
|
8
|
-
customer.validates Comable::Customer.table_name.singularize.foreign_key, presence: true
|
9
|
-
end
|
10
|
-
|
11
|
-
with_options if: :guest_token do |guest|
|
12
|
-
guest.validates :guest_token, uniqueness: { scope: [:guest_token, Comable::Stock.table_name.singularize.foreign_key] }
|
13
|
-
guest.validates :guest_token, presence: true
|
14
|
-
end
|
15
|
-
|
16
|
-
delegate :product, to: :stock
|
17
|
-
|
18
|
-
before_create :generate_guest_token
|
19
|
-
|
20
|
-
def price
|
21
|
-
stock.price * quantity
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def generate_guest_token
|
27
|
-
return if send(Comable::Customer.table_name.singularize.foreign_key)
|
28
|
-
self.guest_token ||= loop do
|
29
|
-
random_token = SecureRandom.urlsafe_base64(nil, false)
|
30
|
-
break random_token unless self.class.exists?(guest_token: random_token)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
class CreateComableCartItems < ActiveRecord::Migration
|
2
|
-
def change
|
3
|
-
create_table :comable_cart_items do |t|
|
4
|
-
t.integer :comable_customer_id
|
5
|
-
t.integer :comable_stock_id, null: false
|
6
|
-
t.integer :quantity, default: 1, null: false
|
7
|
-
t.string :guest_token
|
8
|
-
end
|
9
|
-
|
10
|
-
add_index :comable_cart_items, [:comable_customer_id, :comable_stock_id], unique: true, name: :comable_cart_items_idx_01
|
11
|
-
end
|
12
|
-
end
|
@@ -1,90 +0,0 @@
|
|
1
|
-
module Comable
|
2
|
-
class InvalidOrder < StandardError; end
|
3
|
-
|
4
|
-
class CashRegister
|
5
|
-
attr_accessor :customer
|
6
|
-
attr_accessor :order
|
7
|
-
|
8
|
-
def initialize(attributes)
|
9
|
-
@customer = attributes[:customer]
|
10
|
-
@order = @customer.orders.build(attributes[:order_attributes])
|
11
|
-
end
|
12
|
-
|
13
|
-
def build_order
|
14
|
-
assign_default_attributes_to_order
|
15
|
-
fail Comable::InvalidOrder if invalid
|
16
|
-
order
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_order
|
20
|
-
order = build_order
|
21
|
-
order.save
|
22
|
-
customer.reset_cart
|
23
|
-
order
|
24
|
-
end
|
25
|
-
|
26
|
-
def valid
|
27
|
-
valid_cart && valid_stock
|
28
|
-
end
|
29
|
-
|
30
|
-
def invalid
|
31
|
-
!valid
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
|
36
|
-
def valid_cart
|
37
|
-
cart = customer.cart
|
38
|
-
|
39
|
-
order.order_deliveries.map(&:order_details).flatten.each do |order_detail|
|
40
|
-
next unless order_detail.stock
|
41
|
-
result = cart.reject! { |cart_item| cart_item.stock == order_detail.stock }
|
42
|
-
return false if result.nil?
|
43
|
-
end
|
44
|
-
|
45
|
-
cart.empty?
|
46
|
-
end
|
47
|
-
|
48
|
-
def valid_stock
|
49
|
-
order.order_deliveries.map(&:order_details).flatten.each do |order_detail|
|
50
|
-
next unless order_detail.stock
|
51
|
-
return false unless order_detail.stock.unsold?
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
def assign_default_attributes_to_order
|
56
|
-
order.family_name ||= customer.family_name
|
57
|
-
order.first_name ||= customer.first_name
|
58
|
-
|
59
|
-
order.order_deliveries.build if order.order_deliveries.empty?
|
60
|
-
assign_default_attributes_to_order_deliveries
|
61
|
-
end
|
62
|
-
|
63
|
-
def assign_default_attributes_to_order_deliveries
|
64
|
-
order.order_deliveries.each do |order_delivery|
|
65
|
-
assign_default_attributes_to_order_delivery(order_delivery)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def assign_default_attributes_to_order_delivery(order_delivery)
|
70
|
-
order_delivery.family_name ||= customer.family_name
|
71
|
-
order_delivery.first_name ||= customer.first_name
|
72
|
-
|
73
|
-
assign_default_attributes_to_order_details(order_delivery) if first_order_detail?
|
74
|
-
end
|
75
|
-
|
76
|
-
def assign_default_attributes_to_order_details(order_delivery)
|
77
|
-
customer.cart.each do |cart_item|
|
78
|
-
order_delivery.order_details.build(
|
79
|
-
Comable::Stock.table_name.singularize.foreign_key => cart_item.stock.id,
|
80
|
-
:quantity => cart_item.quantity,
|
81
|
-
:price => cart_item.price
|
82
|
-
)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def first_order_detail?
|
87
|
-
order.order_deliveries.map(&:order_details).all?(&:empty?)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|