comable_core 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8b1fe7b5731e6c24383b541a3bd2552839440b58
4
+ data.tar.gz: b9c63920adae0de9f6c12a695e90d69a4a1ff576
5
+ SHA512:
6
+ metadata.gz: 08063df020955b295602e419a111c870572ee0fa404ea1e1a48ae2d08e5d914da7ce4914939c2089da7ef39a8e85024a29bae5cf958b1362fb0080f267643ae5
7
+ data.tar.gz: 306fc8020d99c8c8195c3c7d3556008545d7c9d2da04d9457bc51ad34e1ac1948ca4938d7b7f790d9923569150064fe54774686b30708314b3cd60b83c73b09e
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'Comable'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('lib/**/*.rb')
14
+ end
15
+
16
+ APP_RAKEFILE = File.expand_path('../spec/dummy/Rakefile', __FILE__)
17
+ load 'rails/tasks/engine.rake'
18
+
19
+ Bundler::GemHelper.install_tasks
20
+
21
+ # from https://github.com/rspec/rspec-rails/issues/936
22
+ task 'test:prepare'
23
+
24
+ task :rubocop do
25
+ exec 'rubocop'
26
+ end
27
+
28
+ namespace :app do
29
+ namespace :spec do
30
+ desc 'Run the code examples'
31
+ RSpec::Core::RakeTask.new(:all) do |t|
32
+ t.pattern << ',backend/spec/**{,/*/**}/*_spec.rb'
33
+ end
34
+
35
+ desc 'Run the code examples in backend/spec'
36
+ RSpec::Core::RakeTask.new(:backend) do |t|
37
+ t.pattern = '../backend/spec/**{,/*/**}/*_spec.rb'
38
+ end
39
+ end
40
+ end
41
+
42
+ task default: ['app:spec:all', 'rubocop']
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,13 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the top of the
9
+ * compiled file, but it's generally better to create a new file per style scope.
10
+ *
11
+ *= require_self
12
+ *= require_tree .
13
+ */
@@ -0,0 +1,18 @@
1
+ module Comable
2
+ module ApplicationHelper
3
+ def current_customer
4
+ @current_customer || load_customer
5
+ end
6
+
7
+ private
8
+
9
+ def load_customer
10
+ @current_customer = logged_in_customer
11
+ @current_customer ||= Comable::Customer.new(cookies)
12
+ end
13
+
14
+ def logged_in_customer
15
+ # Please override this method for logged in customer
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,55 @@
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
@@ -0,0 +1,95 @@
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
+
31
+ # TODO: テストケースの作成
32
+ incomplete_order.destroy if incomplete_order.incomplete?
33
+
34
+ @incomplete_order = nil
35
+ end
36
+
37
+ def cart_items
38
+ incomplete_order.order_deliveries.first.order_details
39
+ end
40
+
41
+ def incomplete_order
42
+ @incomplete_order ||= initialize_incomplete_order
43
+ end
44
+
45
+ def preorder(order_params = {})
46
+ incomplete_order.attributes = order_params
47
+ incomplete_order.precomplete
48
+ end
49
+
50
+ def order(order_params = {})
51
+ incomplete_order.attributes = order_params
52
+ incomplete_order.complete.tap { |completed_flag| reset_cart if completed_flag }
53
+ end
54
+
55
+ private
56
+
57
+ def current_guest_token
58
+ return if logged_in?
59
+ @cookies.signed[:guest_token]
60
+ end
61
+
62
+ def initialize_incomplete_order
63
+ orders = find_incomplete_orders
64
+ return orders.first if orders.any?
65
+ order = orders.create(family_name: family_name, first_name: first_name, order_deliveries_attributes: [{ family_name: family_name, first_name: first_name }])
66
+ @cookies.permanent.signed[:guest_token] = order.guest_token if not_logged_in?
67
+ order
68
+ end
69
+
70
+ def find_incomplete_orders
71
+ Comable::Order
72
+ .incomplete
73
+ .includes(order_deliveries: :order_details)
74
+ .where(
75
+ Comable::Customer.table_name.singularize.foreign_key => self,
76
+ :guest_token => current_guest_token
77
+ )
78
+ .limit(1)
79
+ end
80
+
81
+ # Rails 3.x だと has_many 先のインスタンスが追加されても
82
+ # 親インスタンスが感知できないので、いちいちリロードするように変更
83
+ if Rails::VERSION::MAJOR == 3
84
+ def add_stock_to_cart_with_reload(*args)
85
+ add_stock_to_cart_without_reload(*args).tap { @incomplete_order = nil }
86
+ end
87
+ alias_method_chain :add_stock_to_cart, :reload
88
+
89
+ def reset_stock_from_cart_with_reload(*args)
90
+ reset_stock_from_cart_without_reload(*args).tap { @incomplete_order = nil }
91
+ end
92
+ alias_method_chain :reset_stock_from_cart, :reload
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,93 @@
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
@@ -0,0 +1,16 @@
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
@@ -0,0 +1,42 @@
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
@@ -0,0 +1,26 @@
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
@@ -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,82 @@
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
@@ -0,0 +1,11 @@
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: '注文に失敗しました。入力項目を見直してください。'
@@ -0,0 +1,14 @@
1
+ class CreateComableProducts < ActiveRecord::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,8 @@
1
+ class CreateComableCustomers < ActiveRecord::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 < ActiveRecord::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,15 @@
1
+ class CreateComableOrders < ActiveRecord::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
@@ -0,0 +1,9 @@
1
+ class CreateComableOrderDeliveries < ActiveRecord::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
6
+ t.string :first_name
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ class CreateComableOrderDetails < ActiveRecord::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
7
+ t.integer :quantity, default: 1, null: false
8
+ end
9
+
10
+ add_index :comable_order_details, [:comable_order_delivery_id, :comable_stock_id], unique: true, name: :comable_order_details_idx_01
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ class CreateComablePayments < ActiveRecord::Migration
2
+ def change
3
+ create_table :comable_payments do |t|
4
+ t.string :name, null: false
5
+ t.string :payment_method_type, null: false
6
+ t.integer :payment_method_kind, null: false
7
+ t.integer :enable_price_from
8
+ t.integer :enable_price_to
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,79 @@
1
+ module Comable
2
+ module CartOwner
3
+ def add_cart_item(obj, quantity: 1)
4
+ process_cart_item(obj) do |stock|
5
+ add_stock_to_cart(stock, quantity)
6
+ end
7
+ end
8
+
9
+ def remove_cart_item(obj, quantity: -1)
10
+ add_cart_item(obj, quantity: quantity)
11
+ end
12
+
13
+ def reset_cart_item(obj, quantity: 0)
14
+ process_cart_item(obj) do |stock|
15
+ reset_stock_from_cart(stock, quantity)
16
+ end
17
+ end
18
+
19
+ def cart_items
20
+ fail 'You should implement cart_items method.'
21
+ end
22
+
23
+ def cart
24
+ Cart.new(cart_items)
25
+ end
26
+
27
+ class Cart < Array
28
+ def price
29
+ sum(&:current_subtotal_price)
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def process_cart_item(obj)
36
+ case obj
37
+ when Comable::Product
38
+ yield obj.stocks.first
39
+ when Comable::Stock
40
+ yield obj
41
+ when Array
42
+ obj.map { |item| yield item }
43
+ else
44
+ fail
45
+ end
46
+ end
47
+
48
+ def add_stock_to_cart(stock, quantity)
49
+ fail I18n.t('comable.carts.product_not_stocked') if stock.soldout?
50
+
51
+ cart_items = find_cart_items_by(stock)
52
+ if cart_items.any?
53
+ cart_item = cart_items.first
54
+ cart_item.quantity += quantity
55
+ (cart_item.quantity > 0) ? cart_item.save : cart_item.destroy
56
+ else
57
+ cart_items.create(quantity: quantity)
58
+ end
59
+ end
60
+
61
+ def reset_stock_from_cart(stock, quantity)
62
+ cart_items = find_cart_items_by(stock)
63
+ if quantity > 0
64
+ return add_stock_to_cart(stock, quantity) if cart_items.empty?
65
+ cart_item = cart_items.first
66
+ cart_item.quantity = quantity
67
+ cart_item.save
68
+ else
69
+ return false if cart_items.empty?
70
+ cart_items.first.destroy
71
+ end
72
+ end
73
+
74
+ def find_cart_items_by(stock)
75
+ fail I18n.t('comable.carts.product_not_found') unless stock.is_a?(Comable::Stock)
76
+ cart_items.where(Comable::Stock.table_name.singularize.foreign_key => stock.id)
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,12 @@
1
+ module Comable
2
+ module Core
3
+ class Engine < ::Rails::Engine
4
+ isolate_namespace Comable
5
+
6
+ config.generators do |g|
7
+ g.test_framework :rspec, fixture: true
8
+ g.fixture_replacement :factory_girl, dir: 'spec/factories'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Comable
2
+ module Decoratable
3
+ def self.included(base)
4
+ # refs: http://edgeguides.rubyonrails.org/engines.html#overriding-models-and-controllers
5
+ Dir.glob(Rails.root + "app/decorators/comable/#{base.name.demodulize.underscore}_decorator*.rb").each do |c|
6
+ require_dependency(c)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,4 @@
1
+ module Comable
2
+ class InvalidOrder < StandardError
3
+ end
4
+ end
@@ -0,0 +1,26 @@
1
+ module Comable
2
+ module PaymentMethod
3
+ class Base
4
+ class << self
5
+ def name_symbol
6
+ name.demodulize.underscore.to_sym
7
+ end
8
+
9
+ def display_name
10
+ please_implement_method
11
+ end
12
+
13
+ def kind
14
+ please_implement_method
15
+ end
16
+
17
+ private
18
+
19
+ def please_implement_method
20
+ calling_method_name = caller_locations(1, 1).first.label
21
+ fail "You should implement '#{calling_method_name}' method in #{name}."
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ module Comable
2
+ module PaymentMethod
3
+ class General < Base
4
+ class << self
5
+ def display_name
6
+ '汎用決済モジュール'
7
+ end
8
+
9
+ def kind
10
+ { none: 'なし' }
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require 'comable/payment_method/base'
2
+ require 'comable/payment_method/general'
3
+
4
+ module Comable
5
+ module PaymentMethod
6
+ class << self
7
+ def all
8
+ (constants - [:Base]).map do |constant_name|
9
+ const_get(constant_name)
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ require 'comable/core/engine'
2
+
3
+ require 'comable/decoratable'
4
+ require 'comable/errors'
5
+ require 'comable/cart_owner'
6
+ require 'comable/payment_method'
7
+
8
+ module Comable
9
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :comable do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: comable_core
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - YOSHIDA Hiroki
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-09-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 3.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 3.2.0
27
+ description: Provide core functions for Comable.
28
+ email:
29
+ - hyoshida@appirits.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - Rakefile
35
+ - app/assets/javascripts/comable/application.js
36
+ - app/assets/stylesheets/comable/application.css
37
+ - app/helpers/comable/application_helper.rb
38
+ - app/helpers/comable/products_helper.rb
39
+ - app/models/comable/customer.rb
40
+ - app/models/comable/order.rb
41
+ - app/models/comable/order_delivery.rb
42
+ - app/models/comable/order_detail.rb
43
+ - app/models/comable/payment.rb
44
+ - app/models/comable/product.rb
45
+ - app/models/comable/stock.rb
46
+ - config/locales/ja.yml
47
+ - db/migrate/20131214194807_create_comable_products.rb
48
+ - db/migrate/20140120032559_create_comable_customers.rb
49
+ - db/migrate/20140502060116_create_comable_stocks.rb
50
+ - db/migrate/20140723175431_create_comable_orders.rb
51
+ - db/migrate/20140723175624_create_comable_order_deliveries.rb
52
+ - db/migrate/20140723175810_create_comable_order_details.rb
53
+ - db/migrate/20140817194104_create_comable_payments.rb
54
+ - lib/comable/cart_owner.rb
55
+ - lib/comable/core/engine.rb
56
+ - lib/comable/decoratable.rb
57
+ - lib/comable/errors.rb
58
+ - lib/comable/payment_method.rb
59
+ - lib/comable/payment_method/base.rb
60
+ - lib/comable/payment_method/general.rb
61
+ - lib/comable_core.rb
62
+ - lib/tasks/comable_tasks.rake
63
+ homepage: https://github.com/hyoshida/comable#comable
64
+ licenses: []
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubyforge_project:
82
+ rubygems_version: 2.2.2
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: Provide core functions for Comable.
86
+ test_files: []
87
+ has_rdoc: