comable 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -0
  3. data/Rakefile +60 -4
  4. data/lib/comable/version.rb +14 -1
  5. data/lib/comable.rb +4 -8
  6. metadata +18 -244
  7. data/app/assets/javascripts/comable/application.js +0 -13
  8. data/app/assets/stylesheets/comable/application.css +0 -13
  9. data/app/controllers/comable/application_controller.rb +0 -5
  10. data/app/controllers/comable/carts_controller.rb +0 -40
  11. data/app/controllers/comable/orders_controller.rb +0 -115
  12. data/app/controllers/comable/products_controller.rb +0 -11
  13. data/app/helpers/comable/application_helper.rb +0 -18
  14. data/app/helpers/comable/products_helper.rb +0 -55
  15. data/app/models/comable/customer.rb +0 -97
  16. data/app/models/comable/order.rb +0 -93
  17. data/app/models/comable/order_delivery.rb +0 -16
  18. data/app/models/comable/order_detail.rb +0 -42
  19. data/app/models/comable/payment.rb +0 -26
  20. data/app/models/comable/product.rb +0 -32
  21. data/app/models/comable/stock.rb +0 -82
  22. data/app/views/comable/carts/show.slim +0 -22
  23. data/app/views/comable/orders/confirm.slim +0 -25
  24. data/app/views/comable/orders/create.slim +0 -5
  25. data/app/views/comable/orders/delivery.slim +0 -8
  26. data/app/views/comable/orders/new.slim +0 -4
  27. data/app/views/comable/orders/orderer.slim +0 -7
  28. data/app/views/comable/orders/payment.slim +0 -12
  29. data/app/views/comable/products/index.slim +0 -11
  30. data/app/views/comable/products/show.slim +0 -21
  31. data/app/views/layouts/comable/application.slim +0 -11
  32. data/config/locales/ja.yml +0 -11
  33. data/config/routes.rb +0 -23
  34. data/db/migrate/20131214194807_create_comable_products.rb +0 -14
  35. data/db/migrate/20140120032559_create_comable_customers.rb +0 -8
  36. data/db/migrate/20140502060116_create_comable_stocks.rb +0 -14
  37. data/db/migrate/20140723175431_create_comable_orders.rb +0 -15
  38. data/db/migrate/20140723175624_create_comable_order_deliveries.rb +0 -9
  39. data/db/migrate/20140723175810_create_comable_order_details.rb +0 -12
  40. data/db/migrate/20140817194104_create_comable_payments.rb +0 -11
  41. data/lib/comable/cart_owner.rb +0 -79
  42. data/lib/comable/decoratable.rb +0 -10
  43. data/lib/comable/engine.rb +0 -7
  44. data/lib/comable/errors.rb +0 -4
  45. data/lib/comable/migration.rb +0 -16
  46. data/lib/comable/payment_method/base.rb +0 -26
  47. data/lib/comable/payment_method/general.rb +0 -15
  48. data/lib/comable/payment_method.rb +0 -14
  49. data/lib/tasks/comable_tasks.rake +0 -4
  50. data/lib/tasks/comable_yardoc.task +0 -14
@@ -1,55 +0,0 @@
1
- module Comable
2
- module ProductsHelper
3
- def sku_table(product, options = nil)
4
- stocks = product.stocks
5
- content_tag(:table, nil, options) do
6
- html = ''
7
- html << build_sku_v_table_header(product, stocks)
8
- html << build_sku_table_rows(product, stocks)
9
- html.html_safe
10
- end
11
- end
12
-
13
- private
14
-
15
- def build_sku_v_table_header(product, stocks)
16
- sku_item_name = product.sku_h_item_name
17
- sku_item_name += '/' + product.sku_v_item_name if product.sku_v?
18
-
19
- html = ''
20
- html << content_tag(:th, sku_item_name)
21
- stocks.group_by(&:sku_h_choice_name).keys.each do |sku_h_choice_name|
22
- next if sku_h_choice_name.blank?
23
- html << content_tag(:th, sku_h_choice_name)
24
- end
25
- html.html_safe
26
- end
27
-
28
- def build_sku_table_rows(product, stocks)
29
- return content_tag(:tr, build_sku_table_row(stocks)) unless product.sku_v?
30
-
31
- 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?
34
- html << content_tag(:tr, build_sku_table_row(sku_v_stocks, sku_v_choice_name))
35
- end
36
- html.html_safe
37
- end
38
-
39
- def build_sku_table_row(stocks, sku_v_choice_name = nil)
40
- html = ''
41
- html << content_tag(:th, sku_v_choice_name)
42
- html << stocks.map { |stock| content_tag(:td, build_sku_product_label(stock)) }.join
43
- html.html_safe
44
- end
45
-
46
- 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
52
- end
53
- end
54
- end
55
- end
@@ -1,97 +0,0 @@
1
- module Comable
2
- class Customer < ActiveRecord::Base
3
- include Decoratable
4
- include CartOwner
5
-
6
- has_many :comable_orders, class_name: Comable::Order.name, foreign_key: table_name.singularize.foreign_key
7
- alias_method :orders, :comable_orders
8
-
9
- def initialize(*args)
10
- obj = args.first
11
- case obj.class.name
12
- when /Cookies/
13
- @cookies = obj
14
- super()
15
- else
16
- super
17
- end
18
- end
19
-
20
- def logged_in?
21
- !new_record?
22
- end
23
-
24
- def not_logged_in?
25
- !logged_in?
26
- end
27
-
28
- def reset_cart
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
37
- end
38
-
39
- def cart_items
40
- incomplete_order.order_deliveries.first.order_details
41
- end
42
-
43
- def incomplete_order
44
- @incomplete_order ||= initialize_incomplete_order
45
- end
46
-
47
- def preorder(order_params = {})
48
- incomplete_order.attributes = order_params
49
- incomplete_order.precomplete
50
- end
51
-
52
- def order(order_params = {})
53
- incomplete_order.attributes = order_params
54
- incomplete_order.complete.tap { |completed_flag| reset_cart if completed_flag }
55
- end
56
-
57
- private
58
-
59
- def current_guest_token
60
- return if logged_in?
61
- @cookies.signed[:guest_token]
62
- end
63
-
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
70
- end
71
-
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)
81
- end
82
-
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 }
88
- end
89
- alias_method_chain :add_stock_to_cart, :reload
90
-
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
95
- end
96
- end
97
- end
@@ -1,93 +0,0 @@
1
- module Comable
2
- class Order < ActiveRecord::Base
3
- include Decoratable
4
-
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
7
- has_many :order_deliveries, dependent: :destroy, class_name: Comable::OrderDelivery.name, foreign_key: table_name.singularize.foreign_key
8
-
9
- accepts_nested_attributes_for :order_deliveries
10
-
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
47
-
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
61
-
62
- private
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
-
78
- def generate_code
79
- self.code = loop do
80
- random_token = "C#{Array.new(11) { rand(9) }.join}"
81
- break random_token unless self.class.exists?(code: random_token)
82
- end
83
- end
84
-
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
91
- end
92
- end
93
- end
@@ -1,16 +0,0 @@
1
- module Comable
2
- class OrderDelivery < ActiveRecord::Base
3
- include Decoratable
4
-
5
- belongs_to :order, class_name: Comable::Order.name, foreign_key: Comable::Order.table_name.singularize.foreign_key
6
- has_many :order_details, dependent: :destroy, class_name: Comable::OrderDetail.name, foreign_key: table_name.singularize.foreign_key
7
-
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
15
- end
16
- end
@@ -1,42 +0,0 @@
1
- module Comable
2
- class OrderDetail < ActiveRecord::Base
3
- include Decoratable
4
-
5
- belongs_to :stock, class_name: Comable::Stock.name, foreign_key: Comable::Stock.table_name.singularize.foreign_key
6
- belongs_to :order_delivery, class_name: Comable::OrderDelivery.name, foreign_key: Comable::OrderDelivery.table_name.singularize.foreign_key
7
-
8
- # TODO: バリデーションの追加
9
-
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
41
- end
42
- end
@@ -1,26 +0,0 @@
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
@@ -1,32 +0,0 @@
1
- module Comable
2
- class Product < ActiveRecord::Base
3
- include Decoratable
4
-
5
- has_many :stocks, class_name: Comable::Stock.name, foreign_key: table_name.singularize.foreign_key
6
- after_create :create_stock
7
-
8
- def unsold?
9
- stocks.activated.unsold.exists?
10
- end
11
-
12
- def soldout?
13
- !unsold?
14
- end
15
-
16
- def sku_h?
17
- sku_h_item_name.present?
18
- end
19
-
20
- def sku_v?
21
- sku_v_item_name.present?
22
- end
23
-
24
- alias_method :sku?, :sku_h?
25
-
26
- private
27
-
28
- def create_stock
29
- stocks.create(code: code) unless stocks.exists?
30
- end
31
- end
32
- end
@@ -1,82 +0,0 @@
1
- module Comable
2
- #
3
- # 在庫モデル。
4
- # 商品に複数紐付き、品数やSKU(Stock Keeping Unit)情報を保持する。
5
- #
6
- class Stock < ActiveRecord::Base
7
- include Decoratable
8
-
9
- belongs_to :product, class_name: Comable::Product.name, foreign_key: Comable::Product.table_name.singularize.foreign_key
10
-
11
- #
12
- # @!group Scope
13
- #
14
-
15
- # @!scope class
16
- # 有効な在庫インスタンスを返す
17
- scope :activated, -> { where.not(product_id_num: nil) }
18
-
19
- # @!scope class
20
- # 品切れでない在庫インスタンスを返す
21
- scope :unsold, -> { where('quantity > ?', 0) }
22
-
23
- # @!scope class
24
- # 品切れの在庫インスタンスを返す
25
- scope :soldout, -> { where('quantity <= ?', 0) }
26
-
27
- #
28
- # @!endgroup
29
- #
30
-
31
- delegate :price, to: :product
32
- delegate :sku?, to: :product
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?
48
- def unsold?
49
- return false if product_id_num.nil?
50
- return false if quantity.nil?
51
- quantity > 0
52
- end
53
-
54
- # 在庫の有無を取得する
55
- #
56
- # @example
57
- # stock.soldout? #=> false
58
- #
59
- # @return [Boolean] {#unsold?} の逆。在庫がなければ true を返す
60
- # @see #unsold?
61
- def soldout?
62
- !unsold?
63
- end
64
-
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)
75
- with_lock do
76
- # TODO: カラムマッピングのdecrementメソッドへの対応
77
- self.quantity -= quantity
78
- save!
79
- end
80
- end
81
- end
82
- end
@@ -1,22 +0,0 @@
1
- h1 カート
2
-
3
- ul.cart
4
- - current_customer.cart.each do |cart_item|
5
- = form_tag comable.cart_path, method: :put do
6
- - stock = cart_item.stock
7
- - product = stock.product
8
- li.product
9
- h2.name
10
- = link_to stock.name, comable.product_path(product)
11
- .caption
12
- = product.caption
13
- .price
14
- = number_to_currency product.price
15
- .quantity
16
- - selected = cart_item.quantity
17
- = select_tag :quantity, options_for_select(1.upto([10, selected].max).to_a, selected)
18
- = hidden_field_tag :stock_id, stock.id
19
- = submit_tag '変更'
20
-
21
- .order
22
- = link_to '注文', comable.new_order_path
@@ -1,25 +0,0 @@
1
- h1 注文情報確認
2
-
3
- .order
4
- .orderer
5
- .family_name
6
- = @order.family_name
7
- .first_name
8
- = @order.first_name
9
- .deliveries
10
- - @order.order_deliveries.each do |order_delivery|
11
- .first_name
12
- = order_delivery.family_name
13
- .first_name
14
- = order_delivery.first_name
15
- .details
16
- - order_delivery.order_details.each do |order_detail|
17
- .name
18
- = order_detail.product.name
19
- .price
20
- = order_detail.price
21
- .quantity
22
- = order_detail.quantity
23
-
24
- = form_for @order, as: :order, url: comable.order_path, method: :post do |f|
25
- = f.submit
@@ -1,5 +0,0 @@
1
- h1 注文完了
2
-
3
- .order
4
- .code
5
- = @order.code
@@ -1,8 +0,0 @@
1
- h1 配送先情報入力
2
-
3
- .orderer
4
- = form_for @order, as: :order, url: comable.delivery_order_path, method: :put do |f|
5
- = f.fields_for :order_deliveries do |order_delivery|
6
- = order_delivery.text_field :family_name, placeholder: '姓'
7
- = order_delivery.text_field :first_name, placeholder: '名'
8
- = f.submit
@@ -1,4 +0,0 @@
1
- h1 注文
2
-
3
- .order
4
- = link_to '規約に同意して注文', comable.orderer_order_path
@@ -1,7 +0,0 @@
1
- h1 注文者情報入力
2
-
3
- .orderer
4
- = form_for @order, as: :order, url: comable.orderer_order_path, method: :put do |f|
5
- = f.text_field :family_name, placeholder: '姓'
6
- = f.text_field :first_name, placeholder: '名'
7
- = f.submit
@@ -1,12 +0,0 @@
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
@@ -1,11 +0,0 @@
1
- h1 商品一覧
2
-
3
- ul.products
4
- - @products.each do |product|
5
- li.product
6
- h2.name
7
- = link_to product.name, comable.product_path(product)
8
- .caption
9
- = product.caption
10
- .price
11
- = number_to_currency product.price
@@ -1,21 +0,0 @@
1
- .product
2
- h1.name
3
- = @product.name
4
- .caption
5
- = @product.caption
6
- .price
7
- = number_to_currency @product.price
8
-
9
- = form_tag comable.add_cart_path do
10
- - if @product.sku?
11
- .sku
12
- = sku_table @product, border: 1
13
-
14
- - if @product.unsold?
15
- .add_cart
16
- = hidden_field_tag :product_id, @product.id
17
- = select_tag :quantity, options_for_select(1.upto(10).to_a)
18
- = submit_tag 'カートに入れる'
19
- - else
20
- .sold_out
21
- | 品切れ中
@@ -1,11 +0,0 @@
1
- doctype html
2
- html
3
- head
4
- title Comable
5
- = stylesheet_link_tag "comable/application", media: "all"
6
- = javascript_include_tag "comable/application"
7
- = csrf_meta_tags
8
- body
9
- - flash.each do |name, msg|
10
- = content_tag(:div, msg, id: "flash_#{name}")
11
- == yield
@@ -1,11 +0,0 @@
1
- ja:
2
- comable:
3
- carts:
4
- add_product: '1つの商品がカートに入りしました'
5
- product_not_found: 'ご指定の商品は見つかりませんでした'
6
- product_not_stocked: 'ご指定の商品は在庫がありません'
7
- empty: 'カートに商品が入っていません'
8
- update: 'カートの内容が変更されました'
9
- orders:
10
- success: '注文が完了しました'
11
- failure: '注文に失敗しました。入力項目を見直してください。'
data/config/routes.rb DELETED
@@ -1,23 +0,0 @@
1
- Comable::Engine.routes.draw do
2
- get '/' => 'products#index'
3
-
4
- resources :products
5
-
6
- resource :cart do
7
- collection do
8
- post :add
9
- end
10
- end
11
-
12
- resource :order do
13
- collection do
14
- get :orderer
15
- put :orderer
16
- get :delivery
17
- put :delivery
18
- get :payment
19
- put :payment
20
- get :confirm
21
- end
22
- end
23
- end
@@ -1,14 +0,0 @@
1
- class CreateComableProducts < Comable::Migration
2
- def change
3
- create_table :comable_products do |t|
4
- t.string :name, null: false
5
- t.string :code, null: false
6
- t.integer :price, null: false
7
- t.text :caption
8
- t.string :sku_h_item_name
9
- t.string :sku_v_item_name
10
- end
11
-
12
- add_index :comable_products, :code, unique: true, name: :comable_products_idx_01
13
- end
14
- end
@@ -1,8 +0,0 @@
1
- class CreateComableCustomers < Comable::Migration
2
- def change
3
- create_table :comable_customers do |t|
4
- t.string :family_name, null: false
5
- t.string :first_name, null: false
6
- end
7
- end
8
- end
@@ -1,14 +0,0 @@
1
- class CreateComableStocks < Comable::Migration
2
- def change
3
- create_table :comable_stocks do |t|
4
- t.integer :comable_product_id
5
- t.integer :product_id_num
6
- t.string :code, null: false
7
- t.integer :quantity
8
- t.string :sku_h_choice_name
9
- t.string :sku_v_choice_name
10
- end
11
-
12
- add_index :comable_stocks, :code, unique: true, name: :comable_stocks_idx_01
13
- end
14
- end
@@ -1,15 +0,0 @@
1
- class CreateComableOrders < Comable::Migration
2
- def change
3
- create_table :comable_orders do |t|
4
- t.integer :comable_customer_id
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
11
- end
12
-
13
- add_index :comable_orders, :code, unique: true, name: :comable_orders_idx_01
14
- end
15
- end