comable_core 0.2.3 → 0.3.0

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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +16 -4
  4. data/app/controllers/concerns/comable/permitted_attributes.rb +15 -0
  5. data/app/helpers/comable/application_helper.rb +36 -1
  6. data/app/helpers/comable/products_helper.rb +35 -8
  7. data/app/mailers/comable/order_mailer.rb +1 -1
  8. data/app/models/comable/ability.rb +18 -0
  9. data/app/models/comable/address.rb +6 -2
  10. data/app/models/comable/category.rb +72 -0
  11. data/app/models/comable/customer.rb +53 -53
  12. data/app/models/comable/image.rb +11 -0
  13. data/app/models/comable/order.rb +42 -47
  14. data/app/models/comable/order_detail.rb +30 -37
  15. data/app/models/comable/payment_method.rb +26 -0
  16. data/app/models/comable/product.rb +29 -3
  17. data/app/models/comable/shipment_method.rb +4 -0
  18. data/app/models/comable/stock.rb +8 -24
  19. data/app/models/comable/store.rb +7 -2
  20. data/{lib → app/models/concerns}/comable/cart_owner.rb +25 -11
  21. data/app/models/concerns/comable/checkout.rb +90 -0
  22. data/app/models/concerns/comable/product/search.rb +41 -0
  23. data/app/models/concerns/comable/role_owner.rb +15 -0
  24. data/app/uploaders/image_uploader.rb +7 -0
  25. data/app/views/comable/order_mailer/complete.text.erb +7 -9
  26. data/config/locales/ja.yml +237 -8
  27. data/db/migrate/20140120032559_create_comable_customers.rb +1 -4
  28. data/db/migrate/20140502060116_create_comable_stocks.rb +2 -3
  29. data/db/migrate/20140723175431_create_comable_orders.rb +4 -5
  30. data/db/migrate/20140723175810_create_comable_order_details.rb +3 -3
  31. data/db/migrate/20140817194104_create_comable_payment_methods.rb +11 -0
  32. data/db/migrate/20140926063541_create_comable_stores.rb +1 -1
  33. data/db/migrate/20141024025526_create_comable_addresses.rb +2 -2
  34. data/db/migrate/20150111031228_create_comable_categories.rb +9 -0
  35. data/db/migrate/20150111031229_create_comable_products_categories.rb +8 -0
  36. data/db/migrate/20150112173706_create_comable_images.rb +8 -0
  37. data/lib/comable/core/configuration.rb +6 -0
  38. data/lib/comable/core/engine.rb +23 -11
  39. data/lib/comable/errors.rb +0 -3
  40. data/lib/comable/{payment_method → payment_provider}/base.rb +1 -1
  41. data/lib/comable/{payment_method → payment_provider}/general.rb +1 -1
  42. data/lib/comable/{payment_method.rb → payment_provider.rb} +3 -3
  43. data/lib/comable/state_machine_patch.rb +16 -0
  44. data/lib/comable_core.rb +13 -3
  45. metadata +97 -10
  46. data/app/models/comable/order_delivery.rb +0 -21
  47. data/app/models/comable/payment.rb +0 -24
  48. data/db/migrate/20140723175624_create_comable_order_deliveries.rb +0 -9
  49. data/db/migrate/20140817194104_create_comable_payments.rb +0 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: da4f11f29114534f3c55966b7021770844817bc2
4
- data.tar.gz: 21a2c7ab417d1401a7b79b6ed456e22f40ce0395
3
+ metadata.gz: 79d30fe208de3671ba535bd99829f904cc98b3b2
4
+ data.tar.gz: 31a192ed59a8397d009d7bbc73bc16e4c2edcfc5
5
5
  SHA512:
