comable_core 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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