comable 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +46 -0
  4. data/Rakefile +28 -0
  5. data/app/assets/javascripts/comable/application.js +13 -0
  6. data/app/assets/stylesheets/comable/application.css +13 -0
  7. data/app/controllers/comable/application_controller.rb +5 -0
  8. data/app/controllers/comable/carts_controller.rb +29 -0
  9. data/app/controllers/comable/orders_controller.rb +108 -0
  10. data/app/controllers/comable/products_controller.rb +11 -0
  11. data/app/helpers/comable/application_helper.rb +18 -0
  12. data/app/helpers/comable/products_helper.rb +55 -0
  13. data/app/models/comable/cart_item.rb +36 -0
  14. data/app/models/comable/customer.rb +115 -0
  15. data/app/models/comable/order.rb +29 -0
  16. data/app/models/comable/order_delivery.rb +12 -0
  17. data/app/models/comable/order_detail.rb +13 -0
  18. data/app/models/comable/product.rb +32 -0
  19. data/app/models/comable/stock.rb +31 -0
  20. data/app/views/comable/carts/show.slim +23 -0
  21. data/app/views/comable/orders/confirm.slim +25 -0
  22. data/app/views/comable/orders/create.slim +5 -0
  23. data/app/views/comable/orders/delivery.slim +8 -0
  24. data/app/views/comable/orders/new.slim +4 -0
  25. data/app/views/comable/orders/orderer.slim +7 -0
  26. data/app/views/comable/products/index.slim +11 -0
  27. data/app/views/comable/products/show.slim +20 -0
  28. data/app/views/layouts/comable/application.slim +11 -0
  29. data/config/locales/ja.yml +10 -0
  30. data/config/routes.rb +21 -0
  31. data/db/migrate/20131214194807_create_comable_products.rb +14 -0
  32. data/db/migrate/20140120024159_create_comable_cart_items.rb +12 -0
  33. data/db/migrate/20140120032559_create_comable_customers.rb +8 -0
  34. data/db/migrate/20140502060116_create_comable_stocks.rb +14 -0
  35. data/db/migrate/20140723175431_create_comable_orders.rb +13 -0
  36. data/db/migrate/20140723175624_create_comable_order_deliveries.rb +9 -0
  37. data/db/migrate/20140723175810_create_comable_order_details.rb +10 -0
  38. data/lib/comable.rb +8 -0
  39. data/lib/comable/cash_register.rb +90 -0
  40. data/lib/comable/decoratable.rb +10 -0
  41. data/lib/comable/engine.rb +8 -0
  42. data/lib/comable/migration.rb +16 -0
  43. data/lib/comable/version.rb +3 -0
  44. data/lib/tasks/comable_tasks.rake +4 -0
  45. metadata +284 -0
@@ -0,0 +1,29 @@
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
+ has_many :order_deliveries, dependent: :destroy, class_name: Comable::OrderDelivery.name, foreign_key: table_name.singularize.foreign_key
7
+
8
+ accepts_nested_attributes_for :order_deliveries
9
+
10
+ validates :family_name, presence: true
11
+ validates :first_name, presence: true
12
+
13
+ before_create :generate_code
14
+ before_create :generate_ordered_at
15
+
16
+ private
17
+
18
+ def generate_code
19
+ self.code = loop do
20
+ random_token = "C#{Array.new(11) { rand(9) }.join}"
21
+ break random_token unless self.class.exists?(code: random_token)
22
+ end
23
+ end
24
+
25
+ def generate_ordered_at
26
+ self.ordered_at = Time.now
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,12 @@
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
+ accepts_nested_attributes_for :order_details
9
+
10
+ delegate :customer, to: :order
11
+ end
12
+ end
@@ -0,0 +1,13 @@
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
+ after_create :decrement_quantity!
9
+ delegate :decrement_quantity!, to: :stock
10
+
11
+ delegate :product, to: :stock
12
+ end
13
+ end
@@ -0,0 +1,32 @@
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
@@ -0,0 +1,31 @@
1
+ module Comable
2
+ class Stock < ActiveRecord::Base
3
+ include Decoratable
4
+
5
+ belongs_to :product, class_name: Comable::Product.name, foreign_key: Comable::Product.table_name.singularize.foreign_key
6
+
7
+ scope :activated, -> { where.not(product_id_num: nil) }
8
+ scope :unsold, -> { where('quantity > ?', 0) }
9
+ scope :soldout, -> { where('quantity <= ?', 0) }
10
+
11
+ delegate :price, to: :product
12
+ delegate :sku?, to: :product
13
+
14
+ def unsold?
15
+ return false if product_id_num.nil?
16
+ return false if quantity.nil?
17
+ quantity > 0
18
+ end
19
+
20
+ def soldout?
21
+ !unsold?
22
+ end
23
+
24
+ def decrement_quantity!
25
+ with_lock do
26
+ # TODO: カラムマッピングのdecrementメソッドへの対応
27
+ update_attributes!(quantity: quantity.pred)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ h1 カート
2
+
3
+ ul.cart
4
+ - current_customer.cart.each do |cart_item|
5
+ - stock = cart_item.stock
6
+ - product = stock.product
7
+ li.product
8
+ h2.name
9
+ - if stock.sku?
10
+ - sku_name = stock.sku_h_choice_name
11
+ - sku_name += '/' + stock.sku_v_choice_name if stock.sku_v_choice_name.present?
12
+ = link_to product.name + "(#{sku_name})", comable.product_path(product)
13
+ - else
14
+ = link_to product.name, comable.product_path(product)
15
+ .caption
16
+ = product.caption
17
+ .price
18
+ = number_to_currency product.price
19
+ .quantity
20
+ = number_with_delimiter cart_item.quantity
21
+
22
+ .order
23
+ = link_to '注文', comable.new_order_path
@@ -0,0 +1,25 @@
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
+ .quantity
20
+ = order_detail.price
21
+ .quantity
22
+ = order_detail.quantity
23
+
24
+ = form_for @order, as: :order, url: comable.order_path do |f|
25
+ = f.submit
@@ -0,0 +1,5 @@
1
+ h1 注文完了
2
+
3
+ .order
4
+ .code
5
+ = @order.code
@@ -0,0 +1,8 @@
1
+ h1 配送先情報入力
2
+
3
+ .orderer
4
+ = form_for @order, as: :order, url: comable.delivery_order_path 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
@@ -0,0 +1,4 @@
1
+ h1 注文
2
+
3
+ .order
4
+ = link_to '規約に同意して注文', comable.orderer_order_path
@@ -0,0 +1,7 @@
1
+ h1 注文者情報入力
2
+
3
+ .orderer
4
+ = form_for @order, as: :order, url: comable.orderer_order_path do |f|
5
+ = f.text_field :family_name, placeholder: '姓'
6
+ = f.text_field :first_name, placeholder: '名'
7
+ = f.submit
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,20 @@
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
+ = submit_tag 'カートに入れる'
18
+ - else
19
+ .sold_out
20
+ | 品切れ中
@@ -0,0 +1,11 @@
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
@@ -0,0 +1,10 @@
1
+ ja:
2
+ comable:
3
+ carts:
4
+ add_product: '1つの商品がカートに入りしました'
5
+ product_not_found: 'ご指定の商品は見つかりませんでした'
6
+ product_not_stocked: 'ご指定の商品は在庫がありません'
7
+ empty: 'カートに商品が入っていません'
8
+ orders:
9
+ success: '注文が完了しました'
10
+ failure: '注文に失敗しました。入力項目を見直してください。'
data/config/routes.rb ADDED
@@ -0,0 +1,21 @@
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
+ post :orderer
16
+ get :delivery
17
+ post :delivery
18
+ get :confirm
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,12 @@
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
@@ -0,0 +1,8 @@
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
@@ -0,0 +1,14 @@
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
@@ -0,0 +1,13 @@
1
+ class CreateComableOrders < Comable::Migration
2
+ def change
3
+ create_table :comable_orders do |t|
4
+ t.integer :comable_customer_id
5
+ t.string :code, null: false
6
+ t.string :family_name, null: false
7
+ t.string :first_name, null: false
8
+ t.datetime :ordered_at, null: false
9
+ end
10
+
11
+ add_index :comable_orders, :code, unique: true, name: :comable_orders_idx_01
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ class CreateComableOrderDeliveries < Comable::Migration
2
+ def change
3
+ create_table :comable_order_deliveries do |t|
4
+ t.integer :comable_order_id, null: false
5
+ t.string :family_name, null: false
6
+ t.string :first_name, null: false
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ class CreateComableOrderDetails < Comable::Migration
2
+ def change
3
+ create_table :comable_order_details do |t|
4
+ t.integer :comable_order_delivery_id, null: false
5
+ t.integer :comable_stock_id, null: false
6
+ t.integer :price, null: false
7
+ t.integer :quantity, default: 1, null: false
8
+ end
9
+ end
10
+ end
data/lib/comable.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'comable/engine'
2
+ require 'comable/migration'
3
+ require 'comable/decoratable'
4
+
5
+ require 'comable/cash_register'
6
+
7
+ module Comable
8
+ end
@@ -0,0 +1,90 @@
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