6
- metadata.gz: 3fa65b0505fd616f97943e355e63806c077046c614516adb4f8b5dd10d122bc7fd79221006b8705b782166b469cdce63a1dba780f1ef00f0c4115da7690a9366
7
- data.tar.gz: 6f03560e17a436549e97d6993895e87e8c04a8eed78dd2e9fc50ef16a1181241f3553bdb091e0001b9a1ac412f66ba041df9fd5b24c99073909f0be41defa51f
6
+ metadata.gz: 5e0a6c361cd55ca06ca48fa67e8bb945ac1bbe13d8d672887bba2b325890ccc65e935cd02f089870290cc0234be47560d247a26fb6676a55820a3f738be54ae0
7
+ data.tar.gz: 15a3a2942bf455e146efc547c313858d6318a85abc0dbc511580501e326841ed82233f08f555e72cf3475743d9abfeba83338fec59f6578886ae5c96a170b1b1
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 YOSHIDA Hiroki
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -69,16 +69,28 @@ if File.exist?('comable.gemspec')
69
69
  end
70
70
  end
71
71
 
72
- task default: ['app:spec:all', 'rubocop']
72
+ task default: ['app:spec:all', 'rubocop', 'brakeman:all']
73
+ else
74
+ task default: ['app:spec', 'rubocop', 'brakeman']
73
75
  end
74
76
 
75
- task default: ['app:spec', 'rubocop']
76
-
77
77
  Bundler::GemHelper.install_tasks
78
78
 
79
79
  # from https://github.com/rspec/rspec-rails/issues/936
80
80
  task 'test:prepare'
81
81
 
82
82
  task :rubocop do
83
- exec 'rubocop'
83
+ sh 'rubocop'
84
+ end
85
+
86
+ task :brakeman do
87
+ sh 'brakeman --exit-on-warn --ignore-config .brakeman.ignore'
88
+ end
89
+
90
+ namespace :brakeman do
91
+ task :all do
92
+ FRAMEWORKS.each do |framework|
93
+ sh "brakeman --exit-on-warn --ignore-config .brakeman.ignore #{framework}"
94
+ end
95
+ end
84
96
  end
@@ -0,0 +1,15 @@
1
+ module Comable
2
+ module PermittedAttributes
3
+ def permitted_address_attributes
4
+ [
5
+ :family_name,
6
+ :first_name,
7
+ :zip_code,
8
+ :state_name,
9
+ :city,
10
+ :detail,
11
+ :phone_number
12
+ ]
13
+ end
14
+ end
15
+ end
@@ -15,8 +15,21 @@ module Comable
15
15
  current_customer.incomplete_order
16
16
  end
17
17
 
18
+ def next_order_path
19
+ comable.next_order_path(state: current_order.state)
20
+ end
21
+
22
+ def update_order_path
23
+ return next_order_path unless params[:state]
24
+ comable.next_order_path(state: params[:state])
25
+ end
26
+
27
+ def store_location
28
+ session[:customer_return_to] = request.fullpath.gsub('//', '/')
29
+ end
30
+
18
31
  def name_with_honorific(name)
19
- I18n.t('comable.honorific', name: name)
32
+ Comable.t('honorific', name: name)
20
33
  end
21
34
 
22
35
  def name_with_quantity(name, quantity)
@@ -27,5 +40,27 @@ module Comable
27
40
  "x#{quantity}"
28
41
  ].join(' ')
29
42
  end
43
+
44
+ private
45
+
46
+ def after_sign_in_path_for(_resource)
47
+ session.delete(:customer_return_to) || comable.root_path
48
+ end
49
+
50
+ def after_sign_out_path_for(_resource)
51
+ session.delete(:customer_return_to) || comable.root_path
52
+ end
53
+
54
+ def after_sign_up_path_for(resource)
55
+ signed_in_root_path(resource) || comable.root_path
56
+ end
57
+
58
+ def after_update_path_for(resource)
59
+ signed_in_root_path(resource) || comable.root_path
60
+ end
61
+
62
+ def after_resetting_password_path_for(resource)
63
+ signed_in_root_path(resource) || comable.root_path
64
+ end
30
65
  end
31
66
  end
@@ -1,5 +1,21 @@
1
1
  module Comable
2
2
  module ProductsHelper
3
+ def listed_categories(categories, options = {})
4
+ content_tag(options[:tag] || :ul, class: options[:class]) do
5
+ categories.map do |category|
6
+ content_tag(:li, link_to_category(category), class: "#{'active' if @category == category}")
7
+ end.join.html_safe
8
+ end
9
+ end
10
+
11
+ def link_to_category(category, force_link: false)
12
+ if force_link || @category != category
13
+ link_to category.name, comable.products_path(category_id: category.id)
14
+ else
15
+ category.name
16
+ end
17
+ end
18
+
3
19
  def sku_table(product, options = nil)
