Commit 598b3bb5 by Trong Huu Nguyen

Merge branch 'dhp_order' into 'development'

[REVIEW] Order Feature

See merge request !8
parents 9c71bd06 4c819563
...@@ -1596,6 +1596,15 @@ html .featured-box-primary .box-content { ...@@ -1596,6 +1596,15 @@ html .featured-box-primary .box-content {
/* /*
* Sidebar * Sidebar
*/ */
.sidebar.shop-sidebar ul, .sidebar.shop-sidebar ol {
padding: 0;
margin: -7px 0 0;
list-style: none;
}
.sidebar.shop-sidebar ul li a, .sidebar.shop-sidebar ol li a {
color: #777;
line-height: 2.5;
}
aside ul.nav-list > li > a { aside ul.nav-list > li > a {
font-size: 13px; font-size: 13px;
padding-left: 21px; padding-left: 21px;
......
class AdminController < ApplicationController
before_action :authenticate_admin_user!
# GET /admin
def index
@user = current_user
end
# GET /admin/orders
def orders
@orders = Order.page(params[:page]).per(5)
end
private
def authenticate_admin_user!
authenticate_user!
unless current_user.is_admin?
redirect_to root_path, notice: 'Unauthorized access!'
end
end
end
\ No newline at end of file
...@@ -16,6 +16,13 @@ class ApplicationController < ActionController::Base ...@@ -16,6 +16,13 @@ class ApplicationController < ActionController::Base
end end
end end
def user_is_admin?
return false unless user_signed_in?
unless current_user.is_admin?
redirect_to root_url, notice: "You don't have access to this page"
end
end
protected protected
def configure_permitted_parameters def configure_permitted_parameters
......
class CartsController < ApplicationController class CartsController < ApplicationController
include CartsHelper include CartsHelper
before_action :set_cart
before_action :set_product_item, before_action :set_product_item,
only: [:add_product_item, :update_product_item, :remove_product_item] only: [:add_product_item, :update_product_item, :remove_product_item]
before_action :build_empty_quantity_notice, if: :quantity_equal_zero?, before_action :build_empty_quantity_notice, if: :quantity_equal_zero?,
only: :add_product_item only: :add_product_item
rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart rescue_from ActiveRecord::RecordNotFound, with: :invalid_cart
# GET /cart # GET /cart
...@@ -24,7 +25,6 @@ class CartsController < ApplicationController ...@@ -24,7 +25,6 @@ class CartsController < ApplicationController
else else
render_warning_notice('Product is out of stock') render_warning_notice('Product is out of stock')
end end
end end
# PUT/PATCH /cart/update/1 # PUT/PATCH /cart/update/1
......
class CategoriesController < ApplicationController class CategoriesController < ApplicationController
def show def show
@category = Category.find(params[:id]) @category = Category.find(params[:id])
@products = @category.products.take(6) @products = @category.products.page(params[:page]).per(5)
end end
end end
\ No newline at end of file
class OrdersController < ApplicationController class OrdersController < ApplicationController
include CartsHelper include CartsHelper
before_action :authenticate_user!, only: :new before_action :authenticate_user!, only: [:new, :create]
before_action :set_order_items, only: :new before_action :user_is_admin?, only: [:edit, :update]
before_action :set_order, only: [:show, :edit, :update]
before_action :order_owner?, only: :show
# GET /orders/1
def show
@order = Order.find(params[:id])
end
# GET /orders/new # GET /orders/new
def new def new
redirect_to root_url if @cart.blank? redirect_to root_url if @cart.blank?
@order = Order.new @order = Order.new
@order_items = @cart.product_items
end end
# POST /orders # POST /orders
def create def create
@order = Order.create(user: current_user) @order = Order.new(order_params.merge(user_id: current_user.id))
save_order_items(@order)
if @order.present? if @order.save
save_order_items(@order)
destroy_cart_session destroy_cart_session
OrderMailer.send_order_detail_to_user(current_user, @order).deliver_later OrderMailer.send_order_detail_to_user(current_user, @order).deliver_later
redirect_to root_url, notice: 'Your order is successfully created' redirect_to order_url(@order)
else else
redirect_to root_url, notice: 'Your order can not be created' redirect_to root_url, notice: 'Your order can not be created'
end end
end end
# PATCH/PUT /orders/1
def update
if @order.update(order_params)
redirect_to order_url(@order), flash: { success: "Order ##{@order.id} is sucessfully updated" }
else
render 'edit'
end
end
def save_order_items(order) def save_order_items(order)
@cart.product_items.values.each do |attrs| @cart.product_items.values.each do |attrs|
order.product_items.create(product: attrs[:product], order.product_items.create(product: attrs[:product],
...@@ -33,7 +50,18 @@ class OrdersController < ApplicationController ...@@ -33,7 +50,18 @@ class OrdersController < ApplicationController
private private
def set_order_items # Never trust parameters from the scary internet, only allow the white list through.
@order_items = @cart.product_items def order_params
params.require(:order).permit(:status)
end
def set_order
@order = Order.find(params[:id])
end
def order_owner?
unless @order.user == current_user
return redirect_to root_url, notice: "You don't have access to this order"
end
end end
end end
\ No newline at end of file
...@@ -2,7 +2,7 @@ class ProductsController < ApplicationController ...@@ -2,7 +2,7 @@ class ProductsController < ApplicationController
before_action :authenticate_user!, only: [:new, :edit, :create, :update, :destroy] before_action :authenticate_user!, only: [:new, :edit, :create, :update, :destroy]
before_action :set_product, only: :show before_action :set_product, only: :show
before_action :user_can_edit_product, only: [:edit, :update, :destroy] before_action :user_can_edit_product, only: [:edit, :update, :destroy]
before_action :set_solr, only: [:create, :update, :destroy] before_action :set_solr, only: [:create, :update, :destroy ]
# GET /products/new # GET /products/new
def new def new
...@@ -33,8 +33,8 @@ class ProductsController < ApplicationController ...@@ -33,8 +33,8 @@ class ProductsController < ApplicationController
# DELETE /products/1 # DELETE /products/1
def destroy def destroy
if @product.destroy if @product.destroy
flash[:success] = "Product #{@product.title} deleted"
@solr.delete_product(@product) @solr.delete_product(@product)
flash[:success] = "Product #{@product.title} deleted"
else else
flash[:alert] = "Product #{@product.title} can't be deleted" flash[:alert] = "Product #{@product.title} can't be deleted"
end end
......
...@@ -10,4 +10,9 @@ class UsersController < ApplicationController ...@@ -10,4 +10,9 @@ class UsersController < ApplicationController
def products def products
@products = current_user.products.page(params[:page]).per(5) @products = current_user.products.page(params[:page]).per(5)
end end
# GET /users/orders
def orders
@orders = current_user.orders.page(params[:page]).per(5)
end
end end
\ No newline at end of file
class Order < ApplicationRecord class Order < ApplicationRecord
has_many :product_items, dependent: :destroy has_many :product_items, dependent: :destroy
belongs_to :user belongs_to :user
enum status: { 'Pending' => 0, 'Done' => 1 }
validates :status, presence: true
validate :validate_status, on: :create
def validate_status
errors.add(:status, 'Error') if status != self.status['Pending']
end
def total_price def total_price
product_items.to_a.sum { |item| item.product.price * item.quantity } product_items.to_a.sum { |item| item.product.price * item.quantity }
......
...@@ -22,8 +22,8 @@ class Solr ...@@ -22,8 +22,8 @@ class Solr
end end
def update_product(product) def update_product(product)
add_product(product)
delete_product(product) delete_product(product)
add_product(product)
end end
def add_product(product) def add_product(product)
......
<div class="container">
<div class="row">
<div class="col-md-9 col-md-push-3 my-account">
<h2 class="h2 heading-primary font-weight-normal">
Dashboard
</h2>
<h2 class="h3 mb-sm">
<strong>Account Information</strong>
</h2>
<div class="row">
<div class="col-sm-12">
<div class="panel-box">
<div class="panel-box-title">
<h3>Contact Information</h3>
<%= link_to 'Edit', edit_user_registration_path, class: 'panel-box-edit' %>
</div>
<div class="panel-box-content">
<p><%= @user.first_name %> <%= @user.last_name %></p>
<p><%= @user.email %></p>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-md-pull-9">
<%= render 'shared/admin/admin_sidebar' %>
</div>
</div>
</div>
\ No newline at end of file
<div class="container">
<div class="row">
<div class="col-md-9 col-md-push-3 my-account">
<h2 class="h2 heading-primary font-weight-normal">
Orders
</h2>
<%= render 'admin/orders/order_table' %>
<div class="toolbar-bottom">
<div class="toolbar">
<div class="sorter">
<%= paginate @orders, theme: 'bootstrap' %>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-md-pull-9">
<%= render 'shared/admin/admin_sidebar' %>
</div>
</div>
</div>
\ No newline at end of file
<div class="cart-table-wrap">
<table class="cart-table">
<thead>
<tr>
<th>Order ID</th>
<th>Status</th>
<th>Date created</th>
<th>Total price</th>
<th></th>
</tr>
</thead>
<tbody>
<% @orders.each do |order| %>
<tr>
<td><%= link_to "##{order.id}", order_url(order) %></td>
<td><%= order.status %></td>
<td><%= order.created_at.strftime('%d-%M-%Y %H:%m') %></td>
<td><%= number_to_currency(order.total_price) %></td>
<td><%= link_to fa_icon('pencil'), edit_order_path(order) %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
\ No newline at end of file
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<td class="product-image-td"></td> <td class="product-image-td"></td>
<td class="product-name-td"> <td class="product-name-td">
<h2 class="product-name"> <h2 class="product-name">
<%= link_to product_item[:product].title, product_url(product_item[:product]) %> <%= link_to product_item[:product].title, product_item_url(product_item[:product]) %>
</h2> </h2>
</td> </td>
<td><%= number_to_currency(product_item[:product].price) %></td> <td><%= number_to_currency(product_item[:product].price) %></td>
......
<h2 class="h2 heading-primary mt-lg clearfix">
<span><%= category.title %></span>
</h2>
<%= render partial: 'products/product_list', locals: { products: @products } %>
<div class="toolbar-bottom">
<div class="toolbar">
<div class="sorter">
<%= paginate @products, theme: 'bootstrap' %>
</div>
</div>
</div>
\ No newline at end of file
<div class="row"> <div class="container">
<div class="col-md-9 col-md-push-3"> <div class="row">
<div class="category-header"> <div class="col-md-9 col-md-push-3">
<h2><%= @category.title %></h2> <%= render @category %>
</div> </div>
<div class="shop-row"> <div class="col-md-3 col-md-pull-9 sidebar shop-sidebar">
<div class="shop-container"> <%= render 'shared/sidebar' %>
<ul class="products-list">
<%= render @products %>
</ul>
</div>
</div> </div>
</div> </div>
<!-- End .col-md-9 --> </div>
<div class="col-md-3 col-md-pull-9 sidebar"> \ No newline at end of file
<%= render 'shared/sidebar' %>
</div>
</div>
<!-- End .row -->
\ No newline at end of file
...@@ -16,17 +16,7 @@ ...@@ -16,17 +16,7 @@
<div class="header-column"> <div class="header-column">
<div class="row"> <div class="row">
<div class="cart-area"> <div class="cart-area">
<div class="custom-block"> <%= render 'layouts/header/user_nav' %>
<% if user_signed_in? %>
<%= link_to 'MY PROFILE', user_profile_path %>
<span class="split"></span>
<%= link_to 'SIGN OUT', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'SIGN IN', new_user_session_path %>
<span class="split"></span>
<%= link_to 'SIGN UP', new_user_registration_path %>
<% end %>
</div>
<div class="cart-dropdown"> <div class="cart-dropdown">
<a href="<%= cart_index_url %>" class="cart-dropdown-icon"> <a href="<%= cart_index_url %>" class="cart-dropdown-icon">
<i class="minicart-icon"></i> <i class="minicart-icon"></i>
......
<div class="custom-block">
<% if user_signed_in? %>
<% if current_user.is_admin? %>
<%= link_to 'SITE ADMIN', admin_index_path %>
<span class="split"></span>
<% end %>
<%= link_to 'MY PROFILE', user_profile_path %>
<span class="split"></span>
<%= link_to 'SIGN OUT', destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to 'SIGN IN', new_user_session_path %>
<span class="split"></span>
<%= link_to 'SIGN UP', new_user_registration_path %>
<% end %>
</div>
\ No newline at end of file
<%= form_for(@order) do |f| %>
<%= render 'shared/error_messages', object: @order %>
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<%= f.label :status %>
<%= f.select :status, Order.statuses.keys, {}, class: 'form-control' %>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<div class="form-action clearfix mt-none">
<%= f.submit "Submit", class: "btn btn-primary" %>
</div>
</div>
</div>
</div>
<% end %>
\ No newline at end of file
<div class="cart-table-wrap">
<table class="table table-bordered table-hover">
<thead>
<tr>
<td colspan="2" class="text-left">
Order Detail - <span><%= order.status %></span>
</td>
</tr>
<tbody>
<tr>
<td><strong>Order ID:</strong> #<%= order.id %></td>
<td><strong>Date created:</strong> <%= order.created_at.strftime('%d-%M-%Y %H:%m') %></td>
</tr>
<tr>
<td><strong>Email:</strong> <%= order.user.email %></td>
<td><strong>Total:</strong> <%= number_to_currency(order.total_price) %></td>
</tr>
</tbody>
</thead>
</table>
<div class="cart-table-wrap">
<table class="cart-table">
<thead>
<tr>
<th></th>
<th>Product Name</th>
<th>Unit Price</th>
<th>Qty</th>
<th>Subtotal</th>
</tr>
</thead>
<tbody>
<%= render partial: 'product_item', collection: order.product_items %>
</tbody>
<tfoot>
<tr>
<td colspan="3"></td>
<td><strong>Total</strong></td>
<td><strong><%= number_to_currency(order.total_price) %></strong></td>
</tr>
</tfoot>
</table>
</div>
</div>
\ No newline at end of file
<tr>
<td class="product-image-td"></td>
<td class="product-name-td">
<h2 class="product-name">
<%= link_to product_item.product.title, product_url(product_item.product) %>
</h2>
</td>
<td><%= number_to_currency(product_item.product.price) %></td>
<td><%= product_item.quantity %></td>
<td><%= number_to_currency(product_item.total_price) %></td>
</tr>
\ No newline at end of file
<div class="container">
<div class="row">
<div class="col-md-12 create-product form-section">
<h1 class="h2 heading-primary font-weight-normal">
Edit Order #<%= @order.id %>
(<%= link_to 'Delete', @order, method: :delete, data: { confirm: 'Are your sure?' } %>)
</h1>
<div class="featured-box featured-box-primary featured-box-flat featured-box-text-left mt-md">
<div class="box-content">
<%= render 'shared/redirect_back' %>
<%= render 'form' %>
</div>
</div>
</div>
</div>
</div>
\ No newline at end of file
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
<div class="checkout-review-action"> <div class="checkout-review-action">
<h5>Grand Total <span><%= number_to_currency(cart_total_price) %></span></h5> <h5>Grand Total <span><%= number_to_currency(cart_total_price) %></span></h5>
<%= form_for @order do |f| %> <%= form_for @order do |f| %>
<%= hidden_field_tag 'order[create_order]' %>
<%= f.submit 'Place Order now', class: 'btn btn-primary' %> <%= f.submit 'Place Order now', class: 'btn btn-primary' %>
<% end %> <% end %>
</div> </div>
......
<div class="order-detail">
<div class="container">
<h1 class="h2 heading-primary mt-lg mb-md clearfix">
Order Information
</h1>
<div class="row">
<div class="col-md-12">
<%= render 'shared/flash_messages' %>
<%= render @order %>
</div>
</div>
</div>
</div>
\ No newline at end of file
...@@ -4,5 +4,6 @@ ...@@ -4,5 +4,6 @@
<%= active_link_to 'My Dashboard', user_profile_path, wrap_tag: :li, active: :exclusive %> <%= active_link_to 'My Dashboard', user_profile_path, wrap_tag: :li, active: :exclusive %>
<%= active_link_to 'Edit Account Information', edit_user_registration_path, wrap_tag: :li, active: :exclusive %> <%= active_link_to 'Edit Account Information', edit_user_registration_path, wrap_tag: :li, active: :exclusive %>
<%= active_link_to 'My Products', user_products_path, wrap_tag: :li, active: :exclusive %> <%= active_link_to 'My Products', user_products_path, wrap_tag: :li, active: :exclusive %>
<%= active_link_to 'My Orders', user_orders_path, wrap_tag: :li, active: :exclusive %>
</ul> </ul>
</aisde> </aisde>
\ No newline at end of file
<p><%= link_to 'Back to previous page', request.referrer %></p>
\ No newline at end of file
<div class="panel-group"> <div class="panel-group">
<div class="panel panel-default"> <%= render 'shared/widgets/categories' %>
<div class="panel-heading">
<h4 class="panel-title">
Categories
</h4>
</div>
<div id="panel-filter-category">
<div class="panel-body">
<ul>
</ul>
</div>
</div>
</div>
</div> </div>
\ No newline at end of file
<aisde class="sidebar">
<h4>Admin Area</h4>
<ul class="nav nav-list">
<%= active_link_to 'Dashboard', admin_index_path, wrap_tag: :li, active: :exclusive %>
<%= active_link_to 'Orders', admin_orders_show_path, wrap_tag: :li, active: :exclusive %>
</ul>
</aisde>
\ No newline at end of file
<div class="panel-group">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
Categories
</h4>
</div>
<div id="panel-filter-category">
<div class="panel-body">
<ul>
<% Category.all.each do |category| %>
<%= active_link_to category.title, category_url(category), wrap_tag: :li %>
<% end %>
</ul>
</div>
</div>
</div>
</div>
\ No newline at end of file
<div class="cart-table-wrap">
<table class="cart-table">
<thead>
<tr>
<th>Order ID</th>
<th>Status</th>
<th>Date created</th>
<th>Total price</th>
</tr>
</thead>
<tbody>
<% orders.each do |order| %>
<tr>
<td><%= link_to "##{order.id}", order_url(order) %></td>
<td><%= order.status %></td>
<td><%= order.created_at.strftime('%d-%M-%Y %H:%m') %></td>
<td><%= number_to_currency(order.total_price) %></td>
</tr>
<% end %>
</tbody>
</table>
</div>
\ No newline at end of file
<div class="container">
<div class="row">
<div class="col-md-9 col-md-push-3 my-account">
<h2 class="h2 heading-primary font-weight-normal">
My Orders
</h2>
<%= render partial: 'order', locals: { orders: @orders } %>
<div class="toolbar-bottom">
<div class="toolbar">
<div class="sorter">
<%= paginate @orders, theme: 'bootstrap' %>
</div>
</div>
</div>
</div>
<div class="col-md-3 col-md-pull-9">
<%= render 'shared/account_sidebar' %>
</div>
</div>
</div>
\ No newline at end of file
...@@ -3,7 +3,7 @@ Rails.application.routes.draw do ...@@ -3,7 +3,7 @@ Rails.application.routes.draw do
root 'static_pages#index' root 'static_pages#index'
resources :categories resources :categories
resources :products resources :products
resources :orders, only: [:new, :create, :show] resources :orders
resources :product_items resources :product_items
scope 'cart' do scope 'cart' do
get '/', to: 'carts#index', as: 'cart_index' get '/', to: 'carts#index', as: 'cart_index'
...@@ -19,6 +19,11 @@ Rails.application.routes.draw do ...@@ -19,6 +19,11 @@ Rails.application.routes.draw do
scope 'users' do scope 'users' do
get '/', to: 'users#show', as: 'user_profile' get '/', to: 'users#show', as: 'user_profile'
get '/products', to: 'users#products', as: 'user_products' get '/products', to: 'users#products', as: 'user_products'
get '/orders', to: 'users#orders', as: 'user_orders'
end end
get '/search', to: 'search#show', as: 'search_result' get '/search', to: 'search#show', as: 'search_result'
scope 'admin' do
get '/', to: 'admin#index', as: 'admin_index'
get '/orders', to: 'admin#orders', as: 'admin_orders_show'
end
end end
class AddOrderStatusToOrders < ActiveRecord::Migration[5.1]
def change
add_column :orders, :status, :integer, null: false, default: 0
end
end
class AddAdminToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :is_admin, :boolean, null: false, default: false
end
end
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170615035827) do ActiveRecord::Schema.define(version: 20170623064632) do
create_table "categories", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| create_table "categories", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "title" t.string "title"
...@@ -21,6 +21,8 @@ ActiveRecord::Schema.define(version: 20170615035827) do ...@@ -21,6 +21,8 @@ ActiveRecord::Schema.define(version: 20170615035827) do
t.bigint "user_id" t.bigint "user_id"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.integer "status"
t.integer "status", default: 0, null: false
t.index ["user_id"], name: "index_orders_on_user_id" t.index ["user_id"], name: "index_orders_on_user_id"
end end
...@@ -65,6 +67,8 @@ ActiveRecord::Schema.define(version: 20170615035827) do ...@@ -65,6 +67,8 @@ ActiveRecord::Schema.define(version: 20170615035827) do
t.string "username" t.string "username"
t.string "first_name" t.string "first_name"
t.string "last_name" t.string "last_name"
t.boolean "admin", default: false, null: false
t.boolean "is_admin", default: false, null: false
t.index ["email"], name: "index_users_on_email", unique: true t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end end
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment