Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
dhp-venshop
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Hoang Phuc Do
dhp-venshop
Commits
887f6cb4
Commit
887f6cb4
authored
Jun 19, 2017
by
Hoang Phuc Do
Browse files
Options
Browse Files
Download
Plain Diff
Refactor stock feature
parents
59977d5a
57588ebc
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
127 additions
and
127 deletions
+127
-127
app/controllers/carts_controller.rb
+31
-47
app/controllers/orders_controller.rb
+14
-13
app/controllers/product_items_controller.rb
+0
-0
app/helpers/carts_helper.rb
+1
-1
app/models/order.rb
+3
-2
app/models/product.rb
+1
-1
app/models/product_item.rb
+1
-1
app/services/cart.rb
+40
-24
app/views/carts/_cart_table.html.erb
+2
-2
app/views/carts/_product_item.html.erb
+7
-6
app/views/carts/add_product_item.js.erb
+0
-0
app/views/order_mailer/send_order_detail_to_user.html.erb
+1
-1
app/views/orders/new.html.erb
+2
-2
app/views/product_items/_product_item.html.erb
+5
-4
app/views/products/_product.html.erb
+1
-1
config/routes.rb
+7
-4
db/migrate/20170612023836_create_product_items.rb
+2
-2
db/schema.rb
+9
-9
lib/cart.rb
+0
-7
No files found.
app/controllers/carts_controller.rb
View file @
887f6cb4
class
CartsController
<
ApplicationController
include
CartsHelper
before_action
:set_cart
before_action
:set_item
,
only:
[
:add_line_item
,
:update_line_item
,
:remove_line_item
]
before_action
->
{
render_warning_notice
(
'Please specify quantity'
)
},
if: :quantity_equal_zero?
,
only: :add_line_item
before_action
->
{
render_warning_notice
(
'Product is out of stock'
)
},
unless: :product_is_out_of_stock?
,
only:
[
:add_line_item
,
:update_line_item
]
before_action
:set_product_item
,
only:
[
:add_product_item
,
:update_product_item
,
:remove_product_item
]
before_action
:build_empty_quantity_notice
,
if: :quantity_equal_zero?
,
only: :add_product_item
rescue_from
ActiveRecord
::
RecordNotFound
,
with: :invalid_cart
# GET /cart
def
index
@
line_items
=
@cart
.
get_all
_items
@
product_items
=
@cart
.
product
_items
end
# POST /cart/add/1
def
add_
line
_item
@cart
.
add
(
*
cart_params
.
to_h
.
values
)
respond_to
do
|
format
|
notice_msg
=
{
msg:
"
#{
@
item
.
title
}
was sucessfully added to your cart"
,
def
add_
product
_item
if
@cart
.
add_product_item
(
params
[
:product_id
],
params
[
:product_quantity
]
)
respond_to
do
|
format
|
format
.
js
do
@notice
=
{
msg:
"
#{
@product_
item
.
title
}
was sucessfully added to your cart"
,
type: :success
}
format
.
html
{
redirect_to
cart_index_url
,
notice:
notice_msg
[
:msg
]
}
format
.
js
{
@notice
=
{
msg:
notice_msg
[
:msg
],
type:
notice_msg
[
:type
]
}
}
end
end
else
render_warning_notice
(
'Product is out of stock'
)
end
end
# PUT/PATCH /cart/update/1
def
update_line_item
@cart
.
update
(
*
cart_params
.
to_h
.
values
)
respond_to
do
|
format
|
notice_msg
=
{
msg:
"
#{
@item
.
title
}
was sucessfully updated"
,
type: :success
}
format
.
html
{
redirect_to
cart_index_url
,
notice:
notice_msg
[
:msg
]
}
format
.
js
{
@notice
=
{
msg:
notice_msg
[
:msg
],
type:
notice_msg
[
:type
]
}}
def
update_product_item
if
@cart
.
update_product_item
(
params
[
:product_id
],
params
[
:product_quantity
])
redirect_to
cart_index_url
,
notice:
"
#{
@product_item
.
title
}
was sucessfully updated"
else
redirect_to
cart_index_url
,
notice:
"Can not update
#{
@product_item
.
title
}
"
end
end
# DELETE /cart/1
def
remove_line_item
@cart
.
remove_item
(
params
[
:id
])
respond_to
do
|
format
|
notice_msg
=
"
#{
@item
.
title
}
was sucessfully removed from your cart"
format
.
html
{
redirect_to
cart_index_url
,
notice:
notice_msg
}
def
remove_product_item
if
@cart
.
remove_product_item
(
params
[
:product_id
])
redirect_to
cart_index_url
,
notice:
"
#{
@product_item
.
title
}
was sucessfully removed from your cart"
else
redirect_to
cart_index_url
,
notice:
"
#{
@product_item
.
title
}
can not remove from your cart"
end
end
# DELETE /cart/remove
def
destroy
destroy_cart_session
respond_to
do
|
format
|
format
.
html
{
redirect_to
root_url
}
end
redirect_to
root_url
,
notice:
'Your cart is empty'
end
private
def
cart_params
params
.
permit
(
:id
,
:product_quantity
)
end
def
invalid_cart
destroy_cart_session
redirect_to
root_url
end
def
set_item
@
item
=
Product
.
find
(
params
[
:
id
])
def
set_
product_
item
@
product_item
=
Product
.
find
(
params
[
:product_
id
])
end
def
quantity_equal_zero?
params
[
:product_quantity
].
to_i
.
zero?
end
def
product_is_out_of_stock?
if
action_name
==
'add_line_item'
input_quantity
=
@cart
.
get_item_quantity
(
*
cart_params
.
to_h
.
values
)
else
input_quantity
=
params
[
:product_quantity
]
end
Product
.
find
(
params
[
:id
]).
is_in_stock?
(
input_quantity
)
def
build_empty_quantity_notice
render_warning_notice
(
'Please specify quantity'
)
end
def
render_warning_notice
(
notice
)
...
...
app/controllers/orders_controller.rb
View file @
887f6cb4
...
...
@@ -2,8 +2,7 @@ class OrdersController < ApplicationController
include
CartsHelper
before_action
:authenticate_user!
,
only: :new
before_action
:set_cart
,
only:
[
:new
,
:create
]
before_action
:set_line_items
,
only: :new
before_action
:set_order_items
,
only: :new
# GET /orders/new
def
new
...
...
@@ -13,27 +12,28 @@ class OrdersController < ApplicationController
# POST /orders
def
create
@order
=
current_user
.
orders
.
create!
create_line_items_for_order
(
@order
)
@order
=
Order
.
create
(
user:
current_user
)
save_order_items
(
@order
)
respond_to
do
|
format
|
if
@order
.
present?
destroy_cart_session
OrderMailer
.
send_order_detail_to_user
(
current_user
,
@order
).
deliver_later
format
.
html
{
redirect_to
root_url
,
notice:
'Your order is successfully created'
}
redirect_to
root_url
,
notice:
'Your order is successfully created'
else
redirect_to
root_url
,
notice:
'Your order can not be created'
end
rescue
ActiveRecord
::
RecordNotSaved
redirect_to
root_url
,
notice:
'Your order can not be created'
end
def
create_line_items_for_order
(
order
)
@cart
.
get_all_items
.
each
do
|
_
,
attrs
|
order
.
line_items
.
create
(
product:
attrs
[
:product
],
quantity:
attrs
[
:quantity
])
def
save_order_items
(
order
)
@cart
.
product_items
.
values
.
each
do
|
attrs
|
order
.
product_items
.
create
(
product:
attrs
[
:product
],
quantity:
attrs
[
:quantity
])
end
end
private
def
set_
line
_items
@
line_items
=
@cart
.
get_all
_items
def
set_
order
_items
@
order_items
=
@cart
.
product
_items
end
end
\ No newline at end of file
app/controllers/
line
_items_controller.rb
→
app/controllers/
product
_items_controller.rb
View file @
887f6cb4
File moved
app/helpers/carts_helper.rb
View file @
887f6cb4
module
CartsHelper
def
set_cart
session
[
:cart
]
||=
{}
@cart
=
Cart
.
new
(
session
[
:cart
])
@cart
||=
Cart
.
new
(
Product
,
session
[
:cart
])
end
def
destroy_cart_session
...
...
app/models/order.rb
View file @
887f6cb4
class
Order
<
ApplicationRecord
has_many
:
line
_items
,
dependent: :destroy
has_many
:
product
_items
,
dependent: :destroy
belongs_to
:user
def
total_price
line
_items
.
to_a
.
sum
{
|
item
|
item
.
product
.
price
*
item
.
quantity
}
product
_items
.
to_a
.
sum
{
|
item
|
item
.
product
.
price
*
item
.
quantity
}
end
end
\ No newline at end of file
app/models/product.rb
View file @
887f6cb4
...
...
@@ -7,7 +7,7 @@ class Product < ApplicationRecord
validates
:category_id
,
presence:
true
validates
:user_id
,
presence:
true
def
i
s_i
n_stock?
(
required_quantity
)
def
in_stock?
(
required_quantity
)
quantity
>=
required_quantity
.
to_i
end
...
...
app/models/
line
_item.rb
→
app/models/
product
_item.rb
View file @
887f6cb4
class
Line
Item
<
ApplicationRecord
class
Product
Item
<
ApplicationRecord
belongs_to
:product
,
optional:
true
belongs_to
:order
,
optional:
true
after_create
:update_product_quantity
...
...
app/services/cart.rb
View file @
887f6cb4
class
Cart
def
initialize
(
cart_session
=
{})
def
initialize
(
product
,
cart_session
=
{})
@cart
=
cart_session
@product
=
product
end
def
add
(
id
,
quantity
)
return
if
quantity
.
to_i
.
zero?
if
@cart
.
key?
(
id
.
to_s
)
@cart
[
id
.
to_s
][
:quantity
.
to_s
]
+=
quantity
.
to_i
def
product_items
product_items
=
{}
@cart
.
each
do
|
id
,
attrs
|
product_items
[
id
]
=
{
product:
@product
.
find
(
id
),
quantity:
attrs
[
:quantity
.
to_s
].
to_i
}
end
product_items
end
def
add_product_item
(
product_id
,
quantity
)
real_quantity
=
product_quantity
(
product_id
,
quantity
)
return
false
unless
product_is_in_stock?
(
product_id
,
real_quantity
)
if
product_item_exist?
(
product_id
)
@cart
[
product_id
.
to_s
][
:quantity
.
to_s
]
+=
real_quantity
.
to_i
else
@cart
[
id
.
to_s
]
=
{
quantity:
quantity
.
to_i
}
@cart
[
product_id
.
to_s
]
=
{
quantity:
real_
quantity
.
to_i
}
end
end
def
update
(
id
,
quantity
)
return
unless
@cart
.
key?
(
id
)
def
update
_product_item
(
product_
id
,
quantity
)
return
false
unless
can_update_product_item?
(
product_id
,
quantity
)
if
quantity
.
to_i
.
zero?
remove_
item
(
id
)
remove_
product_item
(
product_
id
)
else
@cart
[
id
][
:quantity
.
to_s
]
=
quantity
.
to_i
@cart
[
product_
id
][
:quantity
.
to_s
]
=
quantity
.
to_i
end
end
def
get_item_quantity
(
id
,
new_quantity
=
0
)
return
new_quantity
.
to_i
if
@cart
.
empty?
||
!
@cart
.
key?
(
id
.
to_s
)
old_quantity
=
@cart
[
id
.
to_s
][
:quantity
]
||
@cart
[
id
.
to_s
][
:quantity
.
to_s
]
def
remove_product_item
(
product_id
)
@cart
.
tap
{
|
cart
|
cart
.
delete
(
product_id
)
}
if
product_item_exist?
(
product_id
)
end
def
product_quantity
(
product_id
,
new_quantity
=
0
)
return
new_quantity
.
to_i
if
@cart
.
empty?
||
!
product_item_exist?
(
product_id
)
old_quantity
=
@cart
[
product_id
.
to_s
][
:quantity
]
||
@cart
[
product_id
.
to_s
][
:quantity
.
to_s
]
new_quantity
.
to_i
+
old_quantity
end
def
get_all_items
line_items
=
{}
@cart
.
each
do
|
id
,
attrs
|
line_items
[
id
]
=
{
product:
Product
.
find
(
id
),
quantity:
attrs
[
:quantity
.
to_s
].
to_i
}
end
line_items
def
can_update_product_item?
(
product_id
,
quantity
)
product_is_in_stock?
(
product_id
,
quantity
)
&&
product_item_exist?
(
product_id
)
end
def
product_is_in_stock?
(
product_id
,
quantity
)
@product
.
find
(
product_id
).
in_stock?
(
quantity
)
end
def
remove_item
(
id
)
@cart
.
tap
{
|
cart
|
cart
.
delete
(
id
)
}
if
@cart
.
key?
(
id
)
def
product_item_exist?
(
product_
id
)
@cart
.
key?
(
product_id
.
to_s
)
end
def
cal_total_price
get_all_items
.
sum
do
|
_
,
attrs
|
product_items
.
sum
do
|
_product_id
,
attrs
|
attrs
[
:product
].
price
*
attrs
[
:quantity
]
end
end
def
cal_total_items
return
0
if
@cart
.
nil?
@cart
.
sum
{
|
_
,
attrs
|
attrs
[
:quantity
]
||
attrs
[
:quantity
.
to_s
]
}
@cart
.
sum
{
|
_
product_id
,
attrs
|
attrs
[
:quantity
]
||
attrs
[
:quantity
.
to_s
]
}
end
end
\ No newline at end of file
app/views/carts/_cart_table.html.erb
View file @
887f6cb4
...
...
@@ -10,8 +10,8 @@
</tr>
</thead>
<tbody>
<%
@
line
_items
.
each
do
|
id
,
line_item
|
%>
<%=
render
partial:
'
line_item'
,
locals:
{
id:
id
,
line
_item:
line_item
}
%>
<%
@
product
_items
.
each
do
|
id
,
line_item
|
%>
<%=
render
partial:
'
product_item'
,
locals:
{
id:
id
,
product
_item:
line_item
}
%>
<%
end
%>
</tbody>
<tfoot>
...
...
app/views/carts/_
line
_item.html.erb
→
app/views/carts/_
product
_item.html.erb
View file @
887f6cb4
<tr>
<td
class=
"product-action-td"
>
<%=
link_to
fa_icon
(
'times'
),
cart_remove_
line
_item_path
(
id
),
method: :delete
,
data:
{
confirm:
'Are you sure?'
}
%>
<%=
link_to
fa_icon
(
'times'
),
cart_remove_
product
_item_path
(
id
),
method: :delete
,
data:
{
confirm:
'Are you sure?'
}
%>
</td>
<td
class=
"product-image-td"
></td>
<td
class=
"product-name-td"
>
<h2
class=
"product-name"
>
<%=
link_to
line_item
[
:product
].
title
,
product_url
(
line
_item
[
:product
])
%>
<%=
link_to
product_item
[
:product
].
title
,
product_item_url
(
product
_item
[
:product
])
%>
</h2>
</td>
<td>
<%=
number_to_currency
(
line
_item
[
:product
].
price
)
%>
</td>
<td>
<%=
number_to_currency
(
product
_item
[
:product
].
price
)
%>
</td>
<td>
<%=
form_tag
cart_update_
line
_item_path
(
id
),
method: :put
do
%>
<%=
form_tag
cart_update_
product
_item_path
(
id
),
method: :put
do
%>
<div
class=
"qty-holder"
>
<%=
number_field_tag
:product_quantity
,
line
_item
[
:quantity
],
id:
nil
,
class:
'qty-input'
%>
<%=
number_field_tag
:product_quantity
,
product
_item
[
:quantity
],
id:
nil
,
class:
'qty-input'
%>
</div>
<%
end
%>
</td>
<td>
<%=
number_to_currency
(
line_item
[
:product
].
price
*
line
_item
[
:quantity
])
%>
</td>
<td>
<%=
number_to_currency
(
product_item
[
:product
].
price
*
product
_item
[
:quantity
])
%>
</td>
</tr>
\ No newline at end of file
app/views/carts/add_
line
_item.js.erb
→
app/views/carts/add_
product
_item.js.erb
View file @
887f6cb4
File moved
app/views/order_mailer/send_order_detail_to_user.html.erb
View file @
887f6cb4
...
...
@@ -75,7 +75,7 @@
<th
align=
"center"
bgcolor=
"#EEEEEE"
style=
"border: 1px solid #CCCCCC;"
>
Price
</th>
<th
align=
"center"
bgcolor=
"#EEEEEE"
style=
"border: 1px solid #CCCCCC;"
>
Total
</th>
</tr>
<%
@order
.
line
_items
.
each
do
|
item
|
%>
<%
@order
.
product
_items
.
each
do
|
item
|
%>
<tr
valign=
"top"
>
<td
align=
"left"
style=
"border: 1px solid #CCCCCC;"
>
<%=
item
.
product
.
id
%>
...
...
app/views/orders/new.html.erb
View file @
887f6cb4
...
...
@@ -28,8 +28,8 @@
</tr>
</thead>
<tbody>
<%
@
line_items
.
each
do
|
id
,
line
_item
|
%>
<%=
render
partial:
'
line_items/line_item'
,
locals:
{
id:
id
,
line_item:
line
_item
}
%>
<%
@
order_items
.
each
do
|
id
,
product
_item
|
%>
<%=
render
partial:
'
product_items/product_item'
,
locals:
{
id:
id
,
product_item:
product
_item
}
%>
<%
end
%>
</tbody>
</table>
...
...
app/views/
line_items/_line
_item.html.erb
→
app/views/
product_items/_product
_item.html.erb
View file @
887f6cb4
...
...
@@ -2,10 +2,10 @@
<td
class=
"product-image-td"
></td>
<td
class=
"product-name-td"
>
<h2
class=
"product-name"
>
<%=
link_to
line_item
[
:product
].
title
,
product_url
(
line
_item
[
:product
])
%>
<%=
link_to
product_item
[
:product
].
title
,
product_url
(
product
_item
[
:product
])
%>
</h2>
</td>
<td>
<%=
number_to_currency
(
line
_item
[
:product
].
price
)
%>
</td>
<td>
<%=
line
_item
[
:quantity
]
%>
</td>
<td>
<%=
number_to_currency
(
line_item
[
:product
].
price
*
line
_item
[
:quantity
])
%>
</td>
<td>
<%=
number_to_currency
(
product
_item
[
:product
].
price
)
%>
</td>
<td>
<%=
product
_item
[
:quantity
]
%>
</td>
<td>
<%=
number_to_currency
(
product_item
[
:product
].
price
*
product
_item
[
:quantity
])
%>
</td>
</tr>
\ No newline at end of file
app/views/products/_product.html.erb
View file @
887f6cb4
...
...
@@ -26,7 +26,7 @@
</p>
</div>
<div
class=
"product-actions"
>
<%=
form_tag
cart_add_
line
_item_path
(
product
.
id
),
remote:
true
do
%>
<%=
form_tag
cart_add_
product
_item_path
(
product
.
id
),
remote:
true
do
%>
<div
class=
"product-detail-qty"
>
<%=
number_field_tag
:product_quantity
,
1
,
min:
0
,
class:
'vertical-spinner'
%>
</div>
...
...
config/routes.rb
View file @
887f6cb4
...
...
@@ -4,12 +4,15 @@ Rails.application.routes.draw do
resources
:categories
resources
:products
resources
:orders
,
only:
[
:new
,
:create
,
:show
]
resources
:
line
_items
resources
:
product
_items
scope
'cart'
do
get
'/'
,
to:
'carts#index'
,
as:
'cart_index'
post
'/add/:id'
,
to:
'carts#add_line_item'
,
as:
'cart_add_line_item'
put
'/update/:id'
,
to:
'carts#update_line_item'
,
as:
'cart_update_line_item'
delete
'/remove/:id'
,
to:
'carts#remove_line_item'
,
as:
'cart_remove_line_item'
post
'/add/:product_id'
,
to:
'carts#add_product_item'
,
as:
'cart_add_product_item'
put
'/update/:product_id'
,
to:
'carts#update_product_item'
,
as:
'cart_update_product_item'
delete
'/remove/:product_id'
,
to:
'carts#remove_product_item'
,
as:
'cart_remove_product_item'
delete
'/remove'
,
to:
'carts#destroy'
,
as:
'cart_destroy'
end
devise_for
:users
...
...
db/migrate/20170612023836_create_
line
_items.rb
→
db/migrate/20170612023836_create_
product
_items.rb
View file @
887f6cb4
class
Create
Line
Items
<
ActiveRecord
::
Migration
[
5.1
]
class
Create
Product
Items
<
ActiveRecord
::
Migration
[
5.1
]
def
change
create_table
:
line
_items
do
|
t
|
create_table
:
product
_items
do
|
t
|
t
.
integer
:quantity
,
default:
1
t
.
references
:product
,
index:
true
t
.
references
:order
,
index:
true
...
...
db/schema.rb
View file @
887f6cb4
...
...
@@ -17,21 +17,21 @@ ActiveRecord::Schema.define(version: 20170615035827) do
t
.
text
"description"
end
create_table
"line_items"
,
force: :cascade
,
options:
"ENGINE=InnoDB DEFAULT CHARSET=utf8"
do
|
t
|
t
.
integer
"quantity"
,
default:
1
t
.
bigint
"product_id"
t
.
bigint
"order_id"
create_table
"orders"
,
force: :cascade
,
options:
"ENGINE=InnoDB DEFAULT CHARSET=utf8"
do
|
t
|
t
.
bigint
"user_id"
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
t
.
index
[
"order_id"
],
name:
"index_line_items_on_order_id"
t
.
index
[
"product_id"
],
name:
"index_line_items_on_product_id"
t
.
index
[
"user_id"
],
name:
"index_orders_on_user_id"
end
create_table
"orders"
,
force: :cascade
,
options:
"ENGINE=InnoDB DEFAULT CHARSET=utf8"
do
|
t
|
t
.
bigint
"user_id"
create_table
"product_items"
,
force: :cascade
,
options:
"ENGINE=InnoDB DEFAULT CHARSET=utf8"
do
|
t
|
t
.
integer
"quantity"
,
default:
1
t
.
bigint
"product_id"
t
.
bigint
"order_id"
t
.
datetime
"created_at"
,
null:
false
t
.
datetime
"updated_at"
,
null:
false
t
.
index
[
"user_id"
],
name:
"index_orders_on_user_id"
t
.
index
[
"order_id"
],
name:
"index_product_items_on_order_id"
t
.
index
[
"product_id"
],
name:
"index_product_items_on_product_id"
end
create_table
"products"
,
force: :cascade
,
options:
"ENGINE=InnoDB DEFAULT CHARSET=utf8"
do
|
t
|
...
...
lib/cart.rb
deleted
100644 → 0
View file @
59977d5a
class
Cart
def
abc
'hi'
end
end
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment