comable_core 0.3.4 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/helpers/comable/application_helper.rb +17 -10
- data/app/models/comable/ability.rb +1 -1
- data/app/models/comable/address.rb +2 -2
- data/app/models/comable/order/associations.rb +22 -0
- data/app/models/comable/order/callbacks.rb +43 -0
- data/app/models/comable/order/scopes.rb +17 -0
- data/app/models/comable/order/validations.rb +39 -0
- data/app/models/comable/order.rb +63 -72
- data/app/models/comable/order_item/csvable.rb +32 -0
- data/app/models/comable/{order_detail.rb → order_item.rb} +19 -10
- data/app/models/comable/payment.rb +82 -0
- data/app/models/comable/payment_method.rb +1 -0
- data/app/models/comable/product/csvable.rb +20 -0
- data/app/models/comable/product.rb +2 -7
- data/app/models/comable/shipment.rb +79 -0
- data/app/models/comable/stock/csvable.rb +26 -0
- data/app/models/comable/stock.rb +2 -17
- data/app/models/comable/tracker.rb +17 -0
- data/app/models/comable/{customer.rb → user.rb} +11 -23
- data/app/models/concerns/comable/checkout.rb +35 -36
- data/app/models/concerns/comable/importable.rb +67 -0
- data/app/views/comable/order_mailer/complete.text.erb +9 -8
- data/config/initializers/comma.rb +8 -0
- data/config/locales/en.yml +105 -14
- data/config/locales/ja.yml +92 -19
- data/db/migrate/{20140120032559_create_comable_customers.rb → 20140120032559_create_comable_users.rb} +6 -6
- data/db/migrate/20140723175431_create_comable_orders.rb +2 -4
- data/db/migrate/{20140723175810_create_comable_order_details.rb → 20140723175810_create_comable_order_items.rb} +3 -3
- data/db/migrate/20140817194104_create_comable_payment_methods.rb +1 -0
- data/db/migrate/20141024025526_create_comable_addresses.rb +1 -1
- data/db/migrate/20150423095210_create_comable_shipments.rb +12 -0
- data/db/migrate/20150511171940_create_comable_payments.rb +11 -0
- data/db/migrate/20150513185230_create_comable_trackers.rb +12 -0
- data/db/seeds/comable/{customers.rb → users.rb} +3 -3
- data/lib/comable/core/configuration.rb +7 -1
- data/lib/comable/core/engine.rb +0 -25
- data/lib/comable/payment_provider/base.rb +16 -0
- data/lib/comable_core.rb +6 -1
- data/lib/comma_extractor_extentions.rb +31 -0
- data/lib/generators/comable/install/templates/config/initializers/comable.rb +16 -1
- metadata +79 -8
- data/lib/comable/errors.rb +0 -4
@@ -0,0 +1,79 @@
|
|
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
|
+
end
|
50
|
+
|
51
|
+
class << self
|
52
|
+
def state_names
|
53
|
+
state_machine.states.keys
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def stated?(target_state)
|
58
|
+
target_state_index = self.class.state_names.index(target_state.to_sym)
|
59
|
+
current_state_index = self.class.state_names.index(state_name)
|
60
|
+
target_state_index < current_state_index
|
61
|
+
end
|
62
|
+
|
63
|
+
def completed?
|
64
|
+
state?(:completed) || state?(:resumed)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def order_completed?
|
70
|
+
order.completed?
|
71
|
+
end
|
72
|
+
|
73
|
+
def copy_attributes_from_shipment_method
|
74
|
+
self.attributes = {
|
75
|
+
fee: shipment_method.fee
|
76
|
+
}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
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
|
data/app/models/comable/stock.rb
CHANGED
@@ -7,6 +7,7 @@ module Comable
|
|
7
7
|
include Comable::SkuItem
|
8
8
|
include Comable::SkuChoice
|
9
9
|
include Comable::Ransackable
|
10
|
+
include Comable::Stock::Csvable
|
10
11
|
|
11
12
|
belongs_to :product, class_name: Comable::Product.name
|
12
13
|
|
@@ -18,25 +19,15 @@ module Comable
|
|
18
19
|
# 品切れでない在庫インスタンスを返す
|
19
20
|
scope :stocked, -> { where('quantity > ?', 0) }
|
20
21
|
|
21
|
-
class << self
|
22
|
-
alias_method :unsold, :stocked
|
23
|
-
deprecate :unsold, deprecator: Comable::Deprecator.instance
|
24
|
-
end
|
25
|
-
|
26
22
|
# @!scope class
|
27
23
|
# 品切れの在庫インスタンスを返す
|
28
24
|
scope :unstocked, -> { where('quantity <= ?', 0) }
|
29
25
|
|
30
|
-
class << self
|
31
|
-
alias_method :soldout, :unstocked
|
32
|
-
deprecate :soldout, deprecator: Comable::Deprecator.instance
|
33
|
-
end
|
34
|
-
|
35
26
|
#
|
36
27
|
# @!endgroup
|
37
28
|
#
|
38
29
|
|
39
|
-
validates :product, presence:
|
30
|
+
validates :product, presence: { message: Comable.t('admin.is_not_exists') }
|
40
31
|
validates :code, presence: true, length: { maximum: 255 }
|
41
32
|
validates :sku_h_choice_name, length: { maximum: 255 }
|
42
33
|
validates :sku_v_choice_name, length: { maximum: 255 }
|
@@ -63,9 +54,6 @@ module Comable
|
|
63
54
|
(self.quantity - quantity) >= 0
|
64
55
|
end
|
65
56
|
|
66
|
-
alias_method :unsold?, :stocked?
|
67
|
-
deprecate :unsold?, deprecator: Comable::Deprecator.instance
|
68
|
-
|
69
57
|
# 在庫の有無を取得する
|
70
58
|
#
|
71
59
|
# @example
|
@@ -78,8 +66,5 @@ module Comable
|
|
78
66
|
def unstocked?(quantity: 1)
|
79
67
|
!stocked?(quantity: quantity)
|
80
68
|
end
|
81
|
-
|
82
|
-
alias_method :soldout?, :unstocked?
|
83
|
-
deprecate :soldout?, deprecator: Comable::Deprecator.instance
|
84
69
|
end
|
85
70
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Comable
|
2
|
+
class Tracker < ActiveRecord::Base
|
3
|
+
extend Enumerize
|
4
|
+
|
5
|
+
validates :name, presence: true, length: { maximum: 255 }
|
6
|
+
validates :tracker_id, length: { maximum: 255 }
|
7
|
+
validates :code, presence: true
|
8
|
+
validates :place, presence: true, length: { maximum: 255 }
|
9
|
+
|
10
|
+
scope :activated, -> { where(activate_flag: true) }
|
11
|
+
|
12
|
+
enumerize :place, in: %i(
|
13
|
+
everywhere
|
14
|
+
checkout
|
15
|
+
), scope: true
|
16
|
+
end
|
17
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Comable
|
2
|
-
class
|
2
|
+
class User < ActiveRecord::Base
|
3
3
|
include Comable::CartOwner
|
4
4
|
include Comable::RoleOwner
|
5
5
|
include Comable::Ransackable
|
@@ -15,7 +15,7 @@ module Comable
|
|
15
15
|
|
16
16
|
validates :email, presence: true, length: { maximum: 255 }
|
17
17
|
|
18
|
-
devise(*Comable::Config.devise_strategies[:
|
18
|
+
devise(*Comable::Config.devise_strategies[:user])
|
19
19
|
|
20
20
|
ransack_options ransackable_attributes: { except: [:encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :bill_address_id, :ship_address_id] }
|
21
21
|
|
@@ -62,28 +62,21 @@ module Comable
|
|
62
62
|
end
|
63
63
|
|
64
64
|
def cart_items
|
65
|
-
|
65
|
+
incomplete_order.order_items
|
66
66
|
end
|
67
67
|
|
68
68
|
def incomplete_order
|
69
|
+
@incomplete_order = nil if @incomplete_order.try(:completed?)
|
69
70
|
@incomplete_order ||= find_incomplete_order || initialize_incomplete_order
|
70
71
|
end
|
71
72
|
|
72
|
-
def order(order_params = {})
|
73
|
-
Rails.logger.debug '[DEPRECATED] Comable::Customer#order is deprecated. Please use Comable::Order#next_state method.'
|
74
|
-
incomplete_order.attributes = order_params
|
75
|
-
incomplete_order.state = 'complete'
|
76
|
-
incomplete_order.complete!
|
77
|
-
incomplete_order.tap { reload }
|
78
|
-
end
|
79
|
-
|
80
73
|
def after_set_user
|
81
74
|
return unless current_guest_token
|
82
75
|
|
83
|
-
guest_order = Comable::Order.incomplete.preload(:
|
76
|
+
guest_order = Comable::Order.incomplete.preload(:order_items).where(guest_token: current_guest_token).first
|
84
77
|
return unless guest_order
|
85
78
|
|
86
|
-
|
79
|
+
incomplete_order.inherit!(guest_order)
|
87
80
|
inherit_cart_items(guest_order)
|
88
81
|
end
|
89
82
|
|
@@ -106,7 +99,7 @@ module Comable
|
|
106
99
|
|
107
100
|
def incomplete_order_attributes
|
108
101
|
{
|
109
|
-
|
102
|
+
user_id: id,
|
110
103
|
email: email
|
111
104
|
}
|
112
105
|
end
|
@@ -115,20 +108,15 @@ module Comable
|
|
115
108
|
guest_token ||= current_guest_token unless signed_in?
|
116
109
|
Comable::Order
|
117
110
|
.incomplete
|
118
|
-
.preload(:
|
111
|
+
.preload(:order_items)
|
119
112
|
.where(guest_token: guest_token)
|
120
|
-
.
|
113
|
+
.by_user(self)
|
121
114
|
.first
|
122
115
|
end
|
123
116
|
|
124
|
-
def inherit_order_state(guest_order)
|
125
|
-
return if incomplete_order.stated?(guest_order.state)
|
126
|
-
incomplete_order.next_state
|
127
|
-
end
|
128
|
-
|
129
117
|
def inherit_cart_items(guest_order)
|
130
|
-
guest_order.
|
131
|
-
move_cart_item(
|
118
|
+
guest_order.order_items.each do |order_item|
|
119
|
+
move_cart_item(order_item)
|
132
120
|
end
|
133
121
|
end
|
134
122
|
end
|
@@ -10,52 +10,35 @@ module Comable
|
|
10
10
|
state :shipment
|
11
11
|
state :payment
|
12
12
|
state :confirm
|
13
|
-
state :
|
13
|
+
state :completed
|
14
|
+
state :canceled
|
15
|
+
state :returned
|
16
|
+
state :resumed
|
14
17
|
|
15
18
|
event :next_state do
|
16
19
|
transition :cart => :orderer, if: :orderer_required?
|
17
20
|
transition [:cart, :orderer] => :delivery, if: :delivery_required?
|
18
21
|
transition [:cart, :orderer, :delivery] => :shipment, if: :shipment_required?
|
19
22
|
transition [:cart, :orderer, :delivery, :shipment] => :payment, if: :payment_required?
|
20
|
-
transition all - [:confirm, :
|
21
|
-
transition :confirm => :
|
23
|
+
transition all - [:confirm, :completed] => :confirm
|
24
|
+
transition :confirm => :completed
|
22
25
|
end
|
23
26
|
|
24
|
-
|
25
|
-
|
27
|
+
event :cancel do
|
28
|
+
transition to: :canceled, from: [:completed, :resumed], if: :allow_cancel?
|
26
29
|
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# TODO: Remove with_options
|
30
|
-
with_options if: -> { state?(:cart) } do |context|
|
31
|
-
context.validates :customer_id, presence: true, uniqueness: { scope: [:customer_id, :completed_at] }, unless: :guest_token
|
32
|
-
context.validates :guest_token, presence: true, uniqueness: { scope: [:guest_token, :completed_at] }, unless: :customer
|
33
|
-
end
|
34
|
-
|
35
|
-
with_options if: -> { stated?(:cart) } do |context|
|
36
|
-
context.validates :email, presence: true
|
37
|
-
end
|
38
30
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
with_options if: -> { stated?(:delivery) } do |context|
|
44
|
-
context.validates :ship_address, presence: true
|
45
|
-
end
|
46
|
-
|
47
|
-
with_options if: -> { stated?(:payment) && payment_required? } do |context|
|
48
|
-
context.validates :payment_method, presence: true
|
49
|
-
end
|
31
|
+
event :return do
|
32
|
+
transition to: :returned, from: [:completed, :resumed], if: :allow_return?
|
33
|
+
end
|
50
34
|
|
51
|
-
|
52
|
-
|
53
|
-
|
35
|
+
event :resume do
|
36
|
+
transition to: :resumed, from: :canceled
|
37
|
+
end
|
54
38
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
context.validates :total_price, presence: true
|
39
|
+
before_transition to: :completed, do: :complete!
|
40
|
+
after_transition to: :canceled, do: :restock!
|
41
|
+
after_transition to: :resumed, do: :unstock!
|
59
42
|
end
|
60
43
|
end
|
61
44
|
|
@@ -71,6 +54,10 @@ module Comable
|
|
71
54
|
target_state_index < current_state_index
|
72
55
|
end
|
73
56
|
|
57
|
+
def completed?
|
58
|
+
state?(:completed) || state?(:resumed)
|
59
|
+
end
|
60
|
+
|
74
61
|
def orderer_required?
|
75
62
|
bill_address.nil? || bill_address.new_record?
|
76
63
|
end
|
@@ -80,11 +67,23 @@ module Comable
|
|
80
67
|
end
|
81
68
|
|
82
69
|
def payment_required?
|
83
|
-
Comable::PaymentMethod.exists?
|
70
|
+
Comable::PaymentMethod.exists? && payment.nil?
|
84
71
|
end
|
85
72
|
|
86
73
|
def shipment_required?
|
87
|
-
Comable::ShipmentMethod.activated.exists?
|
74
|
+
Comable::ShipmentMethod.activated.exists? && shipment.nil?
|
75
|
+
end
|
76
|
+
|
77
|
+
def allow_cancel?
|
78
|
+
# TODO: Implement shipments
|
79
|
+
# !shipments.exists?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def allow_return?
|
84
|
+
# TODO: Implement shipments
|
85
|
+
# shipments.exists?
|
86
|
+
false
|
88
87
|
end
|
89
88
|
end
|
90
89
|
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Comable
|
2
|
+
module Importable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
class Exception < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
class UnknownFileType < Comable::Importable::Exception
|
9
|
+
end
|
10
|
+
|
11
|
+
class RecordInvalid < Comable::Importable::Exception
|
12
|
+
end
|
13
|
+
|
14
|
+
# from http://railscasts.com/episodes/396-importing-csv-and-excel
|
15
|
+
module ClassMethods
|
16
|
+
def import_from(file, primary_key: :code)
|
17
|
+
spreadsheet = open_spreadsheet(file)
|
18
|
+
read_spreadsheet(spreadsheet) do |header, row|
|
19
|
+
attributes = attributes_from_header_and_row(header, row)
|
20
|
+
record = find_by(primary_key => attributes[primary_key]) || new
|
21
|
+
begin
|
22
|
+
record.update_attributes!(attributes)
|
23
|
+
rescue ActiveRecord::RecordInvalid => e
|
24
|
+
raise RecordInvalid, "#{record.class.human_attribute_name(primary_key)} \"#{record.send(primary_key)}\": #{e.message}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def open_spreadsheet(file)
|
32
|
+
case File.extname(file.original_filename)
|
33
|
+
when '.csv' then Roo::CSV.new(file.path)
|
34
|
+
when '.xls' then Roo::Excel.new(file.path, nil, :ignore)
|
35
|
+
when '.xlsx' then Roo::Excelx.new(file.path, nil, :ignore)
|
36
|
+
else fail UnknownFileType, Comable.t('admin.unknown_file_type', filename: file.original_filename)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def read_spreadsheet(spreadsheet)
|
41
|
+
header = spreadsheet.row(1)
|
42
|
+
(2..spreadsheet.last_row).each do |i|
|
43
|
+
yield header, spreadsheet.row(i)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def attributes_from_header_and_row(header, row)
|
48
|
+
human_attributes = Hash[[header, row].transpose].to_hash
|
49
|
+
human_attributes_to_attributes(human_attributes)
|
50
|
+
end
|
51
|
+
|
52
|
+
def human_attributes_to_attributes(human_attributes)
|
53
|
+
comma_column_names.each.with_object({}) do |(key, _value), result|
|
54
|
+
human_key = Comma::HeaderExtractor.value_humanizer.call(key.to_sym, self)
|
55
|
+
result[key.to_sym] = human_attributes[human_key] if human_attributes[human_key]
|
56
|
+
result
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def comma_column_names(style = :default)
|
61
|
+
header_extractor_class = Comma::HeaderExtractor.dup
|
62
|
+
header_extractor_class.value_humanizer = -> (value, _model_class) { value.to_s }
|
63
|
+
extract_with(header_extractor_class, style)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -6,10 +6,10 @@
|
|
6
6
|
|
7
7
|
<%= Comable.t('order_mailer.complete.introductions', store_name: current_store.name) %>
|
8
8
|
|
9
|
-
<%-
|
10
|
-
<%- if
|
11
|
-
<%=
|
12
|
-
<%=
|
9
|
+
<%- shipment = @order.shipment %>
|
10
|
+
<%- if shipment %>
|
11
|
+
<%= @order.class.human_attribute_name(:shipment_method) %>:
|
12
|
+
<%= shipment.name %>
|
13
13
|
<%- end %>
|
14
14
|
|
15
15
|
<%= @order.class.human_attribute_name(:ship_address) %>:
|
@@ -22,19 +22,20 @@
|
|
22
22
|
<%= "#{@order.class.human_attribute_name(:code)}: #{@order.code}" %>
|
23
23
|
<%= "#{@order.class.human_attribute_name(:completed_at)}: #{I18n.l @order.completed_at.to_date}" %>
|
24
24
|
|
25
|
-
<%- @order.
|
26
|
-
<%= name_with_quantity
|
27
|
-
<%= number_to_currency
|
25
|
+
<%- @order.order_items.each do |order_item| %>
|
26
|
+
<%= name_with_quantity order_item.name_with_sku, order_item.quantity %>
|
27
|
+
<%= number_to_currency order_item.subtotal_price %>
|
28
28
|
|
29
29
|
<%- end %>
|
30
30
|
----------------------------------------------------------------------
|
31
31
|
|
32
32
|
<%= "#{@order.class.human_attribute_name(:item_total_price)}: #{number_to_currency @order.item_total_price}" %>
|
33
|
+
<%= "#{@order.class.human_attribute_name(:payment_fee)}: #{number_to_currency @order.payment_fee}" %>
|
33
34
|
<%= "#{@order.class.human_attribute_name(:shipment_fee)}: #{number_to_currency @order.shipment_fee}" %>
|
34
35
|
|
35
36
|
<%= "#{@order.class.human_attribute_name(:total_price)}: #{number_to_currency @order.total_price}" %>
|
36
37
|
|
37
|
-
<%= "#{@order.class.human_attribute_name(:payment_method)}: #{@order.
|
38
|
+
<%= "#{@order.class.human_attribute_name(:payment_method)}: #{@order.payment.name}\n" if @order.payment -%>
|
38
39
|
|
39
40
|
======================================================================
|
40
41
|
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# from https://github.com/comma-csv/comma/pull/50#issuecomment-22819269
|
2
|
+
Comma::HeaderExtractor.value_humanizer = lambda do |value, model_class|
|
3
|
+
if value.is_a?(String) || !model_class.respond_to?(:human_attribute_name)
|
4
|
+
Comma::HeaderExtractor::DEFAULT_VALUE_HUMANIZER.call(value, model_class)
|
5
|
+
else
|
6
|
+
model_class.human_attribute_name(value)
|
7
|
+
end
|
8
|
+
end
|