Skip to main content

Overview

The auction module allows sellers to create time-limited auction products where customers can place bids. The highest bidder wins when the auction ends.

Bid Management

Track all bids with user and product relationships

Time-Limited

Set auction start and end times

Seller & Admin

Both admin and verified sellers can create auctions

Bid History

View complete bidding history per product

Model Structure

AuctionProductBid Model

The AuctionProductBid model tracks all bids placed on auction products:
class AuctionProductBid extends Model
{
    public function product(){
        return $this->belongsTo(Product::class);
    }
    
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}
Key Relationships:
  • product - Links bid to the auction product
  • user - Identifies the bidder
Database Fields:
  • product_id - Reference to auction product
  • user_id - Bidder’s user ID
  • amount - Bid amount
  • created_at - When bid was placed

Product Model Integration

Auction products are regular products with auction-specific fields:
// From Product model
public function bids()
{
    return $this->hasMany(AuctionProductBid::class);
}
Auction-specific product fields:
  • auction_product - Boolean flag (1 for auction products)
  • auction_start_date - When bidding opens
  • auction_end_date - When bidding closes
  • starting_bid - Minimum starting bid amount

Routes

Auction routes are defined in routes/auction.php:

Admin Routes

Route::group(['prefix' =>'admin', 'middleware' => ['auth', 'admin']], function(){
    // Auction product lists
    Route::controller(AuctionProductController::class)->group(function () {
        Route::get('auction/all-products', 'all_auction_product_list')
            ->name('auction.all_products');
        Route::get('auction/inhouse-products', 'inhouse_auction_products')
            ->name('auction.inhouse_products');
        Route::get('auction/seller-products', 'seller_auction_products')
            ->name('auction.seller_products');

        Route::get('/auction-product/create', 'product_create_admin')
            ->name('auction_product_create.admin');
        Route::post('/auction-product/store', 'product_store_admin')
            ->name('auction_product_store.admin');
        Route::get('/auction_products/edit/{id}', 'product_edit_admin')
            ->name('auction_product_edit.admin');
        Route::post('/auction_products/update/{id}', 'product_update_admin')
            ->name('auction_product_update.admin');
        Route::get('/auction_products/destroy/{id}', 'product_destroy_admin')
            ->name('auction_product_destroy.admin');

        // Sales
        Route::get('/auction_products-orders', 'admin_auction_product_orders')
            ->name('auction_products_orders');
    });
    
    Route::controller(AuctionProductBidController::class)->group(function () {
        Route::get('/product-bids/{id}', 'product_bids_admin')
            ->name('product_bids.admin');
        Route::get('/product-bids/destroy/{id}', 'bid_destroy_admin')
            ->name('product_bids_destroy.admin');
    });
});

Seller Routes

Route::group(['prefix' => 'seller', 'middleware' => ['seller', 'verified', 'user']], function() {
    Route::controller(AuctionProductController::class)->group(function () {
        Route::get('/auction_products', 'auction_product_list_seller')
            ->name('auction_products.seller.index');

        Route::get('/auction-product/create', 'product_create_seller')
            ->name('auction_product_create.seller');
        Route::post('/auction-product/store', 'product_store_seller')
            ->name('auction_product_store.seller');
        Route::get('/auction_products/edit/{id}', 'product_edit_seller')
            ->name('auction_product_edit.seller');
        Route::post('/auction_products/update/{id}', 'product_update_seller')
            ->name('auction_product_update.seller');
        Route::get('/auction_products/destroy/{id}', 'product_destroy_seller')
            ->name('auction_product_destroy.seller');

        Route::get('/auction_products-orders', 'seller_auction_product_orders')
            ->name('auction_products_orders.seller');
    });
    
    Route::controller(AuctionProductBidController::class)->group(function () {
        Route::get('/product-bids/{id}', 'product_bids_seller')
            ->name('product_bids.seller');
        Route::get('/product-bids/destroy/{id}', 'bid_destroy_seller')
            ->name('product_bids_destroy.seller');
    });
});

Customer Routes

// Authenticated users can bid
Route::group(['middleware' => ['auth']], function() {
    Route::resource('auction_product_bids', AuctionProductBidController::class);

    Route::post('/auction/cart/show-cart-modal', 
        [CartController::class, 'showCartModalAuction'])
        ->name('auction.cart.showCartModal');
        
    Route::get('/auction/purchase_history', 
        [AuctionProductController::class, 'purchase_history_user'])
        ->name('auction_product.purchase_history');
});

Public Routes

Route::post('/home/section/auction_products', 
    [HomeController::class, 'load_auction_products_section'])
    ->name('home.section.auction_products');

Route::controller(AuctionProductController::class)->group(function () {
    Route::get('/auction-product/{slug}', 'auction_product_details')
        ->name('auction-product');
    Route::get('/auction-products', 'all_auction_products')
        ->name('auction_products.all');
});

Bidding Workflow

1

Create Auction Product

Admin or seller creates product with auction flag, start/end dates, and starting bid
2

Customers View Auction

Browse active auctions and view current highest bid
3

Place Bid

Authenticated users submit bids higher than current highest bid
4

Track Bids

System records all bids with timestamps and user information
5

Auction Ends

Highest bidder wins when auction_end_date is reached
6

Process Order

Winner can complete purchase at their winning bid amount

Managing Bids

View Product Bids (Admin)

// Admin can view all bids for a product
Route::get('/product-bids/{id}', 'product_bids_admin')
    ->name('product_bids.admin');
