Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API_Order #45

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/controllers/admin/orders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def batch_update
private

def update_orders order_ids, status
orders = Order.where(id: order_ids)
orders = Order.by_ids(order_ids)

orders.each do |order|
if order.cancelled?
Expand Down
136 changes: 136 additions & 0 deletions app/controllers/api/v1/admin/orders_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
class Api::V1::Admin::OrdersController < Api::V1::ApplicationController
before_action :find_order, only: %i(show update)

def index
@q = Order.ransack(params[:q])
@orders = filtered_orders(@q.result.order(id: :desc))
render json: @orders, each_serializer: OrderSerializer, status: :ok
end

def show
render json: @order, serializer: OrderSerializer, status: :ok
end

def update
ActiveRecord::Base.transaction do
handle_cancel_order if cancel_reason_present?
@order.update!(order_params)

if params[:order][:address].present? && @order.address.present?
@order.address.update!(address_params)
end

OrderEmailJob.perform_later(@order, @order.user, :update)
render json: {message: I18n.t("admin.orders_admin.update.success")},
status: :ok
rescue ActiveRecord::RecordInvalid => e
handle_update_error(e)
end
end

def batch_update
order_ids = order_ids_param
status = status_param

ActiveRecord::Base.transaction do
update_orders(order_ids, status)
end

render json: {message: I18n.t("admin.orders_admin.batch_update.success")},
status: :ok
rescue ActiveRecord::RecordInvalid => e
handle_batch_update_error(e)
end

private

def update_orders order_ids, status
orders = Order.by_ids(order_ids)

orders.each do |order|
if order.cancelled?
add_cancelled_order_alert(order)
else
order.update!(status:)
OrderEmailJob.perform_later(order, order.user, :update)
end
end
end

def add_cancelled_order_alert order
flash[:alert] ||= ""
flash[:alert] += "#{t('admin.orders_admin.batch_update.cancelled_order',
order_id: order.id)} "
end

def handle_batch_update_error exception
render json: {
error: t("admin.orders_admin.batch_update.error",
errors: exception.record.errors.full_messages.join(", "))
}, status: :unprocessable_entity
end

def order_ids_param
params[:order_ids] || []
end

def status_param
params[:status]
end

def find_order
@order = Order.find_by(id: params[:id])
return if @order

render json: {error: I18n.t("admin.orders_admin.not_found")},
status: :not_found
end

def order_params
params.require(:order).permit(Order::UPDATE_ORDER_ADMIN)
end

def address_params
params.require(:order).require(:address)
.permit(Address::ADDRESS_REQUIRE_ATTRIBUTES)
end

def cancel_reason_present?
params[:order][:cancel_reason].present?
end

def handle_cancel_order
@order.cancel_reason = params[:order][:cancel_reason]
@order.cancelled!
restore_product_stock
end

def restore_product_stock
@order.order_items.each do |order_item|
order_item.product.increment!(:stock, order_item.quantity)
end
end

def handle_update_error exception
render json: {
error: if exception.record == @order
t("admin.orders_admin.update.error_with_order",
errors: order_errors_message)
else
t("admin.orders_admin.update.error_with_address")
end
}, status: :unprocessable_entity
end

def order_errors_message
@order.errors.full_messages.join(", ")
end

def filtered_orders orders
if params[:status].present?
orders.by_status(params[:status])
else
orders
end
end
end
106 changes: 106 additions & 0 deletions app/controllers/api/v1/orders_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
class Api::V1::OrdersController < Api::V1::ApplicationController
before_action :authenticate_user!
before_action :load_cart_items, only: [:create]
before_action :find_order, only: [:show, :cancel]
before_action :load_user, :correct_user, only: [:index, :cancel]

def index
@orders = @user.orders.with_status(params[:status]).order(id: :asc)
render json: @orders, each_serializer: OrderSerializer, status: :ok
end

def show
render json: @order, status: :ok
end

def create
@order = Order.new(order_params)
@order.user = current_user
@order.total = calculate_cart_total

if @order.save
save_order_items(@order)
clear_cart
render json: @order, status: :created
else
Rails.logger.debug("Order errors: #{@order.errors.full_messages}")
render json: {error: I18n.t("orders.create_failed")},
status: :unprocessable_entity
end
end

def cancel
cancel_reason = params.dig(:order, :cancel_reason)

if @order.pending? && cancel_reason.present?
@order.update(cancel_reason:, status: "cancelled")
update_cart_items(@order)
render json: @order, status: :ok
else
render json: {error: I18n.t("orders.cancel_failed")},
status: :unprocessable_entity
end
end

private

def load_cart_items
@cart_items = current_cart_items
end

def current_cart_items
current_user.cart.cart_items.includes(product: :category)
end

def find_order
@order = Order.find_by(id: params[:id])
return if @order

render json: {error: I18n.t("orders.not_found")}, status: :not_found
end

def order_params
params.require(:order).permit(:address_id, :payment_method)
end

def calculate_cart_total
@cart_items.sum{|item| item.product.price * item.quantity}
end

def save_order_items order
@cart_items.each do |item|
order.order_items.create(
product_id: item.product_id,
price: item.product.price,
quantity: item.quantity
)
item.product.decrement!(:stock, item.quantity)
end
end

def clear_cart
current_user.cart.cart_items.destroy_all
end

def update_cart_items order
cart = current_user.cart || current_user.create_cart
order.order_items.each do |order_item|
cart_item = cart.cart_items.find_by(product_id: order_item.product_id)

if cart_item
increment_cart_item_quantity(cart_item, order_item)
else
create_new_cart_item(cart, order_item)
end
Product.find(order_item.product_id).increment!(:stock,
order_item.quantity)
end
end

def load_user
@user = User.find(params[:user_id])
return if @user

render json: {error: I18n.t("users.not_found")}, status: :not_found
end
end
2 changes: 1 addition & 1 deletion app/models/order.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Order < ApplicationRecord
after_create :send_order_notification

scope :ordered_by_updated_at, ->{order(updated_at: :desc)}

scope :by_ids, ->(ids){where(id: ids) if ids.present?}
scope :search, lambda {|query|
if query.present?
joins(:user, :address)
Expand Down
25 changes: 25 additions & 0 deletions app/serializers/order_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
class OrderSerializer < ActiveModel::Serializer
attributes :id, :status, :total, :cancel_reason, :created_at, :updated_at

has_one :user
has_many :order_items

def user
{
id: object.user.id,
name: object.user.user_name,
email: object.user.email
}
end

def order_items
object.order_items.map do |order_item|
{
product_id: order_item.product.id,
product_name: order_item.product.name,
quantity: order_item.quantity,
price: order_item.price
}
end
end
end
12 changes: 12 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@
namespace :v1 do
namespace :admin do
resources :products, only: %i(index show create update destroy)
resources :orders, only: %i(index show update) do
collection do
patch :batch_update
end
end
end
post "login", to: "auths#login"
resources :carts, only: :show do
Expand All @@ -91,6 +96,13 @@
delete "remove_item"
end
end
resources :users do
resources :orders, only: [:index, :show, :create, :update] do
member do
patch :cancel
end
end
end
end
end
end