Refactor
This commit is contained in:
parent
de1436f5c7
commit
b55ba47209
24
app/controllers/concerns/statistics.rb
Normal file
24
app/controllers/concerns/statistics.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
module Statistics
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
def products_group_by_category
|
||||||
|
products
|
||||||
|
.select("products.category", "sum(order_items.count) as count")
|
||||||
|
.group(:category)
|
||||||
|
end
|
||||||
|
|
||||||
|
def all_orders page
|
||||||
|
orders
|
||||||
|
.order(:created_at)
|
||||||
|
.reverse_order
|
||||||
|
.paginate(page: page)
|
||||||
|
end
|
||||||
|
|
||||||
|
def products_group_by_id
|
||||||
|
products
|
||||||
|
.select("products.*", "sum(order_items.count) as count")
|
||||||
|
.group(:product_id)
|
||||||
|
.order("count")
|
||||||
|
.reverse_order
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,13 +1,12 @@
|
||||||
class OrdersController < ApplicationController
|
class OrdersController < ApplicationController
|
||||||
include ActionView::Helpers::NumberHelper
|
|
||||||
include ApplicationHelper
|
|
||||||
|
|
||||||
load_resource :user
|
load_resource :user
|
||||||
load_and_authorize_resource :order, through: :user, shallow: true
|
load_and_authorize_resource :order, through: :user, shallow: true
|
||||||
|
|
||||||
def new
|
def new
|
||||||
products = (@user.products.for_sale.select("products.*", "sum(order_items.count) as count").group(:product_id).order("count desc") | Product.for_sale)
|
products = (@user.products.for_sale.select("products.*", "sum(order_items.count) as count").group(:product_id).order("count desc") | Product.for_sale)
|
||||||
@order.g_order_items products
|
products.each do |p|
|
||||||
|
@order.order_items.build(product: p)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
|
@ -29,18 +28,6 @@ class OrdersController < ApplicationController
|
||||||
@users = User.members.publik.order(:name)
|
@users = User.members.publik.order(:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def quickpay
|
|
||||||
user = User.find(params[:id])
|
|
||||||
order = user.orders.build
|
|
||||||
order.order_items << OrderItem.new(count: 1, product: user.dagschotel, order: order)
|
|
||||||
if order.save
|
|
||||||
flash[:success] = "Quick pay succeeded. #{view_context.link_to("Undo", [user, order], method: :delete)}."
|
|
||||||
else
|
|
||||||
flash[:error] = order.errors.full_messages.first
|
|
||||||
end
|
|
||||||
redirect_to root_path
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def order_params
|
def order_params
|
||||||
|
|
|
@ -4,11 +4,9 @@ class ProductsController < ApplicationController
|
||||||
respond_to :html, :js
|
respond_to :html, :js
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@product = Product.new
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def create
|
||||||
@product = Product.new(product_params)
|
|
||||||
if @product.save
|
if @product.save
|
||||||
flash[:success] = "Product created!"
|
flash[:success] = "Product created!"
|
||||||
redirect_to products_path
|
redirect_to products_path
|
||||||
|
@ -25,12 +23,10 @@ class ProductsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@product = Product.find(params[:id])
|
|
||||||
respond_with @product
|
respond_with @product
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@product = Product.find(params[:id])
|
|
||||||
@product.update_attributes product_params
|
@product.update_attributes product_params
|
||||||
respond_with @product
|
respond_with @product
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,7 +2,6 @@ class StocksController < ApplicationController
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@stock = Stock.new
|
|
||||||
Product.all.each do |p|
|
Product.all.each do |p|
|
||||||
@stock.stock_entries << Stock::StockEntry.new(product: p)
|
@stock.stock_entries << Stock::StockEntry.new(product: p)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
class UsersController < ApplicationController
|
class UsersController < ApplicationController
|
||||||
load_and_authorize_resource
|
load_and_authorize_resource
|
||||||
before_action :init, only: [:show, :edit, :update]
|
before_action :init, only: :show
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@categories = @user.products
|
|
||||||
.select("products.category", "sum(order_items.count) as count")
|
|
||||||
.group(:category)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
|
@ -26,15 +23,12 @@ class UsersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
user = User.find(params[:id])
|
@user.destroy
|
||||||
user.destroy
|
|
||||||
flash[:success] = "Succesfully removed user"
|
flash[:success] = "Succesfully removed user"
|
||||||
redirect_to users_path
|
redirect_to users_path
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit_dagschotel
|
def edit_dagschotel
|
||||||
@user = User.find(params[:id])
|
|
||||||
authorize! :update_dagschotel, @user
|
|
||||||
@dagschotel = @user.dagschotel
|
@dagschotel = @user.dagschotel
|
||||||
|
|
||||||
@products = Product.for_sale
|
@products = Product.for_sale
|
||||||
|
@ -42,14 +36,22 @@ class UsersController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_dagschotel
|
def update_dagschotel
|
||||||
user = User.find(params[:id])
|
@user.dagschotel = Product.find(params[:product_id])
|
||||||
authorize! :update_dagschotel, user
|
@user.save
|
||||||
|
|
||||||
user.dagschotel = Product.find(params[:product_id])
|
|
||||||
user.save
|
|
||||||
|
|
||||||
flash[:success] = "Succesfully updated dagschotel"
|
flash[:success] = "Succesfully updated dagschotel"
|
||||||
redirect_to user
|
redirect_to @user
|
||||||
|
end
|
||||||
|
|
||||||
|
def quickpay
|
||||||
|
order = @user.orders.build
|
||||||
|
order.order_items.build(count: 1, product: user.dagschotel)
|
||||||
|
if order.save
|
||||||
|
flash[:success] = "Quick pay succeeded. #{view_context.link_to("Undo", [user, order], method: :delete)}."
|
||||||
|
else
|
||||||
|
flash[:error] = order.errors.full_messages.first
|
||||||
|
end
|
||||||
|
redirect_to root_path
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -60,14 +62,5 @@ class UsersController < ApplicationController
|
||||||
|
|
||||||
def init
|
def init
|
||||||
@user = User.find_by_id(params[:id]) || current_user
|
@user = User.find_by_id(params[:id]) || current_user
|
||||||
@orders = @user.orders
|
|
||||||
.order(:created_at)
|
|
||||||
.reverse_order
|
|
||||||
.paginate(page: params[:page])
|
|
||||||
@products = @user.products
|
|
||||||
.select("products.*", "sum(order_items.count) as count")
|
|
||||||
.group(:product_id)
|
|
||||||
.order("count")
|
|
||||||
.reverse_order
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
module CallbacksHelper
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
module SessionsHelper
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
module StockHelper
|
|
||||||
end
|
|
|
@ -1,2 +0,0 @@
|
||||||
module WelcomeHelper
|
|
||||||
end
|
|
|
@ -2,8 +2,18 @@ TabApiJob = Struct.new(:order_id) do
|
||||||
def perform(*args)
|
def perform(*args)
|
||||||
order = Order.find_by(id: order_id)
|
order = Order.find_by(id: order_id)
|
||||||
if order && !order.transaction_id
|
if order && !order.transaction_id
|
||||||
body = { transaction: { debtor: order.user.uid, cents: order.price_cents, message: order.to_sentence, id_at_client: order.id } }
|
body = {
|
||||||
headers = { "Authorization" => "Token token=#{Rails.application.secrets.tab_api_key}" }
|
transaction: {
|
||||||
|
debtor: order.user.uid,
|
||||||
|
cents: order.price_cents,
|
||||||
|
message: order.to_sentence,
|
||||||
|
id_at_client: order.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
headers = {
|
||||||
|
"Authorization" => "Token token=#{Rails.application.secrets.tab_api_key}"
|
||||||
|
}
|
||||||
|
|
||||||
result = HTTParty.post("https://zeus.ugent.be/tab/transactions", body: body, headers: headers )
|
result = HTTParty.post("https://zeus.ugent.be/tab/transactions", body: body, headers: headers )
|
||||||
order.update_attribute(:transaction_id, JSON.parse(result.body)["id"].to_i)
|
order.update_attribute(:transaction_id, JSON.parse(result.body)["id"].to_i)
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,18 +2,21 @@ class Ability
|
||||||
include CanCan::Ability
|
include CanCan::Ability
|
||||||
|
|
||||||
def initialize(user)
|
def initialize(user)
|
||||||
user ||= User.new # guest user (not logged in)
|
return unless user
|
||||||
|
|
||||||
if user.admin?
|
if user.admin?
|
||||||
can :manage, :all
|
can :manage, :all
|
||||||
elsif user.koelkast?
|
elsif user.koelkast?
|
||||||
can :manage, Order
|
can :manage, Order
|
||||||
elsif user[:id]
|
else
|
||||||
can :read, :all
|
can :read, :all
|
||||||
can :manage, User, id: user.id
|
can :manage, User, id: user.id
|
||||||
can :manage, Order do |order|
|
can :create, Order do |order|
|
||||||
order.try(:user) == user
|
order.try(:user) == user
|
||||||
end
|
end
|
||||||
|
can :delete, Order do |order|
|
||||||
|
order.try(:user) == user && order.created_at > Rails.application.config.call_api_after.ago
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
# transaction_id :integer
|
# transaction_id :integer
|
||||||
#
|
#
|
||||||
|
|
||||||
require 'httparty'
|
|
||||||
class Order < ActiveRecord::Base
|
class Order < ActiveRecord::Base
|
||||||
include ActionView::Helpers::TextHelper
|
include ActionView::Helpers::TextHelper
|
||||||
|
|
||||||
|
@ -20,11 +19,12 @@ class Order < ActiveRecord::Base
|
||||||
|
|
||||||
before_validation :calculate_price
|
before_validation :calculate_price
|
||||||
before_save { |o| o.order_items = o.order_items.reject{ |oi| oi.count == 0 } }
|
before_save { |o| o.order_items = o.order_items.reject{ |oi| oi.count == 0 } }
|
||||||
after_create { Delayed::Job.enqueue TabApiJob.new(id) }
|
after_create :create_api_job
|
||||||
|
|
||||||
validates :user, presence: true
|
validates :user, presence: true
|
||||||
validates :order_items, presence: true, in_stock: true
|
validates :order_items, presence: true
|
||||||
validates :price_cents, presence: true
|
validates :price_cents, presence: true
|
||||||
|
validates_associated :order_items
|
||||||
|
|
||||||
accepts_nested_attributes_for :order_items
|
accepts_nested_attributes_for :order_items
|
||||||
|
|
||||||
|
@ -34,15 +34,17 @@ class Order < ActiveRecord::Base
|
||||||
}.to_sentence
|
}.to_sentence
|
||||||
end
|
end
|
||||||
|
|
||||||
def g_order_items(products)
|
|
||||||
products.each do |p|
|
|
||||||
self.order_items.build(product: p)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def calculate_price
|
def calculate_price
|
||||||
self.price_cents = self.order_items.map{ |oi| oi.count * oi.product.price_cents }.sum
|
self.price_cents = self.order_items.map{ |oi| oi.count * oi.product.price_cents }.sum
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def create_api_job
|
||||||
|
priority = 0
|
||||||
|
run_at = Rails.application.config.call_api_after.from_now
|
||||||
|
job = TabApiJob.new(id)
|
||||||
|
|
||||||
|
Delayed::Job.enqueue job, priority, run_at
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,25 +13,31 @@ class OrderItem < ActiveRecord::Base
|
||||||
belongs_to :product
|
belongs_to :product
|
||||||
|
|
||||||
validates :product, presence: true
|
validates :product, presence: true
|
||||||
validates :count, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
|
validates :count, presence: true, numericality: { only_integer: true,
|
||||||
|
less_than_or_equal_to: ->(oi) { oi.product.stock },
|
||||||
|
greater_than_or_equal_to: 0 }
|
||||||
|
|
||||||
before_destroy :put_back_in_stock
|
before_destroy :put_back_in_stock!
|
||||||
after_create :remove_from_stock
|
after_create :remove_from_stock!
|
||||||
|
|
||||||
accepts_nested_attributes_for :product
|
accepts_nested_attributes_for :product
|
||||||
|
|
||||||
def product_attributes=(attributes)
|
def product_attributes=(attributes)
|
||||||
self.product = Product.find(attributes[:id])
|
self.product = OrderItem.products.select{ |p| p.id == attributes[:id].to_i }.first
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.products
|
||||||
|
@products || Product.all
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def remove_from_stock
|
def remove_from_stock!
|
||||||
product.decrement!(:stock, count)
|
product.decrement!(:stock, count)
|
||||||
end
|
end
|
||||||
|
|
||||||
def put_back_in_stock
|
def put_back_in_stock!
|
||||||
product.increment!(:stock, self.count)
|
product.increment!(:stock, self.count)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -42,7 +42,7 @@ class Product < ActiveRecord::Base
|
||||||
self.price_cents = (value.to_f * 100).to_int
|
self.price_cents = (value.to_f * 100).to_int
|
||||||
end
|
end
|
||||||
|
|
||||||
def out_of_sale
|
def take_out_of_sale!
|
||||||
update_attribute :deleted, true
|
update_attribute :deleted, true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
|
|
||||||
require 'identicon'
|
require 'identicon'
|
||||||
class User < ActiveRecord::Base
|
class User < ActiveRecord::Base
|
||||||
|
include Statistics
|
||||||
|
|
||||||
devise :database_authenticatable, :trackable, :omniauthable, :omniauth_providers => [:zeuswpi]
|
devise :database_authenticatable, :trackable, :omniauthable, :omniauth_providers => [:zeuswpi]
|
||||||
|
|
||||||
has_paper_trail
|
has_paper_trail
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
class InStockValidator < ActiveModel::Validator
|
|
||||||
def validate(record)
|
|
||||||
p_short = []
|
|
||||||
record.order_items.each do |oi|
|
|
||||||
p_short.append oi.product.name if oi.count > oi.product.stock
|
|
||||||
end
|
|
||||||
record.errors.add(:base, "There is not enough stock for your order of the following products: #{p_short.join(', ')}") if p_short.size > 0
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -8,7 +8,6 @@
|
||||||
<%= order.to_sentence %>
|
<%= order.to_sentence %>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<% p order %>
|
|
||||||
<%= euro_from_cents(order.price_cents) %>
|
<%= euro_from_cents(order.price_cents) %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<ul class="list-group">
|
<ul class="list-group">
|
||||||
<li class="list-group-item text-muted">Orders</li>
|
<li class="list-group-item text-muted">Orders</li>
|
||||||
<li class="list-group-item"><strong>Orders placed</strong><span class="badge"><%= @user.orders_count %></span></li>
|
<li class="list-group-item"><strong>Orders placed</strong><span class="badge"><%= @user.orders_count %></span></li>
|
||||||
<li class="list-group-item"><strong>Products ordered</strong><span class="badge"><%= @products.map(&:count).sum %></span></li>
|
<li class="list-group-item"><strong>Products ordered</strong><span class="badge"><%= @user.products_group_by_id.map(&:count).sum %></span></li>
|
||||||
<% if can? :create, @user.orders.build %>
|
<% if can? :create, @user.orders.build %>
|
||||||
<li class="list-group-item"><%= link_to "Place new order", new_user_order_path(@user), class: "btn btn-default btn-block" %></li>
|
<li class="list-group-item"><%= link_to "Place new order", new_user_order_path(@user), class: "btn btn-default btn-block" %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -2,25 +2,25 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<%= render 'sidebar' %>
|
<%= render 'sidebar' %>
|
||||||
<div id="user_info" class="col-sm-9">
|
<div id="user_info" class="col-sm-9">
|
||||||
<% if @orders.any? %>
|
<% if (all_orders = @user.all_orders(params[:page])).any? %>
|
||||||
<h4>Previously ordered</h4>
|
<h4>Previously ordered</h4>
|
||||||
Total:
|
Total:
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<%= @categories.map{|c| pluralize(c.count, c.category)}.to_sentence %>
|
<%= @user.products_group_by_category.map{|c| pluralize(c.count, c.category)}.to_sentence %>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Specifics:
|
Specifics:
|
||||||
<%= content_tag :ul do %>
|
<%= content_tag :ul do %>
|
||||||
<% @products.each do |p| %>
|
<% @user.products_group_by_id.each do |p| %>
|
||||||
<%= content_tag :li, pluralize(p.count, p.name) %>
|
<%= content_tag :li, pluralize(p.count, p.name) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<h4>All orders (<%= @user.orders_count %>)</h4>
|
<h4>All orders (<%= @user.orders_count %>)</h4>
|
||||||
<table class="orders"><%= render @orders %></table>
|
<table class="orders"><%= render all_orders %></table>
|
||||||
<%= will_paginate @orders %>
|
<%= will_paginate all_orders %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,5 +21,6 @@ module Tab002
|
||||||
# config.i18n.default_locale = :de
|
# config.i18n.default_locale = :de
|
||||||
config.active_record.raise_in_transactional_callbacks = true
|
config.active_record.raise_in_transactional_callbacks = true
|
||||||
config.active_job.queue_adapter = :delayed_job
|
config.active_job.queue_adapter = :delayed_job
|
||||||
|
config.call_api_after = 5.minutes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,17 +18,17 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :users do
|
resources :users, only: [:show, :edit, :update, :destroy] do
|
||||||
resources :orders
|
resources :orders, only: [:new, :create, :destroy]
|
||||||
member do
|
member do
|
||||||
get 'quickpay' => 'orders#quickpay'
|
get 'quickpay' => 'users#quickpay'
|
||||||
get 'dagschotel/edit' => 'users#edit_dagschotel', as: 'edit_dagschotel'
|
get 'dagschotel/edit' => 'users#edit_dagschotel', as: 'edit_dagschotel'
|
||||||
get 'dagschotel/:product_id' => 'users#update_dagschotel', as: 'dagschotel'
|
get 'dagschotel/:product_id' => 'users#update_dagschotel', as: 'dagschotel'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :products
|
resources :products, only: [:new, :create, :index, :edit, :update]
|
||||||
resources :stocks
|
resources :stocks, only: [:new, :create]
|
||||||
|
|
||||||
get 'overview' => 'orders#overview', as: "orders"
|
get 'overview' => 'orders#overview', as: "orders"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue