comable 0.0.1

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 (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