4
20
  stocks = product.stocks
5
21
  content_tag(:table, nil, options) do
@@ -19,7 +35,6 @@ module Comable
19
35
  html = ''
20
36
  html << content_tag(:th, sku_item_name)
21
37
  stocks.group_by(&:sku_h_choice_name).keys.each do |sku_h_choice_name|
22
- next if sku_h_choice_name.blank?
23
38
  html << content_tag(:th, sku_h_choice_name)
24
39
  end
25
40
  html.html_safe
@@ -29,8 +44,7 @@ module Comable
29
44
  return content_tag(:tr, build_sku_table_row(stocks)) unless product.sku_v?
30
45
 
31
46
  html = ''
32
- stocks.group_by(&:sku_v_choice_name).each_pair do |sku_v_choice_name, sku_v_stocks|
33
- next if sku_v_choice_name.blank?
47
+ stocks_groups_by_sku_v(stocks).each_pair do |sku_v_choice_name, sku_v_stocks|
34
48
  html << content_tag(:tr, build_sku_table_row(sku_v_stocks, sku_v_choice_name))
35
49
  end
36
50
  html.html_safe
@@ -44,11 +58,24 @@ module Comable
44
58
  end
45
59
 
46
60
  def build_sku_product_label(stock)
47
- content_tag(:label) do
48
- html = ''
49
- html << radio_button_tag(:stock_id, stock.id, false, disabled: stock.soldout?)
50
- html << stock.code
51
- html.html_safe
61
+ return unless stock
62
+ content_tag(:div, class: 'radio') do
63
+ content_tag(:label) do
64
+ html = ''
65
+ html << radio_button_tag(:stock_id, stock.id, false, disabled: stock.soldout?)
66
+ html << stock.code
67
+ html.html_safe
68
+ end
69
+ end
70
+ end
71
+
72
+ def stocks_groups_by_sku_v(stocks)
73
+ sku_h_choice_names = stocks.group_by(&:sku_h_choice_name).keys
74
+
75
+ stocks.group_by(&:sku_v_choice_name).each_with_object({}) do |(sku_v_choice_name, sku_v_stocks), group|
76
+ group[sku_v_choice_name] = sku_h_choice_names.map do |sku_h_choice_name|
77
+ sku_v_stocks.find { |s| s.sku_h_choice_name == sku_h_choice_name }
78
+ end
52
79
  end
53
80
  end
54
81
  end
@@ -12,7 +12,7 @@ module Comable
12
12
  private
13
13
 
14
14
  def subject_for(order)
15
- I18n.t('comable.order_mailer.complete.subject', store_name: current_store.name, order_code: order.code)
15
+ Comable.t('order_mailer.complete.subject', store_name: current_store.name, order_code: order.code)
16
16
  end
17
17
  end
18
18
  end
@@ -0,0 +1,18 @@
1
+ module Comable
2
+ class Ability
3
+ include CanCan::Ability
4
+
5
+ def initialize(user)
6
+ user ||= Comable::Customer.new # guest user (not logged in)
7
+
8
+ case user.role.to_sym
9
+ when :admin
10
+ can :manage, :all
11
+ when :reporter
12
+ can :read, :all
13
+ else
14
+ fail CanCan::AccessDenied
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,6 +1,6 @@
1
1
  module Comable
2
2
  class Address < ActiveRecord::Base
3
- belongs_to :customer, class_name: Comable::Customer.name, foreign_key: Comable::Customer.table_name.singularize.foreign_key, autosave: false
3
+ belongs_to :customer, class_name: Comable::Customer.name, autosave: false
4
4
 
5
5
  validates :family_name, presence: true, length: { maximum: 255 }
6
6
  validates :first_name, presence: true, length: { maximum: 255 }
@@ -25,7 +25,11 @@ module Comable
25
25
  end
26
26
 
27
27
  def attributes_without_id
28
- attributes.except('id', Comable::Customer.table_name.singularize.foreign_key.to_s)
28
+ attributes.except('id', 'customer_id')
29
+ end
30
+
31
+ def full_name
32
+ "#{family_name} #{first_name}"
29
33
  end
