comable 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +46 -0
- data/Rakefile +28 -0
- data/app/assets/javascripts/comable/application.js +13 -0
- data/app/assets/stylesheets/comable/application.css +13 -0
- data/app/controllers/comable/application_controller.rb +5 -0
- data/app/controllers/comable/carts_controller.rb +29 -0
- data/app/controllers/comable/orders_controller.rb +108 -0
- data/app/controllers/comable/products_controller.rb +11 -0
- data/app/helpers/comable/application_helper.rb +18 -0
- data/app/helpers/comable/products_helper.rb +55 -0
- data/app/models/comable/cart_item.rb +36 -0
- data/app/models/comable/customer.rb +115 -0
- data/app/models/comable/order.rb +29 -0
- data/app/models/comable/order_delivery.rb +12 -0
- data/app/models/comable/order_detail.rb +13 -0
- data/app/models/comable/product.rb +32 -0
- data/app/models/comable/stock.rb +31 -0
- data/app/views/comable/carts/show.slim +23 -0
- data/app/views/comable/orders/confirm.slim +25 -0
- data/app/views/comable/orders/create.slim +5 -0
- data/app/views/comable/orders/delivery.slim +8 -0
- data/app/views/comable/orders/new.slim +4 -0
- data/app/views/comable/orders/orderer.slim +7 -0
- data/app/views/comable/products/index.slim +11 -0
- data/app/views/comable/products/show.slim +20 -0
- data/app/views/layouts/comable/application.slim +11 -0
- data/config/locales/ja.yml +10 -0
- data/config/routes.rb +21 -0
- data/db/migrate/20131214194807_create_comable_products.rb +14 -0
- data/db/migrate/20140120024159_create_comable_cart_items.rb +12 -0
- data/db/migrate/20140120032559_create_comable_customers.rb +8 -0
- data/db/migrate/20140502060116_create_comable_stocks.rb +14 -0
- data/db/migrate/20140723175431_create_comable_orders.rb +13 -0
- data/db/migrate/20140723175624_create_comable_order_deliveries.rb +9 -0
- data/db/migrate/20140723175810_create_comable_order_details.rb +10 -0
- data/lib/comable.rb +8 -0
- data/lib/comable/cash_register.rb +90 -0
- data/lib/comable/decoratable.rb +10 -0
- data/lib/comable/engine.rb +8 -0
- data/lib/comable/migration.rb +16 -0
- data/lib/comable/version.rb +3 -0
- data/lib/tasks/comable_tasks.rake +4 -0
- metadata +284 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cdfd44cf66aa3b1b326e80bef01bdde6f1c0447e
|
4
|
+
data.tar.gz: ef5123467b8427a8ca186b342ae58449fe0b62e0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 91ecb5a8436788eab87d6443b4238cd5473ef327c1a77eb8bc40990b589f0c3c3ff4bca20b96a6895d092ffb6c9ebc2e60c45a3d7681a222e4ea99e0686282d2
|
7
|
+
data.tar.gz: 1b987222eab78a0c8f796b71fdc44cd6327b3fde26f7dec98e249e5162afa53b2e1f33e80a0c1bd6d561b24105d713bcdcea8dd2362b3d7e0e6323af377700c9
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 YOURNAME
|
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/README.md
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# Comable
|
2
|
+
|
3
|
+
[![Build Status](https://secure.travis-ci.org/hyoshida/comable.png)](http://travis-ci.org/hyoshida/comable)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/hyoshida/comable.png)](https://codeclimate.com/github/hyoshida/comable)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/hyoshida/comable/badge.png)](https://coveralls.io/r/hyoshida/comable)
|
6
|
+
[![Dependency Status](https://gemnasium.com/hyoshida/comable.svg)](https://gemnasium.com/hyoshida/comable)
|
7
|
+
|
8
|
+
Comable provides a simple way to add e-commerce features to your Ruby on Rails application.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
1. Add comable in the `Gemfile`:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'comable'
|
16
|
+
```
|
17
|
+
|
18
|
+
2. Download and install by running:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
bundle install
|
22
|
+
```
|
23
|
+
|
24
|
+
3. Get gem migrations:
|
25
|
+
|
26
|
+
```bash
|
27
|
+
bundle exec rake comable:install:migrations
|
28
|
+
```
|
29
|
+
|
30
|
+
## Requirements
|
31
|
+
|
32
|
+
* Ruby on Rails 3.2, 4.1
|
33
|
+
* Ruby 2.1
|
34
|
+
|
35
|
+
And `strong_parameters`, `everywhere` gems are required only for Rails 3.
|
36
|
+
|
37
|
+
## Development
|
38
|
+
|
39
|
+
To set up a development environment, simply do:
|
40
|
+
|
41
|
+
```bash
|
42
|
+
bundle install
|
43
|
+
bundle exec rake db:create
|
44
|
+
bundle exec rake db:migrate
|
45
|
+
bundle exec rake # run the test suite
|
46
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
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
|
+
task default: ['app:spec', '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,29 @@
|
|
1
|
+
module Comable
|
2
|
+
class CartsController < ApplicationController
|
3
|
+
def show
|
4
|
+
end
|
5
|
+
|
6
|
+
def add
|
7
|
+
product = Comable::Product.where(id: params[:product_id]).first
|
8
|
+
return redirect_by_product_not_found unless product
|
9
|
+
|
10
|
+
if product.sku?
|
11
|
+
stock = product.stocks.where(id: params[:stock_id]).first
|
12
|
+
return redirect_by_product_not_found unless stock
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: 在庫確認
|
16
|
+
current_customer.add_cart_item(stock || product)
|
17
|
+
|
18
|
+
flash[:notice] = I18n.t('comable.carts.add_product')
|
19
|
+
redirect_to cart_path
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def redirect_by_product_not_found
|
25
|
+
flash[:error] = I18n.t('comable.carts.product_not_found')
|
26
|
+
redirect_to :back
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Comable
|
2
|
+
class OrdersController < ApplicationController
|
3
|
+
before_filter :load_order
|
4
|
+
before_filter :verify
|
5
|
+
before_filter :redirect_for_logged_in_customer, only: [:new, :orderer]
|
6
|
+
after_filter :save_order, except: :create
|
7
|
+
|
8
|
+
def new
|
9
|
+
end
|
10
|
+
|
11
|
+
def orderer
|
12
|
+
case request.method_symbol
|
13
|
+
when :post
|
14
|
+
redirect_to comable.delivery_order_path
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def delivery
|
19
|
+
case request.method_symbol
|
20
|
+
when :post
|
21
|
+
redirect_to comable.confirm_order_path
|
22
|
+
when :get
|
23
|
+
@order.order_deliveries.build if @order.order_deliveries.empty?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def confirm
|
28
|
+
@order = current_customer.preorder(build_order_nested_attributes)
|
29
|
+
end
|
30
|
+
|
31
|
+
def create
|
32
|
+
@order = current_customer.order(build_order_nested_attributes)
|
33
|
+
if @order.valid?
|
34
|
+
flash[:notice] = I18n.t('comable.orders.success')
|
35
|
+
reset_session
|
36
|
+
else
|
37
|
+
flash[:alert] = I18n.t('comable.orders.failure')
|
38
|
+
redirect_to comable.confirm_order_path
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def reset_session
|
45
|
+
session.delete('comable.order')
|
46
|
+
end
|
47
|
+
|
48
|
+
def verify
|
49
|
+
return if current_customer.cart.any?
|
50
|
+
flash[:alert] = I18n.t('comable.carts.empty')
|
51
|
+
redirect_to comable.cart_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def load_order
|
55
|
+
order_attributes = JSON.parse(session['comable.order'] || '{}')
|
56
|
+
order_attributes.update(order_params) if order_params
|
57
|
+
@order = Comable::Order.new(order_attributes)
|
58
|
+
end
|
59
|
+
|
60
|
+
def save_order
|
61
|
+
session['comable.order'] = build_order_nested_attributes.to_json
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_order_nested_attributes
|
65
|
+
@order.attributes.merge(
|
66
|
+
order_deliveries_attributes: build_order_delivery_nested_attributes
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def build_order_delivery_nested_attributes
|
71
|
+
@order.order_deliveries.map do |order_delivery|
|
72
|
+
order_delivery.attributes.merge(
|
73
|
+
order_details_attributes: order_delivery.order_details.map(&:attributes)
|
74
|
+
)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def order_params
|
79
|
+
return unless params[:order]
|
80
|
+
case action_name.to_sym
|
81
|
+
when :orderer
|
82
|
+
order_params_for_orderer
|
83
|
+
when :delivery
|
84
|
+
order_params_for_delivery
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def order_params_for_orderer
|
89
|
+
params.require(:order).permit(
|
90
|
+
:family_name,
|
91
|
+
:first_name
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def order_params_for_delivery
|
96
|
+
params.require(:order).permit(
|
97
|
+
order_deliveries_attributes: [
|
98
|
+
:family_name,
|
99
|
+
:first_name
|
100
|
+
]
|
101
|
+
)
|
102
|
+
end
|
103
|
+
|
104
|
+
def redirect_for_logged_in_customer
|
105
|
+
return redirect_to delivery_order_path if current_customer.logged_in?
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -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,36 @@
|
|
1
|
+
module Comable
|
2
|
+
class CartItem < ActiveRecord::Base
|
3
|
+
utusemi!
|
4
|
+
|
5
|
+
belongs_to :customer, class_name: Comable::Customer.name, foreign_key: Comable::Customer.table_name.singularize.foreign_key
|
6
|
+
belongs_to :stock, class_name: Comable::Stock.name, foreign_key: Comable::Stock.table_name.singularize.foreign_key
|
7
|
+
|
8
|
+
with_options if: :customer do |customer|
|
9
|
+
customer.validates Comable::Customer.table_name.singularize.foreign_key, uniqueness: { scope: [Comable::Customer.table_name.singularize.foreign_key, Comable::Stock.table_name.singularize.foreign_key] }
|
10
|
+
customer.validates Comable::Customer.table_name.singularize.foreign_key, presence: true
|
11
|
+
end
|
12
|
+
|
13
|
+
with_options if: :guest_token do |guest|
|
14
|
+
guest.validates :guest_token, uniqueness: { scope: [:guest_token, Comable::Stock.table_name.singularize.foreign_key] }
|
15
|
+
guest.validates :guest_token, presence: true
|
16
|
+
end
|
17
|
+
|
18
|
+
delegate :product, to: :stock
|
19
|
+
|
20
|
+
before_create :generate_guest_token
|
21
|
+
|
22
|
+
def price
|
23
|
+
stock.price * quantity
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def generate_guest_token
|
29
|
+
return if send(Comable::Customer.table_name.singularize.foreign_key)
|
30
|
+
self.guest_token ||= loop do
|
31
|
+
random_token = SecureRandom.urlsafe_base64(nil, false)
|
32
|
+
break random_token unless self.class.exists?(guest_token: random_token)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Comable
|
2
|
+
class Customer < ActiveRecord::Base
|
3
|
+
include Decoratable
|
4
|
+
|
5
|
+
has_many :comable_orders, class_name: Comable::Order.name, foreign_key: table_name.singularize.foreign_key
|
6
|
+
alias_method :orders, :comable_orders
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
obj = args.first
|
10
|
+
case obj.class.name
|
11
|
+
when /Cookies/
|
12
|
+
@cookies = obj
|
13
|
+
super()
|
14
|
+
else
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def logged_in?
|
20
|
+
!new_record?
|
21
|
+
end
|
22
|
+
|
23
|
+
def not_logged_in?
|
24
|
+
!logged_in?
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_cart_item(obj)
|
28
|
+
case obj
|
29
|
+
when Comable::Product
|
30
|
+
add_stock_to_cart(obj.stocks.first)
|
31
|
+
when Comable::Stock
|
32
|
+
add_stock_to_cart(obj)
|
33
|
+
when Array
|
34
|
+
obj.map { |item| add_cart_item(item) }
|
35
|
+
else
|
36
|
+
fail
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def remove_cart_item(obj)
|
41
|
+
case obj
|
42
|
+
when Comable::Stock
|
43
|
+
remove_stock_from_cart(obj)
|
44
|
+
else
|
45
|
+
fail
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def reset_cart
|
50
|
+
cart_items.destroy_all
|
51
|
+
end
|
52
|
+
|
53
|
+
def cart_items
|
54
|
+
Comable::CartItem.where(
|
55
|
+
Comable::Customer.table_name.singularize.foreign_key => id,
|
56
|
+
:guest_token => current_guest_token
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
def cart
|
61
|
+
Cart.new(cart_items)
|
62
|
+
end
|
63
|
+
|
64
|
+
class Cart < Array
|
65
|
+
def price
|
66
|
+
cart_item_ids = map(&:id)
|
67
|
+
Comable::CartItem.includes(stock: :product).where(id: cart_item_ids).to_a.sum(&:price)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def preorder(order_params = {})
|
72
|
+
Comable::CashRegister.new(customer: self, order_attributes: order_params).build_order
|
73
|
+
end
|
74
|
+
|
75
|
+
def order(order_params = {})
|
76
|
+
Comable::CashRegister.new(customer: self, order_attributes: order_params).create_order
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def current_guest_token
|
82
|
+
return if logged_in?
|
83
|
+
@cookies.signed[:guest_token]
|
84
|
+
end
|
85
|
+
|
86
|
+
def add_stock_to_cart(stock)
|
87
|
+
fail I18n.t('comable.carts.product_not_stocked') if stock.soldout?
|
88
|
+
|
89
|
+
cart_items = find_cart_items_by(stock)
|
90
|
+
if cart_items.any?
|
91
|
+
cart_item = cart_items.first
|
92
|
+
cart_item.increment!(:quantity)
|
93
|
+
else
|
94
|
+
cart_item = cart_items.create
|
95
|
+
@cookies.permanent.signed[:guest_token] = cart_item.guest_token if not_logged_in?
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def remove_stock_from_cart(stock)
|
100
|
+
cart_item = find_cart_items_by(stock).first
|
101
|
+
return false unless cart_item
|
102
|
+
|
103
|
+
if cart_item.quantity.pred.nonzero?
|
104
|
+
cart_item.decrement!(:quantity)
|
105
|
+
else
|
106
|
+
cart_item.destroy
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def find_cart_items_by(stock)
|
111
|
+
fail I18n.t('comable.carts.product_not_found') unless stock.is_a?(Comable::Stock)
|
112
|
+
cart_items.where(Comable::Stock.table_name.singularize.foreign_key => stock.id)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|