Commit d1deeb42 by Hoang Phuc Do

Add order for user

parent 4d9686ef
......@@ -1596,6 +1596,15 @@ html .featured-box-primary .box-content {
/*
* 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 {
font-size: 13px;
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.all.page(params[:page]).per(5)
end
private
def authenticate_admin_user!
authenticate_user!
unless current_user.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
end
end
def user_is_admin?
return false unless user_signed_in?
unless current_user.admin?
redirect_to root_url, notice: "You don't have access to this page"
end
end
protected
def configure_permitted_parameters
......
class CategoriesController < ApplicationController
def show
@category = Category.find(params[:id])
@products = @category.products.take(6)
@products = @products = @category.products.page(params[:page]).per(5)
end
end
\ No newline at end of file
class OrdersController < ApplicationController
include CartsHelper
before_action :authenticate_user!, only: :new
before_action :set_cart, only: [:new, :create]
before_action :authenticate_user!, only: [:new, :create]
before_action :user_is_admin?, only: [:edit, :update]
before_action :set_order, only: [:show, :edit, :update]
before_action :order_owner?, only: :show
before_action :set_order_items, only: :new
# GET /orders/1
......@@ -18,18 +20,27 @@ class OrdersController < ApplicationController
# POST /orders
def create
@order = Order.create(user: current_user)
save_order_items(@order)
@order = Order.new(order_params.merge(user_id: current_user.id))
if @order.present?
if @order.save
save_order_items(@order)
destroy_cart_session
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
redirect_to root_url, notice: 'Your order can not be created'
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)
@cart.product_items.values.each do |attrs|
order.product_items.create(product: attrs[:product],
......@@ -39,7 +50,23 @@ class OrdersController < ApplicationController
private
# Never trust parameters from the scary internet, only allow the white list through.
def order_params
default_params = { order_status: Order.default_order_status }
params.require(:order).permit(:order_status).reverse_merge(default_params)
end
def set_order
@order = Order.find(params[:id])
end
def set_order_items
@order_items = @cart.product_items
end
def order_owner?
unless @order.user == current_user
redirect_to root_url, notice: "You don't have access to this order"
end
end
end
\ No newline at end of file
......@@ -2,7 +2,6 @@ class ProductsController < ApplicationController
before_action :authenticate_user!, only: [:new, :edit, :create, :update, :destroy]
before_action :set_product, only: :show
before_action :user_can_edit_product, only: [:edit, :update, :destroy]
before_action :set_solr, only: [:create, :update, :destroy]
# GET /products/new
def new
......@@ -13,7 +12,6 @@ class ProductsController < ApplicationController
def create
@product = Product.new(product_params.merge(user_id: current_user.id))
if @product.save
@solr.add_product_index(@product)
redirect_to root_url, flash: { success: "Product #{@product.title} is sucessfully created" }
else
render 'new'
......@@ -23,7 +21,6 @@ class ProductsController < ApplicationController
# PATCH/PUT /products/1
def update
if @product.update(product_params)
@solr.update_product_index(@product)
redirect_to root_url, flash: { success: "Product #{@product.title} is sucessfully updated" }
else
render 'edit'
......@@ -34,7 +31,6 @@ class ProductsController < ApplicationController
def destroy
if @product.destroy
flash[:success] = "Product #{@product.title} deleted"
@solr.delete_product_index(@product)
else
flash[:alert] = "Product #{@product.title} can't be deleted"
end
......@@ -60,8 +56,4 @@ class ProductsController < ApplicationController
@product = current_user.products.find_by(id: params[:id])
redirect_to root_url, flash: { alert: 'You do not have permission to edit this product' } if @product.blank?
end
def set_solr
@solr = Solr.new
end
end
\ No newline at end of file
......@@ -10,4 +10,9 @@ class UsersController < ApplicationController
def products
@products = current_user.products.page(params[:page]).per(5)
end
# GET /users/orders
def orders
@orders = current_user.orders.page(params[:page]).per(5)
end
end
\ No newline at end of file
module ApplicationHelper
def product_categories
Category.all
end
end
require 'active_support/concern'
module SolrProduct
extend ActiveSupport::Concern
included do
attr_accessor :solr
before_commit { self.solr = Solr.new }
after_create_commit :add_product_to_solr
after_update_commit :update_product_in_solr
after_destroy_commit :delete_product_in_solr
end
def add_product_to_solr
solr.add_product(self)
end
def update_product_in_solr
solr.update_product(self)
end
def delete_product_in_solr
solr.delete_product(self)
end
end
\ No newline at end of file
class Order < ApplicationRecord
has_many :product_items, dependent: :destroy
belongs_to :user
after_save :set_default_order_status
enum order_status: { pending: 0, done: 1 }
enum order_status: { 'Pending' => 0, 'Done' => 1 }
def total_price
product_items.to_a.sum { |item| item.product.price * item.quantity }
validates :order_status, presence: true
validate :validate_pending_order, on: :create
def self.default_order_status
'Pending'
end
def set_default_order_status
update_attribute(:order_status, 0)
def validate_pending_order
errors.add(:base, 'Error') if order_status != 'Pending'
end
def total_price
product_items.to_a.sum { |item| item.product.price * item.quantity }
end
end
\ No newline at end of file
class Product < ApplicationRecord
include SolrProduct
belongs_to :category
belongs_to :user
......
class ProductFilter
def self.filter_product_title(title)
title.blank? ? 'title:*' : "title:#{RSolr.solr_escape(title)}"
def self.filter_search_query(query)
return '*' if query.blank?
filtered_query = RSolr.solr_escape(query)
filtered_query[/\D+/] == filtered_query ? "title:#{filtered_query}" : filtered_query
end
def self.filter_suggest_keyword(keyword)
......
......@@ -5,7 +5,7 @@ class Search
# Get matched products with keyword
def products(search_query)
@products_indexes = @solr.exec_select_request(ProductFilter.filter_product_title(search_query))
@products_indexes = @solr.exec_select_request(ProductFilter.filter_search_query(search_query))
matched_products(@products_indexes)
end
......
......@@ -17,28 +17,28 @@ class Solr
response['suggest']['productSuggester'][query]['suggestions']
end
def add_products_indexes(products)
def add_products(products)
rsolr.add products
end
def update_product_index(product)
add_product_index(product)
delete_product_index(product)
def update_product(product)
delete_product(product)
add_product(product)
end
def add_product_index(product)
def add_product(product)
rsolr.add(id: product.id,
title: product.title,
price: product.price)
rsolr.optimize
end
def delete_product_index(product)
def delete_product(product)
rsolr.delete_by_id product.id
rsolr.optimize
end
def delete_all_product_indexes
def delete_all_products
rsolr.update(data: '<delete><query>*:*</query></delete>',
headers: { 'Content-Type' => 'text/xml',
'charset' => 'utf-8' })
......
<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.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
<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="row">
<div class="col-md-9 col-md-push-3">
<div class="category-header">
<h2><%= @category.title %></h2>
<%= render @category %>
</div>
<div class="shop-row">
<div class="shop-container">
<ul class="products-list">
<%= render @products %>
</ul>
</div>
</div>
</div>
<!-- End .col-md-9 -->
<div class="col-md-3 col-md-pull-9 sidebar">
<div class="col-md-3 col-md-pull-9 sidebar shop-sidebar">
<%= render 'shared/sidebar' %>
</div>
</div>
</div>
\ No newline at end of file
<!-- End .row -->
\ No newline at end of file
......@@ -16,17 +16,7 @@
<div class="header-column">
<div class="row">
<div class="cart-area">
<div class="custom-block">
<% 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>
<%= render 'layouts/header/user_nav' %>
<div class="cart-dropdown">
<a href="<%= cart_index_url %>" class="cart-dropdown-icon">
<i class="minicart-icon"></i>
......
<div class="custom-block">
<% if user_signed_in? %>
<% if current_user.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 :order_status %>
<%= f.select :order_status, Order.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
......@@ -31,9 +31,7 @@
</tr>
</thead>
<tbody>
<% order.product_items.each do |product_item| %>
<%= render partial: 'product_item', locals: {product_item: product_item} %>
<% end %>
<%= render partial: 'product_item', collection: order.product_items %>
</tbody>
<tfoot>
<tr>
......
<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 @@
<div class="checkout-review-action">
<h5>Grand Total <span><%= number_to_currency(cart_total_price) %></span></h5>
<%= form_for @order do |f| %>
<%= hidden_field_tag 'order[create_order]' %>
<%= f.submit 'Place Order now', class: 'btn btn-primary' %>
<% end %>
</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 @@
<%= 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 'My Products', user_products_path, wrap_tag: :li, active: :exclusive %>
<%= active_link_to 'My Orders', user_orders_path, wrap_tag: :li, active: :exclusive %>
</ul>
</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 panel-default">
<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>
<%= render 'shared/widgets/product_categories' %>
</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>
<% product_categories.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.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
root 'static_pages#index'
resources :categories
resources :products
resources :orders, only: [:new, :create, :show]
resources :orders
resources :product_items
scope 'cart' do
get '/', to: 'carts#index', as: 'cart_index'
......@@ -19,6 +19,11 @@ Rails.application.routes.draw do
scope 'users' do
get '/', to: 'users#show', as: 'user_profile'
get '/products', to: 'users#products', as: 'user_products'
get '/orders', to: 'users#orders', as: 'user_orders'
end
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
# RSolr
rsolr:
address: http://localhost:8983/solr/dhp_venshop
\ No newline at end of file
class AddOrderStatusToOrders < ActiveRecord::Migration[5.1]
def change
add_column :orders, :order_status, :integer
add_column :orders, :order_status, :integer, null: false, default: 0
end
end
class AddAdminToUsers < ActiveRecord::Migration[5.1]
def change
add_column :users, :admin, :boolean, null: false, default: false
end
end
......@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170619091633) do
ActiveRecord::Schema.define(version: 20170623064632) do
create_table "categories", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "title"
......@@ -21,7 +21,7 @@ ActiveRecord::Schema.define(version: 20170619091633) do
t.bigint "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "order_status"
t.integer "order_status", null: false, default: 0
t.index ["user_id"], name: "index_orders_on_user_id"
end
......@@ -66,6 +66,7 @@ ActiveRecord::Schema.define(version: 20170619091633) do
t.string "username"
t.string "first_name"
t.string "last_name"
t.boolean "admin", default: false, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
......
......@@ -7,11 +7,11 @@ namespace :vs_solr do
title: product.title,
price: product.price }
end
Solr.new.add_products_indexes(products)
Solr.new.add_products(products)
end
desc 'Remove all index from Solr'
task remove: :environment do
Solr.new.delete_all_product_indexes
Solr.new.delete_all_products
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