📄 web.php
📁 Path: //home/skhata/new.chandrapharma.com/routes/web.php
📊 Size: 23.3 KB
🔒 Perm: 0600
📝 MIME: text/x-php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
| Auth routes are loaded by AuthServiceProvider from Modules/Auth/routes.php.
| This file covers the storefront (public + authenticated customer routes).
*/
// ── Public Storefront ─────────────────────────────────────────────────────────
Route::get('/', [\App\Modules\Catalog\Controllers\StorefrontController::class, 'home'])
->name('home');
// Search
Route::get('/search', [\App\Modules\Search\Controllers\SearchController::class, 'index'])
->name('search');
Route::get('/search/autocomplete', [\App\Modules\Search\Controllers\SearchController::class, 'autocomplete'])
->name('search.autocomplete');
// Catalog — Categories
Route::get('/categories', [\App\Modules\Catalog\Controllers\CategoryController::class, 'index'])
->name('categories.index');
Route::get('/category/{slug}', [\App\Modules\Catalog\Controllers\CategoryController::class, 'show'])
->name('categories.show');
// Catalog — Products
Route::get('/products', [\App\Modules\Catalog\Controllers\ProductController::class, 'index'])
->name('products.index');
Route::get('/product/{slug}', [\App\Modules\Catalog\Controllers\ProductController::class, 'show'])
->name('products.show');
// Vendor storefront
Route::get('/store/{vendor:slug}', [\App\Modules\Vendor\Controllers\VendorStorefrontController::class, 'show'])
->name('vendor.store');
// ── Cart (guest + auth) ───────────────────────────────────────────────────────
Route::prefix('cart')->name('cart.')->group(function () {
Route::get('/', [\App\Modules\Cart\Controllers\CartController::class, 'index'])->name('index');
Route::post('/add', [\App\Modules\Cart\Controllers\CartController::class, 'add'])->name('add');
Route::patch('/item/{id}', [\App\Modules\Cart\Controllers\CartController::class, 'update'])->name('update');
Route::delete('/item/{id}', [\App\Modules\Cart\Controllers\CartController::class, 'remove'])->name('remove');
Route::delete('/clear', [\App\Modules\Cart\Controllers\CartController::class, 'clear'])->name('clear');
});
// ── Authenticated Customer Routes ─────────────────────────────────────────────
Route::middleware(['auth', 'verified'])->group(function () {
// Profile
Route::prefix('account')->name('account.')->group(function () {
Route::get('/', [\App\Modules\User\Controllers\ProfileController::class, 'show'])->name('show');
Route::put('/', [\App\Modules\User\Controllers\ProfileController::class, 'update'])->name('update');
// Addresses
Route::resource('addresses', \App\Modules\User\Controllers\AddressController::class)
->except(['show']);
});
// Orders
Route::prefix('orders')->name('orders.')->group(function () {
Route::get('/', [\App\Modules\Order\Controllers\OrderController::class, 'index'])->name('index');
Route::get('/{orderNumber}', [\App\Modules\Order\Controllers\OrderController::class, 'show'])->name('show');
Route::post('/{orderNumber}/cancel', [\App\Modules\Order\Controllers\OrderController::class, 'cancel'])->name('cancel');
});
});
// ── Phase 2: Guest Order Tracking ────────────────────────────────────────────
Route::get('/track', [\App\Modules\Order\Controllers\OrderTrackingController::class, 'trackForm'])
->name('orders.track.form');
Route::post('/track', [\App\Modules\Order\Controllers\OrderTrackingController::class, 'trackLookup'])
->name('orders.track.lookup');
Route::get('/track/{uuid}', [\App\Modules\Order\Controllers\OrderTrackingController::class, 'show'])
->name('orders.track');
// Checkout wizard (Livewire)
Route::get('/checkout', \App\Livewire\Checkout\CheckoutWizard::class)
->name('checkout.index')
->middleware(['web']); // guests allowed for checkout
// Checkout result pages
Route::get('/checkout/success/{order}', function (string $order) {
$orderModel = \App\Modules\Order\Models\Order::where('uuid', $order)->firstOrFail();
return view('checkout.success', compact('orderModel'));
})->name('checkout.success');
Route::get('/checkout/failure/{order}', function (string $order) {
$orderModel = \App\Modules\Order\Models\Order::where('uuid', $order)->firstOrFail();
return view('checkout.failure', compact('orderModel'));
})->name('checkout.failure');
// ── Phase 2: Payment Gateway Callbacks ───────────────────────────────────────
Route::prefix('payment')->name('payment.')->group(function () {
// eSewa
Route::get('/esewa/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'esewaCallback'])
->name('esewa.callback');
// Khalti
Route::get('/khalti/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'khaltiCallback'])
->name('khalti.callback');
// IME Pay (POST from gateway)
Route::match(['GET', 'POST'], '/imepay/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'imepayCallback'])
->name('imepay.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// Connect IPS
Route::match(['GET', 'POST'], '/connectips/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'connectipsCallback'])
->name('connectips.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// ── Phase 3: India + International ────────────────────────────────────────
// Razorpay (POST from Razorpay.js)
Route::post('/razorpay/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'razorpayCallback'])
->name('razorpay.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// Razorpay Webhook
Route::post('/razorpay/webhook', [\App\Modules\Payment\Controllers\PaymentController::class, 'razorpayWebhook'])
->name('razorpay.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// UPI callback (same flow as Razorpay)
Route::post('/upi/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'upiCallback'])
->name('upi.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// UPI polling endpoint (client polls while waiting for UPI app confirmation)
Route::get('/upi/poll/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'upiPoll'])
->name('upi.poll');
// Stripe (GET redirect with ?payment_intent=...)
Route::get('/stripe/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'stripeCallback'])
->name('stripe.callback');
// Stripe Webhook (POST from Stripe)
Route::post('/stripe/webhook', [\App\Modules\Payment\Controllers\PaymentController::class, 'stripeWebhook'])
->name('stripe.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// PayPal (GET redirect with ?token=...)
Route::get('/paypal/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'paypalCallback'])
->name('paypal.callback');
// PayPal Webhook
Route::post('/paypal/webhook', [\App\Modules\Payment\Controllers\PaymentController::class, 'paypalWebhook'])
->name('paypal.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// ── Phase 3: Paytm ────────────────────────────────────────────────────────
// Paytm posts callback to this URL after payment
Route::post('/paytm/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'paytmCallback'])
->name('paytm.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// Paytm server-to-server webhook
Route::post('/paytm/webhook', [\App\Modules\Payment\Controllers\PaymentController::class, 'paytmWebhook'])
->name('paytm.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// ── Phase 3: CCAvenue ─────────────────────────────────────────────────────
// CCAvenue posts encrypted response here after payment
Route::post('/ccavenue/callback/{order}', [\App\Modules\Payment\Controllers\PaymentController::class, 'ccavenueCallback'])
->name('ccavenue.callback')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
// CCAvenue server-to-server webhook
Route::post('/ccavenue/webhook', [\App\Modules\Payment\Controllers\PaymentController::class, 'ccavenueWebhook'])
->name('ccavenue.webhook')
->withoutMiddleware([\Illuminate\Foundation\Http\Middleware\VerifyCsrfToken::class]);
});
// ── Phase 2: Wishlist (auth) ──────────────────────────────────────────────────
Route::middleware('auth')->prefix('wishlist')->name('wishlist.')->group(function () {
Route::get('/', [\App\Modules\User\Controllers\WishlistController::class, 'index'])->name('index');
Route::post('/toggle', [\App\Modules\User\Controllers\WishlistController::class, 'toggle'])->name('toggle');
});
// ── Phase 2: Compare ─────────────────────────────────────────────────────────
Route::prefix('compare')->name('compare.')->group(function () {
Route::get('/', [\App\Modules\Catalog\Controllers\CompareController::class, 'index'])->name('index');
Route::post('/add/{productId}', [\App\Modules\Catalog\Controllers\CompareController::class, 'add'])->name('add');
Route::delete('/remove/{productId}', [\App\Modules\Catalog\Controllers\CompareController::class, 'remove'])->name('remove');
Route::delete('/clear', [\App\Modules\Catalog\Controllers\CompareController::class, 'clear'])->name('clear');
});
// ── Phase 2: Order Returns (auth) ────────────────────────────────────────────
Route::middleware('auth')->prefix('orders')->name('orders.')->group(function () {
Route::get('/{uuid}/detail', [\App\Modules\Order\Controllers\OrderTrackingController::class, 'orderDetail'])
->name('detail');
Route::get('/{uuid}/return/create', [\App\Modules\Order\Controllers\ReturnRequestController::class, 'create'])
->name('return.create');
Route::post('/{uuid}/return', [\App\Modules\Order\Controllers\ReturnRequestController::class, 'store'])
->name('return.store');
});
// ── Order Invoice / Slip (auth; owner or staff — deliberately NOT gated by
// 'verified' so unverified customers and staff can still print/download) ──
Route::middleware('auth')->prefix('orders')->name('orders.')->group(function () {
Route::get('/{orderNumber}/invoice', [\App\Modules\Order\Controllers\OrderInvoiceController::class, 'show'])
->name('invoice');
});
// ── Phase 2: Vendor — Bulk Import/Export + Dispatch ──────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
// Product bulk import/export
Route::get('/products/export', [\App\Modules\Catalog\Controllers\VendorImportExportController::class, 'export'])
->name('products.export');
Route::post('/products/import', [\App\Modules\Catalog\Controllers\VendorImportExportController::class, 'import'])
->name('products.import');
Route::post('/products/{product}/duplicate', [\App\Modules\Catalog\Controllers\VendorImportExportController::class, 'duplicate'])
->name('products.duplicate');
// Order dispatch + label printing
Route::post('/orders/{order}/dispatch', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'dispatch'])
->name('orders.dispatch');
Route::get('/orders/{order}/invoice', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'invoice'])
->name('orders.invoice');
Route::get('/orders/{order}/label/{size}', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'label'])
->name('orders.label');
// Returns
Route::get('/returns', [\App\Modules\Vendor\Controllers\VendorReturnController::class, 'index'])->name('returns.index');
Route::post('/returns/{return}/approve', [\App\Modules\Vendor\Controllers\VendorReturnController::class, 'approve'])->name('returns.approve');
Route::post('/returns/{return}/reject', [\App\Modules\Vendor\Controllers\VendorReturnController::class, 'reject'])->name('returns.reject');
});
// ── Vendor Dashboard (Phase 1 — vendor role) ──────────────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::get('/', [\App\Modules\Vendor\Controllers\VendorDashboardController::class, 'index'])->name('dashboard');
Route::get('/orders', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'index'])->name('orders');
Route::post('/orders/{order}/status', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'updateStatus'])->name('orders.status');
Route::get('/products', [\App\Modules\Vendor\Controllers\VendorProductController::class, 'index'])->name('products');
Route::get('/products/create', [\App\Modules\Vendor\Controllers\VendorProductController::class, 'create'])->name('products.create');
Route::post('/products', [\App\Modules\Vendor\Controllers\VendorProductController::class, 'store'])->name('products.store');
Route::get('/products/{product}/edit', [\App\Modules\Vendor\Controllers\VendorProductController::class, 'edit'])->name('products.edit');
Route::put('/products/{product}', [\App\Modules\Vendor\Controllers\VendorProductController::class, 'update'])->name('products.update');
});
// ── Phase 3: Customer return escalation ──────────────────────────────────────
Route::middleware('auth')->prefix('orders')->name('orders.')->group(function () {
Route::post('/{uuid}/return/{return}/escalate', [\App\Modules\Order\Controllers\ReturnRequestController::class, 'escalate'])
->name('return.escalate');
});
// ── Phase 3: Vendor partial dispatch ─────────────────────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::post('/orders/{order}/partial-dispatch', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'partialDispatch'])
->name('orders.partial-dispatch');
Route::get('/orders/{order}/fulfillment', [\App\Modules\Vendor\Controllers\VendorOrderController::class, 'fulfillment'])
->name('orders.fulfillment');
});
// ── Phase 3: Admin RMA dispute resolution ────────────────────────────────────
// Superseded by Filament ReturnResource — routes now live at /admin/returns
// via the Filament panel. The AdminReturnController actions (approve, reject,
// refund) are now handled by ViewReturn Filament page actions.
// ── Vendor Registration (multi-vendor mode only) ──────────────────────────────
Route::middleware(['auth', 'multivendor.only'])->group(function () {
Route::get('/become-vendor', [\App\Modules\Vendor\Controllers\VendorRegistrationController::class, 'create'])
->name('vendor.register');
Route::post('/become-vendor', [\App\Modules\Vendor\Controllers\VendorRegistrationController::class, 'store'])
->name('vendor.register.store');
});
// ── Phase 4: Reviews & Ratings (vendor) ──────────────────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::get('/reviews', [\App\Modules\Vendor\Controllers\VendorReviewController::class, 'index'])
->name('reviews');
Route::post('/reviews/{review}/reply', [\App\Modules\Vendor\Controllers\VendorReviewController::class, 'reply'])
->name('reviews.reply');
});
// ── Phase 3: Vendor Analytics ────────────────────────────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::get('/analytics', function () {
return view('vendor.analytics');
})->name('analytics');
});
// ── Phase 5: Flash Sales (public + vendor) ───────────────────────────────────
Route::get('/flash-sales', [\App\Modules\Promotions\Http\Controllers\FlashSaleController::class, 'index'])
->name('flash-sales.index');
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::get('/flash-sales', [\App\Modules\Vendor\Controllers\VendorFlashSaleController::class, 'index']) ->name('flash-sales.index');
Route::get('/flash-sales/create', [\App\Modules\Vendor\Controllers\VendorFlashSaleController::class, 'create']) ->name('flash-sales.create');
Route::post('/flash-sales', [\App\Modules\Vendor\Controllers\VendorFlashSaleController::class, 'store']) ->name('flash-sales.store');
Route::delete('/flash-sales/{flashSale}', [\App\Modules\Vendor\Controllers\VendorFlashSaleController::class, 'destroy'])->name('flash-sales.destroy');
});
// ── Phase 4: Vendor Payout & Ledger ──────────────────────────────────────────
Route::middleware(['auth', 'role:vendor'])->prefix('vendor-dashboard')->name('vendor.')->group(function () {
Route::get('/payouts', [\App\Modules\Vendor\Controllers\VendorPayoutController::class, 'index']) ->name('payouts.index');
Route::post('/payouts/request', [\App\Modules\Vendor\Controllers\VendorPayoutController::class, 'request'])->name('payouts.request');
});
// ── Blog & CMS (public) ───────────────────────────────────────────────────────
Route::prefix('blog')->name('blog.')->group(function () {
Route::get('/', [\App\Modules\Blog\Http\Controllers\BlogController::class, 'index']) ->name('index');
Route::get('/category/{slug}', [\App\Modules\Blog\Http\Controllers\BlogController::class, 'category'])->name('category');
Route::get('/{slug}', [\App\Modules\Blog\Http\Controllers\BlogController::class, 'show']) ->name('show');
});
// ── Pharmacy: Prescriptions (auth) ────────────────────────────────────────────
Route::middleware('auth')->prefix('prescriptions')->name('prescriptions.')->group(function () {
Route::get('/', [\App\Modules\Pharmacy\Controllers\PrescriptionController::class, 'index'])->name('index');
Route::get('/upload', [\App\Modules\Pharmacy\Controllers\PrescriptionController::class, 'create'])->name('create');
Route::post('/', [\App\Modules\Pharmacy\Controllers\PrescriptionController::class, 'store'])->name('store');
Route::get('/{prescription}', [\App\Modules\Pharmacy\Controllers\PrescriptionController::class, 'show'])->name('show');
});
// Legacy AdminReturnController route group removed — it shadowed the Filament
// ReturnResource's own routes at the same /admin/returns URL (same prefix,
// registered later), causing the Returns admin page to render via the old
// plain Blade view (no Filament sidebar) instead of inside the Filament panel
// shell. ReturnResource (ListReturns/ViewReturn) fully replaces it, including
// admin approve/reject/refund via header actions on ViewReturn.
// ── Admin: Translation proxy (admin-only) ────────────────────────────────────
Route::middleware(['auth', 'role:admin|super_admin'])->prefix('admin-api')->name('admin-api.')->group(function () {
Route::post('/translate', [\App\Modules\Admin\Controllers\TranslateController::class, 'translate'])
->name('translate');
});
// ── Support Tickets (auth) ───────────────────────────────────────────────────
Route::middleware('auth')->prefix('support')->name('support.')->group(function () {
Route::get('/', [\App\Modules\Support\Controllers\TicketController::class, 'index'])->name('index');
Route::get('/create', [\App\Modules\Support\Controllers\TicketController::class, 'create'])->name('create');
Route::post('/', [\App\Modules\Support\Controllers\TicketController::class, 'store'])->name('store');
Route::get('/{ticket}', [\App\Modules\Support\Controllers\TicketController::class, 'show'])->name('show');
Route::post('/{ticket}/reply', [\App\Modules\Support\Controllers\TicketController::class, 'reply'])->name('reply');
});
// ── CMS Static Pages ─────────────────────────────────────────────────────────
// Dynamic robots.txt from SEO settings
Route::get('/robots.txt', [\App\Modules\CMS\Http\Controllers\CmsPageController::class, 'robotsTxt'])
->name('robots.txt');
// Convenient named shortcuts for common pages
Route::get('/about', [\App\Modules\CMS\Http\Controllers\CmsPageController::class, 'show'])
->defaults('slug', 'about')->name('about');
Route::get('/contact', [\App\Modules\CMS\Http\Controllers\CmsPageController::class, 'show'])
->defaults('slug', 'contact')->name('contact');
Route::post('/contact', [\App\Modules\CMS\Http\Controllers\ContactController::class, 'submit'])
->middleware('throttle:5,1')->name('contact.submit');
// Generic catch-all for any CMS page slug — MUST be declared last to avoid
// conflicting with more-specific routes above.
Route::get('/page/{slug}', [\App\Modules\CMS\Http\Controllers\CmsPageController::class, 'show'])
->name('page.show')
->where('slug', '[a-z0-9\-]+');