30
34
  end
31
35
  end
@@ -0,0 +1,72 @@
1
+ module Comable
2
+ class Category < ActiveRecord::Base
3
+ has_and_belongs_to_many :products, class_name: Comable::Product.name, join_table: :comable_products_categories
4
+ has_ancestry
5
+ acts_as_list scope: [:ancestry]
6
+
7
+ default_scope -> { order('position ASC') }
8
+
9
+ DEFAULT_PATH_NAME_DELIMITER = ' > '
10
+
11
+ class << self
12
+ def path_names(delimiter: DEFAULT_PATH_NAME_DELIMITER)
13
+ categoris.path(&:name).join(delimiter)
14
+ end
15
+
16
+ def find_by_path_names(path_names, delimiter: DEFAULT_PATH_NAME_DELIMITER)
17
+ path_names.map do |path_name|
18
+ find_by_path_name(path_name, delimiter: delimiter)
19
+ end.compact
20
+ end
21
+
22
+ def find_by_path_name(path_name, root: nil, delimiter: DEFAULT_PATH_NAME_DELIMITER)
23
+ names = path_name.split(delimiter)
24
+ names.inject(root) do |category, name|
25
+ (category ? category.children : roots).find_by(name: name) || return
26
+ end
27
+ end
28
+
29
+ def to_jstree(options = {})
30
+ build_to_jstree(arrange_serializable(order: :position), options).to_json
31
+ end
32
+
33
+ def from_jstree!(jstree_json)
34
+ jstree = JSON.parse(jstree_json)
35
+
36
+ transaction do
37
+ restore_from_jstree!(jstree)
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def build_to_jstree(serialized_categories, options = {})
44
+ serialized_categories.map do |serialized_category|
45
+ options.merge(
46
+ id: serialized_category['id'],
47
+ text: serialized_category['name'],
48
+ children: build_to_jstree(serialized_category['children'], options)
49
+ )
50
+ end
51
+ end
52
+
53
+ def restore_from_jstree!(jstree, parent = nil)
54
+ return unless jstree
55
+
56
+ jstree.each.with_index(1) do |node, index|
57
+ return find(node['_destroy']).destroy! if node['_destroy'].present?
58
+
59
+ restore_from_jstree_node!(node, parent, position: index)
60
+ end
61
+ end
62
+
63
+ def restore_from_jstree_node!(node, parent, default_attributes = {})
64
+ attributes = default_attributes.merge(parent: parent, name: node['text'])
65
+ category = node['id'].to_i.zero? ? new : find(node['id'])
66
+ category.update_attributes!(attributes)
67
+
68
+ restore_from_jstree!(node['children'], category)
69
+ end
70
+ end
71
+ end
72
+ end
@@ -1,9 +1,10 @@
1
1
  module Comable
2
2
  class Customer < ActiveRecord::Base
3
3
  include CartOwner
4
+ include RoleOwner
4
5
 
5
- has_many :orders, class_name: Comable::Order.name, foreign_key: table_name.singularize.foreign_key
6
- has_many :addresses, class_name: Comable::Address.name, foreign_key: table_name.singularize.foreign_key, dependent: :destroy
6
+ has_many :orders, class_name: Comable::Order.name
7
+ has_many :addresses, class_name: Comable::Address.name, dependent: :destroy
7
8
  belongs_to :bill_address, class_name: Comable::Address.name, dependent: :destroy
8
9
  belongs_to :ship_address, class_name: Comable::Address.name, dependent: :destroy
9
10
 
@@ -11,21 +12,12 @@ module Comable
11
12
  accepts_nested_attributes_for :bill_address
12
13
  accepts_nested_attributes_for :ship_address
13
14
 
15
+ validates :email, presence: true, length: { maximum: 255 }
16
+
14
17
  devise(*Comable::Config.devise_strategies[:customer])
15
18
 
16
- before_save :inherit_cart_items, if: :current_sign_in_at_changed?
17
-
18
- def initialize(*args)
19
- obj = args.first
20
- case obj.class.name
21
- when /Cookies/
22
- Rails.logger.debug '[DEPRECATED] Comable::Customer#new(cookies) is deprecated. Please use Comable::Customer#with_cookies(cookies) method.'
23
- @cookies = obj
24
- super()
25
- else
26
- super
27
- end
28
- end
19
+ delegate :full_name, to: :bill_address, allow_nil: true, prefix: :bill
20
+ delegate :full_name, to: :ship_address, allow_nil: true, prefix: :ship
29
21
 
30
22
  def with_cookies(cookies)
31
23
  @cookies = cookies
@@ -35,7 +27,7 @@ module Comable
35
27
  # Add conditions for the orders association.
36
28
  # Override method of the orders association to support Rails 3.x.
37
29
  def orders
38
- super.complete
30
+ super.complete.order('completed_at DESC, id DESC')
39
31
  end
40
32
 
41
33
  def other_addresses
@@ -58,33 +50,42 @@ module Comable
58
50
  !signed_in?
59
51
  end
60
52
 
61
- def reset_cart
62
- return unless incomplete_order
63
-
64
- # TODO: テストケースの作成
65
- incomplete_order.destroy if incomplete_order.incomplete?
66
-
67
- @incomplete_order = nil
53
+ # TODO: Add a test case
54
+ def reload(*_)
55
+ super.tap do
56
+ @cart_items = nil
57
+ @incomplete_order = nil
58
+ end
68
59
  end
69
60
 
70
61
  def cart_items
71
- incomplete_order.order_deliveries.first.order_details
62
+ @cart_items ||= incomplete_order.order_details
72
63
  end
73
64
 
74
65
  def incomplete_order
75
- @incomplete_order ||= initialize_incomplete_order
76
- end
77
-
78
- def preorder(order_params = {})
79
- incomplete_order.attributes = order_params
80
- incomplete_order.precomplete!
81
- incomplete_order
66
+ @incomplete_order ||= find_or_initialize_incomplete_order
82
67
  end
83
68
 
84
69
  def order(order_params = {})
70
+ Rails.logger.debug '[DEPRECATED] Comable::Customer#order is deprecated. Please use Comable::Order#next_state method.'
85
71
  incomplete_order.attributes = order_params
72
+ incomplete_order.state = 'complete'
86
73
  incomplete_order.complete!
87
- incomplete_order.tap { |completed_flag| reset_cart if completed_flag }
74
+ incomplete_order.tap { reload }
75
+ end
76
+
77
+ def after_set_user
78
+ return unless current_guest_token
79
+
80
+ guest_order = Comable::Order.incomplete.preload(:order_details).where(guest_token: current_guest_token).first
81
+ return unless guest_order
82
+
83
+ inherit_order_state(guest_order)
84
+ inherit_cart_items(guest_order)
85
+ end
86
+
87
+ def human_id
88
+ "##{id}"
88
89
  end
89
90
 
90
91
  private
@@ -93,44 +94,43 @@ module Comable
93
94
  @cookies.signed[:guest_token] if @cookies
94
95
  end
95
96
 
97
+ def find_or_initialize_incomplete_order
98
+ find_incomplete_order || initialize_incomplete_order
99
+ end
100
+
96
101
  def initialize_incomplete_order
97
- orders = find_incomplete_orders
98
- return orders.first if orders.any?
99
- order = orders.create(incomplete_order_attributes)
102
+ order = Comable::Order.create(incomplete_order_attributes)
100
103
  @cookies.permanent.signed[:guest_token] = order.guest_token if @cookies
101
- order
104
+ # enable preload
105
+ find_incomplete_order
102
106
  end
103
107
 
104
108
  def incomplete_order_attributes
105
109
  {
106
- self.class.table_name.singularize.foreign_key => id,
107
- email: email,
108
- # TODO: Remove
109
- family_name: family_name,
110
- first_name: first_name,
111
- order_deliveries_attributes: [{ family_name: family_name, first_name: first_name }]
110
+ customer_id: id,
111
+ email: email
112
112
  }
113
113
  end
114
114
 
115
- def find_incomplete_orders
116
- guest_token = current_guest_token unless signed_in?
115
+ def find_incomplete_order
116
+ guest_token ||= current_guest_token unless signed_in?
117
117
  Comable::Order