Example implementation:
public function product_bids_admin($id)
{
    $product = Product::findOrFail($id);
    $bids = AuctionProductBid::where('product_id', $id)
        ->with('user')
        ->orderBy('amount', 'desc')
        ->orderBy('created_at', 'asc')
        ->paginate(20);
    
    return view('backend.auction.product_bids', compact('product', 'bids'));
}

View Product Bids (Seller)

// Seller can view bids on their auction products
Route::get('/product-bids/{id}', 'product_bids_seller')
    ->name('product_bids.seller');

Delete Bid

Admins and sellers can remove inappropriate bids:
// Admin delete
Route::get('/product-bids/destroy/{id}', 'bid_destroy_admin')
    ->name('product_bids_destroy.admin');

// Seller delete
Route::get('/product-bids/destroy/{id}', 'bid_destroy_seller')
    ->name('product_bids_destroy.seller');

Retrieving Auction Data

Get Highest Bid

public function getHighestBid($product_id)
{
    return AuctionProductBid::where('product_id', $product_id)
        ->orderBy('amount', 'desc')
        ->first();
}

Get Bid Count

public function getBidCount($product_id)
{
    return AuctionProductBid::where('product_id', $product_id)->count();
}

Get User’s Bids

public function getUserBids($user_id)
{
    return AuctionProductBid::where('user_id', $user_id)
        ->with('product')
        ->orderBy('created_at', 'desc')
        ->paginate(15);
}

Check if User is Winning

public function isUserWinning($product_id, $user_id)
{
    $highest_bid = $this->getHighestBid($product_id);
    return $highest_bid && $highest_bid->user_id == $user_id;
}

Auction Validation

Validate Bid Amount

public function validateBid($product_id, $bid_amount)
{
    $product = Product::findOrFail($product_id);
    
    // Check if auction is active
    if (now() < $product->auction_start_date) {
        return ['valid' => false, 'message' => 'Auction has not started yet'];
    }
    
    if (now() > $product->auction_end_date) {
        return ['valid' => false, 'message' => 'Auction has ended'];
    }
    
    // Check minimum bid
    $highest_bid = $this->getHighestBid($product_id);
    $minimum_required = $highest_bid 
        ? $highest_bid->amount + 1 
        : $product->starting_bid;
    
    if ($bid_amount < $minimum_required) {
        return [
            'valid' => false, 
            'message' => "Bid must be at least $minimum_required"
        ];
    }
    
    return ['valid' => true];
}

Place Bid

public function placeBid(Request $request)
{
    $validation = $this->validateBid(
        $request->product_id, 
        $request->bid_amount
    );
    
    if (!$validation['valid']) {
        flash(translate($validation['message']))->error();
        return back();
    }
    
    $bid = new AuctionProductBid();
    $bid->product_id = $request->product_id;
    $bid->user_id = Auth::user()->id;
    $bid->amount = $request->bid_amount;
    $bid->save();
    
    flash(translate('Bid placed successfully'))->success();
    return back();
}

Auction Listings

Active Auctions

public function getActiveAuctions()
{
    return Product::where('auction_product', 1)
        ->where('auction_start_date', '<=', now())
        ->where('auction_end_date', '>=', now())
        ->where('published', 1)
        ->orderBy('auction_end_date', 'asc')
        ->paginate(20);
}

Ending Soon

public function getEndingSoonAuctions($hours = 24)
{
    return Product::where('auction_product', 1)
        ->where('auction_start_date', '<=', now())
        ->where('auction_end_date', '>=', now())
        ->where('auction_end_date', '<=', now()->addHours($hours))
        ->where('published', 1)
        ->orderBy('auction_end_date', 'asc')
        ->get();
}

Purchase History

Users can view their won auctions:
Route::get('/auction/purchase_history', 
    [AuctionProductController::class, 'purchase_history_user'])
    ->name('auction_product.purchase_history');
Example implementation:
public function purchase_history_user()
{
    $orders = Order::where('user_id', Auth::user()->id)
        ->whereHas('order_details', function($query) {
            $query->whereHas('product', function($q) {
                $q->where('auction_product', 1);
            });
        })
        ->orderBy('created_at', 'desc')
        ->paginate(15);
    
    return view('frontend.user.auction_purchase_history', compact('orders'));
}

Order Management

View auction product orders:
// Admin orders
Route::get('/auction_products-orders', 'admin_auction_product_orders')
    ->name('auction_products_orders');

// Seller orders
Route::get('/auction_products-orders', 'seller_auction_product_orders')
    ->name('auction_products_orders.seller');

Cart Integration

Add winning bid to cart:
Route::post('/auction/cart/show-cart-modal', 
    [CartController::class, 'showCartModalAuction'])
    ->name('auction.cart.showCartModal');

Homepage Section

Load auction products section on homepage:
Route::post('/home/section/auction_products', 
    [HomeController::class, 'load_auction_products_section'])
    ->name('home.section.auction_products');

Best Practices

1

Set Reasonable Start Dates

Give buyers time to discover the auction before it ends
2

Validate Bids Server-Side

Always check bid amounts, auction timing, and user authentication on the backend
3

Notify Bidders

Send notifications when outbid or when auction ends
4

Handle Expired Auctions

Create scheduled tasks to process winning bids and notify winners
5

Prevent Seller Bidding

Ensure sellers cannot bid on their own auction products
Always validate auction timing and bid amounts on the server-side to prevent manipulation.

Wholesale Products

Another specialized product type with tiered pricing

Digital Products

Sell downloadable digital goods

Build docs developers (and LLMs) love