118
118
  .incomplete
119
- .includes(order_deliveries: :order_details)
119
+ .preload(:order_details)
120
120
  .where(guest_token: guest_token)
121
121
  .by_customer(self)
122
- .limit(1)
122
+ .first
123
123
  end
124
124
 
125
- def inherit_cart_items
126
- return unless current_guest_token
127
- guest_order = Comable::Order.incomplete.includes(order_deliveries: :order_details).where(guest_token: current_guest_token).first
128
- return unless guest_order
129
- guest_order.order_deliveries.map(&:order_details).flatten.each do |order_detail|
125
+ def inherit_order_state(guest_order)
126
+ return if incomplete_order.stated?(guest_order.state)
127
+ incomplete_order.next_state
128
+ end
129
+
130
+ def inherit_cart_items(guest_order)
131
+ guest_order.order_details.each do |order_detail|
130
132
  move_cart_item(order_detail)
131
133
  end
132
- # TODO: Remove?
133
- cart_items.reload
134
134
  end
135
135
  end
136
136
  end
@@ -0,0 +1,11 @@
1
+ module Comable
2
+ class Image < ActiveRecord::Base
3
+ mount_uploader :file, ImageUploader
4
+
5
+ belongs_to :product, class_name: Comable::Product.name
6
+
7
+ delegate :url, to: :file, allow_nil: true
8
+ delegate :current_path, to: :file, allow_nil: true
9
+ delegate :identifier, to: :file, allow_nil: true
10
+ end
11
+ end
@@ -1,83 +1,81 @@
1
1
  module Comable
2
2
  class Order < ActiveRecord::Base
3
- belongs_to :customer, class_name: Comable::Customer.name, foreign_key: Comable::Customer.table_name.singularize.foreign_key, autosave: false
4
- belongs_to :payment, class_name: Comable::Payment.name, foreign_key: Comable::Payment.table_name.singularize.foreign_key, autosave: false
3
+ include Comable::Checkout
4
+
5
+ belongs_to :customer, class_name: Comable::Customer.name, autosave: false
6
+ belongs_to :payment_method, class_name: Comable::PaymentMethod.name, autosave: false
5
7
  belongs_to :shipment_method, class_name: Comable::ShipmentMethod.name, autosave: false
6
8
  belongs_to :bill_address, class_name: Comable::Address.name, autosave: true, dependent: :destroy
7
9
  belongs_to :ship_address, class_name: Comable::Address.name, autosave: true, dependent: :destroy
8
- has_many :order_deliveries, dependent: :destroy, class_name: Comable::OrderDelivery.name, foreign_key: table_name.singularize.foreign_key, inverse_of: :order
10
+ has_many :order_details, dependent: :destroy, class_name: Comable::OrderDetail.name, inverse_of: :order
9
11
 
10
12
  accepts_nested_attributes_for :bill_address
11
13
  accepts_nested_attributes_for :ship_address
12
- # TODO: Remove
13
- accepts_nested_attributes_for :order_deliveries
14
-
15
- with_options if: :complete? do |complete_order|
16
- complete_order.validates :code, presence: true
17
- complete_order.validates :first_name, presence: true
18
- complete_order.validates :family_name, presence: true
19
- complete_order.validates :email, presence: true
20
- complete_order.validates :shipment_fee, presence: true
21
- complete_order.validates :total_price, presence: true
22
- end
23
-
24
- with_options unless: :complete? do |incomplete_order|
25
- incomplete_order.validates Comable::Customer.table_name.singularize.foreign_key, uniqueness: { scope: [Comable::Customer.table_name.singularize.foreign_key, :completed_at] }, if: :customer
26
- incomplete_order.validates :guest_token, uniqueness: { scope: [:guest_token, :completed_at] }, if: :guest_token
27
- end
14
+ accepts_nested_attributes_for :order_details
28
15
 
29
16
  define_model_callbacks :complete
30
- before_complete :precomplete
31
17
  before_validation :generate_guest_token, on: :create
32
18
  before_validation :clone_addresses_from_customer, on: :create
33
19
  after_complete :clone_addresses_to_customer
34
20
 
35
21
  scope :complete, -> { where.not(completed_at: nil) }
36
22
  scope :incomplete, -> { where(completed_at: nil) }
37
- scope :by_customer, -> (customer) { where(Comable::Customer.table_name.singularize.foreign_key => customer) }
23
+ scope :by_customer, -> (customer) { where(customer_id: customer) }
24
+ scope :this_month, -> { where(completed_at: Time.now.beginning_of_month..Time.now.end_of_month) }
25
+ scope :this_week, -> { where(completed_at: Time.now.beginning_of_week..Time.now.end_of_week) }
26
+ scope :last_week, -> { where(completed_at: 1.week.ago.beginning_of_week..1.week.ago.end_of_week) }
38
27
 
39
- def precomplete
40
- valid_order_quantity?
41
- end
28
+ delegate :full_name, to: :bill_address, allow_nil: true, prefix: :bill
29
+ delegate :full_name, to: :ship_address, allow_nil: true, prefix: :ship
42
30
 
43
- def precomplete!
44
- fail Comable::InvalidOrder unless precomplete
45
- self
31
+ class << self
32
+ def morris_keys
33
+ %w( count price )
34
+ end
35
+
36
+ def to_morris
37
+ this = (Rails::VERSION::MAJOR == 3) ? scoped : all
38
+ this.group_by { |order| order.completed_at.to_date }.map do |date, orders|
39
+ { date: date, count: orders.count, price: orders.sum(&:total_price) }
40
+ end.to_json
41
+ end
46
42
  end
47
43
 
48
44
  def complete
49
- # TODO: トランザクションの追加
50
- run_callbacks :complete do
51
- save_to_complete
45
+ ActiveRecord::Base.transaction do
46
+ run_callbacks :complete do
47
+ save_to_complete.tap { |completed| self.completed_at = nil unless completed }
48
+ end
52
49
  end
53
50
  end
54
51
 
55
52
  def complete!
53
+ Rails.logger.debug '[DEPRECATED] #complete! is deprecated. Please use #next_state method.'
56
54
  fail Comable::InvalidOrder unless complete
57
55
  self
58
56
  end
59
57
 
60
- def complete?
61
- !incomplete?
58
+ def completed?
59
+ !completed_at.nil?
62
60
  end
63
61
 
64
- def incomplete?
65
- completed_at.nil?
62
+ # TODO: switch to state_machine
63
+ def completing?
64
+ completed_at && completed_at_was.nil?
66
65
  end
67
66
 
68
- # 氏名を取得
69
- def full_name
70
- [family_name, first_name].join(' ')
67
+ def soldout_stocks
68
+ order_details.to_a.select(&:soldout_stock?)
71
69
  end
72
70
 
73
71
  # 時価商品合計を取得
74
72
  def current_item_total_price
75
- order_deliveries.map(&:order_details).flatten.sum(&:current_subtotal_price)
73
+ order_details.to_a.sum(&:current_subtotal_price)
76
74
  end
77
75
 
78
76
  # 売価商品合計を取得
79
77
  def item_total_price
80
- order_deliveries.map(&:order_details).flatten.sum(&:subtotal_price)
78
+ order_details.to_a.sum(&:subtotal_price)
81
79
  end
82
80
 
83
81
  # 時価送料を取得
@@ -97,12 +95,10 @@ module Comable
97
95
  self.shipment_fee = current_shipment_fee
98
96
  self.total_price = current_total_price
99
97
  generate_code
100
- order_deliveries.each(&:save_to_complete)
101
- save
102
- end
103
98
 
104
- def valid_order_quantity?
105
- order_deliveries.map(&:order_details).flatten.map(&:valid_order_quantity?).all?
99
+ order_details.each(&:complete)
100
+
101
+ save
106
102
  end
107
103
 
108
104
  def generate_code
@@ -128,9 +124,8 @@ module Comable
128
124
 
129
125
  def clone_addresses_to_customer
130
126
  return unless customer
131
- # TODO: Remove conditions for compatibility.
132
- customer.update_bill_address_by bill_address if bill_address
133
- customer.update_ship_address_by ship_address if ship_address
127
+ customer.update_bill_address_by bill_address
128
+ customer.update_ship_address_by ship_address
134
129
  end
135
130
  end
136
131
  end